<URL: http://bugs.freeciv.org/Ticket/Display.html?id=40646 >

Attached patch changes the selection rectangle drawing
code to use xor instead overwriting pixel values. This
means that it can be erased by just drawing over itself
again, rather than redrawing all of the sprites at all
of the tiles that it touches.

This is much more efficient than the existing code, but
of course animations and such will now affect it. Since
the situations where animations are occurring and the
user is simulatneously using the selection rectangle
are rare (I assume), I would hope that this is not too
much of a problem.

I tested the gtk, sdl and xaw guis. Apparently there is
not way to use the selection rectangle in sdl and xaw,
so I did not modify their draw_selection_rectangle()
functions.


-----------------------------------------------------------------------
私は長方形に住んでいる。

 client/editor.c               |   43 ++++++++++++++++++++---------------------
 client/editor.h               |    1 -
 client/gui-ftwl/mapview.c     |    2 -
 client/gui-gtk-2.0/gui_main.c |    4 +++
 client/gui-gtk-2.0/gui_main.h |    1 +
 client/gui-gtk-2.0/mapview.c  |   22 +++++++++++++++-----
 client/gui-sdl/mapview.c      |    1 -
 client/gui-win32/mapview.c    |    1 -
 client/gui-xaw/mapview.c      |    1 -
 client/mapctrl_common.c       |   18 ++--------------
 client/mapctrl_common.h       |    1 -
 client/mapview_common.c       |    7 ------
 12 files changed, 45 insertions(+), 57 deletions(-)

diff --git a/client/editor.c b/client/editor.c
index 1f6be9e..a517ee8 100644
--- a/client/editor.c
+++ b/client/editor.c
@@ -670,6 +670,24 @@ void editor_mouse_button_release(int canvas_x, int canvas_y,
 }
 
 /****************************************************************************
+  Draws the editor selection rectangle using draw_selection_rectangle().
+****************************************************************************/
+static void editor_draw_selrect(void)
+{
+  if (!editor) {
+    return;
+  }
+
+  if (editor->selrect_active && editor->selrect_width > 0
+      && editor->selrect_height > 0) {
+    draw_selection_rectangle(editor->selrect_x,
+                             editor->selrect_y,
+                             editor->selrect_width,
+                             editor->selrect_height);
+  }
+}
+
+/****************************************************************************
   Handle a change in the size of the selection rectangle. The given point
   is the new extremity of the rectangle.
 ****************************************************************************/
@@ -693,8 +711,8 @@ static void editor_resize_selection_rectangle(int canvas_x, int canvas_y)
     y2 = editor->selrect_start_y;
   }
 
-  dirty_all();
-  flush_dirty();
+  /* Erase the previously drawn rectangle. */
+  editor_draw_selrect();
 
   if (x1 == x2 || y1 == y2) {
     editor->selrect_width = 0;
@@ -707,7 +725,7 @@ static void editor_resize_selection_rectangle(int canvas_x, int canvas_y)
   editor->selrect_width = x2 - x1;
   editor->selrect_height = y2 - y1;
 
-  editor_redraw();
+  editor_draw_selrect();
 }
 
 /****************************************************************************
@@ -892,25 +910,6 @@ const struct tile *editor_get_current_tile(void)
 }
 
 /****************************************************************************
-  Redraw any editor-specific decorations. This should usually be called
-  whenever the map canvas is redrawn.
-****************************************************************************/
-void editor_redraw(void)
-{
-  if (!editor) {
-    return;
-  }
-
-  if (editor->selrect_active && editor->selrect_width > 0
-      && editor->selrect_height > 0) {
-    draw_selection_rectangle(editor->selrect_x,
-                             editor->selrect_y,
-                             editor->selrect_width,
-                             editor->selrect_height);
-  }
-}
-
-/****************************************************************************
   Toggle the current tool mode between the given mode and ETM_PAINT.
 ****************************************************************************/
 void editor_tool_toggle_mode(enum editor_tool_type ett,
diff --git a/client/editor.h b/client/editor.h
index 093c509..53d4dfc 100644
--- a/client/editor.h
+++ b/client/editor.h
@@ -120,7 +120,6 @@ void editor_mouse_button_press(int canvas_x, int canvas_y,
 void editor_mouse_button_release(int canvas_x, int canvas_y,
                                  int button, int modifiers);
 void editor_mouse_move(int canvas_x, int canvas_y, int modifiers);
-void editor_redraw(void);
 
 void editor_apply_tool(const struct tile *ptile,
                        bool part_of_selection);
diff --git a/client/gui-ftwl/mapview.c b/client/gui-ftwl/mapview.c
index 536a22a..14cc77b 100644
--- a/client/gui-ftwl/mapview.c
+++ b/client/gui-ftwl/mapview.c
@@ -860,7 +860,6 @@ static void my_drag_move(struct sw_widget *widget,
 	    dy, new_x, new_y);
     set_mapview_scroll_pos(new_x, new_y);
     flush_dirty();
-    redraw_selection_rectangle();
     clear_timer_start(drag_timer);
   }
 }
@@ -1065,7 +1064,6 @@ static void action_callback(const char *action)
       }
       set_mapview_scroll_pos(x, y);
       flush_dirty();
-      redraw_selection_rectangle();
     }
   } else {
     freelog(LOG_VERBOSE, "action_callback() action '%s' requested", action);
diff --git a/client/gui-gtk-2.0/gui_main.c b/client/gui-gtk-2.0/gui_main.c
index 7866e30..f01ff84 100644
--- a/client/gui-gtk-2.0/gui_main.c
+++ b/client/gui-gtk-2.0/gui_main.c
@@ -115,6 +115,7 @@ GdkGC *fill_tile_gc;
 GdkGC *thin_line_gc;
 GdkGC *thick_line_gc;
 GdkGC *border_line_gc;
+GdkGC *selection_gc;
 GdkPixmap *gray50, *gray25, *black50;
 GdkPixmap *mask_bitmap;
 
@@ -1552,6 +1553,9 @@ void ui_main(int argc, char **argv)
     gdk_gc_set_foreground(mask_bg_gc, &pixel);
   }
 
+  selection_gc = gdk_gc_new(root_window);
+  gdk_gc_set_function(selection_gc, GDK_XOR);
+
   tileset_init(tileset);
   tileset_load_tiles(tileset);
 
diff --git a/client/gui-gtk-2.0/gui_main.h b/client/gui-gtk-2.0/gui_main.h
index f5ed3fa..f9a1439 100644
--- a/client/gui-gtk-2.0/gui_main.h
+++ b/client/gui-gtk-2.0/gui_main.h
@@ -35,6 +35,7 @@ extern GdkGC *          fill_tile_gc;
 extern GdkGC *          thin_line_gc;
 extern GdkGC *          thick_line_gc;
 extern GdkGC *          border_line_gc;
+extern GdkGC *          selection_gc;
 extern GdkPixmap *      gray50;
 extern GdkPixmap *      gray25;
 extern GdkPixmap *      black50;
diff --git a/client/gui-gtk-2.0/mapview.c b/client/gui-gtk-2.0/mapview.c
index a36bd06..e834968 100644
--- a/client/gui-gtk-2.0/mapview.c
+++ b/client/gui-gtk-2.0/mapview.c
@@ -379,8 +379,6 @@ static bool is_flush_queued = FALSE;
 static gint unqueue_flush(gpointer data)
 {
   flush_dirty();
-  redraw_selection_rectangle();
-  editor_redraw();
   is_flush_queued = FALSE;
   return 0;
 }
@@ -762,14 +760,23 @@ void scrollbar_jump_callback(GtkAdjustment *adj, gpointer hscrollbar)
 }
 
 /**************************************************************************
- Area Selection
+  Draws a rectangle with top left corner at (canvas_x, canvas_y), and
+  width 'w' and height 'h'. It is drawn using the 'selection_gc' context,
+  so the pixel combining function is XOR. This means that drawing twice
+  in the same place will restore the image to its original state.
+
+  NB: A side effect of this function is to set the 'selection_gc' color
+  to COLOR_MAPVIEW_SELECTION.
 **************************************************************************/
 void draw_selection_rectangle(int canvas_x, int canvas_y, int w, int h)
 {
   GdkPoint points[5];
+  struct color *pcolor;
 
-  gdk_gc_set_foreground(civ_gc,
-			&get_color(tileset, COLOR_MAPVIEW_SELECTION)->color);
+  pcolor = get_color(tileset, COLOR_MAPVIEW_SELECTION);
+  if (!pcolor) {
+    return;
+  }
 
   /* gdk_draw_rectangle() must start top-left.. */
   points[0].x = canvas_x;
@@ -786,7 +793,10 @@ void draw_selection_rectangle(int canvas_x, int canvas_y, int w, int h)
 
   points[4].x = canvas_x;
   points[4].y = canvas_y;
-  gdk_draw_lines(map_canvas->window, civ_gc, points, ARRAY_SIZE(points));
+
+  gdk_gc_set_foreground(selection_gc, &pcolor->color);
+  gdk_draw_lines(map_canvas->window, selection_gc,
+                 points, ARRAY_SIZE(points));
 }
 
 /**************************************************************************
diff --git a/client/gui-sdl/mapview.c b/client/gui-sdl/mapview.c
index e3e371e..f20088d 100644
--- a/client/gui-sdl/mapview.c
+++ b/client/gui-sdl/mapview.c
@@ -133,7 +133,6 @@ void flush_rect(SDL_Rect rect, bool force_flush)
 void unqueue_flush(void)
 {
   flush_dirty();
-  redraw_selection_rectangle();
   is_flush_queued = FALSE;
 }
 
diff --git a/client/gui-win32/mapview.c b/client/gui-win32/mapview.c
index 74516b5..0be4b2e 100644
--- a/client/gui-win32/mapview.c
+++ b/client/gui-win32/mapview.c
@@ -361,7 +361,6 @@ static VOID CALLBACK unqueue_flush(HWND hwnd, UINT uMsg, UINT idEvent,
 				   DWORD dwTime)
 {
   flush_dirty();
-  redraw_selection_rectangle();
   is_flush_queued = FALSE;
 }
 
diff --git a/client/gui-xaw/mapview.c b/client/gui-xaw/mapview.c
index 5d86b67..eb1c971 100644
--- a/client/gui-xaw/mapview.c
+++ b/client/gui-xaw/mapview.c
@@ -558,7 +558,6 @@ bool is_flush_queued = FALSE;
 static void unqueue_flush(XtPointer client_data, XtIntervalId * id)
 {
   flush_dirty();
-  redraw_selection_rectangle();
   is_flush_queued = FALSE;
 }
 
diff --git a/client/mapctrl_common.c b/client/mapctrl_common.c
index e59f7f2..6e15758 100644
--- a/client/mapctrl_common.c
+++ b/client/mapctrl_common.c
@@ -85,8 +85,7 @@ static void define_tiles_within_rectangle(void);
  anchor is not the drawing start point, but is used to calculate
  width, height. Also record the current mapview centering.
 **************************************************************************/
-void anchor_selection_rectangle(int canvas_x, int canvas_y,
-				bool append)
+void anchor_selection_rectangle(int canvas_x, int canvas_y, bool append)
 {
   struct tile *ptile = canvas_pos_to_nearest_tile(canvas_x, canvas_y);
 
@@ -199,8 +198,7 @@ void update_selection_rectangle(int canvas_x, int canvas_y)
   rec_tile = ptile;
 
   /* Clear previous rectangle. */
-  dirty_all();
-  flush_dirty();
+  draw_selection_rectangle(rec_corner_x, rec_corner_y, rec_w, rec_h);
 
   /*  Fix canvas coords to the center of the tile.
    */
@@ -256,22 +254,12 @@ void update_selection_rectangle(int canvas_x, int canvas_y)
 /**************************************************************************
   Redraws the selection rectangle after a map flush.
 **************************************************************************/
-void redraw_selection_rectangle(void)
-{
-  if (rectangle_active) {
-    draw_selection_rectangle(rec_corner_x, rec_corner_y, rec_w, rec_h);
-  }
-}
-
-/**************************************************************************
-  Redraws the selection rectangle after a map flush.
-**************************************************************************/
 void cancel_selection_rectangle(void)
 {
   if (rectangle_active) {
     rectangle_active = FALSE;
     rbutton_down = FALSE;
-    dirty_rect(rec_corner_x, rec_corner_y, rec_w, rec_h);
+    draw_selection_rectangle(rec_corner_x, rec_corner_y, rec_w, rec_h);
   }
 }
 
diff --git a/client/mapctrl_common.h b/client/mapctrl_common.h
index b054b7b..7d77529 100644
--- a/client/mapctrl_common.h
+++ b/client/mapctrl_common.h
@@ -29,7 +29,6 @@ extern struct tile *keyboardless_goto_start_tile;
 
 void anchor_selection_rectangle(int canvas_x, int canvas_y, bool append);
 void update_selection_rectangle(int canvas_x, int canvas_y);
-void redraw_selection_rectangle(void);
 void cancel_selection_rectangle(void);
 
 bool is_city_hilited(struct city *pcity);
diff --git a/client/mapview_common.c b/client/mapview_common.c
index 880a487..2b3a533 100644
--- a/client/mapview_common.c
+++ b/client/mapview_common.c
@@ -588,8 +588,6 @@ void set_mapview_origin(int gui_x0, int gui_y0)
       base_set_mapview_origin(start_x + diff_x * (mytime / timing_sec),
 			      start_y + diff_y * (mytime / timing_sec));
       flush_dirty();
-      redraw_selection_rectangle();
-      editor_redraw();
       gui_flush();
       frames++;
     } while (currtime < timing_sec);
@@ -1051,7 +1049,6 @@ void put_nuke_mushroom_pixmaps(struct tile *ptile)
   dirty_rect(canvas_x, canvas_y, width, height);
 
   flush_dirty();
-  redraw_selection_rectangle();
   gui_flush();
 
   myusleep(1000000);
@@ -1844,7 +1841,6 @@ void decrease_unit_hp_smooth(struct unit *punit0, int hp0,
       dirty_rect(canvas_x, canvas_y, tileset_tile_width(tileset), tileset_tile_height(tileset));
 
       flush_dirty();
-      redraw_selection_rectangle();
       gui_flush();
 
       usleep_since_timer_start(anim_timer, 20000);
@@ -1924,7 +1920,6 @@ void move_unit_map_canvas(struct unit *punit,
 
       /* Flush. */
       flush_dirty();
-      redraw_selection_rectangle();
       gui_flush();
 
       /* Restore the backup.  It won't take effect until the next flush. */
@@ -2293,8 +2288,6 @@ void unqueue_mapview_updates(bool write_to_screen)
 
   if (write_to_screen) {
     flush_dirty();
-    redraw_selection_rectangle();
-    editor_redraw();
     flush_dirty_overview();
   }
 }
_______________________________________________
Freeciv-dev mailing list
Freeciv-dev@gna.org
https://mail.gna.org/listinfo/freeciv-dev

Reply via email to