Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Gnome/gtk/ui/   (Gnome Linux Desktop Version 4.23.2©)  Datei vom 30.5.2026 mit Größe 2 kB image not shown  

Quelle  gtktreepopover.c

  Sprache: C
 

/*
 * Copyright © 2019 Red Hat, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the licence, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 *
 * Author: Matthias Clasen
 */


#include "config.h"

#include "gtktreepopoverprivate.h"

#include "gtktreemodel.h"
#include "gtkcellarea.h"
#include "gtkcelllayout.h"
#include "gtkcellview.h"
#include "gtkprivate.h"
#include "gtkgizmoprivate.h"
#include "gtkwidgetprivate.h"
#include "gtkbuiltiniconprivate.h"
#include "gtkscrolledwindow.h"
#include "gtkviewport.h"

G_GNUC_BEGIN_IGNORE_DEPRECATIONS

// TODO
// positioning + sizing

struct _GtkTreePopover
{
  GtkPopover parent_instance;

  GtkTreeModel *model;

  GtkCellArea *area;
  GtkCellAreaContext *context;

  gulong size_changed_id;
  gulong row_inserted_id;
  gulong row_deleted_id;
  gulong row_changed_id;
  gulong row_reordered_id;
  gulong apply_attributes_id;

  GtkTreeViewRowSeparatorFunc row_separator_func;
  gpointer                    row_separator_data;
  GDestroyNotify              row_separator_destroy;

  GtkWidget *active_item;
};

enum {
  PROP_0,
  PROP_MODEL,
  PROP_CELL_AREA,

  NUM_PROPERTIES
};

static GParamSpec *props[NUM_PROPERTIES] = { NULL, };

enum {
  MENU_ACTIVATE,
  NUM_SIGNALS
};

static guint signals[NUM_SIGNALS];

static void gtk_tree_popover_cell_layout_init (GtkCellLayoutIface  *iface);
static void gtk_tree_popover_set_area (GtkTreePopover *popover,
                                       GtkCellArea    *area);
static void rebuild_menu (GtkTreePopover *popover);
static void context_size_changed_cb (GtkCellAreaContext *context,
                                     GParamSpec         *pspec,
                                     GtkWidget          *popover);
static GtkWidget * gtk_tree_popover_create_item (GtkTreePopover *popover,
                                                 GtkTreePath    *path,
                                                 GtkTreeIter    *iter,
                                                 gboolean        header_item);
static GtkWidget * gtk_tree_popover_get_path_item (GtkTreePopover *popover,
                                                   GtkTreePath    *search);
static void gtk_tree_popover_set_active_item (GtkTreePopover *popover,
                                              GtkWidget      *item);

G_DEFINE_TYPE_WITH_CODE (GtkTreePopover, gtk_tree_popover, GTK_TYPE_POPOVER,
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
                                                gtk_tree_popover_cell_layout_init));

static void
gtk_tree_popover_constructed (GObject *object)
{
  GtkTreePopover *popover = GTK_TREE_POPOVER (object);

  G_OBJECT_CLASS (gtk_tree_popover_parent_class)->constructed (object);

  if (!popover->area)
    {
      GtkCellArea *area = gtk_cell_area_box_new ();
      gtk_tree_popover_set_area (popover, area);
    }

  popover->context = gtk_cell_area_create_context (popover->area);

  popover->size_changed_id = g_signal_connect (popover->context, "notify",
                                               G_CALLBACK (context_size_changed_cb), popover);
}

static void
gtk_tree_popover_dispose (GObject *object)
{
  GtkTreePopover *popover = GTK_TREE_POPOVER (object);

  gtk_tree_popover_set_model (popover, NULL);
  gtk_tree_popover_set_area (popover, NULL);

  if (popover->context)
    {
      g_clear_signal_handler (&popover->size_changed_id, popover->context);

      g_clear_object (&popover->context);
    }

  G_OBJECT_CLASS (gtk_tree_popover_parent_class)->dispose (object);
}

static void
gtk_tree_popover_finalize (GObject *object)
{
  GtkTreePopover *popover = GTK_TREE_POPOVER (object);

  if (popover->row_separator_destroy)
    popover->row_separator_destroy (popover->row_separator_data);

  G_OBJECT_CLASS (gtk_tree_popover_parent_class)->finalize (object);
}

static void
gtk_tree_popover_set_property (GObject      *object,
                               guint         prop_id,
                               const GValue *value,
                               GParamSpec   *pspec)
{
  GtkTreePopover *popover = GTK_TREE_POPOVER (object);

  switch (prop_id)
    {
    case PROP_MODEL:
      gtk_tree_popover_set_model (popover, g_value_get_object (value));
      break;

    case PROP_CELL_AREA:
      gtk_tree_popover_set_area (popover, g_value_get_object (value));
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
gtk_tree_popover_get_property (GObject    *object,
                               guint       prop_id,
                               GValue     *value,
                               GParamSpec *pspec)
{
  GtkTreePopover *popover = GTK_TREE_POPOVER (object);

  switch (prop_id)
    {
    case PROP_MODEL:
      g_value_set_object (value, popover->model);
      break;

    case PROP_CELL_AREA:
      g_value_set_object (value, popover->area);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
gtk_tree_popover_class_init (GtkTreePopoverClass *class)
{
  GObjectClass *object_class = G_OBJECT_CLASS (class);

  object_class->constructed  = gtk_tree_popover_constructed;
  object_class->dispose = gtk_tree_popover_dispose;
  object_class->finalize = gtk_tree_popover_finalize;
  object_class->set_property = gtk_tree_popover_set_property;
  object_class->get_property = gtk_tree_popover_get_property;

  props[PROP_MODEL] = g_param_spec_object ("model", NULL, NULL,
                                           GTK_TYPE_TREE_MODEL,
                                           G_PARAM_READWRITE | G_PARAM_STATIC_NAME);

  props[PROP_CELL_AREA] = g_param_spec_object ("cell-area", NULL, NULL,
                                               GTK_TYPE_CELL_AREA,
                                               G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_CONSTRUCT_ONLY);

  g_object_class_install_properties (object_class, NUM_PROPERTIES, props);

  signals[MENU_ACTIVATE] =
    g_signal_new (I_("menu-activate"),
                  G_OBJECT_CLASS_TYPE (object_class),
                  G_SIGNAL_RUN_FIRST,
                  0,
                  NULL, NULL,
                  NULL,
                  G_TYPE_NONE, 1, G_TYPE_STRING);
}

static GtkWidget *
gtk_tree_popover_get_stack (GtkTreePopover *popover)
{
  GtkWidget *sw = gtk_popover_get_child (GTK_POPOVER (popover));
  GtkWidget *vp = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (sw));
  GtkWidget *stack = gtk_viewport_get_child (GTK_VIEWPORT (vp));

  return stack;
}

static void
gtk_tree_popover_add_submenu (GtkTreePopover *popover,
                              GtkWidget      *submenu,
                              const char     *name)
{
  GtkWidget *stack = gtk_tree_popover_get_stack (popover);
  gtk_stack_add_named (GTK_STACK (stack), submenu, name);
}

static GtkWidget *
gtk_tree_popover_get_submenu (GtkTreePopover *popover,
                              const char     *name)
{
  GtkWidget *stack = gtk_tree_popover_get_stack (popover);
  return gtk_stack_get_child_by_name (GTK_STACK (stack), name);
}

void
gtk_tree_popover_open_submenu (GtkTreePopover *popover,
                               const char     *name)
{
  GtkWidget *stack = gtk_tree_popover_get_stack (popover);
  gtk_stack_set_visible_child_name (GTK_STACK (stack), name);
}

static void
gtk_tree_popover_init (GtkTreePopover *popover)
{
  GtkWidget *sw;
  GtkWidget *stack;

  sw = gtk_scrolled_window_new ();
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
  gtk_scrolled_window_set_propagate_natural_width (GTK_SCROLLED_WINDOW (sw), TRUE);
  gtk_scrolled_window_set_propagate_natural_height (GTK_SCROLLED_WINDOW (sw), TRUE);
  gtk_popover_set_child (GTK_POPOVER (popover), sw);

  stack = gtk_stack_new ();
  gtk_stack_set_vhomogeneous (GTK_STACK (stack), FALSE);
  gtk_stack_set_transition_type (GTK_STACK (stack), GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT);
  gtk_stack_set_interpolate_size (GTK_STACK (stack), TRUE);
  gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), stack);

  gtk_widget_add_css_class (GTK_WIDGET (popover), "menu");
}

static GtkCellArea *
gtk_tree_popover_cell_layout_get_area (GtkCellLayout *layout)
{
  return GTK_TREE_POPOVER (layout)->area;
}

static void
gtk_tree_popover_cell_layout_init (GtkCellLayoutIface  *iface)
{
  iface->get_area = gtk_tree_popover_cell_layout_get_area;
}

static void
insert_at_position (GtkBox    *box,
                    GtkWidget *child,
                    int        position)
{
  GtkWidget *sibling = NULL;

  if (position > 0)
    {
      int i;

      sibling = gtk_widget_get_first_child (GTK_WIDGET (box));
      for (i = 1; i < position; i++)
        sibling = gtk_widget_get_next_sibling (sibling);
    }

  gtk_box_insert_child_after (box, child, sibling);
}

static GtkWidget *
ensure_submenu (GtkTreePopover *popover,
                GtkTreePath    *path)
{
  GtkWidget *box;
  char *name;

  if (path)
    name = gtk_tree_path_to_string (path);
  else
    name = NULL;

  box = gtk_tree_popover_get_submenu (popover, name ? name : "main");
  if (!box)
    {
      box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
      gtk_tree_popover_add_submenu (popover, box, name ? name : "main");
      if (path)
        {
          GtkTreeIter iter;
          GtkWidget *item;
          gtk_tree_model_get_iter (popover->model, &iter, path);
          item = gtk_tree_popover_create_item (popover, path, &iter, TRUE);
          gtk_box_append (GTK_BOX (box), item);
          gtk_box_append (GTK_BOX (box), gtk_separator_new (GTK_ORIENTATION_HORIZONTAL));
        }

    }

  g_free (name);

  return box;
}

static void
row_inserted_cb (GtkTreeModel   *model,
                 GtkTreePath    *path,
                 GtkTreeIter    *iter,
                 GtkTreePopover *popover)
{
  int *indices, depth, index;
  GtkWidget *item;
  GtkWidget *box;

  indices = gtk_tree_path_get_indices (path);
  depth = gtk_tree_path_get_depth (path);
  index = indices[depth - 1];

  item = gtk_tree_popover_create_item (popover, path, iter, FALSE);
  if (depth == 1)
    {
      box = ensure_submenu (popover, NULL);
      insert_at_position (GTK_BOX (box), item, index);
    }
  else
    {
      GtkTreePath *ppath;

      ppath = gtk_tree_path_copy (path);
      gtk_tree_path_up (ppath);

      box = ensure_submenu (popover, ppath);
      insert_at_position (GTK_BOX (box), item, index + 2);

      gtk_tree_path_free (ppath);
    }

  gtk_cell_area_context_reset (popover->context);
}

static void
row_deleted_cb (GtkTreeModel   *model,
                GtkTreePath    *path,
                GtkTreePopover *popover)
{
  GtkWidget *item;

  item = gtk_tree_popover_get_path_item (popover, path);

  if (item)
    {
      gtk_widget_unparent (item);
      gtk_cell_area_context_reset (popover->context);
    }
}

static void
row_changed_cb (GtkTreeModel   *model,
                GtkTreePath    *path,
                GtkTreeIter    *iter,
                GtkTreePopover *popover)
{
  gboolean is_separator = FALSE;
  GtkWidget *item;
  int *indices, depth, index;

  item = gtk_tree_popover_get_path_item (popover, path);

  if (!item)
    return;

  indices = gtk_tree_path_get_indices (path);
  depth = gtk_tree_path_get_depth (path);
  index = indices[depth - 1];

  if (popover->row_separator_func)
    is_separator = popover->row_separator_func (model, iter, popover->row_separator_data);

  if (is_separator != GTK_IS_SEPARATOR (item))
    {
      GtkWidget *box = gtk_widget_get_parent (item);

      gtk_box_remove (GTK_BOX (box), item);

      item = gtk_tree_popover_create_item (popover, path, iter, FALSE);

      if (depth == 1)
        insert_at_position (GTK_BOX (box), item, index);
      else
        insert_at_position (GTK_BOX (box), item, index + 2);
    }
}

static void
row_reordered_cb (GtkTreeModel   *model,
                  GtkTreePath    *path,
                  GtkTreeIter    *iter,
                  int            *new_order,
                  GtkTreePopover *popover)
{
  rebuild_menu (popover);
}

static void
context_size_changed_cb (GtkCellAreaContext *context,
                         GParamSpec         *pspec,
                         GtkWidget          *popover)
{
  if (strcmp (pspec->name, "minimum-width") == 0 ||
      strcmp (pspec->name, "natural-width") == 0 ||
      strcmp (pspec->name, "minimum-height") == 0 ||
      strcmp (pspec->name, "natural-height") == 0)
    gtk_widget_queue_resize (popover);
}

static gboolean
area_is_sensitive (GtkCellArea *area)
{
  GList    *cells, *list;
  gboolean  sensitive = FALSE;

  cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (area));

  for (list = cells; list; list = list->next)
    {
      g_object_get (list->data, "sensitive", &sensitive, NULL);

      if (sensitive)
        break;
    }
  g_list_free (cells);

  return sensitive;
}

static GtkWidget *
gtk_tree_popover_get_path_item (GtkTreePopover *popover,
                                GtkTreePath    *search)
{
  GtkWidget *stack = gtk_tree_popover_get_stack (popover);
  GtkWidget *item = NULL;
  GtkWidget *stackchild;
  GtkWidget *child;

  for (stackchild = gtk_widget_get_first_child (stack);
       stackchild != NULL;
       stackchild = gtk_widget_get_next_sibling (stackchild))
    {
      for (child = gtk_widget_get_first_child (stackchild);
           !item && child;
           child = gtk_widget_get_next_sibling (child))
        {
          GtkTreePath *path  = NULL;

          if (GTK_IS_SEPARATOR (child))
            {
              GtkTreeRowReference *row = g_object_get_data (G_OBJECT (child), "gtk-tree-path");

              if (row)
                {
                  path = gtk_tree_row_reference_get_path (row);
                  if (!path)
                    item = child;
                }
            }
          else
            {
              GtkWidget *view = GTK_WIDGET (g_object_get_data (G_OBJECT (child), "view"));

              path = gtk_cell_view_get_displayed_row (GTK_CELL_VIEW (view));

              if (!path)
                item = child;
             }

           if (path)
             {
               if (gtk_tree_path_compare (search, path) == 0)
                 item = child;
               gtk_tree_path_free (path);
             }
        }
    }

  return item;
}

static void
area_apply_attributes_cb (GtkCellArea    *area,
                          GtkTreeModel   *tree_model,
                          GtkTreeIter    *iter,
                          gboolean       is_expander,
                          gboolean       is_expanded,
                          GtkTreePopover *popover)
{
  GtkTreePath*path;
  GtkWidget *item;
  gboolean sensitive;
  GtkTreeIter dummy;
  gboolean has_submenu = FALSE;

  if (gtk_tree_model_iter_children (popover->model, &dummy, iter))
    has_submenu = TRUE;

  path = gtk_tree_model_get_path (tree_model, iter);
  item = gtk_tree_popover_get_path_item (popover, path);

  if (item)
    {
      sensitive = area_is_sensitive (popover->area);
      gtk_widget_set_sensitive (item, sensitive || has_submenu);
    }

  gtk_tree_path_free (path);
}

static void
gtk_tree_popover_set_area (GtkTreePopover *popover,
                           GtkCellArea    *area)
{
  if (popover->area)
    {
      g_clear_signal_handler (&popover->apply_attributes_id, popover->area);
      g_clear_object (&popover->area);
    }

  popover->area = area;

  if (popover->area)
    {
      g_object_ref_sink (popover->area);
      popover->apply_attributes_id = g_signal_connect (popover->area, "apply-attributes",
                                                       G_CALLBACK (area_apply_attributes_cb), popover);
    }
}

static void
activate_item (GtkWidget      *item,
               GtkTreePopover *popover)
{
  GtkCellView *view;
  GtkTreePath *path;
  char *path_str;
  gboolean is_header = FALSE;
  gboolean has_submenu = FALSE;

  is_header = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "is-header"));

  view = GTK_CELL_VIEW (g_object_get_data (G_OBJECT (item), "view"));

  path = gtk_cell_view_get_displayed_row (view);

  if (is_header)
    {
      gtk_tree_path_up (path);
    }
  else
    {
      GtkTreeIter iter;
      GtkTreeIter dummy;

      gtk_tree_model_get_iter (popover->model, &iter, path);
      if (gtk_tree_model_iter_children (popover->model, &dummy, &iter))
        has_submenu = TRUE;
    }

  path_str = gtk_tree_path_to_string (path);

  if (is_header || has_submenu)
    {
      gtk_tree_popover_open_submenu (popover, path_str ? path_str : "main");
    }
  else
    {
      g_signal_emit (popover, signals[MENU_ACTIVATE], 0, path_str);
      gtk_popover_popdown (GTK_POPOVER (popover));
    }

  g_free (path_str);
  gtk_tree_path_free (path);
}

static void
item_activated_cb (GtkGesture     *gesture,
                   guint           n_press,
                   double          x,
                   double          y,
                   GtkTreePopover *popover)
{
  GtkWidget *item = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
  activate_item (item, popover);
}

static void
enter_cb (GtkEventController   *controller,
          double                x,
          double                y,
          GtkTreePopover       *popover)
{
  GtkWidget *item;
  item = gtk_event_controller_get_widget (controller);

  gtk_tree_popover_set_active_item (popover, item);
}

static void
enter_focus_cb (GtkEventController   *controller,
                GtkTreePopover       *popover)
{
  GtkWidget *item = gtk_event_controller_get_widget (controller);

  gtk_tree_popover_set_active_item (popover, item);
}

static gboolean
activate_shortcut (GtkWidget *widget,
                   GVariant  *args,
                   gpointer   user_data)
{
  activate_item (widget, user_data);
  return TRUE;
}

static GtkWidget *
gtk_tree_popover_create_item (GtkTreePopover *popover,
                              GtkTreePath    *path,
                              GtkTreeIter    *iter,
                              gboolean        header_item)
{
  GtkWidget *item, *view;
  gboolean is_separator = FALSE;

  if (popover->row_separator_func)
    is_separator = popover->row_separator_func (popover->model, iter, popover->row_separator_data);

  if (is_separator)
    {
      item = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
      g_object_set_data_full (G_OBJECT (item), "gtk-tree-path",
                                               gtk_tree_row_reference_new (popover->model, path),
                                               (GDestroyNotify)gtk_tree_row_reference_free);
    }
  else
    {
      GtkEventController *controller;
      GtkTreeIter dummy;
      gboolean has_submenu = FALSE;
      GtkWidget *indicator;

      if (!header_item &&
          gtk_tree_model_iter_children (popover->model, &dummy, iter))
        has_submenu = TRUE;

      view = gtk_cell_view_new_with_context (popover->area, popover->context);
      gtk_cell_view_set_model (GTK_CELL_VIEW (view), popover->model);
      gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (view), path);
      gtk_widget_set_hexpand (view, TRUE);

      item = gtk_gizmo_new ("modelbutton", NULL, NULL, NULL, NULL,
                            (GtkGizmoFocusFunc)gtk_widget_focus_self,
                            (GtkGizmoGrabFocusFunc)gtk_widget_grab_focus_self);
      gtk_widget_set_layout_manager (item, gtk_box_layout_new (GTK_ORIENTATION_HORIZONTAL));
      gtk_widget_set_focusable (item, TRUE);
      gtk_widget_add_css_class (item, "flat");

      if (header_item)
        {
          indicator = gtk_builtin_icon_new ("arrow");
          gtk_widget_add_css_class (indicator, "left");
          gtk_widget_set_parent (indicator, item);
        }

      gtk_widget_set_parent (view, item);

      indicator = gtk_builtin_icon_new (has_submenu ? "arrow" : "none");
      gtk_widget_add_css_class (indicator, "right");
      gtk_widget_set_parent (indicator, item);

      controller = GTK_EVENT_CONTROLLER (gtk_gesture_click_new ());
      g_signal_connect (controller, "pressed", G_CALLBACK (item_activated_cb), popover);
      gtk_widget_add_controller (item, GTK_EVENT_CONTROLLER (controller));

      controller = gtk_event_controller_motion_new ();
      g_signal_connect (controller, "enter", G_CALLBACK (enter_cb), popover);
      gtk_widget_add_controller (item, controller);

      controller = gtk_event_controller_focus_new ();
      g_signal_connect (controller, "enter", G_CALLBACK (enter_focus_cb), popover);
      gtk_widget_add_controller (item, controller);

      {
        const guint activate_keyvals[] = { GDK_KEY_space, GDK_KEY_KP_Space,
                                           GDK_KEY_Return, GDK_KEY_ISO_Enter,
                                           GDK_KEY_KP_Enter };
        GtkShortcutTrigger *trigger;
        GtkShortcut *shortcut;

        trigger = g_object_ref (gtk_never_trigger_get ());
        for (int i = 0; i < G_N_ELEMENTS (activate_keyvals); i++)
          trigger = gtk_alternative_trigger_new (gtk_keyval_trigger_new (activate_keyvals[i], 0), trigger);

        shortcut = gtk_shortcut_new (trigger, gtk_callback_action_new (activate_shortcut, popover, NULL));
        controller = gtk_shortcut_controller_new ();
        gtk_shortcut_controller_add_shortcut (GTK_SHORTCUT_CONTROLLER (controller), shortcut);
        gtk_widget_add_controller (item, controller);
      }

      g_object_set_data (G_OBJECT (item), "is-header", GINT_TO_POINTER (header_item));
      g_object_set_data (G_OBJECT (item), "view", view);
    }

  return item;
}

static void
populate (GtkTreePopover *popover,
          GtkTreeIter    *parent)
{
  GtkTreeIter iter;
  gboolean valid = FALSE;

  if (!popover->model)
    return;

  valid = gtk_tree_model_iter_children (popover->model, &iter, parent);

  while (valid)
    {
      GtkTreePath *path;

      path = gtk_tree_model_get_path (popover->model, &iter);
      row_inserted_cb (popover->model, path, &iter, popover);

      populate (popover, &iter);

      valid = gtk_tree_model_iter_next (popover->model, &iter);
      gtk_tree_path_free (path);
    }
}

static void
gtk_tree_popover_populate (GtkTreePopover *popover)
{
  populate (popover, NULL);
}

static void
rebuild_menu (GtkTreePopover *popover)
{
  GtkWidget *stack;
  GtkWidget *child;

  stack = gtk_tree_popover_get_stack (popover);
  while ((child = gtk_widget_get_first_child (stack)))
    gtk_stack_remove (GTK_STACK (stack), child);

  if (popover->model)
    gtk_tree_popover_populate (popover);
}

void
gtk_tree_popover_set_model (GtkTreePopover *popover,
                            GtkTreeModel   *model)
{
  if (popover->model == model)
    return;

  if (popover->model)
    {
      g_signal_handler_disconnect (popover->model, popover->row_inserted_id);
      g_signal_handler_disconnect (popover->model, popover->row_deleted_id);
      g_signal_handler_disconnect (popover->model, popover->row_changed_id);
      g_signal_handler_disconnect (popover->model, popover->row_reordered_id);
      popover->row_inserted_id  = 0;
      popover->row_deleted_id = 0;
      popover->row_changed_id = 0;
      popover->row_reordered_id = 0;

      g_object_unref (popover->model);
    }

  popover->model = model;

  if (popover->model)
    {
      g_object_ref (popover->model);

      popover->row_inserted_id = g_signal_connect (popover->model, "row-inserted",
                                                   G_CALLBACK (row_inserted_cb), popover);
      popover->row_deleted_id = g_signal_connect (popover->model, "row-deleted",
                                                  G_CALLBACK (row_deleted_cb), popover);
      popover->row_changed_id = g_signal_connect (popover->model, "row-changed",
                                                  G_CALLBACK (row_changed_cb), popover);
      popover->row_reordered_id = g_signal_connect (popover->model, "rows-reordered",
                                                    G_CALLBACK (row_reordered_cb), popover);
    }

  rebuild_menu (popover);
}

void
gtk_tree_popover_set_row_separator_func (GtkTreePopover              *popover,
                                         GtkTreeViewRowSeparatorFunc  func,
                                         gpointer                     data,
                                         GDestroyNotify               destroy)
{
  if (popover->row_separator_destroy)
    popover->row_separator_destroy (popover->row_separator_data);

  popover->row_separator_func = func;
  popover->row_separator_data = data;
  popover->row_separator_destroy = destroy;

  rebuild_menu (popover);
}

static void
gtk_tree_popover_set_active_item (GtkTreePopover *popover,
                                  GtkWidget      *item)
{
  if (popover->active_item == item)
    return;

  if (popover->active_item)
    {
      gtk_widget_unset_state_flags (popover->active_item, GTK_STATE_FLAG_SELECTED);
      g_object_remove_weak_pointer (G_OBJECT (popover->active_item), (gpointer *)&popover->active_item);
    }

  popover->active_item = item;

  if (popover->active_item)
    {
      g_object_add_weak_pointer (G_OBJECT (popover->active_item), (gpointer *)&popover->active_item);
      gtk_widget_set_state_flags (popover->active_item, GTK_STATE_FLAG_SELECTED, FALSE);
    }
}

void
gtk_tree_popover_set_active (GtkTreePopover *popover,
                             int             item)
{
  GtkWidget *box;
  GtkWidget *child;
  int pos;

  if (item == -1)
    {
      gtk_tree_popover_set_active_item (popover, NULL);
      return;
    }

  box = gtk_tree_popover_get_submenu (popover, "main");
  if (!box)
    return;

  for (child = gtk_widget_get_first_child (box), pos = 0;
       child;
       child = gtk_widget_get_next_sibling (child), pos++)
    {
      if (pos == item)
        {
          gtk_tree_popover_set_active_item (popover, child);
          break;
        }
    }
}


Messung V0.5 in Prozent
C=97 H=95 G=95

¤ Dauer der Verarbeitung: 0.3 Sekunden  (vorverarbeitet am  2026-07-02) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.