Complete.Org: Mailing Lists: Archives: freeciv-dev: March 2003:
[Freeciv-Dev] (PR#3727) Rectangular selection with right-click-and-drag
Home

[Freeciv-Dev] (PR#3727) Rectangular selection with right-click-and-drag

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: undisclosed-recipients:;
Subject: [Freeciv-Dev] (PR#3727) Rectangular selection with right-click-and-drag
From: "a-l@xxxxxxx" <a-l@xxxxxxx>
Date: Thu, 13 Mar 2003 17:46:41 -0800
Reply-to: rt@xxxxxxxxxxxxxx

Parent: (PR#3529) Map Control patch

On Sun, 2 Mar 2003 01:41:50 -0800
"Jason Short" <jdorje@xxxxxxxxxxxxxxxxxxxxx> wrote:

> [ali - Wed Feb 26 16:32:22 2003]:
> > CONTAINS:
> > 
> > 1. Area Selection on-map.
> > 2. On-map Copy & Paste city production.
> > 3. Quickselect units, bypassing popups.
> > 4. New access keys.

> This patch contains several largely unrelated features.  It would be
> good to separate them into smaller patches that can be handled separately.

I see what you mean. I was thinking more in terms of related ideas from a
player's perspective; A player who doesn't like battling the interface
(me :-)

> I'd give feedback on the other features as well, but I think this would

I appreciate it.

> be much easier to do if you'd split the patch up.  Doing that would also
> make it easier to provide support for other GUIs (which can be done on a

I also ported this to GTK2, and made a pure standalone patch (attached):

Essentially only the mouse features from #3529, minus highlighting of
unit tiles, which was for mass orders.

- Rectangular selection with right click and drag.
- Cities become highlighted with a sprite on the map,
  and become exclusively selected in the City List window.
- Shift + Left click on owned city or visible unit copies to clipboard.
- Shift + Right click does paste city production.
- Shift + Control Right click buys production.
- Wakeup sentries moved to Control + Middle click.
- Adjust workers moved to Shift + Control Left click.

        Function Wakeup sentries had it's own gtk signal connect on mouse
        button press. All combinations of Shift/Control/plain mouse button
        presses are now in one function, one gtk signal connected.

So, this is an intuitive light version of the the most frequently used
features in the City List window, done directly on-map.

And then there is the sprite itself. Attatched here for browsing, but you
still need to apply #3532 to make it work. gfx.tar.gz and gfx-Feb-25.diff.
autogen.sh required.

Of course, if you agree this patch and its sprite belongs in cvs, I can gimp
it into one of the existing .png files, or create a new .png with it's own
.spec, which can be expanded later. But I wouldn't create one new .png for
every new little sprite, it's a bit awkward.


Arnstein



diff -ruN -Xdiff_ignore_makefile cvs-Mar-12/client/control.c 
rectangle/client/control.c
--- cvs-Mar-12/client/control.c Sat Feb 22 10:43:01 2003
+++ rectangle/client/control.c  Thu Mar 13 14:36:44 2003
@@ -1360,6 +1360,9 @@
 void key_cancel_action(void)
 {
   bool popped = FALSE;
+
+  cancel_tile_selection();
+
   if (hover_state == HOVER_GOTO || hover_state == HOVER_PATROL)
     if (draw_goto_line)
       popped = goto_pop_waypoint();
diff -ruN -Xdiff_ignore_makefile cvs-Mar-12/client/gui-gtk/cityrep.c 
rectangle/client/gui-gtk/cityrep.c
--- cvs-Mar-12/client/gui-gtk/cityrep.c Fri Mar  7 12:16:27 2003
+++ rectangle/client/gui-gtk/cityrep.c  Thu Mar 13 14:36:44 2003
@@ -161,6 +161,44 @@
 }
 
 /****************************************************************
+ After a rectangle is defined, make the highlighted cities
+ exclusively selected in the city list window.
+*****************************************************************/
+void cities_on_map_selection(void)
+{
+  gint i;
+
+  if (!city_dialog_shell) return;
+
+  gtk_clist_unselect_all( GTK_CLIST(city_list));
+
+  for(i = 0; i < GTK_CLIST(city_list)->rows; i++)
+  {
+    struct city *pcity = gtk_clist_get_row_data(GTK_CLIST(city_list), i);
+
+    if (map_get_tile(pcity->x, pcity->y)->selected == 1)
+      gtk_clist_select_row(GTK_CLIST(city_list), i, 0);
+  }
+}
+
+/****************************************************************
+ In Area Selection mode, left mouse button toggles a city's
+ selected status on the map.
+*****************************************************************/
+void city_on_map_select(struct city *pcity, bool on_off)
+{
+  gint i;
+
+  if (!city_dialog_shell) return;
+
+  i = gtk_clist_find_row_from_data(GTK_CLIST(city_list), pcity);
+
+  on_off ?
+       gtk_clist_select_row(GTK_CLIST(city_list), i, 0) :
+       gtk_clist_unselect_row(GTK_CLIST(city_list), i, 0);
+}
+
+/****************************************************************
 
                       CITY REPORT DIALOG
  
@@ -182,6 +220,7 @@
     gtk_set_relative_position(toplevel, city_dialog_shell, 10, 10);
   }
   gtk_window_show(GTK_WINDOW(city_dialog_shell));
+  cities_on_map_selection();
 }
 
 /****************************************************************
diff -ruN -Xdiff_ignore_makefile cvs-Mar-12/client/gui-gtk/gui_main.c 
rectangle/client/gui-gtk/gui_main.c
--- cvs-Mar-12/client/gui-gtk/gui_main.c        Fri Feb 28 12:52:16 2003
+++ rectangle/client/gui-gtk/gui_main.c Fri Mar 14 01:19:33 2003
@@ -687,6 +687,7 @@
 
   gtk_widget_set_events(map_canvas, GDK_EXPOSURE_MASK
                                    |GDK_BUTTON_PRESS_MASK
+                                   |GDK_BUTTON_RELEASE_MASK
                                    |GDK_KEY_PRESS_MASK
                                    |GDK_POINTER_MOTION_MASK);
 
@@ -710,12 +711,12 @@
   gtk_signal_connect(GTK_OBJECT(map_canvas), "button_press_event",
                      GTK_SIGNAL_FUNC(butt_down_mapcanvas), NULL);
 
+  gtk_signal_connect(GTK_OBJECT(map_canvas), "button_release_event",
+                     GTK_SIGNAL_FUNC(butt_release_mapcanvas), NULL);
+
   gtk_signal_connect(GTK_OBJECT(toplevel), "key_press_event",
                      GTK_SIGNAL_FUNC(keyboard_handler), NULL);
 
-  gtk_signal_connect(GTK_OBJECT(map_canvas), "button_press_event",
-                     GTK_SIGNAL_FUNC(butt_down_wakeup), NULL);
-
   /* *** The message window -- this is a detachable widget *** */
 
   ahbox = detached_widget_new();
diff -ruN -Xdiff_ignore_makefile cvs-Mar-12/client/gui-gtk/mapctrl.c 
rectangle/client/gui-gtk/mapctrl.c
--- cvs-Mar-12/client/gui-gtk/mapctrl.c Tue Feb 18 15:52:02 2003
+++ rectangle/client/gui-gtk/mapctrl.c  Fri Mar 14 01:26:27 2003
@@ -51,6 +51,8 @@
 /* Color to use to display the workers */
 int city_workers_color = COLOR_STD_WHITE;
 
+static void update_rect_at_mouse_pos(void);
+
 /**************************************************************************
 ...
 **************************************************************************/
@@ -291,50 +293,103 @@
 }
 
 /**************************************************************************
-(RP:) wake up my own sentried units on the tile that was clicked
+ Handle 'Right Mouse Button released'.
 **************************************************************************/
-gint butt_down_wakeup(GtkWidget *w, GdkEventButton *ev)
+gint butt_release_mapcanvas(GtkWidget *w, GdkEventButton *ev)
 {
   int xtile, ytile;
 
-  /* when you get a <SHIFT>+<LMB> pow! */
-  if (!can_client_issue_orders() || !(ev->state & GDK_SHIFT_MASK)) {
+  if(ev->button != 3 || !rbutton_down)  {
     return TRUE;
   }
 
   get_map_xy(ev->x, ev->y, &xtile, &ytile);
+  release_right_button(xtile, ytile);
 
-  wakeup_sentried_units(xtile, ytile);
   return TRUE;
 }
 
 /**************************************************************************
-...
+ Handle all mouse button press on canvas.
 **************************************************************************/
 gint butt_down_mapcanvas(GtkWidget *w, GdkEventButton *ev)
 {
   int xtile, ytile;
+  struct city *pcity;
 
   if (!can_client_change_view()) {
     return TRUE;
   }
 
+  get_map_xy(ev->x, ev->y, &xtile, &ytile);
+  pcity = map_get_tile(xtile, ytile)->city;
+
+  /* <CONTROL> + Middle Mouse Button: Wake up sentries
+  */
   if (can_client_issue_orders()
-      && (ev->button == 1) && (ev->state & GDK_SHIFT_MASK)) {
-    adjust_workers(w, ev);
-    return TRUE;
+    && (ev->button == 2) && (ev->state & GDK_CONTROL_MASK)) {
+      wakeup_sentried_units(xtile, ytile);
   }
 
-  get_map_xy(ev->x, ev->y, &xtile, &ytile);
+  /*  <SHIFT> + <CONTROL> + LMB : Adjust workers
+  */
+  else if(can_client_issue_orders()
+    && (ev->button == 1) && (ev->state & GDK_SHIFT_MASK)
+    && (ev->state & GDK_CONTROL_MASK)) {
+      adjust_workers(w, ev);
+  }
 
-  if (ev->button == 1) {
+  /*  <SHIFT> + <CONTROL> + RMB : Buy Production
+  */
+  else if(can_client_issue_orders()
+    && (ev->button == 3) && (ev->state & GDK_SHIFT_MASK)
+    && (ev->state & GDK_CONTROL_MASK)) {
+      buy_production(pcity);
+      cancel_tile_selection();
+  }
+
+  /*  <SHIFT> + LMB Copy Production
+   *  <SHIFT> + RMB Paste Production
+  */
+  else if((ev->button == 1) && (ev->state & GDK_SHIFT_MASK)) {
+    copy_production(xtile, ytile);
+  }
+  else if(can_client_issue_orders()
+    && (ev->button == 3) && (ev->state & GDK_SHIFT_MASK)) {
+      paste_production(pcity);
+      cancel_tile_selection();
+  }
+
+  else if(ev->button == 1 && tiles_highlighted_cities) {
+    toggle_tile_highlight(xtile, ytile);
+  }
+
+  else if(ev->button == 1) {
     do_map_click(xtile, ytile);
     gtk_widget_grab_focus(turn_done_button);
-  } else if ((ev->button == 2) || (ev->state & GDK_CONTROL_MASK)) {
+  }
+
+  else if(ev->button == 2)  {
     popit(ev, xtile, ytile);
-  } else if (ev->button == 3) {
-    center_tile_mapcanvas(xtile, ytile);
   }
+
+  else if(ev->button == 3)  /* Right Mouse Button Press */
+  {
+    /*  A foolproof user will depress button on canvas,
+     *  release it on another widget, and return to canvas
+     *  to find rectangle still active.
+     */
+    if (rectangle_active) {
+      rbutton_down = TRUE;
+      butt_release_mapcanvas(w, ev);
+      rbutton_down = FALSE;
+      return TRUE;
+    }
+
+    cancel_tile_selection();
+    record_mouse_pos(xtile, ytile);
+  }
+
   return TRUE;
 }
 
@@ -351,11 +406,27 @@
 }
 
 /**************************************************************************
+ Rectangle for Area Selection
+**************************************************************************/
+static void update_rect_at_mouse_pos(void)
+{
+  int x, y;
+
+  gdk_window_get_pointer(map_canvas->window, &x, &y, NULL);
+  get_map_xy(x, y, &x, &y);
+
+  update_rectangle(x, y);
+}
+
+/**************************************************************************
 ...
 **************************************************************************/
 gint move_mapcanvas(GtkWidget *widget, GdkEventButton *event)
 {
   update_line(event->x, event->y);
+  if (!hover_state) {
+    update_rect_at_mouse_pos();
+  }
   return TRUE;
 }
 
diff -ruN -Xdiff_ignore_makefile cvs-Mar-12/client/gui-gtk/mapctrl.h 
rectangle/client/gui-gtk/mapctrl.h
--- cvs-Mar-12/client/gui-gtk/mapctrl.h Fri Jan 10 05:56:35 2003
+++ rectangle/client/gui-gtk/mapctrl.h  Fri Mar 14 01:20:48 2003
@@ -23,8 +23,8 @@
 void key_city_workers(GtkWidget *w, GdkEventKey *ev);
 void adjust_workers(GtkWidget *widget, GdkEventButton *ev);
 
+gint butt_release_mapcanvas(GtkWidget *w, GdkEventButton *ev);
 gint butt_down_mapcanvas(GtkWidget *w, GdkEventButton *ev);
-gint butt_down_wakeup(GtkWidget *w, GdkEventButton *ev);
 gint butt_down_overviewcanvas(GtkWidget *w, GdkEventButton *ev);
 gint move_mapcanvas(GtkWidget *widget, GdkEventButton *event);
 
diff -ruN -Xdiff_ignore_makefile cvs-Mar-12/client/gui-gtk/mapview.c 
rectangle/client/gui-gtk/mapview.c
--- cvs-Mar-12/client/gui-gtk/mapview.c Thu Mar 13 14:26:44 2003
+++ rectangle/client/gui-gtk/mapview.c  Thu Mar 13 14:36:44 2003
@@ -1311,8 +1311,6 @@
 **************************************************************************/
 void draw_segment(int src_x, int src_y, int dir)
 {
-  assert(get_drawn(src_x, src_y, dir) > 0);
-
   if (is_isometric) {
     really_draw_segment(src_x, src_y, dir, TRUE, FALSE);
   } else {
diff -ruN -Xdiff_ignore_makefile cvs-Mar-12/client/gui-gtk-2.0/cityrep.c 
rectangle/client/gui-gtk-2.0/cityrep.c
--- cvs-Mar-12/client/gui-gtk-2.0/cityrep.c     Sat Mar  8 17:33:40 2003
+++ rectangle/client/gui-gtk-2.0/cityrep.c      Thu Mar 13 14:36:44 2003
@@ -118,6 +118,60 @@
 }
 
 /****************************************************************
+ After a rectangle is defined, make the highlighted cities
+ exclusively selected in the city list window.
+*****************************************************************/
+void cities_on_map_selection(void)
+{
+  ITree it;
+  GtkTreeModel *model;
+
+  if (!city_dialog_shell) return;
+
+  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);
+    pcity = res;
+
+    if (map_get_tile(pcity->x, pcity->y)->selected == 1)  {
+      itree_select(city_selection, &it);
+    }
+  }
+}
+
+/****************************************************************
+ In Area Selection mode, left mouse button toggles a city's
+ selected status on the map.
+*****************************************************************/
+void city_on_map_select(struct city *pcity, bool on_off)
+{
+  ITree it;
+  GtkTreeModel *model;
+
+  if (!city_dialog_shell) return;
+
+  model = GTK_TREE_MODEL(city_model);
+
+  for (itree_begin(model, &it); !itree_end(&it); itree_next(&it)) {
+    gint id;
+    itree_get(&it, 1, &id, -1);
+
+    if (id == pcity->id) {
+      on_off ?
+        itree_select(city_selection, &it) :
+        itree_unselect(city_selection, &it);
+      break;
+    }
+  }
+}
+
+/****************************************************************
 
                       CITY REPORT DIALOG
  
@@ -138,6 +192,7 @@
   }
 
   gtk_window_present(GTK_WINDOW(city_dialog_shell));
+  cities_on_map_selection();
 }
 
 /****************************************************************
diff -ruN -Xdiff_ignore_makefile cvs-Mar-12/client/gui-gtk-2.0/gui_main.c 
rectangle/client/gui-gtk-2.0/gui_main.c
--- cvs-Mar-12/client/gui-gtk-2.0/gui_main.c    Fri Mar  7 12:16:16 2003
+++ rectangle/client/gui-gtk-2.0/gui_main.c     Fri Mar 14 01:31:51 2003
@@ -809,6 +809,7 @@
 
   gtk_widget_add_events(map_canvas, GDK_EXPOSURE_MASK
                                    |GDK_BUTTON_PRESS_MASK
+                                   |GDK_BUTTON_RELEASE_MASK
                                    |GDK_KEY_PRESS_MASK
                                    |GDK_POINTER_MOTION_MASK);
 
@@ -835,12 +836,12 @@
   g_signal_connect(map_canvas, "button_press_event",
                    G_CALLBACK(butt_down_mapcanvas), NULL);
 
+  g_signal_connect(map_canvas, "button_release_event",
+                   G_CALLBACK(butt_release_mapcanvas), NULL);
+
   g_signal_connect(toplevel, "key_press_event",
                    G_CALLBACK(keyboard_handler), NULL);
 
-  g_signal_connect(map_canvas, "button_press_event",
-                   G_CALLBACK(butt_down_wakeup), NULL);
-
   /* *** The message window -- this is a detachable widget *** */
 
   ahbox = detached_widget_new();
diff -ruN -Xdiff_ignore_makefile cvs-Mar-12/client/gui-gtk-2.0/mapctrl.c 
rectangle/client/gui-gtk-2.0/mapctrl.c
--- cvs-Mar-12/client/gui-gtk-2.0/mapctrl.c     Mon Jan 27 05:56:13 2003
+++ rectangle/client/gui-gtk-2.0/mapctrl.c      Fri Mar 14 01:31:26 2003
@@ -51,6 +51,8 @@
 /* Color to use to display the workers */
 int city_workers_color=COLOR_STD_WHITE;
 
+static void update_rect_at_mouse_pos(void);
+
 /**************************************************************************
 ...
 **************************************************************************/
@@ -283,22 +285,20 @@
   gtk_widget_set_sensitive(turn_done_button, state);
 }
 
-
 /**************************************************************************
-(RP:) wake up my own sentried units on the tile that was clicked
+ Handle 'Right Mouse Button released'.
 **************************************************************************/
-gboolean butt_down_wakeup(GtkWidget *w, GdkEventButton *ev, gpointer data)
+gboolean butt_release_mapcanvas(GtkWidget *w, GdkEventButton *ev, gpointer 
data)
 {
   int xtile, ytile;
 
-  /* when you get a <SHIFT>+<LMB> pow! */
-  if (!can_client_issue_orders() || !(ev->state & GDK_SHIFT_MASK)) {
+  if(ev->button != 3 || !rbutton_down)  {
     return TRUE;
   }
 
   get_map_xy(ev->x, ev->y, &xtile, &ytile);
+  release_right_button(xtile, ytile);
 
-  wakeup_sentried_units(xtile, ytile);
   return TRUE;
 }
 
@@ -308,27 +308,81 @@
 gboolean butt_down_mapcanvas(GtkWidget *w, GdkEventButton *ev, gpointer data)
 {
   int xtile, ytile;
+  struct city *pcity;
 
   if (!can_client_change_view()) {
     return TRUE;
   }
 
+  get_map_xy(ev->x, ev->y, &xtile, &ytile);
+  pcity = map_get_tile(xtile, ytile)->city;
+
+  /* <CONTROL> + Middle Mouse Button: Wake up sentries
+  */
   if (can_client_issue_orders()
-      && (ev->button == 1) && (ev->state & GDK_SHIFT_MASK)) {
-    adjust_workers(w, ev);
-    return TRUE;
+    && (ev->button == 2) && (ev->state & GDK_CONTROL_MASK)) {
+      wakeup_sentried_units(xtile, ytile);
   }
 
-  get_map_xy(ev->x, ev->y, &xtile, &ytile);
+  /*  <SHIFT> + <CONTROL> + LMB : Adjust workers
+  */
+  else if(can_client_issue_orders()
+    && (ev->button == 1) && (ev->state & GDK_SHIFT_MASK)
+    && (ev->state & GDK_CONTROL_MASK)) {
+      adjust_workers(w, ev);
+  }
 
-  if (ev->button == 1) {
+  /*  <SHIFT> + <CONTROL> + RMB : Buy Production
+  */
+  else if(can_client_issue_orders()
+    && (ev->button == 3) && (ev->state & GDK_SHIFT_MASK)
+    && (ev->state & GDK_CONTROL_MASK)) {
+      buy_production(pcity);
+      cancel_tile_selection();
+  }
+
+  /*  <SHIFT> + LMB Copy Production
+   *  <SHIFT> + RMB Paste Production
+  */
+  else if((ev->button == 1) && (ev->state & GDK_SHIFT_MASK)) {
+    copy_production(xtile, ytile);
+  }
+  else if(can_client_issue_orders()
+    && (ev->button == 3) && (ev->state & GDK_SHIFT_MASK)) {
+      paste_production(pcity);
+      cancel_tile_selection();
+  }
+
+  else if(ev->button == 1 && tiles_highlighted_cities) {
+    toggle_tile_highlight(xtile, ytile);
+  }
+
+  else if(ev->button == 1) {
     do_map_click(xtile, ytile);
-    gtk_widget_grab_focus(map_canvas);
-  } else if ((ev->button == 2) || (ev->state & GDK_CONTROL_MASK)) {
+    gtk_widget_grab_focus(turn_done_button);
+  }
+
+  else if(ev->button == 2)  {
     popit(ev, xtile, ytile);
-  } else if (ev->button == 3) {
-    center_tile_mapcanvas(xtile, ytile);
   }
+
+  else if(ev->button == 3)  /* Right Mouse Button Press */
+  {
+    /*  A foolproof user will depress button on canvas,
+     *  release it on another widget, and return to canvas
+     *  to find rectangle still active.
+     */
+    if (rectangle_active) {
+      rbutton_down = TRUE;
+      butt_release_mapcanvas(w, ev, data);
+      rbutton_down = FALSE;
+      return TRUE;
+    }
+
+    cancel_tile_selection();
+    record_mouse_pos(xtile, ytile);
+  }
+
   return TRUE;
 }
 
@@ -345,11 +399,27 @@
 }
 
 /**************************************************************************
+ Rectangle for Area Selection
+**************************************************************************/
+static void update_rect_at_mouse_pos(void)
+{
+  int x, y;
+
+  gdk_window_get_pointer(map_canvas->window, &x, &y, NULL);
+  get_map_xy(x, y, &x, &y);
+
+  update_rectangle(x, y);
+}
+
+/**************************************************************************
 ...
 **************************************************************************/
 gboolean move_mapcanvas(GtkWidget *widget, GdkEventMotion *event, gpointer 
data)
 {
   update_line(event->x, event->y);
+  if (!hover_state) {
+    update_rect_at_mouse_pos();
+  }
   return TRUE;
 }
 
diff -ruN -Xdiff_ignore_makefile cvs-Mar-12/client/gui-gtk-2.0/mapctrl.h 
rectangle/client/gui-gtk-2.0/mapctrl.h
--- cvs-Mar-12/client/gui-gtk-2.0/mapctrl.h     Fri Jan 10 05:56:35 2003
+++ rectangle/client/gui-gtk-2.0/mapctrl.h      Thu Mar 13 14:36:44 2003
@@ -22,6 +22,7 @@
 void key_city_workers(GtkWidget *w, GdkEventKey *ev);
 void adjust_workers(GtkWidget *widget, GdkEventButton *ev);
 
+gboolean butt_release_mapcanvas(GtkWidget *w, GdkEventButton *ev, gpointer 
data);
 gboolean butt_down_mapcanvas(GtkWidget *w, GdkEventButton *ev, gpointer data);
 gboolean butt_down_wakeup(GtkWidget *w, GdkEventButton *ev, gpointer data);
 gboolean butt_down_overviewcanvas(GtkWidget *w, GdkEventButton *ev, gpointer 
data);
diff -ruN -Xdiff_ignore_makefile cvs-Mar-12/client/gui-gtk-2.0/mapview.c 
rectangle/client/gui-gtk-2.0/mapview.c
--- cvs-Mar-12/client/gui-gtk-2.0/mapview.c     Thu Mar 13 14:26:44 2003
+++ rectangle/client/gui-gtk-2.0/mapview.c      Thu Mar 13 14:36:44 2003
@@ -1390,8 +1390,6 @@
 **************************************************************************/
 void draw_segment(int src_x, int src_y, int dir)
 {
-  assert(get_drawn(src_x, src_y, dir) > 0);
-
   if (is_isometric) {
     really_draw_segment(src_x, src_y, dir, TRUE, FALSE);
   } else {
diff -ruN -Xdiff_ignore_makefile cvs-Mar-12/client/gui-mui/cityrep.c 
rectangle/client/gui-mui/cityrep.c
--- cvs-Mar-12/client/gui-mui/cityrep.c Tue Feb 18 15:52:19 2003
+++ rectangle/client/gui-mui/cityrep.c  Thu Mar 13 15:02:50 2003
@@ -61,6 +61,22 @@
 static Object *cityrep_change_button;
 static Object *cityrep_configure_objects[NUM_CREPORT_COLS];
 
+/****************************************************************
+...
+*****************************************************************/
+void cities_on_map_selection(void)
+{
+  /* PORTME */
+}
+
+/****************************************************************
+...
+*****************************************************************/
+void city_on_map_select(struct city *pcity, bool on_off)
+{
+  /* PORTME */
+}
+
 /**************************************************************************
  Display function for the listview in the city report window
 **************************************************************************/
diff -ruN -Xdiff_ignore_makefile cvs-Mar-12/client/gui-sdl/cityrep.c 
rectangle/client/gui-sdl/cityrep.c
--- cvs-Mar-12/client/gui-sdl/cityrep.c Mon Dec  2 08:47:02 2002
+++ rectangle/client/gui-sdl/cityrep.c  Thu Mar 13 15:02:32 2003
@@ -56,6 +56,22 @@
 #define CMA_NONE       (-1)
 #define CMA_CUSTOM     (-2)
 
+/****************************************************************
+...
+*****************************************************************/
+void cities_on_map_selection(void)
+{
+  /* PORTME */
+}
+
+/****************************************************************
+...
+*****************************************************************/
+void city_on_map_select(struct city *pcity, bool on_off)
+{
+  /* PORTME */
+}
+
 /**************************************************************************
   Pop up or brings forward the city report dialog.  It may or may not
   be modal.
diff -ruN -Xdiff_ignore_makefile cvs-Mar-12/client/gui-stub/cityrep.c 
rectangle/client/gui-stub/cityrep.c
--- cvs-Mar-12/client/gui-stub/cityrep.c        Sun Dec  1 05:55:01 2002
+++ rectangle/client/gui-stub/cityrep.c Thu Mar 13 15:03:15 2003
@@ -19,6 +19,22 @@
 
 #include "cityrep.h"
 
+/****************************************************************
+...
+*****************************************************************/
+void cities_on_map_selection(void)
+{
+  /* PORTME */
+}
+
+/****************************************************************
+...
+*****************************************************************/
+void city_on_map_select(struct city *pcity, bool on_off)
+{
+  /* PORTME */
+}
+
 /**************************************************************************
   Pop up or brings forward the city report dialog.  It may or may not
   be modal.
diff -ruN -Xdiff_ignore_makefile cvs-Mar-12/client/gui-win32/cityrep.c 
rectangle/client/gui-win32/cityrep.c
--- cvs-Mar-12/client/gui-win32/cityrep.c       Wed Feb 26 14:30:29 2003
+++ rectangle/client/gui-win32/cityrep.c        Thu Mar 13 15:02:01 2003
@@ -90,6 +90,22 @@
                                      UINT wParam,
                                      LONG lParam);
 
+/****************************************************************
+...
+*****************************************************************/
+void cities_on_map_selection(void)
+{
+  /* PORTME */
+}
+
+/****************************************************************
+...
+*****************************************************************/
+void city_on_map_select(struct city *pcity, bool on_off)
+{
+  /* PORTME */
+}
+
 static void popup_city_report_config_dialog()
 {
   int i;
diff -ruN -Xdiff_ignore_makefile cvs-Mar-12/client/gui-xaw/cityrep.c 
rectangle/client/gui-xaw/cityrep.c
--- cvs-Mar-12/client/gui-xaw/cityrep.c Tue Feb 18 15:52:19 2003
+++ rectangle/client/gui-xaw/cityrep.c  Thu Mar 13 15:01:19 2003
@@ -111,6 +111,22 @@
 
 
 /****************************************************************
+...
+*****************************************************************/
+void cities_on_map_selection(void)
+{
+  /* PORTME */
+}
+
+/****************************************************************
+...
+*****************************************************************/
+void city_on_map_select(struct city *pcity, bool on_off)
+{
+  /* PORTME */
+}
+
+/****************************************************************
  Create the text for a line in the city report; n is size of buffer
 *****************************************************************/
 static void get_city_text(struct city *pcity, char *text, int n)
diff -ruN -Xdiff_ignore_makefile cvs-Mar-12/client/include/cityrep_g.h 
rectangle/client/include/cityrep_g.h
--- cvs-Mar-12/client/include/cityrep_g.h       Sat Apr 13 06:15:26 2002
+++ rectangle/client/include/cityrep_g.h        Thu Mar 13 14:36:44 2003
@@ -17,6 +17,10 @@
 
 struct city;
 
+/* On-map Area Selection */
+void cities_on_map_selection(void);
+void city_on_map_select(struct city *pcity, bool on_off);
+
 void popup_city_report_dialog(bool make_modal);
 void city_report_dialog_update(void);
 void city_report_dialog_update_city(struct city *pcity);
diff -ruN -Xdiff_ignore_makefile cvs-Mar-12/client/mapctrl_common.c 
rectangle/client/mapctrl_common.c
--- cvs-Mar-12/client/mapctrl_common.c  Fri Jan 10 05:56:34 2003
+++ rectangle/client/mapctrl_common.c   Fri Mar 14 00:59:01 2003
@@ -16,19 +16,377 @@
 #endif
 
 #include "agents.h"
+#include "chatline_common.h"
+#include "cityrep_g.h"
 #include "civclient.h"
+#include "climisc.h" /* city_can_build_impr_or_unit() */
+#include "clinet.h"
 #include "control.h"
+#include "fcintl.h"
 #include "goto.h"
 #include "log.h"
 #include "mapctrl_g.h"
 #include "mapview_g.h"
 #include "options.h"
+#include "support.h"
 
 #include "mapctrl_common.h"
 
 static bool turn_done_state;
 static bool is_turn_done_state_valid = FALSE;
 
+/* Mapcanvas clipboard, defaults to Settler (0) */
+static int clipboard = 0;
+static bool clipboard_is_unit = TRUE;
+
+/* Selection Rectangle */
+static int first_x, first_y, old_x, old_y;
+
+bool rbutton_down = FALSE;
+bool rectangle_active = FALSE;
+
+/* This changes the behaviour of left mouse button */
+bool tiles_highlighted_cities = FALSE;
+
+/*************************************************************************/
+
+static void send_buy_packet(struct city *pcity);
+static void send_production_packet(struct city *pcity);
+
+/**************************************************************************
+ Draw or undraw a rectangle. Takes two sets of coords and figures out
+ directions. Both Iso and Non-Iso. Use drawing funtions from mapview.c.
+
+    (1)
+      *--*
+      |  |
+      *--*
+         (2)
+
+**************************************************************************/
+void draw_rectangle(int src_x, int src_y, int dest_x, int dest_y,
+                    bool draw)
+{
+  int x1, y1, x2, y2;
+  int dist_x, dist_y;
+  int i, test_x;
+
+  dist_x = real_map_distance(src_x, src_y, dest_x, src_y);
+  dist_y = real_map_distance(src_x, src_y, src_x, dest_y);
+
+  test_x = src_x + dist_x;
+  normalize_map_pos(&test_x, &src_y);
+
+  if (test_x == dest_x)  {        /* is dest to the right of src? */
+    x1 = src_x;     x2 = dest_x;
+  } else  {
+    x1 = dest_x;    x2 = src_x;
+  }
+  if (dest_y >= src_y) {          /* vertical is simple */
+    y1 = src_y;     y2 = dest_y;
+  } else  {
+    y1 = dest_y;    y2 = src_y;
+  }
+
+  if (x1 != x2) {
+    for (i = 0; i < dist_x; i++) {
+      if (draw) {
+        draw_segment(x1 + i, y1, DIR8_EAST);
+        draw_segment(x1 + i, y2, DIR8_EAST);
+      } else  {
+        undraw_segment(x1 + i, y1, DIR8_EAST);
+        undraw_segment(x1 + i, y2, DIR8_EAST);
+      }
+    }
+  }
+  if (y1 != y2) {
+    for (i = 0; i < dist_y; i++) {
+      if (draw) {
+        draw_segment(x1, y1 + i, DIR8_SOUTH);
+        draw_segment(x2, y1 + i, DIR8_SOUTH);
+      } else  {
+        undraw_segment(x1, y1 + i, DIR8_SOUTH);
+        undraw_segment(x2, y1 + i, DIR8_SOUTH);
+      }
+    }
+  }
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+void record_mouse_pos(int tile_x, int tile_y)
+{
+  first_x = old_x = tile_x;
+  first_y = old_y = tile_y;
+  rbutton_down = TRUE;
+}
+
+/**************************************************************************
+ 1) Define a rectangle finished.
+ 2) Or just recenter map if there was a simple right-click.
+**************************************************************************/
+void release_right_button(int tile_x, int tile_y)
+{
+  int test_x;
+  int dist_x, dist_y; /* width, height */
+  int x, y, xx, yy;   /* macro substitute */
+  int x1, y1, x2, y2; /* NW and SE corners */
+  struct tile *ptile;
+  struct city *pcity;
+
+  /* Did user move mouse pointer between press and release? */
+
+  if (!same_pos(tile_x, tile_y, first_x, first_y) && !hover_state) {
+    if (rectangle_active) {
+      draw_rectangle(first_x, first_y, old_x, old_y, FALSE);
+      rectangle_active = FALSE;
+    }
+
+    test_x = first_x + real_map_distance(first_x, first_y, tile_x, first_y);
+    normalize_map_pos(&test_x, &first_y);
+
+    /* Define NW & SE corners */
+
+    if (test_x == tile_x)  {
+      x1 = first_x;   x2 = tile_x;
+    } else  {
+      x1 = tile_x;    x2 = first_x;
+    }
+    if (tile_y >= first_y) {
+      y1 = first_y;   y2 = tile_y;
+    } else  {
+      y1 = tile_y;    y2 = first_y;
+    }
+
+    /*  Now we make tiles within the rectangle, that contain owned
+     *  cities, highlighted on the map and selected in the City List
+     *  window.
+     *
+     *      ptile->selected == 1    owned city
+     */
+
+    dist_x = real_map_distance(x1, y1, x2, y1);
+    dist_y = real_map_distance(x1, y1, x1, y2);
+
+    /* Maybe use new macro rectangle_iterate here */
+    for (yy = 0; yy <= dist_y; yy++) {
+      for (xx = 0; xx <= dist_x; xx++) {
+        x = x1 + xx;
+        y = y1 + yy;
+        normalize_map_pos(&x, &y);
+
+        ptile = map_get_tile(x, y);
+        pcity = map_get_city(x, y);
+
+        if (pcity && pcity->owner == game.player_idx) {
+          ptile->selected = 1;  /* highlight */
+          refresh_tile_mapcanvas(x, y, TRUE);
+          tiles_highlighted_cities = TRUE;
+        }
+      }
+    }
+
+    if (tiles_highlighted_cities) {
+      cities_on_map_selection();  /* cityrep.c */
+    }
+  }
+
+  /* Simple right click */
+  else  {
+    rectangle_active = FALSE;
+    center_tile_mapcanvas(tile_x, tile_y);
+  }
+
+  rbutton_down = FALSE;
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+void update_rectangle(int tile_x, int tile_y)
+{
+  if (rbutton_down && !same_pos(old_x, old_y, tile_x, tile_y)) {
+    draw_rectangle(first_x, first_y, old_x, old_y, FALSE);
+    draw_rectangle(first_x, first_y, tile_x, tile_y, TRUE);
+    rectangle_active = TRUE;
+
+    old_x = tile_x;
+    old_y = tile_y;
+  }
+}
+
+/**************************************************************************
+ Left Mouse Button in area selection mode.
+**************************************************************************/
+void toggle_tile_highlight(int tile_x, int tile_y)
+{
+  struct tile *ptile = map_get_tile(tile_x, tile_y);
+  struct city *pcity = map_get_city(tile_x, tile_y);
+
+  if (ptile->selected == 1) {
+    city_on_map_select(pcity, FALSE); /* cityrep.c */
+    ptile->selected = 0;
+  }
+  else if (pcity && pcity->owner == game.player_idx) {
+    ptile->selected = 1;
+    tiles_highlighted_cities = TRUE;
+    city_on_map_select(pcity, TRUE);
+  }
+  else  {
+    return;
+  }
+
+  refresh_tile_mapcanvas(tile_x, tile_y, TRUE);
+}
+
+/**************************************************************************
+ The mapcanvas clipboard.
+ Shift-Left-Click on owned city or any visible unit to copy.
+**************************************************************************/
+void copy_production(int tile_x, int tile_y)
+{
+  char msg[MAX_LEN_MSG];
+  struct city *pcity = map_get_city(tile_x, tile_y);
+  struct tile *ptile = map_get_tile(tile_x, tile_y);
+
+  if (pcity) {
+    if (pcity->owner != game.player_idx)  {
+      return;
+    }
+    clipboard = pcity->currently_building;
+    clipboard_is_unit = pcity->is_building_unit;
+  } else  {
+    struct unit *punit = find_visible_unit(ptile);
+    if (!punit) {
+      return;
+    }
+    if (!can_player_build_unit_direct(game.player_ptr, punit->type))  {
+      my_snprintf(msg, sizeof(msg), _("Game: You cannot build %s!"),
+        unit_types[punit->type].name);
+      append_output_window(msg);
+      return;
+    }
+    clipboard_is_unit = TRUE;
+    clipboard = punit->type;
+  }
+  upgrade_clipboard();
+
+  my_snprintf(msg, sizeof(msg), _("Game: Copy %s."),
+    clipboard_is_unit ? unit_types[clipboard].name :
+    get_improvement_name(clipboard));
+  append_output_window(msg);
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+void paste_production(struct city *pcity)
+{
+  if (!tiles_highlighted_cities) {
+    if (pcity && pcity->owner == game.player_idx)
+      send_production_packet(pcity);
+    return;
+  }
+  else {
+    connection_do_buffer(&aconnection);
+    city_list_iterate(game.player_ptr->cities, pcity) {
+      if (map_get_tile(pcity->x, pcity->y)->selected == 1)
+        send_production_packet(pcity);
+    } city_list_iterate_end;
+    connection_do_unbuffer(&aconnection);
+  }
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+static void send_production_packet(struct city *pcity)
+{
+  struct packet_city_request packet;
+  int cid = clipboard;
+
+  if (clipboard_is_unit)  {
+    cid += B_LAST;
+  }
+
+  if ((pcity->currently_building == clipboard
+    && pcity->is_building_unit == clipboard_is_unit)
+      || !city_can_build_impr_or_unit(pcity, cid))  {
+    return;
+  }
+
+  packet.city_id = pcity->id;
+  packet.name[0] = '\0';
+  packet.worklist.name[0] = '\0';
+  packet.build_id = clipboard;
+  packet.is_build_id_unit_id = clipboard_is_unit;
+  send_packet_city_request(&aconnection, &packet, PACKET_CITY_CHANGE);
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+void buy_production(struct city *pcity)
+{
+  if (!tiles_highlighted_cities) {
+    if (pcity && pcity->owner == game.player_idx) {
+      send_buy_packet(pcity);
+    }
+  }
+  else {
+    connection_do_buffer(&aconnection);
+    city_list_iterate(game.player_ptr->cities, pcity) {
+      if (map_get_tile(pcity->x, pcity->y)->selected == 1)
+        send_buy_packet(pcity);
+    } city_list_iterate_end;
+    connection_do_unbuffer(&aconnection);
+  }
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+static void send_buy_packet(struct city *pcity)
+{
+  struct packet_city_request packet;
+
+  packet.city_id = pcity->id;
+  send_packet_city_request(&aconnection, &packet, PACKET_CITY_BUY);
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+void upgrade_clipboard(void)
+{
+  if (clipboard_is_unit)  {
+    int u = can_upgrade_unittype(game.player_ptr, clipboard);
+    if (u != -1)  {
+      clipboard = u;
+    }
+  }
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+void cancel_tile_selection(void)
+{
+  if (tiles_highlighted_cities)  {
+    struct tile *ptile;
+    tiles_highlighted_cities = FALSE;
+
+    whole_map_iterate(x, y) {
+      ptile = map_get_tile(x, y);
+      if (ptile->selected) {
+        ptile->selected = 0;
+        refresh_tile_mapcanvas(x, y, TRUE);
+      }
+    } whole_map_iterate_end;
+  }
+}
+
 /**************************************************************************
  Return TRUE iff the turn done button is enabled.
 **************************************************************************/
diff -ruN -Xdiff_ignore_makefile cvs-Mar-12/client/mapctrl_common.h 
rectangle/client/mapctrl_common.h
--- cvs-Mar-12/client/mapctrl_common.h  Fri Jan 10 05:56:34 2003
+++ rectangle/client/mapctrl_common.h   Fri Mar 14 00:51:21 2003
@@ -16,6 +16,25 @@
 
 #include "shared.h"            /* bool type */
 
+extern bool rbutton_down;
+extern bool rectangle_active;
+
+extern bool tiles_highlighted_cities;
+
+void draw_rectangle(int src_x, int src_y, int dest_x, int dest_y,
+                    bool draw);
+
+void record_mouse_pos(int tile_x, int tile_y);
+void release_right_button(int tile_x, int tile_y);
+void update_rectangle(int tile_x, int tile_y);
+void toggle_tile_highlight(int tile_x, int tile_y);
+
+void copy_production(int tile_x, int tile_y);
+void paste_production(struct city *pcity);
+void buy_production(struct city *pcity);
+void upgrade_clipboard(void);
+void cancel_tile_selection(void);
+
 bool get_turn_done_button_state(void);
 void update_turn_done_button_state(void);
 void update_line(int canvas_x, int canvas_y);
diff -ruN -Xdiff_ignore_makefile cvs-Mar-12/client/packhand.c 
rectangle/client/packhand.c
--- cvs-Mar-12/client/packhand.c        Sat Mar  8 17:33:41 2003
+++ rectangle/client/packhand.c Thu Mar 13 14:36:44 2003
@@ -1366,6 +1366,7 @@
   
   update_players_dialog();
   update_worklist_report_dialog();
+  upgrade_clipboard();
 
   if (pplayer == game.player_ptr && can_client_change_view()) {
     update_info_label();
diff -ruN -Xdiff_ignore_makefile cvs-Mar-12/client/tilespec.c 
rectangle/client/tilespec.c
--- cvs-Mar-12/client/tilespec.c        Fri Mar  7 12:16:40 2003
+++ rectangle/client/tilespec.c Thu Mar 13 14:36:44 2003
@@ -830,6 +830,7 @@
   SET_SPRITE(upkeep.shield, "upkeep.shield");
   
   SET_SPRITE(user.attention, "user.attention");
+  SET_SPRITE(user.city_selected,  "user.city_selected");
 
   SET_SPRITE(tx.fallout,    "tx.fallout");
   SET_SPRITE(tx.farmland,   "tx.farmland");
@@ -1892,6 +1893,10 @@
     dither[dir] = get_dither(ttype, other);
   }
 
+  if (map_get_tile(x, y)->selected == 1)  {
+    *sprs++ = sprites.user.city_selected;
+  }
+
   return sprs - save_sprs;
 }
 
@@ -2100,6 +2105,10 @@
     }
   }
 
+  if (ptile->selected == 1) {
+    *sprs++ = sprites.user.city_selected;
+  }
+
   return sprs - save_sprs;
 }
 
diff -ruN -Xdiff_ignore_makefile cvs-Mar-12/client/tilespec.h 
rectangle/client/tilespec.h
--- cvs-Mar-12/client/tilespec.h        Sun Feb  2 05:58:31 2003
+++ rectangle/client/tilespec.h Thu Mar 13 14:36:44 2003
@@ -174,7 +174,9 @@
       ***tile;
   } city;
   struct {
-    struct Sprite *attention;
+    struct Sprite
+      *attention,
+      *city_selected;
   } user;
   struct {
     struct Sprite
diff -ruN -Xdiff_ignore_makefile cvs-Mar-12/common/map.c rectangle/common/map.c
--- cvs-Mar-12/common/map.c     Sat Feb 22 10:43:01 2003
+++ rectangle/common/map.c      Thu Mar 13 14:36:44 2003
@@ -214,6 +214,7 @@
   unit_list_init(&ptile->units);
   ptile->worked   = NULL; /* pointer to city working tile */
   ptile->assigned = 0; /* bitvector */
+  ptile->selected = 0;        /* Area Selection */
 }
 
 /***************************************************************
diff -ruN -Xdiff_ignore_makefile cvs-Mar-12/common/map.h rectangle/common/map.h
--- cvs-Mar-12/common/map.h     Thu Mar 13 14:27:49 2003
+++ rectangle/common/map.h      Thu Mar 13 14:36:44 2003
@@ -62,6 +62,8 @@
   struct city *worked;      /* city working tile, or NULL if none */
   unsigned short continent;
   signed char move_cost[8]; /* don't know if this helps! */
+  int selected;             /* Area Selection. 1=city. Client only.
+                               Leave as int. */
 };
 
 

PNG image

PNG image


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