#54720 -button children should optionally move



I took a look at this patch and ended up rewriting it quite a bit.

 * I simplified a lot of the logic in GtkButton and GtkToggleButton to centralize
   all the state maintanence in one place for each widget.

 * I removed the movement for the child of check/radio buttons with 
   draw_indicator == TRUE. This just looked very weird to me, and windows
   does not do this.

 * Instead of adding a ->depressed() virtual function, I added a function
   _gtk_button_set_depressed() that sets a depressed flag. This resulted
   in more consistent code since the state of the widget was maintained via
   gtk_widget_set_state() rather than a callback.

Remaining possible questions about this patch:

 * Should we have separate child_displacement_x/child_displacement_y 
   properties? Does it ever make sense for them to be separate

 * Should we increase the amount of space requested for the button
   based on the amount of displacement? Currently, things don't
   work very will if the displacement is more than 1.

 * Should _gtk_button_set_depressed() be exported? If someone wanted
   to write a like-toggle-button widget right now, they wouldn't 
   be able to. On the other hand, making it public is inviting
   confusion and abuse.

Regards,
                                        Owen

? gtkcontainer.c.bench
Index: gtkbutton.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkbutton.c,v
retrieving revision 1.65
diff -u -r1.65 gtkbutton.c
--- gtkbutton.c	2001/07/18 23:39:21	1.65
+++ gtkbutton.c	2001/08/22 16:35:40
@@ -97,9 +97,8 @@
 				       GtkWidget        *widget);
 static void gtk_real_button_pressed   (GtkButton        *button);
 static void gtk_real_button_released  (GtkButton        *button);
-static void gtk_real_button_enter     (GtkButton        *button);
-static void gtk_real_button_leave     (GtkButton        *button);
 static void gtk_real_button_activate (GtkButton         *button);
+static void gtk_button_update_state   (GtkButton        *button);
 static GtkType gtk_button_child_type  (GtkContainer     *container);
 
 static void gtk_button_finish_activate (GtkButton *button,
@@ -169,8 +168,8 @@
   klass->pressed = gtk_real_button_pressed;
   klass->released = gtk_real_button_released;
   klass->clicked = NULL;
-  klass->enter = gtk_real_button_enter;
-  klass->leave = gtk_real_button_leave;
+  klass->enter = gtk_button_update_state;
+  klass->leave = gtk_button_update_state;
   klass->activate = gtk_real_button_activate;
 
   g_object_class_install_property (G_OBJECT_CLASS(object_class),
@@ -247,6 +246,22 @@
 							       _("Extra space to add for CAN_DEFAULT buttons that is always drawn outside the border"),
 							       GTK_TYPE_BORDER,
 							       G_PARAM_READABLE));
+  gtk_widget_class_install_style_property (widget_class,
+					   g_param_spec_int ("child_displacement_x",
+							     _("Child X Displacement"),
+							     _("How far in the x direction to move the child when the button is depressed"),
+							     G_MININT,
+							     G_MAXINT,
+							     0,
+							     G_PARAM_READABLE));
+  gtk_widget_class_install_style_property (widget_class,
+					   g_param_spec_int ("child_displacement_y",
+							     _("Child Y Displacement"),
+							     _("How far in the y direction to move the child when the button is depressed"),
+							     G_MININT,
+							     G_MAXINT,
+							     0,
+							     G_PARAM_READABLE));
 }
 
 static void
@@ -259,6 +274,7 @@
   button->in_button = FALSE;
   button->button_down = FALSE;
   button->relief = GTK_RELIEF_NORMAL;
+  button->depressed = FALSE;
 }
 
 static GtkType
@@ -656,6 +672,19 @@
 	  child_allocation.height = MAX (1, child_allocation.height - default_border.top - default_border.bottom);
 	}
 
+      if (button->depressed)
+	{
+	  gint child_displacement_x;
+	  gint child_displacement_y;
+	  
+	  gtk_widget_style_get (widget,
+				"child_displacement_x", &child_displacement_x, 
+				"child_displacement_y", &child_displacement_y,
+				NULL);
+	  child_allocation.x += child_displacement_x;
+	  child_allocation.y += child_displacement_y;
+	}
+
       gtk_widget_size_allocate (GTK_BIN (button)->child, &child_allocation);
     }
 }
@@ -740,12 +769,9 @@
 	  width -= 2;
 	  height -= 2;
 	}
-	
-      if (GTK_WIDGET_STATE (widget) == GTK_STATE_ACTIVE)
-	shadow_type = GTK_SHADOW_IN;
-      else
-	shadow_type = GTK_SHADOW_OUT;
 
+      shadow_type = button->depressed ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
+
       if ((button->relief != GTK_RELIEF_NONE) ||
 	  ((GTK_WIDGET_STATE(widget) != GTK_STATE_NORMAL) &&
 	   (GTK_WIDGET_STATE(widget) != GTK_STATE_INSENSITIVE)))
@@ -937,88 +963,30 @@
 static void
 gtk_real_button_pressed (GtkButton *button)
 {
-  GtkStateType new_state;
-
-  g_return_if_fail (GTK_IS_BUTTON (button));
-
   if (button->activate_timeout)
     return;
   
   button->button_down = TRUE;
-
-  new_state = (button->in_button ? GTK_STATE_ACTIVE : GTK_STATE_NORMAL);
-
-  if (GTK_WIDGET_STATE (button) != new_state)
-    {
-      gtk_widget_set_state (GTK_WIDGET (button), new_state);
-      gtk_widget_queue_draw (GTK_WIDGET (button));
-    }
+  gtk_button_update_state (button);
 }
 
 static void
 gtk_real_button_released (GtkButton *button)
 {
-  GtkStateType new_state;
-
-  g_return_if_fail (GTK_IS_BUTTON (button));
-
   if (button->button_down)
     {
       button->button_down = FALSE;
 
       if (button->activate_timeout)
 	return;
-  
+      
       if (button->in_button)
 	gtk_button_clicked (button);
-
-      new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL);
 
-      if (GTK_WIDGET_STATE (button) != new_state)
-	{
-	  gtk_widget_set_state (GTK_WIDGET (button), new_state);
-	  /* We _draw () instead of queue_draw so that if the operation
-	   * blocks, the label doesn't vanish.
-	   */
-	  gtk_widget_draw (GTK_WIDGET (button), NULL);
-	}
+      gtk_button_update_state (button);
     }
 }
 
-static void
-gtk_real_button_enter (GtkButton *button)
-{
-  GtkStateType new_state;
-
-  g_return_if_fail (GTK_IS_BUTTON (button));
-
-  new_state = (button->button_down ? GTK_STATE_ACTIVE : GTK_STATE_PRELIGHT);
-
-  if (button->activate_timeout)
-    return;
-  
-  if (GTK_WIDGET_STATE (button) != new_state)
-    {
-      gtk_widget_set_state (GTK_WIDGET (button), new_state);
-      gtk_widget_queue_draw (GTK_WIDGET (button));
-    }
-}
-
-static void
-gtk_real_button_leave (GtkButton *button)
-{
-  g_return_if_fail (GTK_IS_BUTTON (button));
-  
-  if (button->activate_timeout)
-    return;
-  
-  if (GTK_WIDGET_STATE (button) != GTK_STATE_NORMAL)
-    {
-      gtk_widget_set_state (GTK_WIDGET (button), GTK_STATE_NORMAL);
-      gtk_widget_queue_draw (GTK_WIDGET (button));
-    }
-}
-
 static gboolean
 button_activate_timeout (gpointer data)
 {
@@ -1049,7 +1017,7 @@
 						    button_activate_timeout,
 						    button);
 	  button->button_down = TRUE;
-	  gtk_widget_set_state (widget, GTK_STATE_ACTIVE);
+	  gtk_button_update_state (button);
 	}
     }
 }
@@ -1067,10 +1035,49 @@
   gtk_grab_remove (widget);
 
   button->button_down = FALSE;
-  gtk_widget_set_state (GTK_WIDGET (button),
-			button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL);
+  gtk_button_update_state (button);
 
   if (do_it)
     gtk_button_clicked (button);
 }
 
+/**
+ * _gtk_button_set_depressed:
+ * @button: a #GtkButton
+ * @depressed: %TRUE if the button should be drawn with a recessed shadow.
+ * 
+ * Sets whether the button is currently drawn as down or not. This is 
+ * purely a visual setting, and is meant only for use by derived widgets
+ * such as #GtkToggleButton.
+ **/
+void
+_gtk_button_set_depressed (GtkButton *button,
+			   gboolean   depressed)
+{
+  GtkWidget *widget = GTK_WIDGET (button);
+
+  depressed = depressed != FALSE;
+
+  if (depressed != button->depressed)
+    {
+      button->depressed = depressed;
+      gtk_widget_queue_resize (widget);
+    }
+}
+
+static void
+gtk_button_update_state (GtkButton *button)
+{
+  gboolean depressed;
+  GtkStateType new_state;
+
+  depressed = button->in_button && button->button_down;
+      
+  if (!button->button_down && button->in_button)
+    new_state = GTK_STATE_PRELIGHT;
+  else
+    new_state = depressed ? GTK_STATE_ACTIVE: GTK_STATE_NORMAL;
+
+  _gtk_button_set_depressed (button, depressed); 
+  gtk_widget_set_state (GTK_WIDGET (button), new_state);
+}
Index: gtkbutton.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkbutton.h,v
retrieving revision 1.17
diff -u -r1.17 gtkbutton.h
--- gtkbutton.h	2001/03/23 23:39:23	1.17
+++ gtkbutton.h	2001/08/22 16:35:40
@@ -61,6 +61,7 @@
   guint in_button : 1;
   guint button_down : 1;
   guint relief : 2;
+  guint depressed : 1;
 };
 
 struct _GtkButtonClass
@@ -76,7 +77,7 @@
 };
 
 
-GtkType        gtk_button_get_type       (void) G_GNUC_CONST;
+GtkType        gtk_button_get_type          (void) G_GNUC_CONST;
 GtkWidget*     gtk_button_new               (void);
 GtkWidget*     gtk_button_new_with_label    (const gchar    *label);
 GtkWidget*     gtk_button_new_from_stock    (const gchar    *stock_id);
@@ -89,7 +90,8 @@
 void           gtk_button_set_relief        (GtkButton      *button,
 					     GtkReliefStyle  newstyle);
 GtkReliefStyle gtk_button_get_relief        (GtkButton      *button);
-
+void          _gtk_button_set_depressed     (GtkButton      *button,
+					     gboolean        depressed);
 
 #ifdef __cplusplus
 }
Index: gtktogglebutton.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtktogglebutton.c,v
retrieving revision 1.39
diff -u -r1.39 gtktogglebutton.c
--- gtktogglebutton.c	2001/07/18 23:39:23	1.39
+++ gtktogglebutton.c	2001/08/22 16:35:40
@@ -58,8 +58,6 @@
 static void gtk_toggle_button_pressed       (GtkButton            *button);
 static void gtk_toggle_button_released      (GtkButton            *button);
 static void gtk_toggle_button_clicked       (GtkButton            *button);
-static void gtk_toggle_button_enter         (GtkButton            *button);
-static void gtk_toggle_button_leave         (GtkButton            *button);
 static void gtk_toggle_button_set_property  (GObject              *object,
 					     guint                 prop_id,
 					     const GValue         *value,
@@ -68,11 +66,11 @@
 					     guint                 prop_id,
 					     GValue               *value,
 					     GParamSpec           *pspec);
-static void gtk_toggle_button_leave         (GtkButton            *button);
 static void gtk_toggle_button_realize       (GtkWidget            *widget);
 static void gtk_toggle_button_unrealize     (GtkWidget            *widget);
 static void gtk_toggle_button_map           (GtkWidget            *widget);
 static void gtk_toggle_button_unmap         (GtkWidget            *widget);
+static void gtk_toggle_button_update_state  (GtkButton            *button);
 
 static guint toggle_button_signals[LAST_SIGNAL] = { 0 };
 static GtkContainerClass *parent_class = NULL;
@@ -133,8 +131,8 @@
   button_class->pressed = gtk_toggle_button_pressed;
   button_class->released = gtk_toggle_button_released;
   button_class->clicked = gtk_toggle_button_clicked;
-  button_class->enter = gtk_toggle_button_enter;
-  button_class->leave = gtk_toggle_button_leave;
+  button_class->enter = gtk_toggle_button_update_state;
+  button_class->leave = gtk_toggle_button_update_state;
 
   class->toggled = NULL;
 
@@ -406,6 +404,8 @@
   if (setting != toggle_button->inconsistent)
     {
       toggle_button->inconsistent = setting;
+      
+      gtk_toggle_button_update_state (GTK_BUTTON (toggle_button));
       gtk_widget_queue_draw (GTK_WIDGET (toggle_button));
 
       g_object_notify (G_OBJECT (toggle_button), "inconsistent");      
@@ -490,11 +490,8 @@
             state_type = GTK_STATE_NORMAL;
           shadow_type = GTK_SHADOW_ETCHED_IN;
         }
-      else if ((GTK_WIDGET_STATE (widget) == GTK_STATE_ACTIVE) ||
-	  toggle_button->active)
-        shadow_type = GTK_SHADOW_IN;
       else
-	shadow_type = GTK_SHADOW_OUT;
+	shadow_type = button->depressed ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
 
       if (button->relief != GTK_RELIEF_NONE ||
 	  (GTK_WIDGET_STATE(widget) != GTK_STATE_NORMAL &&
@@ -557,117 +554,39 @@
 static void
 gtk_toggle_button_pressed (GtkButton *button)
 {
-  GtkToggleButton *toggle_button;
-  GtkStateType new_state;
-
-  g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button));
-
-  toggle_button = GTK_TOGGLE_BUTTON (button);
-
   button->button_down = TRUE;
-
-  if (toggle_button->active)
-    new_state = (button->in_button ? GTK_STATE_NORMAL : GTK_STATE_ACTIVE);
-  else
-    new_state = (button->in_button ? GTK_STATE_ACTIVE : GTK_STATE_NORMAL);
 
-  if (GTK_WIDGET_STATE (button) != new_state)
-    gtk_widget_set_state (GTK_WIDGET (button), new_state);
+  gtk_toggle_button_update_state (button);
 }
 
 static void
 gtk_toggle_button_released (GtkButton *button)
 {
-  GtkToggleButton *toggle_button;
-  GtkStateType new_state;
-
-  g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button));
-
   if (button->button_down)
     {
-      toggle_button = GTK_TOGGLE_BUTTON (button);
-
       button->button_down = FALSE;
 
       if (button->in_button)
-	{
-	  gtk_button_clicked (button);
-	}
-      else
-	{
-	  if (toggle_button->active)
-	    new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_ACTIVE);
-	  else
-	    new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL);
+	gtk_button_clicked (button);
 
-	  if (GTK_WIDGET_STATE (button) != new_state)
-	    gtk_widget_set_state (GTK_WIDGET (button), new_state);
-	}
+      gtk_toggle_button_update_state (button);
     }
 }
 
 static void
 gtk_toggle_button_clicked (GtkButton *button)
 {
-  GtkToggleButton *toggle_button;
-  GtkStateType new_state;
-
-  g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button));
-
-  toggle_button = GTK_TOGGLE_BUTTON (button);
+  GtkToggleButton *toggle_button = GTK_TOGGLE_BUTTON (button);
   toggle_button->active = !toggle_button->active;
 
   gtk_toggle_button_toggled (toggle_button);
-
-  if (toggle_button->active)
-    new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_ACTIVE);
-  else
-    new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL);
 
-  if (GTK_WIDGET_STATE (button) != new_state)
-    gtk_widget_set_state (GTK_WIDGET (button), new_state);
-  else
-    gtk_widget_queue_draw (GTK_WIDGET (button));
+  gtk_toggle_button_update_state (button);
 
   g_object_notify (G_OBJECT (toggle_button), "active");
 }
 
 static void
-gtk_toggle_button_enter (GtkButton *button)
-{
-  GtkToggleButton *toggle_button;
-  GtkStateType new_state;
-
-  g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button));
-
-  toggle_button = GTK_TOGGLE_BUTTON (button);
-
-  if (toggle_button->active)
-    new_state = (button->button_down ? GTK_STATE_NORMAL : GTK_STATE_PRELIGHT);
-  else
-    new_state = (button->button_down ? GTK_STATE_ACTIVE : GTK_STATE_PRELIGHT);
-
-  if (GTK_WIDGET_STATE (button) != new_state)
-    gtk_widget_set_state (GTK_WIDGET (button), new_state);
-}
-
-static void
-gtk_toggle_button_leave (GtkButton *button)
-{
-  GtkToggleButton *toggle_button;
-  GtkStateType new_state;
-
-  g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button));
-
-  toggle_button = GTK_TOGGLE_BUTTON (button);
-
-  new_state = (toggle_button->active ? GTK_STATE_ACTIVE : GTK_STATE_NORMAL);
-
-  if (GTK_WIDGET_STATE (button) != new_state)
-    gtk_widget_set_state (GTK_WIDGET (button), new_state);
-}
-
-static void
 gtk_toggle_button_realize (GtkWidget *widget)
 {
   GtkToggleButton *toggle_button;
@@ -763,4 +682,27 @@
     gdk_window_hide (GTK_TOGGLE_BUTTON (widget)->event_window);
 
   GTK_WIDGET_CLASS (parent_class)->unmap (widget);
+}
+
+static void
+gtk_toggle_button_update_state (GtkButton *button)
+{
+  GtkToggleButton *toggle_button = GTK_TOGGLE_BUTTON (button);
+  gboolean depressed;
+  GtkStateType new_state;
+
+  if (toggle_button->inconsistent)
+    depressed = FALSE;
+  else if (button->in_button && button->button_down)
+    depressed = !toggle_button->active;
+  else
+    depressed = toggle_button->active;
+      
+  if (!button->button_down && button->in_button)
+    new_state = GTK_STATE_PRELIGHT;
+  else
+    new_state = depressed ? GTK_STATE_ACTIVE: GTK_STATE_NORMAL;
+
+  _gtk_button_set_depressed (button, depressed); 
+  gtk_widget_set_state (GTK_WIDGET (toggle_button), new_state);
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]