[gtk+] combobox: Refactor cell view treatment



commit 2550c6a4db0e5427d5c793eb1757acd51642471c
Author: Benjamin Otte <otte redhat com>
Date:   Wed Jul 29 01:12:09 2015 +0200

    combobox: Refactor cell view treatment
    
    Instead of putting it inside the button manually, put it there properly
    by adding a box containing the cell view and the arrow.
    
    Do the same thing in list mode, instead of creating an event box that
    tries to behave as a button.

 gtk/gtkcombobox.c     |  366 ++++++++++++-------------------------------------
 gtk/ui/gtkcombobox.ui |   12 ++-
 2 files changed, 98 insertions(+), 280 deletions(-)
---
diff --git a/gtk/gtkcombobox.c b/gtk/gtkcombobox.c
index 0f77a2d..4d2d825 100644
--- a/gtk/gtkcombobox.c
+++ b/gtk/gtkcombobox.c
@@ -1530,7 +1530,8 @@ gtk_combo_box_create_cell_view (GtkComboBox *combo_box)
   priv->cell_view = gtk_cell_view_new_with_context (priv->area, NULL);
   gtk_cell_view_set_fit_model (GTK_CELL_VIEW (priv->cell_view), TRUE);
   gtk_cell_view_set_model (GTK_CELL_VIEW (priv->cell_view), priv->model);
-  gtk_widget_set_parent (priv->cell_view, GTK_WIDGET (combo_box));
+  gtk_container_add (GTK_CONTAINER (gtk_widget_get_parent (priv->arrow)),
+                     priv->cell_view);
   _gtk_bin_set_child (GTK_BIN (combo_box), priv->cell_view);
   gtk_widget_show (priv->cell_view);
 }
@@ -1550,10 +1551,10 @@ gtk_combo_box_add (GtkContainer *container,
       return;
     }
 
-  if (priv->cell_view &&
-      gtk_widget_get_parent (priv->cell_view))
+  if (priv->cell_view)
     {
-      gtk_widget_unparent (priv->cell_view);
+      gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (priv->cell_view)),
+                            priv->cell_view);
       _gtk_bin_set_child (GTK_BIN (container), NULL);
       gtk_widget_queue_resize (GTK_WIDGET (container));
       priv->cell_view = NULL;
@@ -1599,9 +1600,6 @@ gtk_combo_box_remove (GtkContainer *container,
         }
     }
 
-  if (widget == priv->cell_view)
-    priv->cell_view = NULL;
-
   gtk_widget_unparent (widget);
   _gtk_bin_set_child (GTK_BIN (container), NULL);
 
@@ -2507,26 +2505,6 @@ gtk_combo_box_popdown (GtkComboBox *combo_box)
   priv->grab_keyboard = NULL;
 }
 
-#define GTK_COMBO_BOX_SIZE_ALLOCATE_BUTTON                      \
-  GtkAllocation button_allocation;                              \
-  gtk_widget_get_preferred_size (combo_box->priv->button,       \
-                                 &req, NULL);                   \
-                                                                \
-  if (is_rtl)                                                   \
-    button_allocation.x = allocation->x;                        \
-  else                                                          \
-    button_allocation.x = allocation->x + allocation->width     \
-     - req.width;                                               \
-                                                                \
-  button_allocation.y = allocation->y;                          \
-  button_allocation.width = MAX (1, req.width);                 \
-  button_allocation.height = allocation->height;                \
-  button_allocation.height = MAX (1, button_allocation.height); \
-                                                                \
-  gtk_widget_size_allocate (combo_box->priv->button,            \
-                            &button_allocation);
-
-
 static void
 gtk_combo_box_size_allocate (GtkWidget     *widget,
                              GtkAllocation *allocation)
@@ -2548,135 +2526,74 @@ gtk_combo_box_size_allocate (GtkWidget     *widget,
   allocation->width -= padding.left + padding.right;
   allocation->height -= padding.top + padding.bottom;
 
-  if (!priv->tree_view)
+  if (child_widget == priv->cell_view)
     {
-      if (priv->cell_view)
-        {
-          GtkBorder button_padding;
-          gint width;
-          guint border_width;
-
-          border_width = gtk_container_get_border_width (GTK_CONTAINER (priv->button));
-          get_widget_padding_and_border (priv->button, &button_padding);
-
-          /* menu mode; child_widget is priv->cell_view.
-           * Allocate the button to the full combobox allocation (minus the
-           * padding).
-           */
-          gtk_widget_size_allocate (priv->button, allocation);
-
-          child.x = allocation->x;
-          child.y = allocation->y;
-          width = allocation->width;
-          child.height = allocation->height;
-
-          if (!priv->is_cell_renderer)
-            {
-              /* restrict allocation of the child into the button box
-               * if we're not in cell renderer mode.
-               */
-              child.x += border_width + button_padding.left;
-              child.y += border_width + button_padding.top;
-              width -= 2 * border_width +
-                button_padding.left + button_padding.right;
-              child.height -= 2 * border_width +
-                button_padding.top + button_padding.bottom;
-            }
-
-          /* allocate the box containing the separator and the arrow */
-          gtk_widget_get_preferred_size (priv->arrow, &req, NULL);
-          child.width = req.width;
-          if (!is_rtl)
-            child.x += width - req.width;
-          child.width = MAX (1, child.width);
-          child.height = MAX (1, child.height);
-          gtk_widget_size_allocate (priv->arrow, &child);
+      gtk_widget_size_allocate (priv->button, allocation);
+    }
+  else
+    {
+      GtkAllocation button_allocation;
 
-          if (is_rtl)
-            {
-              child.x += req.width;
-              child.width = allocation->x + allocation->width
-                - border_width - child.x - button_padding.right;
-            }
-          else
-            {
-              child.width = child.x;
-              child.x = allocation->x
-                + border_width + button_padding.left;
-              child.width -= child.x;
-            }
+      gtk_widget_get_preferred_size (combo_box->priv->button,
+                                     &req, NULL);
 
-          if (gtk_widget_get_visible (priv->popup_widget))
-            {
-              gint menu_width;
+      if (is_rtl)
+        button_allocation.x = allocation->x;
+      else
+        button_allocation.x = allocation->x + allocation->width
+         - req.width;
 
-              if (priv->wrap_width == 0)
-                {
-                  GtkAllocation combo_box_allocation;
+      button_allocation.y = allocation->y;
+      button_allocation.width = MAX (1, req.width);
+      button_allocation.height = allocation->height;
+      button_allocation.height = MAX (1, button_allocation.height);
 
-                  gtk_widget_get_allocation (GTK_WIDGET (combo_box), &combo_box_allocation);
-                  gtk_widget_set_size_request (priv->popup_widget, -1, -1);
+      gtk_widget_size_allocate (combo_box->priv->button,
+                                &button_allocation);
 
-                  if (combo_box->priv->popup_fixed_width)
-                    gtk_widget_get_preferred_width (priv->popup_widget, &menu_width, NULL);
-                  else
-                    gtk_widget_get_preferred_width (priv->popup_widget, NULL, &menu_width);
+      if (is_rtl)
+        child.x = button_allocation.x + button_allocation.width;
+      else
+        child.x = allocation->x;
 
-                  gtk_widget_set_size_request (priv->popup_widget,
-                                               MAX (combo_box_allocation.width, menu_width), -1);
-               }
+      child.y = allocation->y;
+      child.width = allocation->width - button_allocation.width;
+      child.height = button_allocation.height;
 
-              /* reposition the menu after giving it a new width */
-              gtk_menu_reposition (GTK_MENU (priv->popup_widget));
-            }
+      /* allocate the child */
+      child.width = MAX (1, child.width);
+      child.height = MAX (1, child.height);
+      gtk_widget_size_allocate (child_widget, &child);
+    }
 
-          child.width = MAX (1, child.width);
-          child.height = MAX (1, child.height);
-          gtk_widget_size_allocate (child_widget, &child);
-        }
-      else
+  if (!priv->tree_view)
+    {
+      if (gtk_widget_get_visible (priv->popup_widget))
         {
-          /* menu mode; child_widget has been set with gtk_container_add().
-           * E.g. it might be a GtkEntry if priv->has_entry is TRUE.
-           * Allocate the button at the far end, according to the direction
-           * of the widget.
-           */
-          GTK_COMBO_BOX_SIZE_ALLOCATE_BUTTON
-
-            /* After the macro, button_allocation has the button allocation rect */
-
-          if (is_rtl)
-            child.x = button_allocation.x + button_allocation.width;
-          else
-            child.x = allocation->x;
+          gint menu_width;
+          
+          if (priv->wrap_width == 0)
+            {
+              GtkAllocation combo_box_allocation;
 
-          child.y = allocation->y;
-          child.width = allocation->width - button_allocation.width;
-          child.height = button_allocation.height;
+              gtk_widget_get_allocation (GTK_WIDGET (combo_box), &combo_box_allocation);
+              gtk_widget_set_size_request (priv->popup_widget, -1, -1);
 
-          child.width = MAX (1, child.width);
+              if (combo_box->priv->popup_fixed_width)
+                gtk_widget_get_preferred_width (priv->popup_widget, &menu_width, NULL);
+              else
+                gtk_widget_get_preferred_width (priv->popup_widget, NULL, &menu_width);
 
-          gtk_widget_size_allocate (child_widget, &child);
+              gtk_widget_set_size_request (priv->popup_widget,
+                                           MAX (combo_box_allocation.width, menu_width), -1);
+            }
+          
+          /* reposition the menu after giving it a new width */
+          gtk_menu_reposition (GTK_MENU (priv->popup_widget));
         }
     }
   else
     {
-      /* list mode; child_widget might be either priv->cell_view or a child
-       * added with gtk_container_add().
-       */
-
-      /* After the macro, button_allocation has the button allocation rect */
-      GTK_COMBO_BOX_SIZE_ALLOCATE_BUTTON
-
-      if (is_rtl)
-        child.x = button_allocation.x + button_allocation.width;
-      else
-        child.x = allocation->x;
-
-      child.y = allocation->y;
-      child.width = allocation->width - button_allocation.width;
-      child.height = button_allocation.height;
-
       if (gtk_widget_get_visible (priv->popup_window))
         {
           gint x, y, width, height;
@@ -2684,18 +2601,11 @@ gtk_combo_box_size_allocate (GtkWidget     *widget,
           gtk_window_move (GTK_WINDOW (priv->popup_window), x, y);
           gtk_widget_set_size_request (priv->popup_window, width, height);
         }
-
-      /* allocate the child */
-      child.width = MAX (1, child.width);
-      child.height = MAX (1, child.height);
-      gtk_widget_size_allocate (child_widget, &child);
     }
 
   _gtk_widget_set_simple_clip (widget, NULL);
 }
 
-#undef GTK_COMBO_BOX_ALLOCATE_BUTTON
-
 static void
 gtk_combo_box_unset_model (GtkComboBox *combo_box)
 {
@@ -2746,7 +2656,7 @@ gtk_combo_box_forall (GtkContainer *container,
     }
 
   child = gtk_bin_get_child (GTK_BIN (container));
-  if (child)
+  if (child && child != priv->cell_view)
     (* callback) (child, callback_data);
 }
 
@@ -2777,6 +2687,7 @@ gtk_combo_box_draw (GtkWidget *widget,
   GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
   GtkComboBoxPrivate *priv = combo_box->priv;
   GtkStyleContext *context;
+  GtkWidget *child;
 
   context = gtk_widget_get_style_context (widget);
 
@@ -2790,9 +2701,12 @@ gtk_combo_box_draw (GtkWidget *widget,
   gtk_container_propagate_draw (GTK_CONTAINER (widget),
                                 priv->button, cr);
 
-  gtk_container_propagate_draw (GTK_CONTAINER (widget),
-                                gtk_bin_get_child (GTK_BIN (widget)),
-                                cr);
+  child = gtk_bin_get_child (GTK_BIN (widget));
+
+  if (child != priv->cell_view)
+    gtk_container_propagate_draw (GTK_CONTAINER (widget),
+                                  child,
+                                  cr);
 
   return FALSE;
 }
@@ -3135,11 +3049,6 @@ gtk_combo_box_update_sensitivity (GtkComboBox *combo_box)
     }
 
   gtk_widget_set_sensitive (combo_box->priv->button, sensitive);
-
-  /* In list-mode, we also need to update sensitivity of the event box */
-  if (GTK_IS_TREE_VIEW (combo_box->priv->tree_view)
-      && combo_box->priv->cell_view)
-    gtk_widget_set_sensitive (combo_box->priv->box, sensitive);
 }
 
 static void
@@ -3269,21 +3178,6 @@ gtk_combo_box_list_setup (GtkComboBox *combo_box)
   g_signal_connect (priv->button, "button-press-event",
                     G_CALLBACK (gtk_combo_box_list_button_pressed), combo_box);
 
-  if (priv->cell_view)
-    {
-      priv->box = gtk_event_box_new ();
-      gtk_widget_add_events (priv->box, GDK_SCROLL_MASK);
-      gtk_event_box_set_visible_window (GTK_EVENT_BOX (priv->box),
-                                        FALSE);
-
-      gtk_widget_set_parent (priv->box, GTK_WIDGET (combo_box));
-      gtk_widget_show_all (priv->box);
-
-      g_signal_connect (priv->box, "button-press-event",
-                        G_CALLBACK (gtk_combo_box_list_button_pressed),
-                        combo_box);
-    }
-
   priv->tree_view = gtk_tree_view_new ();
   sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->tree_view));
   gtk_tree_selection_set_mode (sel, GTK_SELECTION_BROWSE);
@@ -4458,6 +4352,11 @@ gtk_combo_box_destroy (GtkWidget *widget)
       gtk_widget_unparent (priv->button);
       priv->button = NULL;
       priv->arrow = NULL;
+      if (priv->cell_view)
+        {
+          priv->cell_view = NULL;
+          _gtk_bin_set_child (GTK_BIN (combo_box), NULL);
+        }
     }
 
   gtk_combo_box_popdown (combo_box);
@@ -5273,8 +5172,8 @@ gtk_combo_box_get_preferred_width (GtkWidget *widget,
   PangoContext          *context;
   PangoFontMetrics      *metrics;
   GtkWidget             *child;
-  gint                   minimum_width = 0, natural_width = 0;
   gint                   child_min, child_nat;
+  gint                   but_min, but_nat;
   GtkBorder              padding;
   gfloat                 arrow_scaling;
   gint                   dummy;
@@ -5285,8 +5184,10 @@ gtk_combo_box_get_preferred_width (GtkWidget *widget,
 
   child = gtk_bin_get_child (GTK_BIN (widget));
 
-  /* common */
-  gtk_widget_get_preferred_width (child, &child_min, &child_nat);
+  if (child == priv->cell_view)
+    child_min = child_nat = 0;
+  else
+    gtk_widget_get_preferred_width (child, &child_min, &child_nat);
 
   gtk_widget_style_get (GTK_WIDGET (widget),
                         "arrow-size", &arrow_size,
@@ -5307,55 +5208,11 @@ gtk_combo_box_get_preferred_width (GtkWidget *widget,
 
   gtk_widget_set_size_request (priv->arrow, arrow_size, arrow_size);
 
-  if (!priv->tree_view)
-    {
-      /* menu mode */
-      if (priv->cell_view)
-        {
-          gint arrow_width, xpad;
-          GtkBorder button_padding;
-
-          get_widget_padding_and_border (priv->button, &button_padding);
-
-          gtk_widget_get_preferred_width (priv->arrow, &arrow_width, NULL);
-          xpad = button_padding.left + button_padding.right + padding.left + padding.right;
+  gtk_widget_get_preferred_width (priv->button,
+                                  &but_min, &but_nat);
 
-          minimum_width  = child_min + arrow_width + xpad;
-          natural_width  = child_nat + arrow_width + xpad;
-        }
-      else
-        {
-          gint but_width, but_nat_width;
-
-          gtk_widget_get_preferred_width (priv->button,
-                                          &but_width, &but_nat_width);
-
-          minimum_width  = child_min + but_width;
-          natural_width  = child_nat + but_nat_width;
-        }
-    }
-  else
-    {
-      /* list mode */
-      gint button_width, button_nat_width;
-
-      /* sample + frame */
-      minimum_width = child_min;
-      natural_width = child_nat;
-
-      /* the button */
-      gtk_widget_get_preferred_width (priv->button,
-                                      &button_width, &button_nat_width);
-
-      minimum_width += button_width;
-      natural_width += button_nat_width;
-    }
-
-  minimum_width += padding.left + padding.right;
-  natural_width += padding.left + padding.right;
-
-  *minimum_size = minimum_width;
-  *natural_size = natural_width;
+  *minimum_size = child_min + but_min + padding.left + padding.right;
+  *natural_size = child_nat + but_nat + padding.left + padding.right;
 }
 
 static void
@@ -5391,79 +5248,32 @@ gtk_combo_box_get_preferred_height_for_width (GtkWidget *widget,
 {
   GtkComboBox           *combo_box = GTK_COMBO_BOX (widget);
   GtkComboBoxPrivate    *priv = combo_box->priv;
-  gint                   min_height = 0, nat_height = 0;
+  gint                   min_height, nat_height;
+  gint                   but_width, but_height;
   gint                   size;
   GtkWidget             *child;
   GtkBorder              padding;
-
+ 
   child = gtk_bin_get_child (GTK_BIN (widget));
 
   get_widget_padding_and_border (widget, &padding);
-  size = avail_size;
+  size = avail_size - padding.left - padding.right;
 
-  if (!priv->tree_view)
+  if (child == priv->cell_view)
     {
-      /* menu mode */
-      if (priv->cell_view)
-        {
-          /* calculate x/y padding and separator/arrow size */
-          gint arrow_width, box_height;
-          gint xpad, ypad;
-          GtkBorder button_padding;
-
-          get_widget_padding_and_border (priv->button, &button_padding);
-
-          gtk_widget_get_preferred_width (priv->arrow, &arrow_width, NULL);
-          gtk_widget_get_preferred_height_for_width (priv->arrow,
-                                                     arrow_width, &box_height, NULL);
-
-          xpad = button_padding.left + button_padding.right;
-          ypad = button_padding.top + button_padding.bottom;
-
-          size -= arrow_width + xpad;
-
-          /* Get height-for-width of the child widget, usually a GtkCellArea calculating
-           * and fitting the whole treemodel */
-          gtk_widget_get_preferred_height_for_width (child, size, &min_height, &nat_height);
-
-          min_height = MAX (min_height, box_height);
-          nat_height = MAX (nat_height, box_height);
-
-          min_height += ypad;
-          nat_height += ypad;
-        }
-      else
-        {
-          /* there is a custom child widget inside (no priv->cell_view) */
-          gint but_width, but_height;
-
-          gtk_widget_get_preferred_width (priv->button, &but_width, NULL);
-          gtk_widget_get_preferred_height_for_width (priv->button,
-                                                     but_width, &but_height, NULL);
-
-          size -= but_width;
-
-          /* Get height-for-width of the child widget, usually a GtkCellArea calculating
-           * and fitting the whole treemodel */
-          gtk_widget_get_preferred_height_for_width (child, size, &min_height, &nat_height);
-
-          min_height = MAX (min_height, but_height);
-          nat_height = MAX (nat_height, but_height);
-        }
+      gtk_widget_get_preferred_height_for_width (priv->button,
+                                                 size,
+                                                 &min_height, &nat_height);
     }
   else
     {
-      /* list mode */
-      gint but_width, but_height;
-
       gtk_widget_get_preferred_width (priv->button, &but_width, NULL);
       gtk_widget_get_preferred_height_for_width (priv->button,
-                                                 but_width, &but_height, NULL);
+                                                 but_width,
+                                                 &but_height, NULL);
 
       size -= but_width;
 
-      /* Get height-for-width of the child widget, usually a GtkCellArea calculating
-       * and fitting the whole treemodel */
       gtk_widget_get_preferred_height_for_width (child, size, &min_height, &nat_height);
 
       min_height = MAX (min_height, but_height);
diff --git a/gtk/ui/gtkcombobox.ui b/gtk/ui/gtkcombobox.ui
index cd06621..64e5396 100644
--- a/gtk/ui/gtkcombobox.ui
+++ b/gtk/ui/gtkcombobox.ui
@@ -8,9 +8,17 @@
         <property name="focus-on-click">True</property>
         <signal name="toggled" handler="gtk_combo_box_button_toggled" swapped="no"/>
         <child>
-          <object class="GtkImage" id="arrow">
+          <object class="GtkBox">
             <property name="visible">True</property>
-            <property name="icon-name">pan-down-symbolic</property>
+            <child>
+              <object class="GtkImage" id="arrow">
+                <property name="visible">True</property>
+                <property name="icon-name">pan-down-symbolic</property>
+              </object>
+              <packing>
+                <property name="pack_type">end</property>
+              </packing>
+            </child>
           </object>
         </child>
       </object>


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