rnd-20100521-1-src
[rocksndiamonds.git] / src / libgame / gadgets.c
index b01fe169245ebb414aa3122a1867bf410854076f..4ac2a294202b249eb88fc6831dc7b0c623fd6d6b 100644 (file)
@@ -1,7 +1,7 @@
 /***********************************************************
 * Artsoft Retro-Game Library                               *
 *----------------------------------------------------------*
-* (c) 1994-2002 Artsoft Entertainment                      *
+* (c) 1994-2006 Artsoft Entertainment                      *
 *               Holger Schemel                             *
 *               Detmolder Strasse 189                      *
 *               33604 Bielefeld                            *
@@ -32,6 +32,17 @@ static struct GadgetInfo *last_info_gi = NULL;
 static int next_free_gadget_id = 1;
 static boolean gadget_id_wrapped = FALSE;
 
+static void (*PlayGadgetSoundActivating)(void) = NULL;
+static void (*PlayGadgetSoundSelecting)(void) = NULL;
+
+
+void InitGadgetsSoundCallback(void (*activating_function)(void),
+                             void (*selecting_function)(void))
+{
+  PlayGadgetSoundActivating = activating_function;
+  PlayGadgetSoundSelecting = selecting_function;
+}
+
 static struct GadgetInfo *getGadgetInfoFromGadgetID(int id)
 {
   struct GadgetInfo *gi = gadget_list_first_entry;
@@ -71,9 +82,11 @@ static struct GadgetInfo *getGadgetInfoFromMousePosition(int mx, int my,
   struct GadgetInfo *gi;
 
   /* first check for scrollbars in case of mouse scroll wheel button events */
-  if (button == 4 || button == 5)
+  if (IS_WHEEL_BUTTON(button))
   {
-    boolean check_horizontal = (GetKeyModState() & KMOD_Control);
+    /* real horizontal wheel or vertical wheel with modifier key pressed */
+    boolean check_horizontal = (IS_WHEEL_BUTTON_HORIZONTAL(button) ||
+                               GetKeyModState() & KMOD_Shift);
 
     /* check for the first active scrollbar with matching mouse wheel area */
     for (gi = gadget_list_first_entry; gi != NULL; gi = gi->next)
@@ -368,10 +381,16 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct)
                                   gi->height - 2 * border_y);
 
        /* gadget text value */
+#if 1
+       DrawTextBuffer(gi->x + border_x, gi->y + border_y, gi->textarea.value,
+                      font_nr, gi->textarea.xsize, 0, -1, gi->textarea.ysize,
+                      BLIT_ON_BACKGROUND, FALSE, FALSE, FALSE);
+#else
        DrawTextToTextArea(gi->x + border_x, gi->y + border_y,
                           gi->textarea.value, font_nr, gi->textarea.xsize,
                           gi->textarea.xsize, gi->textarea.ysize,
                           BLIT_ON_BACKGROUND);
+#endif
 
        cursor_letter = gi->textarea.value[gi->textarea.cursor_position];
        cursor_string[0] = (cursor_letter != '\0' ? cursor_letter : ' ');
@@ -729,7 +748,7 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap)
 
       case GDI_INFO_TEXT:
        {
-         int max_textsize = MAX_INFO_TEXTSIZE - 1;
+         int max_textsize = MAX_INFO_TEXTSIZE;
          char *text = va_arg(ap, char *);
 
          if (text != NULL)
@@ -766,20 +785,14 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap)
        break;
 
       case GDI_ACTIVE:
-       /* take care here: "boolean" is typedef'ed as "unsigned char",
-          which gets promoted to "int" */
        gi->active = (boolean)va_arg(ap, int);
        break;
 
       case GDI_DIRECT_DRAW:
-       /* take care here: "boolean" is typedef'ed as "unsigned char",
-          which gets promoted to "int" */
        gi->direct_draw = (boolean)va_arg(ap, int);
        break;
 
       case GDI_CHECKED:
-       /* take care here: "boolean" is typedef'ed as "unsigned char",
-          which gets promoted to "int" */
        gi->checked = (boolean)va_arg(ap, int);
        break;
 
@@ -819,7 +832,7 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap)
          int max_textsize = MAX_GADGET_TEXTSIZE;
 
          if (gi->textinput.size)
-           max_textsize = MIN(gi->textinput.size, MAX_GADGET_TEXTSIZE - 1);
+           max_textsize = MIN(gi->textinput.size, MAX_GADGET_TEXTSIZE);
 
          strncpy(gi->textinput.value, va_arg(ap, char *), max_textsize);
          strcpy(gi->textinput.last_value, gi->textinput.value);
@@ -837,7 +850,7 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap)
       case GDI_TEXT_SIZE:
        {
          int tag_value = va_arg(ap, int);
-         int max_textsize = MIN(tag_value, MAX_GADGET_TEXTSIZE - 1);
+         int max_textsize = MIN(tag_value, MAX_GADGET_TEXTSIZE);
 
          gi->textinput.size = max_textsize;
          gi->textinput.value[max_textsize] = '\0';
@@ -1499,7 +1512,7 @@ boolean HandleGadgets(int mx, int my, int button)
        (gadget_pressed_inside_select_line && !mouse_inside_select_area)))
   {
     struct GadgetInfo *gi = last_gi;
-    boolean gadget_changed = (gi->event_mask & GD_EVENT_TEXT_LEAVING);
+    boolean gadget_changed = ((gi->event_mask & GD_EVENT_TEXT_LEAVING) != 0);
 
     /* check if text gadget has changed its value */
     if (gi->type & GD_TYPE_TEXT_INPUT)
@@ -1686,8 +1699,6 @@ boolean HandleGadgets(int mx, int my, int button)
     last_info_gi = new_gi;
   }
 
-#if 1
-
   gadget_draggable = (gi && gi->type & GD_TYPE_SCROLLBAR);
 
   /* reset drag position for newly pressed scrollbar to "not dragging" */
@@ -1725,10 +1736,11 @@ boolean HandleGadgets(int mx, int my, int button)
     {
       int mpos = (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL ? mx    : my);
       int gpos = (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL ? gi->x : gi->y);
+      int slider_start = gpos + gi->scrollbar.position;
+      int slider_end   = gpos + gi->scrollbar.position + gi->scrollbar.size - 1;
+      boolean inside_slider = (mpos >= slider_start && mpos <= slider_end);
 
-      if (button > 3 ||
-         mpos < gpos + gi->scrollbar.position ||
-         mpos >= gpos + gi->scrollbar.position + gi->scrollbar.size)
+      if (IS_WHEEL_BUTTON(button) || !inside_slider)
       {
        /* click scrollbar one scrollbar length up/left or down/right */
 
@@ -1737,10 +1749,13 @@ boolean HandleGadgets(int mx, int my, int button)
        int item_steps = gs->items_visible - 1;
        int item_direction = (mpos < gpos + gi->scrollbar.position ? -1 : +1);
 
-       if (button > 3)
+       if (IS_WHEEL_BUTTON(button))
        {
-         item_steps = 3;
-         item_direction = (button == 4 ? -1 : +1);
+         boolean scroll_single_step = ((GetKeyModState() & KMOD_Alt) != 0);
+
+         item_steps = (scroll_single_step ? 1 : DEFAULT_WHEEL_STEPS);
+         item_direction = (button == MB_WHEEL_UP ||
+                           button == MB_WHEEL_LEFT ? -1 : +1);
        }
 
        changed_position = FALSE;
@@ -1783,10 +1798,10 @@ boolean HandleGadgets(int mx, int my, int button)
     }
   }
 
-#endif
-
   if (gadget_pressed)
   {
+    PlayGadgetSoundActivating();
+
     if (gi->type == GD_TYPE_CHECK_BUTTON)
     {
       gi->checked = !gi->checked;
@@ -1815,10 +1830,11 @@ boolean HandleGadgets(int mx, int my, int button)
     {
       int mpos = (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL ? mx    : my);
       int gpos = (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL ? gi->x : gi->y);
+      int slider_start = gpos + gi->scrollbar.position;
+      int slider_end   = gpos + gi->scrollbar.position + gi->scrollbar.size - 1;
+      boolean inside_slider = (mpos >= slider_start && mpos <= slider_end);
 
-      if (button >= 1 && button <= 3 &&
-         mpos >= gpos + gi->scrollbar.position &&
-         mpos < gpos + gi->scrollbar.position + gi->scrollbar.size)
+      if (!IS_WHEEL_BUTTON(button) && inside_slider)
       {
        /* start dragging scrollbar */
        gi->scrollbar.drag_position =
@@ -1964,9 +1980,7 @@ boolean HandleGadgets(int mx, int my, int button)
     if (gi->type & GD_TYPE_SCROLLBAR)
       DrawGadget(gi, DG_UNPRESSED, gi->direct_draw);
 
-#if 1
     gi->state = GD_BUTTON_UNPRESSED;
-#endif
     gi->event.type = GD_EVENT_RELEASED;
 
     if (gi->event_mask & GD_EVENT_RELEASED &&
@@ -1984,10 +1998,10 @@ boolean HandleGadgets(int mx, int my, int button)
 
 static void insertCharIntoTextArea(struct GadgetInfo *gi, char c)
 {
-  char text[MAX_GADGET_TEXTSIZE];
+  char text[MAX_GADGET_TEXTSIZE + 1];
   int cursor_position = gi->textarea.cursor_position;
 
-  if (strlen(gi->textarea.value) == MAX_GADGET_TEXTSIZE) /* no space left */
+  if (strlen(gi->textarea.value) >= MAX_GADGET_TEXTSIZE) /* no space left */
     return;
 
   strcpy(text, gi->textarea.value);
@@ -2009,7 +2023,7 @@ boolean HandleGadgetsKeyInput(Key key)
 
   if (key == KSYM_Return)      /* valid for both text input and selectbox */
   {
-    boolean gadget_changed = (gi->event_mask & GD_EVENT_TEXT_RETURN);
+    boolean gadget_changed = ((gi->event_mask & GD_EVENT_TEXT_RETURN) != 0);
 
     if (gi->type & GD_TYPE_TEXT_INPUT)
     {
@@ -2048,7 +2062,7 @@ boolean HandleGadgetsKeyInput(Key key)
   }
   else if (gi->type & GD_TYPE_TEXT_INPUT)      /* only valid for text input */
   {
-    char text[MAX_GADGET_TEXTSIZE];
+    char text[MAX_GADGET_TEXTSIZE + 1];
     int text_length = strlen(gi->textinput.value);
     int cursor_pos = gi->textinput.cursor_position;
     char letter = getCharFromKey(key);
@@ -2095,7 +2109,7 @@ boolean HandleGadgetsKeyInput(Key key)
   }
   else if (gi->type & GD_TYPE_TEXT_AREA)       /* only valid for text area */
   {
-    char text[MAX_GADGET_TEXTSIZE];
+    char text[MAX_GADGET_TEXTSIZE + 1];
     int text_length = strlen(gi->textarea.value);
     int area_ysize = gi->textarea.ysize;
     int cursor_x_pref = gi->textarea.cursor_x_preferred;