Complete.Org: Mailing Lists: Archives: freeciv-dev: December 2005:
[Freeciv-Dev] (PR#7171) Patch: sdl client - mouse behavior
Home

[Freeciv-Dev] (PR#7171) Patch: sdl client - mouse behavior

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: jpliberato@xxxxxxxxx
Subject: [Freeciv-Dev] (PR#7171) Patch: sdl client - mouse behavior
From: "Christian Prochaska" <cp.ml.freeciv.dev@xxxxxxxxxxxxxx>
Date: Fri, 30 Dec 2005 06:58:36 -0800
Reply-to: bugs@xxxxxxxxxxx

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

> [jpliberato@xxxxxxxxx - Mo 29. Dez 2003, 15:31:28]:
> 
> This patch changes the mouse behavior in the sdl
> client.
> left button -> keep pressed for a goto order.  You can
> drag the mouse to change the goto location, like in
> civ3 or alpha centauri.  Just click for actions like
> selecting a unit or a city.
> right button -> Open a popup menu.
> center button -> recenter screen.
> 
> Joao Paulo Liberato
> jpliberato at yahoo dot com
> 
> __________________________________
> Do you Yahoo!?
> New Yahoo! Photos - easier uploading and sharing.
> http://photos.yahoo.com/
> 

Inspired by Joao Paulo's patch, here's another one. It implements the
"click-and-hold" feature with three hold states:

short hold: simple click (delay < 750ms)
medium hold: delay between 750ms and 2000ms
long hold: delay above 2000ms

The "long hold" state is meant for the Pocket PC interface where you
have only one 'mouse button' (tap on screen with stylus). On a desktop
PC currently the same action as in "medium hold" state is performed.

The mouse behavior with this patch is the following:

- left mouse button (short hold): usual left click action (no change)
- left mouse button (medium hold): enter goto mode, like described above
by Joao Paulo
- left mouse button (long hold): nothing/no effect on medium hold action
on desktop PC / cancel goto mode and popup the context menu on Pocket PC
unless the mouse has already been moved over another tile in goto mode

- middle mouse button (any hold state): popup context menu (no change)

- right mouse button (short hold): recenter screen (no change)
- right mouse button (medium hold): popup context menu (meant for
2-button mice)
- right mouse button (long hold): nothing/no effect on medium hold action

Index: client/gui-sdl/mapview.c
===================================================================
--- client/gui-sdl/mapview.c    (Revision 11410)
+++ client/gui-sdl/mapview.c    (Arbeitskopie)
@@ -55,9 +55,6 @@
 #include "mapview.h"
 
 extern SDL_Event *pFlush_User_Event;
-extern enum cursor_type mouse_cursor_type;
-extern bool mouse_cursor_changed;
-extern bool do_cursor_animation;
 
 int OVERVIEW_START_X;
 int OVERVIEW_START_Y;
Index: client/gui-sdl/gui_main.c
===================================================================
--- client/gui-sdl/gui_main.c   (Revision 11411)
+++ client/gui-sdl/gui_main.c   (Arbeitskopie)
@@ -58,6 +58,7 @@
 #include "cityrep.h"
 #include "graphics.h"
 #include "gui_id.h"
+#include "gui_mem.h"
 #include "gui_stuff.h"         /* gui */
 #include "gui_tilespec.h"
 #include "inteldlg.h"
@@ -102,6 +103,9 @@
 static bool autoconnect = FALSE;
 static bool is_map_scrolling = FALSE;
 static enum direction8 scroll_dir;
+
+static struct mouse_button_behavior button_behavior;
+  
 static SDL_Event *pNet_User_Event = NULL;
 static SDL_Event *pAnim_User_Event = NULL;
 static SDL_Event *pInfo_User_Event = NULL;
@@ -280,9 +284,19 @@
     return widget_pressed_action(pWidget);
   } else {
 #ifdef UNDER_CE
-    check_scroll_area(pButtonEvent->x, pButtonEvent->y);
+    if (!check_scroll_area(pButtonEvent->x, pButtonEvent->y)) {
 #endif        
-  } 
+    if (!button_behavior.button_down_ticks) {
+      /* start counting */
+      button_behavior.button_down_ticks = SDL_GetTicks();   
+      *button_behavior.event = *pButtonEvent;
+      button_behavior.hold_state = MB_HOLD_SHORT;
+      button_behavior.ptile = canvas_pos_to_tile(pButtonEvent->x, 
pButtonEvent->y);
+    }
+#ifdef UNDER_CE
+    }
+#endif    
+  }
   
   return ID_ERROR;
 }
@@ -290,9 +304,12 @@
 static Uint16 main_mouse_button_up_handler(SDL_MouseButtonEvent *pButtonEvent, 
void *pData)
 {
   if (!MainWidgetListScaner(pButtonEvent->x, pButtonEvent->y)) {
-    button_down_on_map(pButtonEvent);
+    *button_behavior.event = *pButtonEvent;
+    button_up_on_map(&button_behavior);
   }
 
+  button_behavior.button_down_ticks = 0;  
+  
 #ifdef UNDER_CE
   is_map_scrolling = FALSE;
 #endif
@@ -308,7 +325,18 @@
 static Uint16 main_mouse_motion_handler(SDL_MouseMotionEvent *pMotionEvent, 
void *pData)
 {
   static struct GUI *pWidget;
-    
+  struct tile *ptile;
+
+  /* stop evaluating button hold time when moving to another tile in medium
+   * hold state or above */
+  if (button_behavior.hold_state >= MB_HOLD_MEDIUM) {
+    ptile = canvas_pos_to_tile(pMotionEvent->x, pMotionEvent->y);
+    if ((ptile->x != button_behavior.ptile->x)
+        || (ptile->y != button_behavior.ptile->y)) {
+      button_behavior.button_down_ticks = 0;
+    }
+  }
+  
   if(draw_goto_patrol_lines) {
     update_line(pMotionEvent->x, pMotionEvent->y);
   }
@@ -376,7 +404,28 @@
 
     flip = !flip;
   }
-    
+  
+  /* button pressed */
+  if (button_behavior.button_down_ticks) {
+    if (((SDL_GetTicks() - button_behavior.button_down_ticks) >= 
MB_MEDIUM_HOLD_DELAY)
+      && ((SDL_GetTicks() - button_behavior.button_down_ticks) < 
MB_LONG_HOLD_DELAY)) {
+      
+      if (button_behavior.hold_state != MB_HOLD_MEDIUM) {
+        button_behavior.hold_state = MB_HOLD_MEDIUM;
+        button_down_on_map(&button_behavior);
+      }
+          
+    } else if (((SDL_GetTicks() - button_behavior.button_down_ticks)
+                                                    >= MB_LONG_HOLD_DELAY)) {
+
+      if (button_behavior.hold_state != MB_HOLD_LONG) {
+        button_behavior.hold_state = MB_HOLD_LONG;
+        button_down_on_map(&button_behavior);
+      }
+      
+    }    
+  }
+  
   return;
 }
 
@@ -699,6 +748,10 @@
   SDL_Surface *pBgd;
   Uint32 iSDL_Flags;
 
+  button_behavior.button_down_ticks = 0;
+  button_behavior.hold_state = MB_HOLD_SHORT;
+  button_behavior.event = MALLOC(sizeof(SDL_MouseButtonEvent));
+  
   SDL_Client_Flags = 0;
   iSDL_Flags = SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE;
   
@@ -914,6 +967,8 @@
   
   unload_cursors();
   
+  FREE(button_behavior.event);
+  
 /* FIXME: the font system cannot be freed yet, because it is still 
  * needed in civclient.c for message window output */
 #if 0 
Index: client/gui-sdl/gui_main.h
===================================================================
--- client/gui-sdl/gui_main.h   (Revision 11410)
+++ client/gui-sdl/gui_main.h   (Arbeitskopie)
@@ -56,6 +56,24 @@
 #define CF_DRAW_PLAYERS_ALLIANCE_STATUS        (1<<22)
 #define CF_DRAW_PLAYERS_NEUTRAL_STATUS (1<<23)
 
+/* mouse button behavior */
+#define MB_MEDIUM_HOLD_DELAY  750         /* medium hold:  750ms */
+#define MB_LONG_HOLD_DELAY   2000         /* long hold:   2000ms */
+
+enum mouse_button_hold_state {
+  MB_HOLD_SHORT,
+  MB_HOLD_MEDIUM,
+  MB_HOLD_LONG
+};
+
+struct mouse_button_behavior {
+  Uint32 button_down_ticks;
+  enum mouse_button_hold_state hold_state;
+  SDL_MouseButtonEvent *event;
+  struct tile *ptile;
+};
+
+
 extern struct GUI *pSellected_Widget;
 extern Uint32 SDL_Client_Flags;
 extern bool LSHIFT;
@@ -66,6 +84,8 @@
 extern bool do_focus_animation;
 extern int city_names_font_size;
 extern int city_productions_font_size;
+extern enum cursor_type mouse_cursor_type;
+extern bool mouse_cursor_changed;
 
 void force_exit_from_event_loop(void);
 void add_autoconnect_to_timer(void);
Index: client/gui-sdl/mapctrl.c
===================================================================
--- client/gui-sdl/mapctrl.c    (Revision 11410)
+++ client/gui-sdl/mapctrl.c    (Arbeitskopie)
@@ -26,6 +26,7 @@
 
 /* utility */
 #include "fcintl.h"
+#include "log.h"
 
 /* common */
 #include "unit.h"
@@ -1959,9 +1960,76 @@
 /**************************************************************************
   mouse click handler
 **************************************************************************/
-void button_down_on_map(SDL_MouseButtonEvent * pButtonEvent)
+void button_down_on_map(struct mouse_button_behavior *button_behavior)
 {
   struct tile *ptile;
+  
+  if (get_client_state() != CLIENT_GAME_RUNNING_STATE) {
+    return;
+  }
+  
+  if (button_behavior->event->button == SDL_BUTTON_LEFT) {
+    switch(button_behavior->hold_state) {
+      case MB_HOLD_SHORT:
+        break;
+      case MB_HOLD_MEDIUM:
+        /* switch to goto mode */
+        key_unit_goto();
+        mouse_cursor_type = CURSOR_GOTO;      
+        mouse_cursor_changed = TRUE;
+        break;
+      case MB_HOLD_LONG:
+#ifdef UNDER_CE
+        /* cancel goto mode and open context menu on Pocket PC since we have
+         * only one 'mouse button' */
+        key_cancel_action();
+        draw_goto_patrol_lines = FALSE;
+        mouse_cursor_type = CURSOR_DEFAULT;
+        mouse_cursor_changed = TRUE;
+        /* popup context menu */
+        if ((ptile = canvas_pos_to_tile((int) button_behavior->event->x,
+                                        (int) button_behavior->event->y))) {
+          popup_advanced_terrain_dialog(ptile);
+        }
+#endif
+        break;
+      default:
+        break;
+    }
+  } else if (button_behavior->event->button == SDL_BUTTON_MIDDLE) {
+    switch(button_behavior->hold_state) {
+      case MB_HOLD_SHORT:
+        break;      
+      case MB_HOLD_MEDIUM:
+        break;
+      case MB_HOLD_LONG:
+        break;
+      default:
+        break;
+    }
+  } else if (button_behavior->event->button == SDL_BUTTON_RIGHT) {
+    switch (button_behavior->hold_state) {
+      case MB_HOLD_SHORT:
+        break;
+      case MB_HOLD_MEDIUM:      
+        /* popup context menu */
+        if ((ptile = canvas_pos_to_tile((int) button_behavior->event->x,
+                                        (int) button_behavior->event->y))) {
+          popup_advanced_terrain_dialog(ptile);
+        }
+        break;
+      case MB_HOLD_LONG:
+        break;
+      default:
+        break;
+    }
+  }
+    
+}
+
+void button_up_on_map(struct mouse_button_behavior *button_behavior)
+{
+  struct tile *ptile;
   struct city *pCity;
     
   if (get_client_state() != CLIENT_GAME_RUNNING_STATE) {
@@ -1970,40 +2038,86 @@
   
   draw_goto_patrol_lines = FALSE;
   
-  if (pButtonEvent->button == SDL_BUTTON_LEFT) {
-    if(LSHIFT || LALT || LCTRL) {
-      if ((ptile = canvas_pos_to_tile((int) pButtonEvent->x,
-                                      (int) pButtonEvent->y))) {
-       if(LSHIFT) {
-         popup_advanced_terrain_dialog(ptile);
-       } else {
-         if(((pCity = ptile->city) != NULL) &&
-           (pCity->owner == game.player_ptr)) {
-           if(LCTRL) {
-             popup_worklist_editor(pCity, &(pCity->worklist));
-           } else {
-             /* LALT - this work only with fullscreen mode */
-             popup_hurry_production_dialog(pCity, NULL);
-           }
-         }
-       }                     
-      }
-    } else {
-      action_button_pressed(pButtonEvent->x, pButtonEvent->y, SELECT_POPUP);
+  if (button_behavior->event->button == SDL_BUTTON_LEFT) {
+    switch(button_behavior->hold_state) {
+      case MB_HOLD_SHORT:
+        if(LSHIFT || LALT || LCTRL) {
+          if ((ptile = canvas_pos_to_tile((int) button_behavior->event->x,
+                                          (int) button_behavior->event->y))) {
+            if(LSHIFT) {
+              popup_advanced_terrain_dialog(ptile);
+            } else {
+              if(((pCity = ptile->city) != NULL) &&
+                (pCity->owner == game.player_ptr)) {
+                if(LCTRL) {
+                  popup_worklist_editor(pCity, &(pCity->worklist));
+                } else {
+                  /* LALT - this work only with fullscreen mode */
+                  popup_hurry_production_dialog(pCity, NULL);
+                }
+              }
+            }                
+          }
+        } else {
+          mouse_cursor_type = CURSOR_DEFAULT;
+          mouse_cursor_changed = TRUE;
+          action_button_pressed(button_behavior->event->x,
+                                     button_behavior->event->y, SELECT_POPUP);
+        }
+        break;
+      case MB_HOLD_MEDIUM:
+        /* finish goto */
+        mouse_cursor_type = CURSOR_DEFAULT;
+        mouse_cursor_changed = TRUE;
+        action_button_pressed(button_behavior->event->x,
+                                     button_behavior->event->y, SELECT_POPUP);
+        break;
+      case MB_HOLD_LONG:
+#ifndef UNDER_CE
+        /* finish goto */
+        mouse_cursor_type = CURSOR_DEFAULT;
+        mouse_cursor_changed = TRUE;
+        action_button_pressed(button_behavior->event->x,
+                                     button_behavior->event->y, SELECT_POPUP);
+#endif
+        break;
+      default:
+        break;
     }
-  } else {
-    if (pButtonEvent->button == SDL_BUTTON_MIDDLE) {
-      if ((ptile = canvas_pos_to_tile((int) pButtonEvent->x,
-                                      (int) pButtonEvent->y))) {
-        popup_advanced_terrain_dialog(ptile);
-      }
-    } else {
-      recenter_button_pressed(pButtonEvent->x, pButtonEvent->y);
-      flush_dirty();
+  } else if (button_behavior->event->button == SDL_BUTTON_MIDDLE) {
+    switch(button_behavior->hold_state) {
+      case MB_HOLD_SHORT:
+/*        break;*/
+      case MB_HOLD_MEDIUM:
+/*        break;*/
+      case MB_HOLD_LONG:
+/*        break;*/
+      default:
+        /* popup context menu */
+        if ((ptile = canvas_pos_to_tile((int) button_behavior->event->x,
+                                        (int) button_behavior->event->y))) {
+          popup_advanced_terrain_dialog(ptile);
+        }
+        break;
     }
+  } else if (button_behavior->event->button == SDL_BUTTON_RIGHT) {
+    switch (button_behavior->hold_state) {
+      case MB_HOLD_SHORT:
+        /* recenter map */
+        recenter_button_pressed(button_behavior->event->x, 
button_behavior->event->y);
+        flush_dirty();
+        break;
+      case MB_HOLD_MEDIUM:      
+        break;
+      case MB_HOLD_LONG:
+        break;
+      default:
+        break;
+    }
   }
+  
 }
-
+  
 /**************************************************************************
   Toggle map drawing stuff.
 **************************************************************************/
@@ -2015,6 +2129,8 @@
     case SDLK_ESCAPE:
       key_cancel_action();
       draw_goto_patrol_lines = FALSE;
+      mouse_cursor_type = CURSOR_DEFAULT;
+      mouse_cursor_changed = TRUE;
     return FALSE;
 
     case SDLK_UP:
@@ -2400,7 +2516,10 @@
 **************************************************************************/
 void create_line_at_mouse_pos(void)
 {
-  update_line(Main.event.motion.x, Main.event.motion.y);
+  int pos_x, pos_y;
+    
+  SDL_GetMouseState(&pos_x, &pos_y);
+  update_line(pos_x, pos_y);
   draw_goto_patrol_lines = TRUE;
 }
 
Index: client/gui-sdl/mapctrl.h
===================================================================
--- client/gui-sdl/mapctrl.h    (Revision 11410)
+++ client/gui-sdl/mapctrl.h    (Arbeitskopie)
@@ -73,6 +73,8 @@
 void enable_main_widgets(void);
 void disable_main_widgets(void);
 bool map_event_handler(SDL_keysym Key);
-void button_down_on_map(SDL_MouseButtonEvent * pButtonEvent);
 
+void button_down_on_map(struct mouse_button_behavior *button_behavior);
+void button_up_on_map(struct mouse_button_behavior *button_behavior);
+
 #endif /* FC__MAPCTRL_H */

[Prev in Thread] Current Thread [Next in Thread]
  • [Freeciv-Dev] (PR#7171) Patch: sdl client - mouse behavior, Christian Prochaska <=