Complete.Org: Mailing Lists: Archives: freeciv-dev: August 2003:
[Freeciv-Dev] Re: (PR#4426) Adding worklist commands to gui-gtk-2.0 city
Home

[Freeciv-Dev] Re: (PR#4426) Adding worklist commands to gui-gtk-2.0 city

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: undisclosed-recipients: ;
Subject: [Freeciv-Dev] Re: (PR#4426) Adding worklist commands to gui-gtk-2.0 city report dialog
From: "jjc@xxxxxxxxxxxxxxxxxx" <jjc@xxxxxxxxxxxxxxxxxx>
Date: Fri, 29 Aug 2003 15:03:13 -0700
Reply-to: rt@xxxxxxxxxxxxxx

Detailed description of patch:
Adds three new menus after the change menu in the city report dialog
(the city report dialog is the one with the list of all the cities) for
the gtk2 client.  These menus implement the following abilities for 
modifying cities worklists:
First: Add the new production ahead of everything (including current
        production), moving everything back.
Next: Add the new production ahead of everything EXCEPT current production
Last: Add it to the end of the worklist.

This patch adds two new convenience function for working with worklists
in common/worklist.h :

/***************************************************************
Adds the id to the next available slot in the worklist
Returns true if successful.
***************************************************************/
bool worklist_append(struct worklist *pwl, int id, bool is_unit);

/***************************************************************
Inserts the id to the location idx in the worklist
Moves all other ids back an index.
Returns true if successful.
***************************************************************/
bool worklist_insert(struct worklist *pwl, int id, bool is_unit, int idx);

These functions are used to implement the above abilities.


Reason for existance:
I often want to add something to several cities worklists.  For example,
when I discover university I would like to have all my science producing
cities build one.  With this patch I can sort the list by CMA or by amount
of science, and then select the first few cities, and then go to last->
improvement->University and university will be added to the worklist of 
all those cities. If I had used the change instead, it would have killed the 
current projects of the cities that I had selected.

Additional Comments:
A patch to do this has been requested at least twice on freeciv-dev.

This patch does not implement any new network protocols and can be built into
a client and used with standard unmodified servers.

This patch will silently refuse to do a command that will cause the 
worklist to overflow.

The commands Next and Last do not check to see if and pending improvements
will allow additional improvements to be made. For example, if a Library is
currently being built, they do not allow University to be added until the 
library is completed.

Changes since last posting:
Added the function worklist_insert
Added an implementation of the First and Next commands as requested by 
        John Wheeler.
Changed name of Append to Last.
Fixed bug in worklist_append that would occur if the worklist was almost
        full.  Previously, append would put a WEF_END in the entry after 
        the last location in the worklist array.

Patch review comment:
I will gladly review a patch or three in exchange for someone reviewing this
patch.  Just email me the rt patch number that you want reviewed (I use the 
gtk2 gui so probably can't review other gui's) by Sunday and I will take 
a look at it then.


-- 
Josh Cogliati


Index: client/gui-gtk-2.0/cityrep.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/cityrep.c,v
retrieving revision 1.47
diff -U9 -r1.47 cityrep.c
--- client/gui-gtk-2.0/cityrep.c        2003/07/29 04:49:53     1.47
+++ client/gui-gtk-2.0/cityrep.c        2003/08/29 20:36:18
@@ -46,51 +46,74 @@
 #include "climisc.h"
 
 #include "cityrep.h"
 #include "cma_fec.h"
 
 #define NEG_VAL(x)  ((x)<0 ? (x) : (-x))
 #define CMA_NONE       (-1)
 #define CMA_CUSTOM     (-2)
 
+enum city_operation_type { CO_CHANGE, CO_LAST, CO_NEXT, CO_FIRST, CO_NONE };
+
 /******************************************************************/
 static void create_city_report_dialog(bool make_modal);
 static void city_model_init(void);
 
 static void city_center_callback(GtkWidget *w, gpointer data);
 static void city_popup_callback(GtkWidget *w, gpointer data);
 static void city_activated_callback(GtkTreeView *view, GtkTreePath *path,
                                    GtkTreeViewColumn *col, gpointer data);
 
 static void city_buy_callback(GtkWidget *w, gpointer data);
 static void city_refresh_callback(GtkWidget *w, gpointer data);
 static void city_selection_changed_callback(GtkTreeSelection *selection);
 
 static void create_select_menu(GtkWidget *item);
 static void create_change_menu(GtkWidget *item);
+static void create_last_menu(GtkWidget *item);
+static void create_first_menu(GtkWidget *item);
+static void create_next_menu(GtkWidget *item);
 
 static GtkWidget *city_dialog_shell=NULL;
 
 static GtkWidget *city_view;
 static GtkTreeSelection *city_selection;
 static GtkListStore *city_model;
 
 static void popup_select_menu(GtkMenuShell *menu, gpointer data);
 static void popup_change_menu(GtkMenuShell *menu, gpointer data);
+static void popup_last_menu(GtkMenuShell *menu, gpointer data);
+static void popup_first_menu(GtkMenuShell *menu, gpointer data);
+static void popup_next_menu(GtkMenuShell *menu, gpointer data);
 
 static GtkWidget *city_center_command, *city_popup_command, *city_buy_command;
 static GtkWidget *city_change_command;
+static GtkWidget *city_last_command, *city_first_command, *city_next_command;
+
 
 static GtkWidget *change_improvements_item;
 static GtkWidget *change_units_item;
 static GtkWidget *change_wonders_item;
 static GtkWidget *change_cma_item;
 
+static GtkWidget *last_improvements_item;
+static GtkWidget *last_units_item;
+static GtkWidget *last_wonders_item;
+
+static GtkWidget *first_improvements_item;
+static GtkWidget *first_units_item;
+static GtkWidget *first_wonders_item;
+
+static GtkWidget *next_improvements_item;
+static GtkWidget *next_units_item;
+static GtkWidget *next_wonders_item;
+
+
 static GtkWidget *select_island_item;
 
 static GtkWidget *select_bunit_item;
 static GtkWidget *select_bimprovement_item;
 static GtkWidget *select_bwonder_item;
 
 static GtkWidget *select_supported_item;
 static GtkWidget *select_present_item;
 static GtkWidget *select_built_improvements_item;
@@ -159,19 +182,20 @@
 *****************************************************************/
 typedef bool (*TestCityFunc)(struct city *, gint);
 
 /****************************************************************
 ...
 *****************************************************************/
 static void append_impr_or_unit_to_menu_item(GtkMenuItem *parent_item,
                                             bool append_units,
                                             bool append_wonders,
-                                            bool change_prod,
+                                            enum city_operation_type 
+                                            city_operation, 
                                             TestCityFunc test_func,
                                             GCallback callback,
                                             int size)
 {
   GtkWidget *menu;
   cid cids[U_LAST + B_LAST];
   struct item items[U_LAST + B_LAST];
   int i, item, cids_used;
   char *row[4];
@@ -182,19 +206,19 @@
     "weight=\"bold\"",
     "",
     ""
   };
 
   gtk_menu_item_remove_submenu(parent_item);
   menu = gtk_menu_new();
   gtk_menu_item_set_submenu(parent_item, menu);
 
-  if (change_prod) {
+  if (city_operation != CO_NONE) {
     GPtrArray *selected;
     ITree it;
     int num_selected = 0;
     GtkTreeModel *model = GTK_TREE_MODEL(city_model);
     struct city **data;
 
     selected = g_ptr_array_sized_new(size);
 
     for (itree_begin(model, &it); !itree_end(&it); itree_next(&it)) {
@@ -204,34 +228,34 @@
        continue;
 
       itree_get(&it, 0, &res, -1);
       g_ptr_array_add(selected, res);
       num_selected++;
     }
 
     data = (struct city **)g_ptr_array_free(selected, FALSE);
     cids_used = collect_cids1(cids, data, num_selected, append_units,
-                             append_wonders, change_prod, test_func);
+                             append_wonders, TRUE, test_func);
     g_free(data);
   } else {
     cids_used = collect_cids1(cids, NULL, 0, append_units,
-                             append_wonders, change_prod, test_func);
+                             append_wonders, FALSE, test_func);
   }
 
-  name_and_sort_items(cids, cids_used, items, change_prod, NULL);
+  name_and_sort_items(cids, cids_used, items, city_operation != CO_NONE, NULL);
 
   for (i = 0; i < 4; i++) {
     row[i] = buf[i];
   }
 
   g_object_set_data(G_OBJECT(menu), "freeciv_test_func", test_func);
-  g_object_set_data(G_OBJECT(menu), "freeciv_change_prod",
-                   GINT_TO_POINTER(change_prod));
+  g_object_set_data(G_OBJECT(menu), "freeciv_city_operation",
+                   GINT_TO_POINTER(city_operation));
 
   for (i = 0; i < 3; i++) {
     group[i] = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
   }
   
   for (item = 0; item < cids_used; item++) {
     cid cid = items[item].cid;
     GtkWidget *menu_item, *hbox, *label;
     char txt[256];
@@ -290,30 +314,124 @@
   /* FIXME: don't use network packet structures here. */
   packet = *(struct packet_city_request *)data;
   gtk_tree_model_get(model, it, 1, &id, -1);
 
   city_change_production(find_city_by_id(id),
                         packet.is_build_id_unit_id, packet.build_id);
 }
 
 /****************************************************************
+called by select_impr_or_unit_callback for each city that 
+is selected in the city list dialog to have a object appended
+to the worklist.  Sends a packet adding the item to the 
+end of the worklist.
+*****************************************************************/
+static void worklist_last_impr_or_unit_iterate(GtkTreeModel *model, 
+                                                GtkTreePath *path,
+                                                GtkTreeIter *it, 
+                                                gpointer data)
+{
+  struct packet_city_request packet;
+  gint id;
+  struct city *pcity;  
+
+  packet = *(struct packet_city_request *)data;
+  gtk_tree_model_get(model, it, 1, &id, -1);
+  pcity = city_list_find_id(&game.player_ptr->cities,id);
+  /* try to add the object to the worklist */
+  if(worklist_append(&pcity->worklist, packet.build_id, 
+                    packet.is_build_id_unit_id)) {
+    copy_worklist(&packet.worklist, &pcity->worklist);
+    
+    packet.city_id = id;
+    send_packet_city_request(&aconnection, &packet, PACKET_CITY_WORKLIST);
+  } /* Perhaps should warn the user if not successful? */
+}
+
+/****************************************************************
+called by select_impr_or_unit_callback for each city that 
+is selected in the city list dialog to have a object inserted first
+to the worklist.  Sends a packet adding the current production to the 
+first place after the current production of the worklist.
+Then changes the production to the requested item.
+*****************************************************************/
+static void worklist_first_impr_or_unit_iterate(GtkTreeModel *model, 
+                                                GtkTreePath *path,
+                                                GtkTreeIter *it, 
+                                                gpointer data)
+{
+  struct packet_city_request packet;
+  gint id;
+  struct city *pcity;  
+  int old_id;
+  bool old_is_build_id_unit_id;
+
+  packet = *(struct packet_city_request *)data;
+  gtk_tree_model_get(model, it, 1, &id, -1);
+  pcity = city_list_find_id(&game.player_ptr->cities,id);
+  old_id = pcity->currently_building;
+  old_is_build_id_unit_id = pcity->is_building_unit;
+  /* First try and insert the old production into the worklist */
+  if (worklist_insert(&pcity->worklist, old_id, 
+                     old_is_build_id_unit_id, 0)) {
+    copy_worklist(&packet.worklist, &pcity->worklist);
+
+    packet.city_id = id;
+    send_packet_city_request(&aconnection, &packet, PACKET_CITY_WORKLIST);
+
+    /* next change the current production to the new production */
+    city_change_production(find_city_by_id(id),
+                          packet.is_build_id_unit_id, packet.build_id);
+
+  }
+}
+
+/****************************************************************
+called by select_impr_or_unit_callback for each city that 
+is selected in the city list dialog to have a object added next
+to the worklist.  Sends a packet adding the item to the 
+first place after the current production of the worklist.
+*****************************************************************/
+static void worklist_next_impr_or_unit_iterate(GtkTreeModel *model, 
+                                                GtkTreePath *path,
+                                                GtkTreeIter *it, 
+                                                gpointer data)
+{
+  struct packet_city_request packet;
+  gint id;
+  struct city *pcity;  
+
+  packet = *(struct packet_city_request *)data;
+  gtk_tree_model_get(model, it, 1, &id, -1);
+  pcity = city_list_find_id(&game.player_ptr->cities,id);
+  if (worklist_insert(&pcity->worklist, packet.build_id, 
+                     packet.is_build_id_unit_id, 0)) {
+    copy_worklist(&packet.worklist, &pcity->worklist);
+
+    packet.city_id = id;
+    send_packet_city_request(&aconnection, &packet, PACKET_CITY_WORKLIST);
+  }
+}
+
+
+/****************************************************************
 ...
 *****************************************************************/
 static void select_impr_or_unit_callback(GtkWidget *w, gpointer data)
 {
   cid cid = GPOINTER_TO_INT(data);
   GObject *parent = G_OBJECT(w->parent);
   TestCityFunc test_func = g_object_get_data(parent, "freeciv_test_func");
-  bool change_prod = 
-    GPOINTER_TO_INT(g_object_get_data(parent, "freeciv_change_prod"));
+  enum city_operation_type city_operation = 
+    GPOINTER_TO_INT(g_object_get_data(parent, "freeciv_city_operation"));  
 
-  /* If this is not the change production button */
-  if (!change_prod) {
+  /* If this is not a city operation */
+  if (city_operation == CO_NONE) {
     ITree it;
     GtkTreeModel *model = GTK_TREE_MODEL(city_model);
 
     gtk_tree_selection_unselect_all(city_selection);
     for (itree_begin(model, &it); !itree_end(&it); itree_next(&it)) {
       struct city *pcity;
       gpointer res;
       
       itree_get(&it, 0, &res, -1);
@@ -326,20 +444,41 @@
   } else {
     bool is_unit = cid_is_unit(cid);
     int id = cid_id(cid);
     struct packet_city_request packet;
 
     packet.build_id = id;
     packet.is_build_id_unit_id = is_unit;
 
     connection_do_buffer(&aconnection);
-    gtk_tree_selection_selected_foreach(city_selection, impr_or_unit_iterate,
-       &packet);
+    switch (city_operation) {
+    case CO_LAST:
+      gtk_tree_selection_selected_foreach(city_selection, 
+                                         worklist_last_impr_or_unit_iterate,
+                                         &packet);
+      break;
+    case CO_CHANGE:
+      gtk_tree_selection_selected_foreach(city_selection, impr_or_unit_iterate,
+                                         &packet);
+      break;
+    case CO_FIRST:
+      gtk_tree_selection_selected_foreach(city_selection, 
+                                         worklist_first_impr_or_unit_iterate,
+                                         &packet);
+      break;
+    case CO_NEXT:
+      gtk_tree_selection_selected_foreach(city_selection, 
+                                         worklist_next_impr_or_unit_iterate,
+                                         &packet);
+      break;
+    default:
+      assert(FALSE); /* should never get here */
+    }
     connection_do_unbuffer(&aconnection);
   }
 }
 
 /****************************************************************
 ...
 *****************************************************************/
 static void cma_iterate(GtkTreeModel *model, GtkTreePath *path,
                        GtkTreeIter *it, gpointer data)
@@ -557,18 +696,33 @@
   GtkWidget *menubar, *item;
 
   menubar = gtk_menu_bar_new();
   
   item = gtk_menu_item_new_with_mnemonic(_("_Change"));
   gtk_menu_shell_append(GTK_MENU_SHELL(menubar), item);
   city_change_command = item;
   create_change_menu(item);
 
+  item = gtk_menu_item_new_with_mnemonic(_("_First"));
+  gtk_menu_shell_append(GTK_MENU_SHELL(menubar), item);
+  city_first_command = item;
+  create_first_menu(item);
+
+  item = gtk_menu_item_new_with_mnemonic(_("_Next"));
+  gtk_menu_shell_append(GTK_MENU_SHELL(menubar), item);
+  city_next_command = item;
+  create_next_menu(item);
+
+  item = gtk_menu_item_new_with_mnemonic(_("_Last"));
+  gtk_menu_shell_append(GTK_MENU_SHELL(menubar), item);
+  city_last_command = item;
+  create_last_menu(item);
+
   item = gtk_menu_item_new_with_mnemonic(_("_Select"));
   gtk_menu_shell_append(GTK_MENU_SHELL(menubar), item);
   create_select_menu(item);
 
   item = gtk_menu_item_new_with_mnemonic(_("S_how"));
   gtk_menu_shell_append(GTK_MENU_SHELL(menubar), item);
   update_view_menu(item);
   return menubar;
 }
@@ -1163,43 +1317,176 @@
   change_improvements_item = gtk_menu_item_new_with_label(_("Improvements"));
   gtk_menu_shell_append(GTK_MENU_SHELL(menu), change_improvements_item);
   change_wonders_item = gtk_menu_item_new_with_label(_("Wonders"));
   gtk_menu_shell_append(GTK_MENU_SHELL(menu), change_wonders_item);
   change_cma_item = gtk_menu_item_new_with_label(_("CMA"));
   gtk_menu_shell_append(GTK_MENU_SHELL(menu), change_cma_item);
 }
 
 /****************************************************************
+Creates the last menu.
+*****************************************************************/
+static void create_last_menu(GtkWidget *item)
+{
+  GtkWidget *menu;
+
+  menu = gtk_menu_new();
+  gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);
+  g_signal_connect(menu, "show", G_CALLBACK(popup_last_menu), NULL);
+
+  last_units_item = gtk_menu_item_new_with_label(_("Units"));
+  gtk_menu_shell_append(GTK_MENU_SHELL(menu), last_units_item);
+  last_improvements_item = gtk_menu_item_new_with_label(_("Improvements"));
+  gtk_menu_shell_append(GTK_MENU_SHELL(menu), last_improvements_item);
+  last_wonders_item = gtk_menu_item_new_with_label(_("Wonders"));
+  gtk_menu_shell_append(GTK_MENU_SHELL(menu), last_wonders_item);
+}
+
+/****************************************************************
+Creates the first menu.
+*****************************************************************/
+static void create_first_menu(GtkWidget *item)
+{
+  GtkWidget *menu;
+
+  menu = gtk_menu_new();
+  gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);
+  g_signal_connect(menu, "show", G_CALLBACK(popup_first_menu), NULL);
+
+  first_units_item = gtk_menu_item_new_with_label(_("Units"));
+  gtk_menu_shell_append(GTK_MENU_SHELL(menu), first_units_item);
+  first_improvements_item = gtk_menu_item_new_with_label(_("Improvements"));
+  gtk_menu_shell_append(GTK_MENU_SHELL(menu), first_improvements_item);
+  first_wonders_item = gtk_menu_item_new_with_label(_("Wonders"));
+  gtk_menu_shell_append(GTK_MENU_SHELL(menu), first_wonders_item);
+}
+
+/****************************************************************
+Creates the next menu.
+*****************************************************************/
+static void create_next_menu(GtkWidget *item)
+{
+  GtkWidget *menu;
+
+  menu = gtk_menu_new();
+  gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);
+  g_signal_connect(menu, "show", G_CALLBACK(popup_next_menu), NULL);
+
+  next_units_item = gtk_menu_item_new_with_label(_("Units"));
+  gtk_menu_shell_append(GTK_MENU_SHELL(menu), next_units_item);
+  next_improvements_item = gtk_menu_item_new_with_label(_("Improvements"));
+  gtk_menu_shell_append(GTK_MENU_SHELL(menu), next_improvements_item);
+  next_wonders_item = gtk_menu_item_new_with_label(_("Wonders"));
+  gtk_menu_shell_append(GTK_MENU_SHELL(menu), next_wonders_item);
+}
+
+
+
+/****************************************************************
 ...
 *****************************************************************/
 static void popup_change_menu(GtkMenuShell *menu, gpointer data)
 {
   int n;
 
   n = 0;
   gtk_tree_selection_selected_foreach(city_selection, selected_iterate, &n);
 
   append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(change_improvements_item),
-                                 FALSE, FALSE, TRUE,
+                                 FALSE, FALSE, CO_CHANGE,
                                  city_can_build_impr_or_unit,
                                  G_CALLBACK(select_impr_or_unit_callback), n);
   append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(change_units_item),
-                                 TRUE, FALSE, TRUE,
+                                 TRUE, FALSE, CO_CHANGE,
                                  city_can_build_impr_or_unit,
                                  G_CALLBACK(select_impr_or_unit_callback), n);
   append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(change_wonders_item),
-                                 FALSE, TRUE, TRUE,
+                                 FALSE, TRUE, CO_CHANGE,
                                  city_can_build_impr_or_unit,
                                  G_CALLBACK(select_impr_or_unit_callback), n);
   append_cma_to_menu_item(GTK_MENU_ITEM(change_cma_item), TRUE);
 }
 
 /****************************************************************
+pops up the last menu.
+*****************************************************************/
+static void popup_last_menu(GtkMenuShell *menu, gpointer data)
+{
+  int n;
+
+  n = 0;
+  gtk_tree_selection_selected_foreach(city_selection, selected_iterate, &n);
+
+  append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(last_improvements_item),
+                                 FALSE, FALSE, CO_LAST,
+                                 city_can_build_impr_or_unit,
+                                 G_CALLBACK(select_impr_or_unit_callback), n);
+  append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(last_units_item),
+                                 TRUE, FALSE, CO_LAST,
+                                 city_can_build_impr_or_unit,
+                                 G_CALLBACK(select_impr_or_unit_callback), n);
+  append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(last_wonders_item),
+                                 FALSE, TRUE, CO_LAST,
+                                 city_can_build_impr_or_unit,
+                                 G_CALLBACK(select_impr_or_unit_callback), n);
+}
+
+/****************************************************************
+pops up the first menu.
+*****************************************************************/
+static void popup_first_menu(GtkMenuShell *menu, gpointer data)
+{
+  int n;
+
+  n = 0;
+  gtk_tree_selection_selected_foreach(city_selection, selected_iterate, &n);
+
+  append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(first_improvements_item),
+                                 FALSE, FALSE, CO_FIRST,
+                                 city_can_build_impr_or_unit,
+                                 G_CALLBACK(select_impr_or_unit_callback), n);
+  append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(first_units_item),
+                                 TRUE, FALSE, CO_FIRST,
+                                 city_can_build_impr_or_unit,
+                                 G_CALLBACK(select_impr_or_unit_callback), n);
+  append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(first_wonders_item),
+                                 FALSE, TRUE, CO_FIRST,
+                                 city_can_build_impr_or_unit,
+                                 G_CALLBACK(select_impr_or_unit_callback), n);
+}
+
+/****************************************************************
+pops up the next menu.
+*****************************************************************/
+static void popup_next_menu(GtkMenuShell *menu, gpointer data)
+{
+  int n;
+
+  n = 0;
+  gtk_tree_selection_selected_foreach(city_selection, selected_iterate, &n);
+
+  append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(next_improvements_item),
+                                 FALSE, FALSE, CO_NEXT,
+                                 city_can_build_impr_or_unit,
+                                 G_CALLBACK(select_impr_or_unit_callback), n);
+  append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(next_units_item),
+                                 TRUE, FALSE, CO_NEXT,
+                                 city_can_build_impr_or_unit,
+                                 G_CALLBACK(select_impr_or_unit_callback), n);
+  append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(next_wonders_item),
+                                 FALSE, TRUE, CO_NEXT,
+                                 city_can_build_impr_or_unit,
+                                 G_CALLBACK(select_impr_or_unit_callback), n);
+}
+
+
+
+/****************************************************************
 ...
 *****************************************************************/
 static void create_select_menu(GtkWidget *item)
 {
   GtkWidget *menu;
 
   menu = gtk_menu_new();
   gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);
   g_signal_connect(menu, "show", G_CALLBACK(popup_select_menu), NULL);
@@ -1329,57 +1616,57 @@
 
   if (select_menu_cached)
     return;
 
   n = 0;
   gtk_tree_selection_selected_foreach(city_selection, selected_iterate, &n);
   gtk_widget_set_sensitive(select_island_item, (n > 0));
 
   append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_bunit_item),
-                                 TRUE, FALSE, FALSE,
+                                 TRUE, FALSE, CO_NONE,
                                  city_building_impr_or_unit,
                                  G_CALLBACK(select_impr_or_unit_callback), -1);
   append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_bimprovement_item),
-                                 FALSE, FALSE, FALSE,
+                                 FALSE, FALSE, CO_NONE,
                                  city_building_impr_or_unit,
                                  G_CALLBACK(select_impr_or_unit_callback), -1);
   append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_bwonder_item),
-                                 FALSE, TRUE, FALSE,
+                                 FALSE, TRUE, CO_NONE,
                                  city_building_impr_or_unit,
                                  G_CALLBACK(select_impr_or_unit_callback), -1);
 
   append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_supported_item),
-                                 TRUE, FALSE, FALSE,
+                                 TRUE, FALSE, CO_NONE,
                                  city_unit_supported,
                                  G_CALLBACK(select_impr_or_unit_callback), -1);
   append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_present_item),
-                                 TRUE, FALSE, FALSE,
+                                 TRUE, FALSE, CO_NONE,
                                  city_unit_present,
                                  G_CALLBACK(select_impr_or_unit_callback), -1);
   
append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_built_improvements_item),
-                                 FALSE, FALSE, FALSE,
+                                 FALSE, FALSE, CO_NONE,
                                  city_got_building,
                                  G_CALLBACK(select_impr_or_unit_callback), -1);
   append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_built_wonders_item),
-                                 FALSE, TRUE, FALSE,
+                                 FALSE, TRUE, CO_NONE,
                                  city_got_building,
                                  G_CALLBACK(select_impr_or_unit_callback), -1);
 
   append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_improvements_item),
-                                 FALSE, FALSE, FALSE,
+                                 FALSE, FALSE, CO_NONE,
                                  city_can_build_impr_or_unit,
                                  G_CALLBACK(select_impr_or_unit_callback), -1);
   append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_units_item),
-                                 TRUE, FALSE, FALSE,
+                                 TRUE, FALSE, CO_NONE,
                                  city_can_build_impr_or_unit,
                                  G_CALLBACK(select_impr_or_unit_callback), -1);
   append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_wonders_item),
-                                 FALSE, TRUE, FALSE,
+                                 FALSE, TRUE, CO_NONE,
                                  city_can_build_impr_or_unit,
                                  G_CALLBACK(select_impr_or_unit_callback), -1);
   append_cma_to_menu_item(GTK_MENU_ITEM(select_cma_item), FALSE);
 
   select_menu_cached = TRUE;
 }
 
 /****************************************************************
 ...
@@ -1387,19 +1674,25 @@
 static void city_selection_changed_callback(GtkTreeSelection *selection)
 {
   int n;
 
   n = 0;
   gtk_tree_selection_selected_foreach(selection, selected_iterate, &n);
 
   if (n == 0) {
     gtk_widget_set_sensitive(city_change_command, FALSE);
+    gtk_widget_set_sensitive(city_last_command, FALSE);
+    gtk_widget_set_sensitive(city_first_command, FALSE);
+    gtk_widget_set_sensitive(city_next_command, FALSE);
     gtk_widget_set_sensitive(city_center_command, FALSE);
     gtk_widget_set_sensitive(city_popup_command, FALSE);
     gtk_widget_set_sensitive(city_buy_command, FALSE);
   } else {
     gtk_widget_set_sensitive(city_change_command, can_client_issue_orders());
+    gtk_widget_set_sensitive(city_last_command, can_client_issue_orders());
+    gtk_widget_set_sensitive(city_first_command, can_client_issue_orders());
+    gtk_widget_set_sensitive(city_next_command, can_client_issue_orders());
     gtk_widget_set_sensitive(city_center_command, TRUE);
     gtk_widget_set_sensitive(city_popup_command, TRUE);
     gtk_widget_set_sensitive(city_buy_command, can_client_issue_orders());
   }
 }
Index: common/worklist.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/worklist.c,v
retrieving revision 1.14
diff -U9 -r1.14 worklist.c
--- common/worklist.c   2002/11/14 09:15:03     1.14
+++ common/worklist.c   2003/08/29 20:36:22
@@ -38,28 +38,29 @@
   strcpy(pwl->name, "a worklist");
 
   for (i = 0; i < MAX_LEN_WORKLIST; i++) {
     pwl->wlefs[i] = WEF_END;
     pwl->wlids[i] = 0;
   }
 }
 
 /****************************************************************
-...
+returns the number of entries in the worklist.
+The returned value can also be used as the next available
+index (assuming that len < MAX_LEN_WORKLIST)
 ****************************************************************/
 int worklist_length(const struct worklist *pwl)
 {
   int len = 0;
 
   if (pwl) {
-    for (len = 0; len < MAX_LEN_WORKLIST && pwl->wlefs[len] != WEF_END;
-        len++) {
-      /* nothing */
+    while (len < MAX_LEN_WORKLIST && pwl->wlefs[len] != WEF_END) {
+      len++;
     }
   }
 
   return len;
 }
 
 /****************************************************************
 ...
 ****************************************************************/
@@ -134,10 +135,68 @@
   if (idx < MAX_LEN_WORKLIST-1) {
     memmove(&pwl->wlefs[idx], &pwl->wlefs[idx+1],
            sizeof(enum worklist_elem_flag) * (MAX_LEN_WORKLIST-1-idx));
     memmove(&pwl->wlids[idx], &pwl->wlids[idx+1],
            sizeof(int) * (MAX_LEN_WORKLIST-1-idx));
   }
 
   pwl->wlefs[MAX_LEN_WORKLIST-1] = WEF_END;
   pwl->wlids[MAX_LEN_WORKLIST-1] = 0;
+}
+
+/***************************************************************
+Adds the id to the next available slot in the worklist
+Returns true if successful.
+***************************************************************/
+bool worklist_append(struct worklist *pwl, int id, bool is_unit)
+{
+  int next_index = worklist_length(pwl);
+  if (next_index >= MAX_LEN_WORKLIST) {
+    return FALSE;
+  }
+  
+  pwl->wlefs[next_index] = is_unit ? WEF_UNIT : WEF_IMPR;
+  pwl->wlids[next_index] = id;
+  
+  if(next_index + 1 < MAX_LEN_WORKLIST)
+  {
+    pwl->wlefs[next_index + 1] = WEF_END;
+    pwl->wlids[next_index + 1] = 0;
+  }
+
+  return TRUE;
+}
+
+/***************************************************************
+Inserts the id to the location idx in the worklist
+Moves all other ids back an index.
+Returns true if successful.
+***************************************************************/
+bool worklist_insert(struct worklist *pwl, int id, bool is_unit, int idx)
+{
+  int len = worklist_length(pwl);
+  if (len >= MAX_LEN_WORKLIST) {
+    return FALSE;
+  }
+
+  /* move all active values back an index to get room for new id
+     move from idx .. len - 1 to idx + 1 .. len
+     Don't copy WEF_END because that might end up outside of the list.
+  */
+  memmove(&pwl->wlefs[idx+1], &pwl->wlefs[idx],
+         sizeof(enum worklist_elem_flag) * (len - idx));
+  memmove(&pwl->wlids[idx+1], &pwl->wlids[idx],
+        sizeof(int) * (len - idx));
+  
+  pwl->wlefs[idx] = is_unit ? WEF_UNIT : WEF_IMPR;
+  pwl->wlids[idx] = id;
+  
+  /* since we don't copy the WEF_END, need to reinsert it at the end
+     if there is room */
+  if(len + 1 < MAX_LEN_WORKLIST)
+  {
+    pwl->wlefs[len + 1] = WEF_END;
+    pwl->wlids[len + 1] = 0;
+  }
+  
+  return TRUE;
 }
Index: common/worklist.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/worklist.h,v
retrieving revision 1.7
diff -U9 -r1.7 worklist.h
--- common/worklist.h   2002/11/15 21:24:30     1.7
+++ common/worklist.h   2003/08/29 20:36:22
@@ -39,11 +39,13 @@
 int worklist_length(const struct worklist *pwl);
 bool worklist_is_empty(const struct worklist *pwl);
 bool worklist_peek(const struct worklist *pwl, int *id, bool *is_unit);
 bool worklist_peek_ith(const struct worklist *pwl, int *id, bool *is_unit,
                      int idx);
 void worklist_advance(struct worklist *pwl);
 
 void copy_worklist(struct worklist *dst, const struct worklist *src);
 void worklist_remove(struct worklist *pwl, int idx);
+bool worklist_append(struct worklist *pwl, int id, bool is_unit);
+bool worklist_insert(struct worklist *pwl, int id, bool is_unit, int idx);
 
 #endif /* FC__WORKLIST_H */

[Prev in Thread] Current Thread [Next in Thread]