Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  gtkcolumnviewrowwidget.c

  Sprache: C
 

/*
 * Copyright © 2023 Benjamin Otte
 *
 * 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.1 of the License, 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/>.
 *
 * Authors: Benjamin Otte <otte@gnome.org>
 */


#include "config.h"

#include "gtkcolumnviewrowwidgetprivate.h"

#include "gtkbinlayout.h"
#include "gtkcolumnviewprivate.h"
#include "gtkcolumnviewcellwidgetprivate.h"
#include "gtkcolumnviewcolumnprivate.h"
#include "gtkcolumnviewrowprivate.h"
#include "gtkcolumnviewtitleprivate.h"
#include "gtklistitemfactoryprivate.h"
#include "gtklistbaseprivate.h"
#include "gtkwidget.h"
#include "gtkwidgetprivate.h"

G_DEFINE_TYPE (GtkColumnViewRowWidget, gtk_column_view_row_widget, GTK_TYPE_LIST_FACTORY_WIDGET)

static GtkColumnView *
gtk_column_view_row_widget_get_column_view (GtkColumnViewRowWidget *self)
{
  GtkWidget *parent = _gtk_widget_get_parent (GTK_WIDGET (self));

  if (GTK_IS_COLUMN_VIEW (parent))
    return GTK_COLUMN_VIEW (parent);

  parent = _gtk_widget_get_parent (parent);
  g_assert (GTK_IS_COLUMN_VIEW (parent));

  return GTK_COLUMN_VIEW (parent);
}

static gboolean
gtk_column_view_row_widget_is_header (GtkColumnViewRowWidget *self)
{
  return gtk_widget_get_css_name (GTK_WIDGET (self)) == g_intern_static_string ("header");
}

static GtkColumnViewColumn *
gtk_column_view_row_child_get_column (GtkWidget *child)
{
  if (GTK_IS_COLUMN_VIEW_CELL_WIDGET (child))
    return gtk_column_view_cell_widget_get_column (GTK_COLUMN_VIEW_CELL_WIDGET (child));
  else
    return gtk_column_view_title_get_column (GTK_COLUMN_VIEW_TITLE (child));

  g_return_val_if_reached (NULL);
}

static GtkWidget *
gtk_column_view_row_widget_find_child (GtkColumnViewRowWidget *self,
                                       GtkColumnViewColumn    *column)
{
  GtkWidget *child;

  for (child = gtk_widget_get_first_child (GTK_WIDGET (self));
       child;
       child = gtk_widget_get_next_sibling (child))
    {
      if (gtk_column_view_row_child_get_column (child) == column)
        return child;
    }

  return NULL;
}

static void
gtk_column_view_row_widget_update (GtkListItemBase *base,
                                   guint            position,
                                   gpointer         item,
                                   gboolean         selected)
{
  GtkColumnViewRowWidget *self = GTK_COLUMN_VIEW_ROW_WIDGET (base);
  GtkWidget *child;

  if (gtk_column_view_row_widget_is_header (self))
    return;

  GTK_LIST_ITEM_BASE_CLASS (gtk_column_view_row_widget_parent_class)->update (base, position, item, selected);

  for (child = gtk_widget_get_first_child (GTK_WIDGET (self));
       child;
       child = gtk_widget_get_next_sibling (child))
    {
      gtk_list_item_base_update (GTK_LIST_ITEM_BASE (child), position, item, selected);
    }
}

static gpointer
gtk_column_view_row_widget_create_object (GtkListFactoryWidget *fw)
{
  return gtk_column_view_row_new ();
}

static void
gtk_column_view_row_widget_setup_object (GtkListFactoryWidget *fw,
                                         gpointer              object)
{
  GtkColumnViewRowWidget *self = GTK_COLUMN_VIEW_ROW_WIDGET (fw);
  GtkColumnViewRow *row = object;

  g_assert (!gtk_column_view_row_widget_is_header (self));

  GTK_LIST_FACTORY_WIDGET_CLASS (gtk_column_view_row_widget_parent_class)->setup_object (fw, object);

  row->owner = self;

  gtk_list_factory_widget_set_activatable (fw, row->activatable);
  gtk_list_factory_widget_set_selectable (fw, row->selectable);
  gtk_widget_set_focusable (GTK_WIDGET (self), row->focusable);

  gtk_accessible_update_property (GTK_ACCESSIBLE (self),
                                  GTK_ACCESSIBLE_PROPERTY_LABEL, row->accessible_label,
                                  GTK_ACCESSIBLE_PROPERTY_DESCRIPTION, row->accessible_description,
                                  -1);

  gtk_column_view_row_do_notify (row,
                                 gtk_list_item_base_get_item (GTK_LIST_ITEM_BASE (self)) != NULL,
                                 gtk_list_item_base_get_position (GTK_LIST_ITEM_BASE (self)) != GTK_INVALID_LIST_POSITION,
                                 gtk_list_item_base_get_selected (GTK_LIST_ITEM_BASE (self)));
}

static void
gtk_column_view_row_widget_teardown_object (GtkListFactoryWidget *fw,
                                            gpointer              object)
{
  GtkColumnViewRowWidget *self = GTK_COLUMN_VIEW_ROW_WIDGET (fw);
  GtkColumnViewRow *row = object;

  g_assert (!gtk_column_view_row_widget_is_header (self));

  GTK_LIST_FACTORY_WIDGET_CLASS (gtk_column_view_row_widget_parent_class)->teardown_object (fw, object);

  row->owner = NULL;

  gtk_list_factory_widget_set_activatable (fw, FALSE);
  gtk_list_factory_widget_set_selectable (fw, FALSE);
  gtk_widget_set_focusable (GTK_WIDGET (self), TRUE);

  gtk_accessible_reset_property (GTK_ACCESSIBLE (self), GTK_ACCESSIBLE_PROPERTY_LABEL);
  gtk_accessible_reset_property (GTK_ACCESSIBLE (self), GTK_ACCESSIBLE_PROPERTY_DESCRIPTION);

  gtk_column_view_row_do_notify (row,
                                 gtk_list_item_base_get_item (GTK_LIST_ITEM_BASE (self)) != NULL,
                                 gtk_list_item_base_get_position (GTK_LIST_ITEM_BASE (self)) != GTK_INVALID_LIST_POSITION,
                                 gtk_list_item_base_get_selected (GTK_LIST_ITEM_BASE (self)));
}

static void
gtk_column_view_row_widget_update_object (GtkListFactoryWidget *fw,
                                          gpointer              object,
                                          guint                 position,
                                          gpointer              item,
                                          gboolean              selected)
{
  GtkColumnViewRowWidget *self = GTK_COLUMN_VIEW_ROW_WIDGET (fw);
  GtkListItemBase *base = GTK_LIST_ITEM_BASE (self);
  GtkColumnViewRow *row = object;
  /* Track notify manually instead of freeze/thaw_notify for performance reasons. */
  gboolean notify_item = FALSE, notify_position = FALSE, notify_selected = FALSE;

  g_assert (!gtk_column_view_row_widget_is_header (self));

  /* FIXME: It's kinda evil to notify external objects from here... */
  notify_item = gtk_list_item_base_get_item (base) != item;
  notify_position = gtk_list_item_base_get_position (base) != position;
  notify_selected = gtk_list_item_base_get_selected (base) != selected;

  GTK_LIST_FACTORY_WIDGET_CLASS (gtk_column_view_row_widget_parent_class)->update_object (fw,
                                                                                          object,
                                                                                          position,
                                                                                          item,
                                                                                          selected);

  if (row)
    gtk_column_view_row_do_notify (row, notify_item, notify_position, notify_selected);
}

static GtkWidget *
gtk_column_view_next_focus_widget (GtkWidget        *widget,
                                   GtkWidget        *current,
                                   GtkDirectionType  direction)
{
  gboolean forward;

  switch (direction)
    {
      case GTK_DIR_TAB_FORWARD:
        forward = TRUE;
        break;
      case GTK_DIR_TAB_BACKWARD:
        forward = FALSE;
        break;
      case GTK_DIR_LEFT:
        forward = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
        break;
      case GTK_DIR_RIGHT:
        forward = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL;
        break;
      case GTK_DIR_UP:
      case GTK_DIR_DOWN:
        return NULL;
      default:
        g_return_val_if_reached (NULL);
    }

  if (forward)
    {
      if (current == NULL)
        return widget;
      else if (current == widget)
        return gtk_widget_get_first_child (widget);
      else
        return gtk_widget_get_next_sibling (current);
    }
  else
    {
      if (current == NULL)
        return gtk_widget_get_last_child (widget);
      else if (current == widget)
        return NULL;
      else
        {
          current = gtk_widget_get_prev_sibling (current);
          if (current)
            return current;
          else
            return widget;
        }
    }
}

static gboolean
gtk_column_view_row_widget_focus (GtkWidget        *widget,
                                  GtkDirectionType  direction)
{
  GtkColumnViewRowWidget *self = GTK_COLUMN_VIEW_ROW_WIDGET (widget);
  GtkWidget *child, *current;
  GtkColumnView *view;

  current = gtk_widget_get_focus_child (widget);

  view = gtk_column_view_row_widget_get_column_view (self);
  if (gtk_column_view_get_tab_behavior (view) == GTK_LIST_TAB_CELL &&
      (direction == GTK_DIR_TAB_FORWARD || direction == GTK_DIR_TAB_BACKWARD))
    {
      if (current || gtk_widget_is_focus (widget))
        return FALSE;
    }

  if (current &&
      (direction == GTK_DIR_UP || direction == GTK_DIR_DOWN ||
      direction == GTK_DIR_LEFT || direction == GTK_DIR_RIGHT))
    {
      if (gtk_widget_child_focus (current, direction))
        return TRUE;
    }

  if (current == NULL)
    {
      GtkColumnViewColumn *focus_column = gtk_column_view_get_focus_column (view);
      if (focus_column)
        {
          current = gtk_column_view_row_widget_find_child (self, focus_column);
          if (current && gtk_widget_child_focus (current, direction))
            return TRUE;
        }
    }

  if (gtk_widget_is_focus (widget))
    current = widget;

  for (child = gtk_column_view_next_focus_widget (widget, current, direction);
       child;
       child = gtk_column_view_next_focus_widget (widget, child, direction))
    {
      if (child == widget)
        {
          if (gtk_widget_grab_focus_self (widget))
            {
              gtk_column_view_set_focus_column (view, NULL, FALSE);
              return TRUE;
            }
        }
      else if (child)
        {
          if (gtk_widget_child_focus (child, direction))
            return TRUE;
        }
    }

  return FALSE;
}

static gboolean
gtk_column_view_row_widget_grab_focus (GtkWidget *widget)
{
  GtkColumnViewRowWidget *self = GTK_COLUMN_VIEW_ROW_WIDGET (widget);
  GtkWidget *child, *focus_child;
  GtkColumnViewColumn *focus_column;
  GtkColumnView *view;

  view = gtk_column_view_row_widget_get_column_view (self);
  focus_column = gtk_column_view_get_focus_column (view);
  if (focus_column)
    {
      focus_child = gtk_column_view_row_widget_find_child (self, focus_column);
      if (focus_child && gtk_widget_grab_focus (focus_child))
        return TRUE;
    }
  else
    focus_child = NULL;

  if (gtk_widget_grab_focus_self (widget))
    {
      gtk_column_view_set_focus_column (view, NULL, FALSE);
      return TRUE;
    }

  for (child = focus_child ? gtk_widget_get_next_sibling (focus_child) : gtk_widget_get_first_child (widget);
       child != focus_child;
       child = child ? gtk_widget_get_next_sibling (child) : gtk_widget_get_first_child (widget))
    {
      /* When we started iterating at focus_child, we want to iterate over the rest
       * of the children, too */

      if (child == NULL)
        continue;

      if (gtk_widget_grab_focus (child))
        return TRUE;
    }

  return FALSE;
}

static void
gtk_column_view_row_widget_set_focus_child (GtkWidget *widget,
                                            GtkWidget *child)
{
  GtkColumnViewRowWidget *self = GTK_COLUMN_VIEW_ROW_WIDGET (widget);

  GTK_WIDGET_CLASS (gtk_column_view_row_widget_parent_class)->set_focus_child (widget, child);

  if (child)
    {
      gtk_column_view_set_focus_column (gtk_column_view_row_widget_get_column_view (self),
                                        gtk_column_view_row_child_get_column (child),
                                        TRUE);
    }
}

static void
gtk_column_view_row_widget_dispose (GObject *object)
{
  GtkColumnViewRowWidget *self = GTK_COLUMN_VIEW_ROW_WIDGET (object);
  GtkWidget *child;

  while ((child = gtk_widget_get_first_child (GTK_WIDGET (self))))
    {
      gtk_column_view_row_widget_remove_child (self, child);
    }

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

static GtkSizeRequestMode
gtk_column_view_row_widget_get_request_mode (GtkWidget *widget)
{
  GtkWidget *child;
  GtkSizeRequestMode child_mode;

  for (child = _gtk_widget_get_first_child (widget);
       child != NULL;
       child = _gtk_widget_get_next_sibling (child))
    {
      child_mode = gtk_widget_get_request_mode (child);
      if (child_mode != GTK_SIZE_REQUEST_CONSTANT_SIZE)
        return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
    }

  return GTK_SIZE_REQUEST_CONSTANT_SIZE;
}

static void
gtk_column_view_row_widget_measure_along (GtkColumnViewRowWidget *self,
                                          int                     for_size,
                                          int                    *minimum,
                                          int                    *natural,
                                          int                    *minimum_baseline,
                                          int                    *natural_baseline)
{
  GtkOrientation orientation = GTK_ORIENTATION_VERTICAL;
  GtkColumnView *view;
  GtkWidget *child;
  guint i, n;
  GtkRequestedSize *sizes = NULL;

  view = gtk_column_view_row_widget_get_column_view (self);

  if (for_size > -1)
    {
      n = g_list_model_get_n_items (gtk_column_view_get_columns (view));
      sizes = g_newa (GtkRequestedSize, n);
      gtk_column_view_distribute_width (view, for_size, sizes);
    }

  for (child = _gtk_widget_get_first_child (GTK_WIDGET (self)), i = 0;
       child != NULL;
       child = _gtk_widget_get_next_sibling (child), i++)
    {
      int child_min = 0;
      int child_nat = 0;
      int child_min_baseline = -1;
      int child_nat_baseline = -1;

      if (!gtk_widget_should_layout (child))
        continue;

      gtk_widget_measure (child, orientation,
                          for_size > -1 ? sizes[i].minimum_size : -1,
                          &child_min, &child_nat,
                          &child_min_baseline, &child_nat_baseline);

      *minimum = MAX (*minimum, child_min);
      *natural = MAX (*natural, child_nat);

      if (child_min_baseline > -1)
        *minimum_baseline = MAX (*minimum_baseline, child_min_baseline);
      if (child_nat_baseline > -1)
        *natural_baseline = MAX (*natural_baseline, child_nat_baseline);
    }
}

static void
gtk_column_view_row_widget_measure (GtkWidget      *widget,
                                    GtkOrientation  orientation,
                                    int             for_size,
                                    int            *minimum,
                                    int            *natural,
                                    int            *minimum_baseline,
                                    int            *natural_baseline)
{
  GtkColumnViewRowWidget *self = GTK_COLUMN_VIEW_ROW_WIDGET (widget);

  if (orientation == GTK_ORIENTATION_HORIZONTAL)
    {
      gtk_column_view_measure_across (gtk_column_view_row_widget_get_column_view (self),
                                      minimum,
                                      natural);
    }
  else
    {
      gtk_column_view_row_widget_measure_along (self,
                                                for_size,
                                                minimum,
                                                natural,
                                                minimum_baseline,
                                                natural_baseline);
    }
}

static void
gtk_column_view_row_widget_allocate (GtkWidget *widget,
                                     int        width,
                                     int        height,
                                     int        baseline)
{
  GtkWidget *child;

  for (child = _gtk_widget_get_first_child (widget);
       child != NULL;
       child = _gtk_widget_get_next_sibling (child))
    {
      GtkColumnViewColumn *column;
      int col_x, col_width, min;

      if (!gtk_widget_should_layout (child))
        continue;

      column = gtk_column_view_row_child_get_column (child);
      gtk_column_view_column_get_header_allocation (column, &col_x, &col_width);

      gtk_widget_measure (child, GTK_ORIENTATION_HORIZONTAL, -1, &min, NULL, NULL, NULL);

      gtk_widget_size_allocate (child, &(GtkAllocation) { col_x, 0, MAX (min, col_width), height }, baseline);
    }
}

static void
add_arrow_bindings (GtkWidgetClass   *widget_class,
      guint             keysym,
      GtkDirectionType  direction)
{
  guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;

  gtk_widget_class_add_binding_signal (widget_class,
                                       keysym, GDK_NO_MODIFIER_MASK,
                                       "move-focus",
                                       "(i)",
                                       direction);
  gtk_widget_class_add_binding_signal (widget_class,
                                       keysym, GDK_CONTROL_MASK,
                                       "move-focus",
                                       "(i)",
                                       direction);
  gtk_widget_class_add_binding_signal (widget_class,
                                       keypad_keysym, GDK_NO_MODIFIER_MASK,
                                       "move-focus",
                                       "(i)",
                                       direction);
  gtk_widget_class_add_binding_signal (widget_class,
                                       keypad_keysym, GDK_CONTROL_MASK,
                                       "move-focus",
                                       "(i)",
                                       direction);
}

static void
gtk_column_view_row_widget_class_init (GtkColumnViewRowWidgetClass *klass)
{
  GtkListFactoryWidgetClass *factory_class = GTK_LIST_FACTORY_WIDGET_CLASS (klass);
  GtkListItemBaseClass *base_class = GTK_LIST_ITEM_BASE_CLASS (klass);
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
  GObjectClass *object_class = G_OBJECT_CLASS (klass);

  factory_class->create_object = gtk_column_view_row_widget_create_object;
  factory_class->setup_object = gtk_column_view_row_widget_setup_object;
  factory_class->update_object = gtk_column_view_row_widget_update_object;
  factory_class->teardown_object = gtk_column_view_row_widget_teardown_object;

  base_class->update = gtk_column_view_row_widget_update;

  widget_class->focus = gtk_column_view_row_widget_focus;
  widget_class->grab_focus = gtk_column_view_row_widget_grab_focus;
  widget_class->set_focus_child = gtk_column_view_row_widget_set_focus_child;
  widget_class->get_request_mode = gtk_column_view_row_widget_get_request_mode;
  widget_class->measure = gtk_column_view_row_widget_measure;
  widget_class->size_allocate = gtk_column_view_row_widget_allocate;

  object_class->dispose = gtk_column_view_row_widget_dispose;

  add_arrow_bindings (widget_class, GDK_KEY_Left, GTK_DIR_LEFT);
  add_arrow_bindings (widget_class, GDK_KEY_Right, GTK_DIR_RIGHT);

  /* This gets overwritten by gtk_column_view_row_widget_new() but better safe than sorry */
  gtk_widget_class_set_css_name (widget_class, g_intern_static_string ("row"));
  gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_ROW);
}

static void
gtk_column_view_row_widget_init (GtkColumnViewRowWidget *self)
{
  gtk_widget_set_focusable (GTK_WIDGET (self), TRUE);
}

GtkWidget *
gtk_column_view_row_widget_new (GtkListItemFactory *factory,
                                gboolean            is_header)
{
  return g_object_new (GTK_TYPE_COLUMN_VIEW_ROW_WIDGET,
                       "factory", factory,
                       "css-name", is_header ? "header" : "row",
                       "selectable"TRUE,
                       "activatable"TRUE,
                       NULL);
}

void
gtk_column_view_row_widget_add_child (GtkColumnViewRowWidget *self,
                                      GtkWidget              *child)
{
  gtk_widget_set_parent (child, GTK_WIDGET (self));
}

void
gtk_column_view_row_widget_reorder_child (GtkColumnViewRowWidget *self,
                                          GtkWidget              *child,
                                          guint                   position)
{
  GtkWidget *widget = GTK_WIDGET (self);
  GtkWidget *sibling = NULL;

  if (position > 0)
    {
      GtkWidget *c;
      guint i;

      for (c = gtk_widget_get_first_child (widget), i = 0;
           c;
           c = gtk_widget_get_next_sibling (c), i++)
        {
          if (i + 1 == position)
            {
              sibling = c;
              break;
            }
        }
    }

  if (child != sibling)
    gtk_widget_insert_after (child, widget, sibling);
}

void
gtk_column_view_row_widget_remove_child (GtkColumnViewRowWidget *self,
                                         GtkWidget              *child)
{
  if (GTK_IS_COLUMN_VIEW_CELL_WIDGET (child))
    gtk_column_view_cell_widget_unset_column (GTK_COLUMN_VIEW_CELL_WIDGET (child));

  gtk_widget_unparent (child);
}


Messung V0.5 in Prozent
C=98 H=95 G=96

¤ Dauer der Verarbeitung: 0.13 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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik