This is the mail archive of the cygwin mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: setup.exe suggestion + patch


Igor Peshansky wrote:


Third, I have to apologize -- I've had a partial reply to your message
sitting in my drafts since the day you sent it, but got bogged down.

OK, I understand of course, I just wanted to check. Thanks for getting back to me Igor and Dave!


A few comments on the patch:
1) It would be great if you used "diff -up" -- unified diffs are so much
easier to read.

I attached the output of cvs diff -up. I also attached the two new files PopupMenu.{cc,h}, which I didn't realize were not included in the diff already.


2) Is there a reason you use popup menus, rather than pull-down lists?

I think pull-down lists would probably be nicer and more intuitive. Adding this is a much larger change, though, because you have to change the PickLine classes to paint the controls, and you have to modify the window procedures, etc. I can do all that, but wanted to gauge interest first. The drop-down menu way only takes a couple lines, and doesn't require dealing with the window procedure, so I thought it was a good way to start anyway. Note that my implementation of packagemeta::select_action(), which builds the menu, is also admittedly pretty quick and dirty. It's clear how to improve it, but it works fine the way it is and re-uses the already-debugged packagemeta::set_action() code.


-Lewis
/*
 * Copyright (c) 2002 Lewis Hyatt.
 *
 *     This program is free software; you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation; either version 2 of the License, or
 *     (at your option) any later version.
 *
 *     A copy of the GNU General Public License can be found at
 *     http://www.gnu.org/
 *
 * Written by Lewis Hyatt <lhyatt@princeton.edu>
 *
 */

#include "PopupMenu.h"
#include "Exception.h"
#include "resource.h"
#include "String++.h"
using namespace std;

void PopupMenu::init_menu(char const* const* const items, size_t const num_items)
{
	hMenu=0;
	static size_t const max_items = IDM_POPUP_LAST - IDM_POPUP_FIRST + 1;
	if(num_items > max_items) throw new Exception(TOSTRING (__LINE__) " " __FILE__, "Too many popup menu items");
	
	hMenu = CreatePopupMenu();
	for(size_t i=0; i!=num_items; ++i)
	  	AppendMenu(hMenu, MF_STRING, IDM_POPUP_FIRST+i, items[i]);
}

void PopupMenu::init_menu(string const* const items, size_t const num_items)
{
	vector<char const*> items_c(num_items);
	for(size_t i=0; i!=num_items; ++i) items_c[i] = items[i].c_str();
	init_menu(&items_c[0], num_items);
}

int PopupMenu::get_selection(int x, int y) const {
	if(x==position_undefined || y==position_undefined)	{
		POINT point;
		GetCursorPos(&point);
		if(x==position_undefined) x=point.x;
		if(y==position_undefined) y=point.y;
	}
	
	int const result = TrackPopupMenuEx(
		hMenu,
		TPM_CENTERALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RETURNCMD, 
		x, y,
		GetActiveWindow(),
		0
	);
	
	return result==0 ? -1 : result - IDM_POPUP_FIRST;
}
/*
 * Copyright (c) 2007 Lewis Hyatt.
 *
 *     This program is free software; you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation; either version 2 of the License, or
 *     (at your option) any later version.
 *
 *     A copy of the GNU General Public License can be found at
 *     http://www.gnu.org/
 *
 * Written by Lewis Hyatt <lhyatt@princeton.edu>
 *
 */
 
//the purpose of this class is to create a popup menu on the fly from a list of strings.
//the menu is displayed and then the index of the selected string is returned, or -1 if
//no string was selected. this class needs a block of IDs reserved for the menu items,
//which is defined by IDM_POPUP_FIRST and IDM_POPUP_LAST in resource.h.
 

#ifndef SETUP_POPUPMENU_H
#define SETUP_POPUPMENU_H

#include "win32.h"
#include <string>
#include <vector>

class PopupMenu	{
	HMENU hMenu;
	
	//make non-copyable for simplicity
	PopupMenu(PopupMenu const&);
	PopupMenu& operator=(PopupMenu const*);
	
	//the init function is private because it is only called from the constructor
	void init_menu(char const* const* items, size_t num_items);
	void init_menu(std::string const* items, size_t num_items);
public:

	//constructor creates the menu but does not show it. there are a few overloads so you can pass an
	//array of char*, an array of string, or a vector of string.
	
	PopupMenu(char const* const* items, size_t num_items)
	{
		init_menu(items, num_items);
	}
	
	PopupMenu(std::string const* items, size_t num_items)
	{
		init_menu(items, num_items);
	}
	
	explicit PopupMenu(std::vector<std::string> const& items)
	{
		init_menu(&items[0], items.size());
	}
	
	//get_selection shows the menu and returns the index of the selected item.
	//the x and y parameters let you pick where to show the menu; leave them
	//undefined to show at the current cursor location.
	
	enum {position_undefined = -1};
	int get_selection(int x=position_undefined, int y=position_undefined) const;
	
	//destructor frees the menu
	~PopupMenu()
	{
		DestroyMenu(hMenu);
	}
};

#endif /* SETUP_POPUPMENU_H */
? setup/.deps
? setup/.libs
? setup/Makefile
? setup/PopupMenu.cc
? setup/PopupMenu.h
? setup/config.cache
? setup/config.log
? setup/config.status
? setup/inilex.cc
? setup/iniparse.cc
? setup/iniparse.h
? setup/libtool
? setup/setup_version.c
? setup/csu_util/.deps
? setup/csu_util/.dirstamp
? setup/libgetopt++/.libs
? setup/libgetopt++/Makefile
? setup/libgetopt++/config.log
? setup/libgetopt++/config.status
? setup/libgetopt++/libgetopt++.la
? setup/libgetopt++/libtool
? setup/libgetopt++/include/autoconf.h
? setup/libgetopt++/include/stamp-h1
? setup/libgetopt++/src/.deps
? setup/libgetopt++/src/.dirstamp
? setup/libgetopt++/src/BoolOption.lo
? setup/libgetopt++/src/GetOption.lo
? setup/libgetopt++/src/Option.lo
? setup/libgetopt++/src/OptionSet.lo
? setup/libgetopt++/src/StringOption.lo
? setup/libgetopt++/tests/.deps
? setup/libmd5-rfc/.deps
? setup/libmd5-rfc/.dirstamp
? setup/tests/.deps
? setup/tests/Makefile
Index: setup/Makefile.am
===================================================================
RCS file: /cvs/cygwin-apps/setup/Makefile.am,v
retrieving revision 2.68
diff -u -p -r2.68 Makefile.am
--- setup/Makefile.am	30 Jul 2007 22:55:49 -0000	2.68
+++ setup/Makefile.am	13 Sep 2007 18:37:32 -0000
@@ -228,6 +228,8 @@ setup_SOURCES = \
 	PickPackageLine.h \
 	PickView.cc \
 	PickView.h \
+	PopupMenu.h \
+	PopupMenu.cc \
 	postinstall.cc \
 	prereq.cc \
 	prereq.h \
Index: setup/PickCategoryLine.cc
===================================================================
RCS file: /cvs/cygwin-apps/setup/PickCategoryLine.cc,v
retrieving revision 2.10
diff -u -p -r2.10 PickCategoryLine.cc
--- setup/PickCategoryLine.cc	24 May 2006 13:01:34 -0000	2.10
+++ setup/PickCategoryLine.cc	13 Sep 2007 18:37:32 -0000
@@ -16,6 +16,7 @@
 #include "PickCategoryLine.h"
 #include "package_db.h"
 #include "PickView.h"
+#include "PopupMenu.h"
 
 void
 PickCategoryLine::empty (void)
@@ -110,11 +111,12 @@ PickCategoryLine::click (int const myrow
     {
       if ((size_t) x >= spin_x)
 	{
-	  ++current_default;
-	  
-          packagedb().markUnVisited();
-
-	  return set_action (current_default);
+	  //create a popup menu for the user to select the desired action
+	  PopupMenu menu(packagemeta::_actions::captions, packagemeta::_actions::num_actions);
+	  int const selection = menu.get_selection();
+	  if(selection<0) return 0;	  
+	  packagedb().markUnVisited();
+	  return set_action(selection);
 	}
       else
 	{
Index: setup/PickPackageLine.cc
===================================================================
RCS file: /cvs/cygwin-apps/setup/PickPackageLine.cc,v
retrieving revision 2.21
diff -u -p -r2.21 PickPackageLine.cc
--- setup/PickPackageLine.cc	24 May 2006 13:01:34 -0000	2.21
+++ setup/PickPackageLine.cc	13 Sep 2007 18:37:32 -0000
@@ -134,7 +134,10 @@ PickPackageLine::click (int const myrow,
 
   if (x >= theView.headers[theView.new_col].x - HMARGIN / 2
       && x <= theView.headers[theView.new_col + 1].x - HMARGIN / 2)
-    pkg.set_action (pkg.trustp(theView.deftrust));
+  {
+    	//pkg.set_action (pkg.trustp(theView.deftrust));
+    	pkg.select_action(pkg.trustp(theView.deftrust));
+  }
 
   packagedb().markUnVisited();
   /* Add any packages that are needed by this package */
Index: setup/package_meta.cc
===================================================================
RCS file: /cvs/cygwin-apps/setup/package_meta.cc,v
retrieving revision 2.52
diff -u -p -r2.52 package_meta.cc
--- setup/package_meta.cc	17 Apr 2006 16:13:17 -0000	2.52
+++ setup/package_meta.cc	13 Sep 2007 18:37:33 -0000
@@ -18,6 +18,7 @@ static const char *cvsid = "\n%%% $Id: p
 #endif
 
 #include "package_meta.h"
+#include "PopupMenu.h"
 
 #include <string>
 #include <set>
@@ -65,23 +66,14 @@ const
   packagemeta::_actions
 packagemeta::Uninstall_action (3);
 
-char const *
-packagemeta::_actions::caption ()
-{
-  switch (_value)
-    {
-    case 0:
-      return "Default";
-    case 1:
-      return "Install";
-    case 2:
-      return "Reinstall";
-    case 3:
-      return "Uninstall";
-    }
-  // Pacify GCC: (all case options are checked above)
-  return 0;
-}
+//action caption definitions
+//TODO: this could be grabbed from the resource file instead
+char const* const packagemeta::_actions::captions[packagemeta::_actions::num_actions] = {
+	"Default",
+	"Install",
+	"Reinstall",
+	"Uninstall"
+};
 
 packagemeta::packagemeta (packagemeta const &rhs) :
   name (rhs.name), key (rhs.name), installed_from (), 
@@ -99,7 +91,7 @@ packagemeta::packagemeta (packagemeta co
 packagemeta::_actions & packagemeta::_actions::operator++ ()
 {
   ++_value;
-  if (_value > 3)
+  if (_value >= num_actions)
     _value = 0;
   return *this;
 }
@@ -410,6 +402,30 @@ packagemeta::set_action (packageversion 
     }
 }
 
+void packagemeta::select_action(packageversion const& default_version)	{
+	vector<string> actions;
+	
+	//in order to avoid duplicating all of the logic in set_action() above, we will instead just call set_action repeatedly
+	//to see what it would have done, and then put all of that in the menu.
+	//this is a little silly, but the assumption is that set_action() is fast, so it isn't such a waste to just call it once for
+	//all actions, and then call it again for the one the user actually wanted.
+	//this is quick and dirty, a better solution would be to get rid of set_action, and just reformulate its logic into this function.
+	//I am willing to do that, if there is agreement that this is an improvement over the old way of just cycling through. -Lewis
+	
+	string next_action=action_caption();
+	do	{
+		actions.push_back(next_action);
+		set_action(default_version);
+		next_action = action_caption();
+	} while(next_action != actions.front());
+	
+	PopupMenu menu(actions);
+	int const selection = menu.get_selection();
+	
+	//again we use a silly inefficient for loop so we don't have to think about what all set_action was actually doing.
+	for(int i=0; i<selection; ++i) set_action(default_version); //note case i<0 (no selection) is handled correctly.
+}
+
 int
 packagemeta::set_requirements (trusts deftrust, size_t depth)
 {
Index: setup/package_meta.h
===================================================================
RCS file: /cvs/cygwin-apps/setup/package_meta.h,v
retrieving revision 2.36
diff -u -p -r2.36 package_meta.h
--- setup/package_meta.h	17 Apr 2006 16:13:17 -0000	2.36
+++ setup/package_meta.h	13 Sep 2007 18:37:33 -0000
@@ -60,16 +60,19 @@ public:
   class _actions
   {
   public:
+  	enum {num_actions = 4};
+  	static char const* const captions[num_actions];
     _actions ():_value (0) {};
     _actions (int aInt) {
-    _value = aInt;
-    if (_value < 0 ||  _value > 3)
+    	_value = aInt;
+       if (_value < 0 ||  _value >= num_actions)
       _value = 0;
     }
     _actions & operator ++ ();
     bool operator == (_actions const &rhs) { return _value == rhs._value; }
     bool operator != (_actions const &rhs) { return _value != rhs._value; }
-    const char *caption ();
+    const char *caption() const {return caption(_value);}
+    static const char* caption(int const value) {return captions[value];}
   private:
     int _value;
   };
@@ -78,6 +81,7 @@ public:
   static const _actions Reinstall_action;
   static const _actions Uninstall_action;
   void set_action (packageversion const &default_version);
+  void select_action(packageversion const &default_version);
   void set_action (_actions, packageversion const & default_version);
   void uninstall ();
   int set_requirements (trusts deftrust, size_t depth);
Index: setup/resource.h
===================================================================
RCS file: /cvs/cygwin-apps/setup/resource.h,v
retrieving revision 2.35
diff -u -p -r2.35 resource.h
--- setup/resource.h	4 May 2007 21:56:53 -0000	2.35
+++ setup/resource.h	13 Sep 2007 18:37:35 -0000
@@ -159,3 +159,9 @@
 #define IDC_STATUS_HEADER                 582
 #define IDC_STATUS                        583
 #define IDC_STATIC_HEADER                 584
+
+//popup menus
+
+//note: numbers 600-699 are reserved for popup menus; see PopupMenu.h
+#define IDM_POPUP_FIRST			600
+#define IDM_POPUP_LAST			699

--
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
Problem reports:       http://cygwin.com/problems.html
Documentation:         http://cygwin.com/docs.html
FAQ:                   http://cygwin.com/faq/

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]