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

The attached patch implements traderoute line drawing on
the main map, toggled by ctrl-t.

This is a minimal backport of 40447 + 40667 for S2_1. I
know this is a feature rather than a bugfix, but it is
fairly often requested by users, and the code is pretty
well tested (having been used in warclient for a long
time now).

Or we can keep the current traderoute interface in 2.1
as is, and have this feature for 2.2 only.


-----------------------------------------------------------------------
俺が雄牛を新しい戦闘機と交換した。
 client/control.c          |   21 +++++++
 client/control.h          |    2 +
 client/gui-gtk-2.0/menu.c |    8 +++
 client/mapview_common.c   |  136 +++++++++++++++++++++++++++++++++++++++++++++
 client/options.c          |    2 +
 client/options.h          |    1 +
 6 files changed, 170 insertions(+), 0 deletions(-)

diff --git a/client/control.c b/client/control.c
index 31a9a09..7f97299 100644
--- a/client/control.c
+++ b/client/control.c
@@ -1623,6 +1623,19 @@ void request_toggle_city_productions(void)
 }
 
 /**************************************************************************
+ Toggle display of city traderoutes
+**************************************************************************/
+void request_toggle_city_traderoutes(void)
+{
+  if (!can_client_change_view()) {
+    return;
+  }
+
+  draw_city_traderoutes ^= 1;
+  update_map_canvas_visible();
+}
+
+/**************************************************************************
  Toggle display of terrain
 **************************************************************************/
 void request_toggle_terrain(void)
@@ -2686,6 +2699,14 @@ void key_city_productions_toggle(void)
 /**************************************************************************
 ...
 **************************************************************************/
+void key_city_traderoutes_toggle(void)
+{
+  request_toggle_city_traderoutes();
+}
+
+/**************************************************************************
+...
+**************************************************************************/
 void key_terrain_toggle(void)
 {
   request_toggle_terrain();
diff --git a/client/control.h b/client/control.h
index 6bdbb27..63b7f0c 100644
--- a/client/control.h
+++ b/client/control.h
@@ -107,6 +107,7 @@ void request_toggle_map_borders(void);
 void request_toggle_city_names(void);
 void request_toggle_city_growth(void);
 void request_toggle_city_productions(void);
+void request_toggle_city_traderoutes(void);
 void request_toggle_terrain(void);
 void request_toggle_coastline(void);
 void request_toggle_roads_rails(void);
@@ -151,6 +152,7 @@ void key_center_capital(void);
 void key_city_names_toggle(void);
 void key_city_growth_toggle(void);
 void key_city_productions_toggle(void);
+void key_city_traderoutes_toggle(void);
 void key_terrain_toggle(void);
 void key_coastline_toggle(void);
 void key_roads_rails_toggle(void);
diff --git a/client/gui-gtk-2.0/menu.c b/client/gui-gtk-2.0/menu.c
index 009ec01..ba77872 100644
--- a/client/gui-gtk-2.0/menu.c
+++ b/client/gui-gtk-2.0/menu.c
@@ -100,6 +100,7 @@ enum MenuID {
   MENU_VIEW_SHOW_CITY_NAMES,
   MENU_VIEW_SHOW_CITY_GROWTH_TURNS,
   MENU_VIEW_SHOW_CITY_PRODUCTIONS,
+  MENU_VIEW_SHOW_CITY_TRADEROUTES,
   MENU_VIEW_SHOW_CITY_WORKERS,
   MENU_VIEW_SHOW_TERRAIN,
   MENU_VIEW_SHOW_COASTLINE,
@@ -329,6 +330,10 @@ static void view_menu_callback(gpointer callback_data, guint callback_action,
     if (draw_city_productions ^ GTK_CHECK_MENU_ITEM(widget)->active)
       key_city_productions_toggle();
     break;
+  case MENU_VIEW_SHOW_CITY_TRADEROUTES:
+    if (draw_city_traderoutes ^ GTK_CHECK_MENU_ITEM(widget)->active)
+      key_city_traderoutes_toggle();
+    break;
   case MENU_VIEW_SHOW_CITY_WORKERS:
     key_city_workers();
     break;
@@ -781,6 +786,8 @@ static GtkItemFactoryEntry menu_items[]	=
 	view_menu_callback,	MENU_VIEW_SHOW_CITY_GROWTH_TURNS,	"<CheckItem>"	},
   { "/" N_("View") "/" N_("City _Productions"),		"<control>p",
 	view_menu_callback,	MENU_VIEW_SHOW_CITY_PRODUCTIONS,	"<CheckItem>"	},
+  { "/" N_("View") "/" N_("City Traderoutes"),		"<control>t",
+	view_menu_callback,	MENU_VIEW_SHOW_CITY_TRADEROUTES,	"<CheckItem>"	},
   { "/" N_("View") "/" N_("Draw city worker map grid"),	"t",
         view_menu_callback,     MENU_VIEW_SHOW_CITY_WORKERS				},
   { "/" N_("View") "/sep1",				NULL,
@@ -1325,6 +1332,7 @@ void update_menus(void)
 
     menus_set_active("<main>/_View/City G_rowth", draw_city_growth);
     menus_set_active("<main>/_View/City _Productions", draw_city_productions);
+    menus_set_active("<main>/_View/City Traderoutes", draw_city_traderoutes);
     menus_set_active("<main>/_View/Terrain", draw_terrain);
     menus_set_active("<main>/_View/Coastline", draw_coastline);
     menus_set_sensitive("<main>/_View/Coastline", !draw_terrain);
diff --git a/client/mapview_common.c b/client/mapview_common.c
index 0fcff9d..fe10f4d 100644
--- a/client/mapview_common.c
+++ b/client/mapview_common.c
@@ -23,6 +23,7 @@
 #include "support.h"
 #include "timing.h"
 
+#include "game.h"
 #include "map.h"
 #include "unitlist.h"
 
@@ -68,6 +69,15 @@ static void queue_mapview_update(enum update_type update);
 static void queue_mapview_tile_update(struct tile *ptile,
 				      enum tile_update_type type);
 
+/* Helper struct for drawing traderoutes. */
+struct traderoute_line {
+  int x, y, width, height;
+};
+
+/* A traderoute line might need to be drawn in two parts. */
+static const int MAX_TRADEROUTE_DRAW_LINES = 2;
+
+
 /**************************************************************************
  Refreshes a single tile on the map canvas.
 **************************************************************************/
@@ -1071,6 +1081,130 @@ static void put_one_tile(struct canvas *pcanvas, enum mapview_layer layer,
 }
 
 /**************************************************************************
+  Depending on where ptile1 and ptile2 are on the map canvas, a traderoute
+  line may need to be drawn as two disjointed line segments. This function
+  fills the given line array 'lines' with the necessary line segments.
+
+  The return value is the number of line segments that need to be drawn.
+
+  NB: It is assumed ptile1 and ptile2 are already consistently ordered.
+  NB: 'lines' must be able to hold least MAX_TRADEROUTE_DRAW_LINES
+  elements.
+**************************************************************************/
+static int traderoute_to_canvas_lines(const struct tile *ptile1,
+                                      const struct tile *ptile2,
+                                      struct traderoute_line *lines)
+{
+  int dx, dy;
+
+  if (!ptile1 || !ptile2 || !lines) {
+    return 0;
+  }
+
+  base_map_distance_vector(&dx, &dy, TILE_XY(ptile1), TILE_XY(ptile2));
+  map_to_gui_pos(tileset, &lines[0].width, &lines[0].height, dx, dy);
+
+  /* FIXME: Remove these casts. */
+  tile_to_canvas_pos(&lines[0].x, &lines[0].y, (struct tile *)ptile1);
+  tile_to_canvas_pos(&lines[1].x, &lines[1].y, (struct tile *)ptile2);
+
+  if (lines[1].x - lines[0].x == lines[0].width
+      && lines[1].y - lines[0].y == lines[0].height) {
+    return 1;
+  }
+
+  lines[1].width = -lines[0].width;
+  lines[1].height = -lines[0].height;
+  return 2;
+}
+
+/**************************************************************************
+  Draw a colored traderoute line from one tile to another.
+**************************************************************************/
+static void draw_traderoute_line(const struct tile *ptile1,
+                                 const struct tile *ptile2,
+                                 enum color_std color)
+{
+  struct traderoute_line lines[MAX_TRADEROUTE_DRAW_LINES];
+  int line_count, i;
+  struct color *pcolor;
+
+  if (!ptile1 || !ptile2) {
+    return;
+  }
+
+  pcolor = get_color(tileset, color);
+  if (!pcolor) {
+    return;
+  }
+
+  /* Order the source and destination tiles consistently
+   * so that if a line is drawn twice it does not produce
+   * ugly effects due to dashes not lining up. */
+  if (ptile2->index > ptile1->index) {
+    const struct tile *tmp;
+    tmp = ptile1;
+    ptile1 = ptile2;
+    ptile2 = tmp;
+  }
+
+  line_count = traderoute_to_canvas_lines(ptile1, ptile2, lines);
+  for (i = 0; i < line_count; i++) {
+    canvas_put_line(mapview.store, pcolor, LINE_BORDER,
+                    lines[i].x + tileset_tile_width(tileset) / 2,
+                    lines[i].y + tileset_tile_height(tileset) / 2,
+                    lines[i].width, lines[i].height);
+  }
+}
+
+/**************************************************************************
+  Draw all traderoutes for the given city.
+**************************************************************************/
+static void draw_traderoutes_for_city(const struct city *pcity_src)
+{
+  int i;
+  const struct city *pcity_dest;
+
+  if (!pcity_src) {
+    return;
+  }
+
+  for (i = 0; i < NUM_TRADEROUTES; i++) {
+    pcity_dest = game_find_city_by_number(pcity_src->trade[i]);
+    if (!pcity_dest) {
+      continue;
+    }
+    draw_traderoute_line(pcity_src->tile, pcity_dest->tile,
+                         COLOR_OVERVIEW_LAND); /* Green. */
+  }
+}
+
+/**************************************************************************
+  Draw traderoutes between cities as lines on the main map canvas.
+**************************************************************************/
+static void draw_traderoutes(void)
+{
+  struct player *pplayer = game.player_ptr;
+
+  if (!draw_city_traderoutes) {
+    return;
+  }
+
+  if (client_is_observer() && !pplayer) {
+    cities_iterate(pcity) {
+      draw_traderoutes_for_city(pcity);
+    } cities_iterate_end;
+  } else {
+    if (!pplayer) {
+      return;
+    }
+    city_list_iterate(pplayer->cities, pcity) {
+      draw_traderoutes_for_city(pcity);
+    } city_list_iterate_end;
+  }
+}
+
+/**************************************************************************
   Update (refresh) the map canvas starting at the given tile (in map
   coordinates) and with the given dimensions (also in map coordinates).
 
@@ -1152,6 +1286,8 @@ void update_map_canvas(int canvas_x, int canvas_y, int width, int height)
     } gui_rect_iterate_end;
   } mapview_layer_iterate_end;
 
+  draw_traderoutes();
+
   /* Draw the goto lines on top of the whole thing. This is done last as
    * we want it completely on top.
    *
diff --git a/client/options.c b/client/options.c
index f72717b..2d040ef 100644
--- a/client/options.c
+++ b/client/options.c
@@ -285,6 +285,7 @@ bool draw_map_grid = FALSE;
 bool draw_city_names = TRUE;
 bool draw_city_growth = TRUE;
 bool draw_city_productions = FALSE;
+bool draw_city_traderoutes = FALSE;
 bool draw_terrain = TRUE;
 bool draw_coastline = FALSE;
 bool draw_roads_rails = TRUE;
@@ -312,6 +313,7 @@ view_option view_options[] = {
   VIEW_OPTION(draw_city_names),
   VIEW_OPTION(draw_city_growth),
   VIEW_OPTION(draw_city_productions),
+  VIEW_OPTION(draw_city_traderoutes),
   VIEW_OPTION(draw_terrain),
   VIEW_OPTION(draw_coastline),
   VIEW_OPTION(draw_roads_rails),
diff --git a/client/options.h b/client/options.h
index 31268ea..ece60ae 100644
--- a/client/options.h
+++ b/client/options.h
@@ -129,6 +129,7 @@ extern bool draw_map_grid;
 extern bool draw_city_names;
 extern bool draw_city_growth;
 extern bool draw_city_productions;
+extern bool draw_city_traderoutes;
 extern bool draw_terrain;
 extern bool draw_coastline;
 extern bool draw_roads_rails;
_______________________________________________
Freeciv-dev mailing list
Freeciv-dev@gna.org
https://mail.gna.org/listinfo/freeciv-dev

Reply via email to