Complete.Org: Mailing Lists: Archives: freeciv-dev: December 2005:
[Freeciv-Dev] Re: (PR#13773) Improved cursors
Home

[Freeciv-Dev] Re: (PR#13773) Improved cursors

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: andrearo@xxxxxxxxxxxx
Subject: [Freeciv-Dev] Re: (PR#13773) Improved cursors
From: "Jason Short" <jdorje@xxxxxxxxxxxxxxxxxxxxx>
Date: Sat, 10 Dec 2005 14:25:12 -0800
Reply-to: bugs@xxxxxxxxxxx

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

Andreas Røsdal wrote:
> <URL: http://bugs.freeciv.org/Ticket/Display.html?id=13773 >
> 
> On Sat, 10 Dec 2005, Jason Short wrote:
> 
>>The patch should be fixed up and committed.
>>
>>The only parts I think need fixing are those in common/.  I don't
>>understand these changes, and I suspect they are wrong.  For instance a
>>query on the goto status should go not through common/movement.c, it
>>should go through client/goto.c.  And the diplomat change looks wrong to
>>me.  But as I said I don't understand them.
> 
> 
> Ok. Here's an updated patch with these fixes.

I made a few little fixes:

* Style fixes.
* Changed fc_cursors to be a double-array.
* Renamed valid_goto_dest and added FIXME comment.

For valid_goto_dest, the problem is that we are unnecessarily doing the 
PF lookup a second (or more) times.  When we're in the goto hover state 
and the mouse moves over a tile, the PF search is already done inside 
update_last_part and is then duplicated inside 
is_valid_goto_destination.  This would be easy to fix except that 
is_valid_goto_destination is called _before_ update_last_part.

Nonetheless I'm going to go ahead and commit this.

-jason

Index: data/misc/cursors.png
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: data/misc/cursors.spec
===================================================================
--- data/misc/cursors.spec      (revision 11332)
+++ data/misc/cursors.spec      (working copy)
@@ -7,7 +7,7 @@
 [info]
 
 artists = "
-    ???
+    Andreas Røsdal <andrearo@xxxxxxxxxxxx>
 "
 
 [file]
@@ -15,15 +15,53 @@
 
 [grid_main]
 
-x_top_left = 0
-y_top_left = 0
-dx = 27
-dy = 27
-pixel_border=0
+x_top_left = 1
+y_top_left = 1
+dx = 32
+dy = 32
+pixel_border = 1
 
 tiles = { "row", "column", "tag", "hot_x", "hot_y"
-       0, 0, "cursor.goto", 25, 1
-       0, 1, "cursor.patrol", 13, 13
-       0, 2, "cursor.paradrop", 13, 25
-       0, 3, "cursor.nuke", 13, 13
+       0, 0, "cursor.goto0", 16, 16
+       1, 0, "cursor.goto1", 16, 16
+       2, 0, "cursor.goto2", 16, 16
+       3, 0, "cursor.goto3", 16, 16
+       4, 0, "cursor.goto4", 16, 16
+       5, 0, "cursor.goto5", 16, 16
+       0, 1, "cursor.patrol0", 16, 16
+       1, 1, "cursor.patrol1", 16, 16
+       2, 1, "cursor.patrol2", 16, 16
+       3, 1, "cursor.patrol3", 16, 16
+       4, 1, "cursor.patrol4", 16, 16
+       5, 1, "cursor.patrol5", 16, 16
+       0, 2, "cursor.paradrop0", 16, 16
+       1, 2, "cursor.paradrop1", 16, 16
+       2, 2, "cursor.paradrop2", 16, 16
+       3, 2, "cursor.paradrop3", 16, 16
+       4, 2, "cursor.paradrop4", 16, 16
+       5, 2, "cursor.paradrop5", 16, 16
+       0, 3, "cursor.nuke0", 16, 16
+       1, 3, "cursor.nuke1", 16, 16
+       2, 3, "cursor.nuke2", 16, 16
+       3, 3, "cursor.nuke3", 16, 16
+       4, 3, "cursor.nuke4", 16, 16
+       5, 3, "cursor.nuke5", 16, 16
+       0, 4, "cursor.select0", 16, 16
+       1, 4, "cursor.select1", 16, 16
+       2, 4, "cursor.select2", 16, 16
+       3, 4, "cursor.select3", 16, 16
+       4, 4, "cursor.select4", 16, 16
+       5, 4, "cursor.select5", 16, 16
+       0, 5, "cursor.invalid0", 16, 16
+       1, 5, "cursor.invalid1", 16, 16
+       2, 5, "cursor.invalid2", 16, 16
+       3, 5, "cursor.invalid3", 16, 16
+       4, 5, "cursor.invalid4", 16, 16
+       5, 5, "cursor.invalid5", 16, 16
+       0, 6, "cursor.attack0", 16, 16
+       1, 6, "cursor.attack1", 16, 16
+       2, 6, "cursor.attack2", 16, 16
+       3, 6, "cursor.attack3", 16, 16
+       4, 6, "cursor.attack4", 16, 16
+       5, 6, "cursor.attack5", 16, 16
 }
Index: client/control.c
===================================================================
--- client/control.c    (revision 11332)
+++ client/control.c    (working copy)
@@ -31,6 +31,7 @@
 #include "climap.h"
 #include "climisc.h"
 #include "clinet.h"
+#include "combat.h"
 #include "dialogs_g.h"
 #include "goto.h"
 #include "gui_main_g.h"
@@ -57,6 +58,8 @@
 /* These should be set via set_hover_state() */
 int hover_unit = 0; /* id of unit hover_state applies to */
 enum cursor_hover_state hover_state = HOVER_NONE;
+struct tile *hover_tile = NULL;
+enum cursor_action_state action_state = CURSOR_ACTION_DEFAULT;
 enum unit_activity connect_activity;
 enum unit_orders goto_last_order; /* Last order for goto */
 
@@ -682,7 +685,7 @@
 
   if (hover_state != HOVER_GOTO) {
     set_hover_state(punit, HOVER_GOTO, ACTIVITY_LAST, last_order);
-    update_unit_info_label(punit);
+    handle_mouse_cursor(NULL);
     enter_goto_state(punit);
     create_line_at_mouse_pos();
   } else {
@@ -692,6 +695,70 @@
 }
 
 /**************************************************************************
+  Determines which mouse cursor should be used, according to hover_state,
+  and the information gathered from the tile which is under the mouse 
+  cursor (ptile).
+**************************************************************************/
+void handle_mouse_cursor(struct tile *ptile)
+{
+  struct unit *punit = NULL;
+  struct city *pcity = NULL;
+  struct unit *active_unit = get_unit_in_focus();
+
+  if (!ptile) {
+    if (hover_tile) {
+      /* hover_tile is the tile which is currently under the mouse cursor. */
+      ptile = hover_tile;
+    } else {
+      return;
+    }
+  }
+
+  punit = find_visible_unit(ptile);
+  pcity = ptile ? ptile->city : NULL;
+
+  if (hover_state == HOVER_NONE) {
+    if (punit && game.player_ptr == punit->owner) {
+      /* Set mouse cursor to select a unit.  */
+      action_state = CURSOR_ACTION_SELECT;
+    } else if (pcity && can_player_see_city_internals(game.player_ptr, pcity)) 
{
+      /* Set mouse cursor to select a city. */
+      action_state = CURSOR_ACTION_SELECT;
+    } else {
+      /* Set default mouse cursor, because nothing selectable found. */
+      action_state = CURSOR_ACTION_DEFAULT;
+    }
+
+  } else if (hover_state == HOVER_GOTO) {
+    /* Determine if the goto is valid, invalid or will attack. */
+    if (is_valid_goto_destination(ptile)) {
+      if (is_attack_unit(active_unit)
+         && can_unit_attack_tile(active_unit, ptile)) {
+        /* Goto results in military attack. */
+        action_state = CURSOR_ACTION_ATTACK;
+      } else if (is_enemy_city_tile(ptile, unit_owner(active_unit))
+                && is_attack_unit(active_unit)
+                && can_unit_attack_tile(active_unit, ptile)) {
+        /* Goto results in attack of enemy city. */
+        action_state = CURSOR_ACTION_ATTACK;
+      } else {
+        action_state = CURSOR_ACTION_GOTO;
+      }
+    } else {
+      action_state = CURSOR_ACTION_INVALID;
+    }
+  } else if (hover_state == HOVER_PATROL || hover_state == HOVER_CONNECT) {
+    if (is_valid_goto_destination(ptile)) {
+      action_state = CURSOR_ACTION_GOTO;
+    } else {
+      action_state = CURSOR_ACTION_INVALID;
+    }
+  }
+
+  update_unit_info_label(active_unit);
+}
+
+/**************************************************************************
   Return TRUE if there are any units doing the activity on the tile.
 **************************************************************************/
 static bool is_activity_on_tile(struct tile *ptile,
Index: client/gui-gtk-2.0/mapview.c
===================================================================
--- client/gui-gtk-2.0/mapview.c        (revision 11332)
+++ client/gui-gtk-2.0/mapview.c        (working copy)
@@ -55,8 +55,8 @@
 #include "mapview.h"
 
 static GtkObject *map_hadj, *map_vadj;
+static int cursor_timer_id = 0, cursor_type = -1, cursor_frame = 0;
 
-
 /**************************************************************************
   If do_restore is FALSE it will invert the turn done button style. If
   called regularly from a timer this will give a blinking turn done
@@ -157,6 +157,43 @@
 }
 
 /**************************************************************************
+  This function is used to animate the mouse cursor. 
+**************************************************************************/
+static gint anim_cursor_cb(gpointer data)
+{
+  if (!cursor_timer_id) {
+    return FALSE;
+  }
+
+  cursor_frame++;
+  if (cursor_frame == NUM_CURSOR_FRAMES) {
+    cursor_frame = 0;
+  }
+
+  if (cursor_type == CURSOR_DEFAULT) {
+    gdk_window_set_cursor(root_window, NULL);
+    cursor_timer_id = 0;
+    return FALSE; 
+  }
+
+  gdk_window_set_cursor(root_window,
+                fc_cursors[cursor_type][cursor_frame]);
+  handle_mouse_cursor(NULL);
+  return TRUE;
+}
+
+/**************************************************************************
+  This function will change the current mouse cursor.
+**************************************************************************/
+static void modify_mouse_cursor(enum cursor_type new_cursor_type)
+{
+  cursor_type = new_cursor_type;
+  if (!cursor_timer_id) {
+    cursor_timer_id = gtk_timeout_add(CURSOR_INTERVAL, anim_cursor_cb, NULL);
+  }
+}
+
+/**************************************************************************
   Update the information label which gives info on the current unit and the
   square under the current unit, for specified unit.  Note that in practice
   punit is always the focus unit.
@@ -168,6 +205,7 @@
 **************************************************************************/
 void update_unit_info_label(struct unit *punit)
 {
+  enum cursor_type mouse_cursor_type = CURSOR_DEFAULT;
   GtkWidget *label;
 
   label = gtk_frame_get_label_widget(GTK_FRAME(unit_info_frame));
@@ -177,31 +215,53 @@
   gtk_label_set_text(GTK_LABEL(unit_info_label),
                     get_unit_info_label_text2(punit));
 
-  if(punit) {
-    if (hover_unit != punit->id)
-      set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, ORDER_LAST);
-
-    switch (hover_state) {
-    case HOVER_NONE:
-      gdk_window_set_cursor (root_window, NULL);
-      break;
-    case HOVER_PATROL:
-      gdk_window_set_cursor(root_window, fc_cursors[CURSOR_PATROL]);
-      break;
-    case HOVER_GOTO:
-    case HOVER_CONNECT:
-      gdk_window_set_cursor(root_window, fc_cursors[CURSOR_GOTO]);
-      break;
-    case HOVER_NUKE:
-      gdk_window_set_cursor(root_window, fc_cursors[CURSOR_NUKE]);
-      break;
-    case HOVER_PARADROP:
-      gdk_window_set_cursor(root_window, fc_cursors[CURSOR_PARADROP]);
-      break;
+  switch (hover_state) {
+  case HOVER_NONE:
+    if (action_state == CURSOR_ACTION_SELECT) {
+      mouse_cursor_type = CURSOR_SELECT;
+    } else if (action_state == CURSOR_ACTION_PARATROOPER) {
+      mouse_cursor_type = CURSOR_PARADROP;
+    } else if (action_state == CURSOR_ACTION_NUKE) {
+      mouse_cursor_type = CURSOR_NUKE;
+    } else {
+      mouse_cursor_type = CURSOR_DEFAULT;
     }
-  } else {
-    gdk_window_set_cursor(root_window, NULL);
+    break;
+  case HOVER_PATROL:
+    if (action_state == CURSOR_ACTION_INVALID) {
+      mouse_cursor_type = CURSOR_INVALID;
+    } else {
+      mouse_cursor_type = CURSOR_PATROL;
+    }
+    break;
+  case HOVER_GOTO:
+    if (action_state == CURSOR_ACTION_GOTO) {
+      mouse_cursor_type = CURSOR_GOTO;
+    } else if (action_state == CURSOR_ACTION_DEFAULT) {
+      mouse_cursor_type = CURSOR_DEFAULT;
+    } else if (action_state == CURSOR_ACTION_ATTACK) {
+      mouse_cursor_type = CURSOR_ATTACK;
+    } else {
+      mouse_cursor_type = CURSOR_INVALID;
+    }
+    break;
+  case HOVER_CONNECT:
+    if (action_state == CURSOR_ACTION_INVALID) {
+      mouse_cursor_type = CURSOR_INVALID;
+    } else {
+      mouse_cursor_type = CURSOR_GOTO;
+    }
+    break;
+  case HOVER_NUKE:
+    mouse_cursor_type = CURSOR_NUKE;
+    break;
+  case HOVER_PARADROP:
+    mouse_cursor_type = CURSOR_PARADROP;
+    break;
   }
+
+  modify_mouse_cursor(mouse_cursor_type);
+
   update_unit_pix_label(punit);
 }
 
Index: client/gui-gtk-2.0/mapview.h
===================================================================
--- client/gui-gtk-2.0/mapview.h        (revision 11332)
+++ client/gui-gtk-2.0/mapview.h        (working copy)
@@ -28,6 +28,8 @@
 
 GdkPixbuf *get_thumb_pixbuf(int onoff);
 
+#define CURSOR_INTERVAL 200 /* milliseconds */
+
 gboolean overview_canvas_expose(GtkWidget *w, GdkEventExpose *ev, gpointer 
data);
 gboolean map_canvas_expose(GtkWidget *w, GdkEventExpose *ev, gpointer data);
 gboolean map_canvas_configure(GtkWidget *w, GdkEventConfigure *ev,
Index: client/gui-gtk-2.0/gui_main.c
===================================================================
--- client/gui-gtk-2.0/gui_main.c       (revision 11332)
+++ client/gui-gtk-2.0/gui_main.c       (working copy)
@@ -1003,6 +1003,9 @@
   g_signal_connect(map_canvas, "motion_notify_event",
                    G_CALLBACK(move_mapcanvas), NULL);
 
+  g_signal_connect(toplevel, "enter_notify_event",
+                   G_CALLBACK(leave_mapcanvas), NULL);
+
   g_signal_connect(map_canvas, "button_press_event",
                    G_CALLBACK(butt_down_mapcanvas), NULL);
 
Index: client/gui-gtk-2.0/graphics.c
===================================================================
--- client/gui-gtk-2.0/graphics.c       (revision 11332)
+++ client/gui-gtk-2.0/graphics.c       (working copy)
@@ -44,7 +44,7 @@
 struct sprite *intro_gfx_sprite;
 struct sprite *radar_gfx_sprite;
 
-GdkCursor *fc_cursors[CURSOR_LAST];
+GdkCursor *fc_cursors[CURSOR_LAST][NUM_CURSOR_FRAMES];
 
 /***************************************************************************
 ...
@@ -88,14 +88,18 @@
 {
   enum cursor_type cursor;
   GdkDisplay *display = gdk_display_get_default();
+  int frame;
 
   for (cursor = 0; cursor < CURSOR_LAST; cursor++) {
-    int hot_x, hot_y;
-    struct sprite *sprite = get_cursor_sprite(tileset, cursor, &hot_x, &hot_y);
-    GdkPixbuf *pixbuf = sprite_get_pixbuf(sprite);
+    for (frame = 0; frame < NUM_CURSOR_FRAMES; frame++) {
+      int hot_x, hot_y;
+      struct sprite *sprite
+       = get_cursor_sprite(tileset, cursor, &hot_x, &hot_y, frame);
+      GdkPixbuf *pixbuf = sprite_get_pixbuf(sprite);
 
-    fc_cursors[cursor] = gdk_cursor_new_from_pixbuf(display, pixbuf,
-                                                hot_x, hot_y);
+      fc_cursors[cursor][frame] = gdk_cursor_new_from_pixbuf(display, pixbuf,
+                                                            hot_x, hot_y);
+    }
   }
 }
 
Index: client/gui-gtk-2.0/mapctrl.c
===================================================================
--- client/gui-gtk-2.0/mapctrl.c        (revision 11332)
+++ client/gui-gtk-2.0/mapctrl.c        (working copy)
@@ -363,10 +363,13 @@
 }
 
 /**************************************************************************
-...
+  Triggered by the mouse moving on the mapcanvas, this function will
+  update the mouse cursor and goto lines. 
 **************************************************************************/
 gboolean move_mapcanvas(GtkWidget *w, GdkEventMotion *ev, gpointer data)
 {
+  struct tile *ptile = NULL;
+
   if (!GTK_WIDGET_HAS_FOCUS(map_canvas)) {
     gtk_widget_grab_focus(map_canvas);
   }
@@ -376,10 +379,26 @@
   if (keyboardless_goto_button_down && hover_state == HOVER_NONE) {
     maybe_activate_keyboardless_goto(ev->x, ev->y);
   }
+  ptile = canvas_pos_to_tile(ev->x, ev->y);
+  handle_mouse_cursor(ptile);
+  hover_tile = ptile;
+
   return TRUE;
 }
 
 /**************************************************************************
+  This function will reset the mouse cursor if it leaves the map.
+**************************************************************************/
+gboolean leave_mapcanvas(GtkWidget *widget, GdkEventCrossing *event)
+{
+  struct unit *active_unit = get_unit_in_focus();
+
+  action_state = CURSOR_ACTION_DEFAULT;
+  update_unit_info_label(active_unit); 
+  return TRUE;
+}
+
+/**************************************************************************
 ...
 **************************************************************************/
 gboolean move_overviewcanvas(GtkWidget *w, GdkEventMotion *ev, gpointer data)
Index: client/gui-gtk-2.0/graphics.h
===================================================================
--- client/gui-gtk-2.0/graphics.h       (revision 11332)
+++ client/gui-gtk-2.0/graphics.h       (working copy)
@@ -28,7 +28,7 @@
 
 /* This name is to avoid a naming conflict with a global 'cursors'
  * variable in GTK+-2.6.  See PR#12459. */
-extern GdkCursor *fc_cursors[CURSOR_LAST];
+extern GdkCursor *fc_cursors[CURSOR_LAST][NUM_CURSOR_FRAMES];
 
 void gtk_draw_shadowed_string(GdkDrawable *drawable,
                              GdkGC *black_gc,
Index: client/gui-gtk-2.0/mapctrl.h
===================================================================
--- client/gui-gtk-2.0/mapctrl.h        (revision 11332)
+++ client/gui-gtk-2.0/mapctrl.h        (working copy)
@@ -25,6 +25,7 @@
 gboolean butt_down_mapcanvas(GtkWidget *w, GdkEventButton *ev, gpointer data);
 gboolean butt_down_overviewcanvas(GtkWidget *w, GdkEventButton *ev, gpointer 
data);
 gboolean move_mapcanvas(GtkWidget *w, GdkEventMotion *ev, gpointer data);
+gboolean leave_mapcanvas(GtkWidget *widget, GdkEventCrossing *event);
 gboolean move_overviewcanvas(GtkWidget *w, GdkEventMotion *ev, gpointer data);
 
 void center_on_unit(void);
Index: client/control.h
===================================================================
--- client/control.h    (revision 11332)
+++ client/control.h    (working copy)
@@ -24,6 +24,16 @@
   HOVER_PATROL
 };
 
+enum cursor_action_state {
+  CURSOR_ACTION_DEFAULT,
+  CURSOR_ACTION_GOTO,
+  CURSOR_ACTION_SELECT,
+  CURSOR_ACTION_INVALID,
+  CURSOR_ACTION_ATTACK,
+  CURSOR_ACTION_NUKE,
+  CURSOR_ACTION_PARATROOPER
+};
+
 /* Selecting unit from a stack without popup. */
 enum quickselect_type {
   SELECT_POPUP = 0, SELECT_SEA, SELECT_LAND
@@ -34,10 +44,13 @@
 
 extern int hover_unit; /* unit hover_state applies to */
 extern enum cursor_hover_state hover_state;
+extern enum cursor_action_state action_state;
 extern enum unit_activity connect_activity;
 extern enum unit_orders goto_last_order;
 extern bool non_ai_unit_focus;
 
+extern struct tile *hover_tile;
+
 bool can_unit_do_connect(struct unit *punit, enum unit_activity activity);
 
 void do_move_unit(struct unit *punit, struct unit *target_unit);
@@ -48,6 +61,7 @@
 void do_unit_connect(struct unit *punit, struct tile *ptile,
                     enum unit_activity activity);
 void do_map_click(struct tile *ptile, enum quickselect_type qtype);
+void handle_mouse_cursor(struct tile *ptile);
 
 void set_hover_state(struct unit *punit, enum cursor_hover_state state,
                     enum unit_activity connect_activity,
Index: client/gui-xaw/graphics.c
===================================================================
--- client/gui-xaw/graphics.c   (revision 11332)
+++ client/gui-xaw/graphics.c   (working copy)
@@ -237,7 +237,7 @@
   XQueryColor(display, cmap, &black);
 
   for (cursor = 0; cursor < CURSOR_LAST; cursor++) {
-    sprite = get_cursor_sprite(tileset, cursor, &hot_x, &hot_y);
+    sprite = get_cursor_sprite(tileset, cursor, &hot_x, &hot_y, 0);
 
     /* FIXME: this is entirely wrong.  It should be rewritten using
      * XcursorImageLoadCursor.  See gdkcursor-x11.c in the GTK sources for
Index: client/gui-win32/mapview.c
===================================================================
--- client/gui-win32/mapview.c  (revision 11332)
+++ client/gui-win32/mapview.c  (working copy)
@@ -58,6 +58,8 @@
 
 static HBITMAP intro_gfx;
 
+static int cursor_type = -1;
+
 extern void do_mainwin_layout();
 
 extern int seconds_to_turndone;   
@@ -66,7 +68,21 @@
 static void draw_rates(HDC hdc);
 
 /**************************************************************************
+  This function is used to animate the mouse cursor. 
+**************************************************************************/
+void anim_cursor(float time)
+{
+  int cursor_frame = (int)(time * 15.0f) % NUM_CURSOR_FRAMES;
 
+  if (cursor_type == CURSOR_DEFAULT) {
+    SetCursor (LoadCursor(NULL, IDC_ARROW));
+  } else {
+    SetCursor(cursors[cursor_type * NUM_CURSOR_FRAMES + cursor_frame]);
+  }
+}
+
+/**************************************************************************
+
 **************************************************************************/
 void map_expose(int x, int y, int width, int height)
 {
@@ -182,32 +198,52 @@
   SetWindowText(unit_info_frame, get_unit_info_label_text1(punit));
   SetWindowText(unit_info_label, get_unit_info_label_text2(punit));
 
-  if(punit) {
-    if (hover_unit != punit->id)
-      set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, ORDER_LAST);
-    switch (hover_state) {
-      case HOVER_NONE:
-       SetCursor (LoadCursor(NULL, IDC_ARROW));
-       break;
-      case HOVER_PATROL:
-       SetCursor (cursors[CURSOR_PATROL]);
-       break;
-      case HOVER_GOTO:
-      case HOVER_CONNECT:
-       SetCursor (cursors[CURSOR_GOTO]);
-       break;
-      case HOVER_NUKE:
-       SetCursor (cursors[CURSOR_NUKE]);
-       break;
-      case HOVER_PARADROP:
-       SetCursor (cursors[CURSOR_PARADROP]);
-       break;
-    }
-  } else {
-    SetCursor (LoadCursor(NULL, IDC_ARROW));
+  switch (hover_state) {
+    case HOVER_NONE:
+      if (action_state == CURSOR_ACTION_SELECT) {
+        cursor_type = CURSOR_SELECT;
+      } else if (action_state == CURSOR_ACTION_PARATROOPER) {
+        cursor_type = CURSOR_PARADROP;
+      } else if (action_state == CURSOR_ACTION_NUKE) {
+        cursor_type = CURSOR_NUKE;
+      } else {
+        cursor_type = CURSOR_DEFAULT;
+      }
+      break;
+    case HOVER_PATROL:
+      if (action_state == CURSOR_ACTION_INVALID) {
+        cursor_type = CURSOR_INVALID;
+      } else {
+        cursor_type = CURSOR_PATROL;
+      }
+      break;
+    case HOVER_GOTO:
+      if (action_state == CURSOR_ACTION_GOTO) {
+        cursor_type = CURSOR_GOTO;
+      } else if (action_state == CURSOR_ACTION_DEFAULT) {
+        cursor_type = CURSOR_DEFAULT;
+      } else if (action_state == CURSOR_ACTION_ATTACK) {
+        cursor_type = CURSOR_ATTACK;
+      } else {
+        cursor_type = CURSOR_INVALID;
+      }
+      break;
+    case HOVER_CONNECT:
+      if (action_state == CURSOR_ACTION_INVALID) {
+        cursor_type = CURSOR_INVALID;
+      } else {
+        cursor_type = CURSOR_GOTO;
+      }
+      break;
+    case HOVER_NUKE:
+      cursor_type = CURSOR_NUKE;
+      break;
+    case HOVER_PARADROP:
+      cursor_type = CURSOR_PARADROP;
+      break;
   }
 
-    do_mainwin_layout();
+  do_mainwin_layout();
 }
 
 /**************************************************************************
Index: client/gui-win32/gui_main.c
===================================================================
--- client/gui-win32/gui_main.c (revision 11332)
+++ client/gui-win32/gui_main.c (working copy)
@@ -711,6 +711,8 @@
   return TRUE;
 }
 
+extern void anim_cursor(float time);
+
 /**************************************************************************
 
 **************************************************************************/
@@ -722,6 +724,7 @@
   bool quit = FALSE;
   bool idle;
   struct timer *callback_timer;
+  struct timer *anim_timer;
   float callback_seconds = 0;
 
   freecivhinst = GetModuleHandle(NULL); /* There is no WinMain! */
@@ -754,6 +757,7 @@
   callbacks = callback_list_new();
 
   callback_timer = new_timer_start(TIMER_USER, TIMER_ACTIVE);
+  anim_timer = new_timer_start(TIMER_USER, TIMER_ACTIVE);
 
   while (!quit) {
 
@@ -785,12 +789,15 @@
       }
     }
 
-    /* If nothing happened in the three blocks above, call an idle function */
+    /* If nothing happened in the three blocks above, call an idle function
+     * and do animations */
     if (idle && callbacks && callback_list_size(callbacks) > 0) {
       struct callback *cb = callback_list_get(callbacks, 0);
       callback_list_unlink(callbacks, cb);
       (cb->callback)(cb->data);
       free(cb);
+
+      anim_cursor(read_timer_seconds(anim_timer));
     }
 
     /* If we're idle, give up the CPU. */
@@ -799,6 +806,7 @@
     }
   }
 
+  free_timer(anim_timer);
   free_timer(callback_timer);
   callback_list_unlink_all(callbacks);
   free(callbacks);
Index: client/gui-win32/graphics.c
===================================================================
--- client/gui-win32/graphics.c (revision 11332)
+++ client/gui-win32/graphics.c (working copy)
@@ -56,7 +56,7 @@
 
 extern HINSTANCE freecivhinst;
 
-HCURSOR cursors[CURSOR_LAST];
+HCURSOR cursors[CURSOR_LAST * NUM_CURSOR_FRAMES];
 
 struct sprite *intro_gfx_sprite = NULL;
 struct sprite *radar_gfx_sprite = NULL;
@@ -95,6 +95,7 @@
 {
   enum cursor_type cursor;
   ICONINFO ii;
+  int frame, i;
 
   /* For some reason win32 lets you enter a cursor size, which
    * only works as long as it's this size. */
@@ -112,8 +113,12 @@
     int hot_x, hot_y;
     int x, y;
     int minwidth, minheight;
-    struct sprite *sprite = get_cursor_sprite(tileset, cursor, &hot_x, &hot_y);
 
+    for (frame = 0; frame < NUM_CURSOR_FRAMES; frame++) {
+
+    struct sprite *sprite = get_cursor_sprite(tileset, cursor, 
+                                             &hot_x, &hot_y, frame);
+
     ii.xHotspot = MIN(hot_x, width);
     ii.yHotspot = MIN(hot_y, height);
 
@@ -148,10 +153,14 @@
     ii.hbmMask = BITMAP2HBITMAP(and_bmp);
     ii.hbmColor = BITMAP2HBITMAP(xor_bmp);
 
-    cursors[cursor] = CreateIconIndirect(&ii);
+    i = cursor * NUM_CURSOR_FRAMES + frame;
 
+    cursors[i] = CreateIconIndirect(&ii);
+
     DeleteObject(ii.hbmMask);
     DeleteObject(ii.hbmColor);
+
+    }
   }
 
   bmp_free(xor_bmp);
Index: client/gui-win32/mapctrl.c
===================================================================
--- client/gui-win32/mapctrl.c  (revision 11332)
+++ client/gui-win32/mapctrl.c  (working copy)
@@ -60,7 +60,13 @@
 *************************************************************************/
 void map_handle_move(int window_x, int window_y)
 {
+  struct tile *ptile = NULL;
+
   update_line(window_x, window_y);
+
+  ptile = canvas_pos_to_tile(window_x, window_y);
+  handle_mouse_cursor(ptile);
+  hover_tile = ptile;
 }
 
 /*************************************************************************
Index: client/goto.c
===================================================================
--- client/goto.c       (revision 11332)
+++ client/goto.c       (working copy)
@@ -123,6 +123,31 @@
   }
 }
 
+/**********************************************************************
+  Determines if a goto to the destination tile is allowed.
+
+  FIXME: This requires a duplicate and unnecessary PF search, since when
+  we're in hover mode the search is already done once when calculating
+  how to draw the map...then we do it again here.
+***********************************************************************/
+bool is_valid_goto_destination(struct tile *ptile) 
+{
+  struct part *p = &goto_map.parts[goto_map.num_parts - 1];
+  struct pf_path *new_path;
+
+  if (!goto_is_active()) {
+    return FALSE;
+  } 
+
+  new_path = pf_get_path(p->map, ptile);
+
+  if (new_path) {
+    return TRUE;
+  } else {
+    return FALSE;
+  }
+}
+
 /********************************************************************** 
   Change the destination of the last part to the given position if a
   path can be found. If not the destination is set to the start.
Index: client/goto.h
===================================================================
--- client/goto.h       (revision 11332)
+++ client/goto.h       (working copy)
@@ -26,6 +26,7 @@
 int get_goto_turns(void);
 void goto_add_waypoint(void);
 bool goto_pop_waypoint(void);
+bool is_valid_goto_destination(struct tile *ptile);
 
 void draw_line(struct tile *dest_tile);
 bool is_drawn_line(struct tile *dest_tile, int dir);
Index: client/tilespec.c
===================================================================
--- client/tilespec.c   (revision 11332)
+++ client/tilespec.c   (working copy)
@@ -157,7 +157,7 @@
   struct sprite *spaceship[SPACESHIP_COUNT];
   struct {
     int hot_x, hot_y;
-    struct sprite *icon;
+    struct sprite *frame[NUM_CURSOR_FRAMES];
   } cursor[CURSOR_LAST];
   struct {
     struct sprite
@@ -1965,7 +1965,7 @@
   char buffer[512];
   const char dir_char[] = "nsew";
   const int W = t->normal_tile_width, H = t->normal_tile_height;
-  int i, j;
+  int i, j, f;
   
   assert(t->sprite_hash != NULL);
 
@@ -2006,14 +2006,18 @@
   }
 
   for (i = 0; i < CURSOR_LAST; i++) {
-    const char *names[CURSOR_LAST] = {"goto", "patrol", "paradrop", "nuke"};
-    struct small_sprite *ss;
+    for (f = 0; f < NUM_CURSOR_FRAMES; f++) {
+      const char *names[CURSOR_LAST] =
+               {"goto", "patrol", "paradrop", "nuke", "select", 
+               "invalid", "attack"};
+      struct small_sprite *ss;
 
-    my_snprintf(buffer, sizeof(buffer), "cursor.%s", names[i]);
-    SET_SPRITE(cursor[i].icon, buffer);
-    ss = hash_lookup_data(t->sprite_hash, buffer);
-    t->sprites.cursor[i].hot_x = ss->hot_x;
-    t->sprites.cursor[i].hot_y = ss->hot_y;
+      my_snprintf(buffer, sizeof(buffer), "cursor.%s%d", names[i], f);
+      SET_SPRITE(cursor[i].frame[f], buffer);
+      ss = hash_lookup_data(t->sprite_hash, buffer);
+      t->sprites.cursor[i].hot_x = ss->hot_x;
+      t->sprites.cursor[i].hot_y = ss->hot_y;
+    }
   }
 
   for (i = 0; i < ICON_COUNT; i++) {
@@ -4528,15 +4532,16 @@
 /**************************************************************************
   Returns a sprite for the given cursor.  The "hot" coordinates (the
   active coordinates of the mouse relative to the sprite) are placed int
-  (*hot_x, *hot_y).
+  (*hot_x, *hot_y). 
+  A cursor can consist of several frames to be used for animation.
 **************************************************************************/
 struct sprite *get_cursor_sprite(const struct tileset *t,
                                 enum cursor_type cursor,
-                                int *hot_x, int *hot_y)
+                                int *hot_x, int *hot_y, int frame)
 {
   *hot_x = t->sprites.cursor[cursor].hot_x;
   *hot_y = t->sprites.cursor[cursor].hot_y;
-  return t->sprites.cursor[cursor].icon;
+  return t->sprites.cursor[cursor].frame[frame];
 }
 
 /****************************************************************************
Index: client/tilespec.h
===================================================================
--- client/tilespec.h   (revision 11332)
+++ client/tilespec.h   (working copy)
@@ -148,9 +148,15 @@
   CURSOR_PATROL,
   CURSOR_PARADROP,
   CURSOR_NUKE,
-  CURSOR_LAST
+  CURSOR_SELECT,
+  CURSOR_INVALID,
+  CURSOR_ATTACK,
+  CURSOR_LAST,
+  CURSOR_DEFAULT,
 };
 
+#define NUM_CURSOR_FRAMES 6
+
 enum indicator_type {
   INDICATOR_BULB,
   INDICATOR_WARMING,
@@ -209,7 +215,7 @@
 struct sprite *get_nuke_explode_sprite(const struct tileset *t);
 struct sprite *get_cursor_sprite(const struct tileset *t,
                                 enum cursor_type cursor,
-                                int *hot_x, int *hot_y);
+                                int *hot_x, int *hot_y, int frame);
 const struct citybar_sprites *get_citybar_sprites(const struct tileset *t);
 struct sprite *get_icon_sprite(const struct tileset *t, enum icon_type icon);
 struct sprite *get_attention_crosshair_sprite(const struct tileset *t);

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