forked from AuroraMiddleware/gtk
listitem: Make this a GObject
This splits GtkListItem into 2 parts: 1. GtkListItem This is purely a GObject with public API for developers who want to populate lists. There is no chance to cause conflict with GtkWidget properties that the list implementation assumed control over and defines a clear boundary. 2. GtkListItemWidget The widget part of the listitem. This is not only fully in control of the list machinery, the machinery can also use different widget implementations for different list widgets like I inted to for GtkColumnView.
This commit is contained in:
parent
db3e225f09
commit
30f09ea10b
@ -137,6 +137,7 @@ private_headers = [
|
||||
'gtklistitemprivate.h',
|
||||
'gtklistitemfactoryprivate.h',
|
||||
'gtklistitemmanagerprivate.h',
|
||||
'gtklistitemwidgetprivate.h',
|
||||
'gtklockbuttonprivate.h',
|
||||
'gtkmagnifierprivate.h',
|
||||
'gtkmediafileprivate.h',
|
||||
|
@ -23,6 +23,7 @@
|
||||
|
||||
#include "gtkadjustment.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtklistitemwidgetprivate.h"
|
||||
#include "gtkorientableprivate.h"
|
||||
#include "gtkscrollable.h"
|
||||
#include "gtksingleselection.h"
|
||||
@ -749,10 +750,10 @@ gtk_list_base_update_focus_tracker (GtkListBase *self)
|
||||
guint pos;
|
||||
|
||||
focus_child = gtk_widget_get_focus_child (GTK_WIDGET (self));
|
||||
if (!GTK_IS_LIST_ITEM (focus_child))
|
||||
if (!GTK_IS_LIST_ITEM_WIDGET (focus_child))
|
||||
return;
|
||||
|
||||
pos = gtk_list_item_get_position (GTK_LIST_ITEM (focus_child));
|
||||
pos = gtk_list_item_widget_get_position (GTK_LIST_ITEM_WIDGET (focus_child));
|
||||
if (pos != gtk_list_item_tracker_get_position (priv->item_manager, priv->focus))
|
||||
{
|
||||
gtk_list_item_tracker_set_position (priv->item_manager,
|
||||
|
@ -25,7 +25,6 @@
|
||||
#endif
|
||||
|
||||
#include <gtk/gtkwidget.h>
|
||||
#include <gtk/gtklistitem.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
@ -21,14 +21,7 @@
|
||||
|
||||
#include "gtklistitemprivate.h"
|
||||
|
||||
#include "gtkbinlayout.h"
|
||||
#include "gtkcssnodeprivate.h"
|
||||
#include "gtkeventcontrollerfocus.h"
|
||||
#include "gtkgestureclick.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtkmain.h"
|
||||
#include "gtkwidget.h"
|
||||
#include "gtkwidgetprivate.h"
|
||||
|
||||
/**
|
||||
* SECTION:gtklistitem
|
||||
@ -53,24 +46,9 @@
|
||||
* The #GtkListItem:item property is not %NULL.
|
||||
*/
|
||||
|
||||
struct _GtkListItem
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
|
||||
GObject *item;
|
||||
GtkWidget *child;
|
||||
guint position;
|
||||
|
||||
guint activatable : 1;
|
||||
guint selectable : 1;
|
||||
guint selected : 1;
|
||||
};
|
||||
|
||||
struct _GtkListItemClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
|
||||
void (* activate_signal) (GtkListItem *self);
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
enum
|
||||
@ -86,81 +64,17 @@ enum
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ACTIVATE_SIGNAL,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GtkListItem, gtk_list_item, GTK_TYPE_WIDGET)
|
||||
G_DEFINE_TYPE (GtkListItem, gtk_list_item, G_TYPE_OBJECT)
|
||||
|
||||
static GParamSpec *properties[N_PROPS] = { NULL, };
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
static void
|
||||
gtk_list_item_activate_signal (GtkListItem *self)
|
||||
{
|
||||
if (!self->activatable)
|
||||
return;
|
||||
|
||||
gtk_widget_activate_action (GTK_WIDGET (self),
|
||||
"list.activate-item",
|
||||
"u",
|
||||
self->position);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_list_item_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction)
|
||||
{
|
||||
GtkListItem *self = GTK_LIST_ITEM (widget);
|
||||
|
||||
/* The idea of this function is the following:
|
||||
* 1. If any child can take focus, do not ever attempt
|
||||
* to take focus.
|
||||
* 2. Otherwise, if this item is selectable or activatable,
|
||||
* allow focusing this widget.
|
||||
*
|
||||
* This makes sure every item in a list is focusable for
|
||||
* activation and selection handling, but no useless widgets
|
||||
* get focused and moving focus is as fast as possible.
|
||||
*/
|
||||
if (self->child)
|
||||
{
|
||||
if (gtk_widget_get_focus_child (widget))
|
||||
return FALSE;
|
||||
if (gtk_widget_child_focus (self->child, direction))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (gtk_widget_is_focus (widget))
|
||||
return FALSE;
|
||||
|
||||
if (!gtk_widget_get_can_focus (widget) ||
|
||||
!self->selectable)
|
||||
return FALSE;
|
||||
|
||||
return gtk_widget_grab_focus (widget);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_list_item_grab_focus (GtkWidget *widget)
|
||||
{
|
||||
GtkListItem *self = GTK_LIST_ITEM (widget);
|
||||
|
||||
if (self->child && gtk_widget_grab_focus (self->child))
|
||||
return TRUE;
|
||||
|
||||
return GTK_WIDGET_CLASS (gtk_list_item_parent_class)->grab_focus (widget);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_item_dispose (GObject *object)
|
||||
{
|
||||
GtkListItem *self = GTK_LIST_ITEM (object);
|
||||
|
||||
g_assert (self->item == NULL);
|
||||
g_clear_pointer (&self->child, gtk_widget_unparent);
|
||||
g_assert (self->owner == NULL); /* would hold a reference */
|
||||
g_clear_object (&self->child);
|
||||
|
||||
G_OBJECT_CLASS (gtk_list_item_parent_class)->dispose (object);
|
||||
}
|
||||
@ -233,36 +147,11 @@ gtk_list_item_set_property (GObject *object,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_item_select_action (GtkWidget *widget,
|
||||
const char *action_name,
|
||||
GVariant *parameter)
|
||||
{
|
||||
GtkListItem *self = GTK_LIST_ITEM (widget);
|
||||
gboolean modify, extend;
|
||||
|
||||
if (!self->selectable)
|
||||
return;
|
||||
|
||||
g_variant_get (parameter, "(bb)", &modify, &extend);
|
||||
|
||||
gtk_widget_activate_action (GTK_WIDGET (self),
|
||||
"list.select-item",
|
||||
"(ubb)",
|
||||
self->position, modify, extend);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_item_class_init (GtkListItemClass *klass)
|
||||
{
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
klass->activate_signal = gtk_list_item_activate_signal;
|
||||
|
||||
widget_class->focus = gtk_list_item_focus;
|
||||
widget_class->grab_focus = gtk_list_item_grab_focus;
|
||||
|
||||
gobject_class->dispose = gtk_list_item_dispose;
|
||||
gobject_class->get_property = gtk_list_item_get_property;
|
||||
gobject_class->set_property = gtk_list_item_set_property;
|
||||
@ -340,197 +229,25 @@ gtk_list_item_class_init (GtkListItemClass *klass)
|
||||
G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (gobject_class, N_PROPS, properties);
|
||||
|
||||
/**
|
||||
* GtkListItem::activate-signal:
|
||||
*
|
||||
* This is a keybinding signal, which will cause this row to be activated.
|
||||
*
|
||||
* Do not use it, it is an implementation detail.
|
||||
*
|
||||
* If you want to be notified when the user activates a listitem (by key or not),
|
||||
* look at the list widget this item is contained in.
|
||||
*/
|
||||
signals[ACTIVATE_SIGNAL] =
|
||||
g_signal_new (I_("activate-keybinding"),
|
||||
G_OBJECT_CLASS_TYPE (gobject_class),
|
||||
G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
|
||||
G_STRUCT_OFFSET (GtkListItemClass, activate_signal),
|
||||
NULL, NULL,
|
||||
NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
widget_class->activate_signal = signals[ACTIVATE_SIGNAL];
|
||||
|
||||
/**
|
||||
* GtkListItem|listitem.select:
|
||||
* @modify: %TRUE to toggle the existing selection, %FALSE to select
|
||||
* @extend: %TRUE to extend the selection
|
||||
*
|
||||
* Changes selection if the item is selectable.
|
||||
* If the item is not selectable, nothing happens.
|
||||
*
|
||||
* This function will emit the list.select-item action and the resulting
|
||||
* behavior, in particular the interpretation of @modify and @extend
|
||||
* depends on the view containing this listitem. See for example
|
||||
* GtkListView|list.select-item or GtkGridView|list.select-item.
|
||||
*/
|
||||
gtk_widget_class_install_action (widget_class,
|
||||
"listitem.select",
|
||||
"(bb)",
|
||||
gtk_list_item_select_action);
|
||||
|
||||
gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_Return, 0,
|
||||
"activate-keybinding", 0);
|
||||
gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_ISO_Enter, 0,
|
||||
"activate-keybinding", 0);
|
||||
gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_KP_Enter, 0,
|
||||
"activate-keybinding", 0);
|
||||
|
||||
/* note that some of these may get overwritten by child widgets,
|
||||
* such as GtkTreeExpander */
|
||||
gtk_widget_class_add_binding_action (widget_class, GDK_KEY_space, 0,
|
||||
"listitem.select", "(bb)", TRUE, FALSE);
|
||||
gtk_widget_class_add_binding_action (widget_class, GDK_KEY_space, GDK_CONTROL_MASK,
|
||||
"listitem.select", "(bb)", TRUE, FALSE);
|
||||
gtk_widget_class_add_binding_action (widget_class, GDK_KEY_space, GDK_SHIFT_MASK,
|
||||
"listitem.select", "(bb)", TRUE, FALSE);
|
||||
gtk_widget_class_add_binding_action (widget_class, GDK_KEY_space, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
|
||||
"listitem.select", "(bb)", TRUE, FALSE);
|
||||
gtk_widget_class_add_binding_action (widget_class, GDK_KEY_KP_Space, 0,
|
||||
"listitem.select", "(bb)", TRUE, FALSE);
|
||||
gtk_widget_class_add_binding_action (widget_class, GDK_KEY_KP_Space, GDK_CONTROL_MASK,
|
||||
"listitem.select", "(bb)", TRUE, FALSE);
|
||||
gtk_widget_class_add_binding_action (widget_class, GDK_KEY_KP_Space, GDK_SHIFT_MASK,
|
||||
"listitem.select", "(bb)", TRUE, FALSE);
|
||||
gtk_widget_class_add_binding_action (widget_class, GDK_KEY_KP_Space, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
|
||||
"listitem.select", "(bb)", TRUE, FALSE);
|
||||
|
||||
/* This gets overwritten by gtk_list_item_new() but better safe than sorry */
|
||||
gtk_widget_class_set_css_name (widget_class, I_("row"));
|
||||
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_item_click_gesture_pressed (GtkGestureClick *gesture,
|
||||
int n_press,
|
||||
double x,
|
||||
double y,
|
||||
GtkListItem *self)
|
||||
{
|
||||
GtkWidget *widget = GTK_WIDGET (self);
|
||||
|
||||
if (!self->selectable && !self->activatable)
|
||||
{
|
||||
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_DENIED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->selectable)
|
||||
{
|
||||
GdkModifierType state;
|
||||
GdkEvent *event;
|
||||
gboolean extend, modify;
|
||||
|
||||
event = gtk_gesture_get_last_event (GTK_GESTURE (gesture),
|
||||
gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture)));
|
||||
state = gdk_event_get_modifier_state (event);
|
||||
extend = (state & GDK_SHIFT_MASK) != 0;
|
||||
modify = (state & GDK_CONTROL_MASK) != 0;
|
||||
|
||||
gtk_widget_activate_action (widget,
|
||||
"list.select-item",
|
||||
"(ubb)",
|
||||
self->position, modify, extend);
|
||||
}
|
||||
|
||||
if (self->activatable)
|
||||
{
|
||||
if (n_press == 2)
|
||||
{
|
||||
gtk_widget_activate_action (widget,
|
||||
"list.activate-item",
|
||||
"u",
|
||||
self->position);
|
||||
}
|
||||
}
|
||||
|
||||
gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_ACTIVE, FALSE);
|
||||
|
||||
if (gtk_widget_get_focus_on_click (widget))
|
||||
gtk_widget_grab_focus (widget);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_item_enter_cb (GtkEventControllerFocus *controller,
|
||||
GtkListItem *self)
|
||||
{
|
||||
GtkWidget *widget = GTK_WIDGET (self);
|
||||
|
||||
gtk_widget_activate_action (widget,
|
||||
"list.scroll-to-item",
|
||||
"u",
|
||||
self->position);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_item_click_gesture_released (GtkGestureClick *gesture,
|
||||
int n_press,
|
||||
double x,
|
||||
double y,
|
||||
GtkListItem *self)
|
||||
{
|
||||
gtk_widget_unset_state_flags (GTK_WIDGET (self), GTK_STATE_FLAG_ACTIVE);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_item_click_gesture_canceled (GtkGestureClick *gesture,
|
||||
GdkEventSequence *sequence,
|
||||
GtkListItem *self)
|
||||
{
|
||||
gtk_widget_unset_state_flags (GTK_WIDGET (self), GTK_STATE_FLAG_ACTIVE);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_item_init (GtkListItem *self)
|
||||
{
|
||||
GtkEventController *controller;
|
||||
GtkGesture *gesture;
|
||||
|
||||
self->selectable = TRUE;
|
||||
self->activatable = TRUE;
|
||||
gtk_widget_set_can_focus (GTK_WIDGET (self), TRUE);
|
||||
|
||||
gesture = gtk_gesture_click_new ();
|
||||
gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (gesture),
|
||||
GTK_PHASE_BUBBLE);
|
||||
gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (gesture),
|
||||
FALSE);
|
||||
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture),
|
||||
GDK_BUTTON_PRIMARY);
|
||||
g_signal_connect (gesture, "pressed",
|
||||
G_CALLBACK (gtk_list_item_click_gesture_pressed), self);
|
||||
g_signal_connect (gesture, "released",
|
||||
G_CALLBACK (gtk_list_item_click_gesture_released), self);
|
||||
g_signal_connect (gesture, "cancel",
|
||||
G_CALLBACK (gtk_list_item_click_gesture_canceled), self);
|
||||
gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (gesture));
|
||||
|
||||
controller = gtk_event_controller_focus_new ();
|
||||
g_signal_connect (controller, "enter", G_CALLBACK (gtk_list_item_enter_cb), self);
|
||||
gtk_widget_add_controller (GTK_WIDGET (self), controller);
|
||||
}
|
||||
|
||||
GtkListItem *
|
||||
gtk_list_item_new (const char *css_name)
|
||||
gtk_list_item_new (GtkListItemWidget *owner)
|
||||
{
|
||||
GtkListItem *result;
|
||||
|
||||
g_return_val_if_fail (css_name != NULL, NULL);
|
||||
g_return_val_if_fail (owner != NULL, NULL);
|
||||
|
||||
result = g_object_new (GTK_TYPE_LIST_ITEM,
|
||||
"css-name", css_name,
|
||||
NULL);
|
||||
result->owner = owner;
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -590,12 +307,17 @@ gtk_list_item_set_child (GtkListItem *self,
|
||||
if (self->child == child)
|
||||
return;
|
||||
|
||||
g_clear_pointer (&self->child, gtk_widget_unparent);
|
||||
if (self->child && self->owner)
|
||||
gtk_list_item_widget_remove_child (self->owner, self->child);
|
||||
|
||||
g_clear_object (&self->child);
|
||||
|
||||
if (child)
|
||||
{
|
||||
gtk_widget_insert_after (child, GTK_WIDGET (self), NULL);
|
||||
g_object_ref_sink (child);
|
||||
self->child = child;
|
||||
if (self->owner)
|
||||
gtk_list_item_widget_add_child (self->owner, child);
|
||||
}
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ITEM]);
|
||||
@ -615,8 +337,6 @@ gtk_list_item_set_item (GtkListItem *self,
|
||||
if (item)
|
||||
self->item = g_object_ref (item);
|
||||
|
||||
gtk_css_node_invalidate (gtk_widget_get_css_node (GTK_WIDGET (self)), GTK_CSS_CHANGE_ANIMATIONS);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ITEM]);
|
||||
}
|
||||
|
||||
@ -680,11 +400,6 @@ gtk_list_item_set_selected (GtkListItem *self,
|
||||
|
||||
self->selected = selected;
|
||||
|
||||
if (selected)
|
||||
gtk_widget_set_state_flags (GTK_WIDGET (self), GTK_STATE_FLAG_SELECTED, FALSE);
|
||||
else
|
||||
gtk_widget_unset_state_flags (GTK_WIDGET (self), GTK_STATE_FLAG_SELECTED);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECTED]);
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
#include "gtklistitemmanagerprivate.h"
|
||||
|
||||
#include "gtklistitemprivate.h"
|
||||
#include "gtklistitemwidgetprivate.h"
|
||||
#include "gtkwidgetprivate.h"
|
||||
|
||||
#define GTK_LIST_VIEW_MAX_LIST_ITEMS 200
|
||||
@ -47,7 +47,7 @@ struct _GtkListItemManagerClass
|
||||
struct _GtkListItemTracker
|
||||
{
|
||||
guint position;
|
||||
GtkListItem *widget;
|
||||
GtkListItemWidget *widget;
|
||||
guint n_before;
|
||||
guint n_after;
|
||||
};
|
||||
@ -595,7 +595,7 @@ gtk_list_item_manager_model_items_changed_cb (GListModel *model,
|
||||
if (tracker->widget == NULL)
|
||||
continue;
|
||||
|
||||
if (g_hash_table_lookup (change, gtk_list_item_get_item (tracker->widget)))
|
||||
if (g_hash_table_lookup (change, gtk_list_item_widget_get_item (tracker->widget)))
|
||||
break;
|
||||
}
|
||||
|
||||
@ -678,7 +678,7 @@ gtk_list_item_manager_model_items_changed_cb (GListModel *model,
|
||||
}
|
||||
else if (tracker->position >= position)
|
||||
{
|
||||
if (g_hash_table_lookup (change, gtk_list_item_get_item (tracker->widget)))
|
||||
if (g_hash_table_lookup (change, gtk_list_item_widget_get_item (tracker->widget)))
|
||||
{
|
||||
/* The item is gone. Guess a good new position */
|
||||
tracker->position = position + (tracker->position - position) * added / removed;
|
||||
@ -696,7 +696,7 @@ gtk_list_item_manager_model_items_changed_cb (GListModel *model,
|
||||
/* item was put in its right place in the expensive loop above,
|
||||
* and we updated its position while at it. So grab it from there.
|
||||
*/
|
||||
tracker->position = gtk_list_item_get_position (tracker->widget);
|
||||
tracker->position = gtk_list_item_widget_get_position (tracker->widget);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -723,7 +723,7 @@ gtk_list_item_manager_model_items_changed_cb (GListModel *model,
|
||||
item = gtk_list_item_manager_get_nth (self, tracker->position, NULL);
|
||||
g_assert (item != NULL);
|
||||
g_assert (item->widget);
|
||||
tracker->widget = GTK_LIST_ITEM (item->widget);
|
||||
tracker->widget = GTK_LIST_ITEM_WIDGET (item->widget);
|
||||
}
|
||||
|
||||
g_hash_table_iter_init (&iter, change);
|
||||
@ -850,7 +850,7 @@ gtk_list_item_manager_set_factory (GtkListItemManager *self,
|
||||
|
||||
item = gtk_list_item_manager_get_nth (self, tracker->position, NULL);
|
||||
g_assert (item);
|
||||
tracker->widget = GTK_LIST_ITEM (item->widget);
|
||||
tracker->widget = GTK_LIST_ITEM_WIDGET (item->widget);
|
||||
}
|
||||
}
|
||||
|
||||
@ -922,23 +922,21 @@ gtk_list_item_manager_acquire_list_item (GtkListItemManager *self,
|
||||
guint position,
|
||||
GtkWidget *prev_sibling)
|
||||
{
|
||||
GtkListItem *result;
|
||||
GtkWidget *result;
|
||||
gpointer item;
|
||||
gboolean selected;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_LIST_ITEM_MANAGER (self), NULL);
|
||||
g_return_val_if_fail (prev_sibling == NULL || GTK_IS_WIDGET (prev_sibling), NULL);
|
||||
|
||||
result = gtk_list_item_new (self->item_css_name);
|
||||
if (self->factory)
|
||||
gtk_list_item_factory_setup (self->factory, result);
|
||||
result = gtk_list_item_widget_new (self->factory,
|
||||
self->item_css_name);
|
||||
|
||||
item = g_list_model_get_item (G_LIST_MODEL (self->model), position);
|
||||
selected = gtk_selection_model_is_selected (self->model, position);
|
||||
if (self->factory)
|
||||
gtk_list_item_factory_bind (self->factory, result, position, item, selected);
|
||||
gtk_list_item_widget_bind (GTK_LIST_ITEM_WIDGET (result), position, item, selected);
|
||||
g_object_unref (item);
|
||||
gtk_widget_insert_after (GTK_WIDGET (result), self->widget, prev_sibling);
|
||||
gtk_widget_insert_after (result, self->widget, prev_sibling);
|
||||
|
||||
return GTK_WIDGET (result);
|
||||
}
|
||||
@ -964,7 +962,7 @@ gtk_list_item_manager_try_reacquire_list_item (GtkListItemManager *self,
|
||||
guint position,
|
||||
GtkWidget *prev_sibling)
|
||||
{
|
||||
GtkListItem *result;
|
||||
GtkWidget *result;
|
||||
gpointer item;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_LIST_ITEM_MANAGER (self), NULL);
|
||||
@ -974,11 +972,10 @@ gtk_list_item_manager_try_reacquire_list_item (GtkListItemManager *self,
|
||||
item = g_list_model_get_item (G_LIST_MODEL (self->model), position);
|
||||
if (g_hash_table_steal_extended (change, item, NULL, (gpointer *) &result))
|
||||
{
|
||||
if (self->factory)
|
||||
gtk_list_item_factory_update (self->factory, result, position, FALSE);
|
||||
gtk_widget_insert_after (GTK_WIDGET (result), self->widget, prev_sibling);
|
||||
gtk_list_item_widget_update (GTK_LIST_ITEM_WIDGET (result), position, FALSE);
|
||||
gtk_widget_insert_after (result, self->widget, prev_sibling);
|
||||
/* XXX: Should we let the listview do this? */
|
||||
gtk_widget_queue_resize (GTK_WIDGET (result));
|
||||
gtk_widget_queue_resize (result);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -986,7 +983,7 @@ gtk_list_item_manager_try_reacquire_list_item (GtkListItemManager *self,
|
||||
}
|
||||
g_object_unref (item);
|
||||
|
||||
return GTK_WIDGET (result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1013,8 +1010,7 @@ gtk_list_item_manager_move_list_item (GtkListItemManager *self,
|
||||
|
||||
item = g_list_model_get_item (G_LIST_MODEL (self->model), position);
|
||||
selected = gtk_selection_model_is_selected (self->model, position);
|
||||
if (self->factory)
|
||||
gtk_list_item_factory_rebind (self->factory, GTK_LIST_ITEM (list_item), position, item, selected);
|
||||
gtk_list_item_widget_rebind (GTK_LIST_ITEM_WIDGET (list_item), position, item, selected);
|
||||
gtk_widget_insert_after (list_item, _gtk_widget_get_parent (list_item), prev_sibling);
|
||||
g_object_unref (item);
|
||||
}
|
||||
@ -1036,11 +1032,10 @@ gtk_list_item_manager_update_list_item (GtkListItemManager *self,
|
||||
gboolean selected;
|
||||
|
||||
g_return_if_fail (GTK_IS_LIST_ITEM_MANAGER (self));
|
||||
g_return_if_fail (GTK_IS_LIST_ITEM (item));
|
||||
g_return_if_fail (GTK_IS_LIST_ITEM_WIDGET (item));
|
||||
|
||||
selected = gtk_selection_model_is_selected (self->model, position);
|
||||
if (self->factory)
|
||||
gtk_list_item_factory_update (self->factory, GTK_LIST_ITEM (item), position, selected);
|
||||
gtk_list_item_widget_update (GTK_LIST_ITEM_WIDGET (item), position, selected);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1060,21 +1055,16 @@ gtk_list_item_manager_release_list_item (GtkListItemManager *self,
|
||||
GtkWidget *item)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_LIST_ITEM_MANAGER (self));
|
||||
g_return_if_fail (GTK_IS_LIST_ITEM (item));
|
||||
g_return_if_fail (GTK_IS_LIST_ITEM_WIDGET (item));
|
||||
|
||||
if (change != NULL)
|
||||
{
|
||||
if (g_hash_table_insert (change, gtk_list_item_get_item (GTK_LIST_ITEM (item)), item))
|
||||
if (g_hash_table_insert (change, gtk_list_item_widget_get_item (GTK_LIST_ITEM_WIDGET (item)), item))
|
||||
return;
|
||||
|
||||
g_warning ("FIXME: Handle the same item multiple times in the list.\nLars says this totally should not happen, but here we are.");
|
||||
}
|
||||
|
||||
if (self->factory)
|
||||
{
|
||||
gtk_list_item_factory_unbind (self->factory, GTK_LIST_ITEM (item));
|
||||
gtk_list_item_factory_teardown (self->factory, GTK_LIST_ITEM (item));
|
||||
}
|
||||
gtk_widget_unparent (item);
|
||||
}
|
||||
|
||||
@ -1136,7 +1126,7 @@ gtk_list_item_tracker_set_position (GtkListItemManager *self,
|
||||
|
||||
item = gtk_list_item_manager_get_nth (self, position, NULL);
|
||||
if (item)
|
||||
tracker->widget = GTK_LIST_ITEM (item->widget);
|
||||
tracker->widget = GTK_LIST_ITEM_WIDGET (item->widget);
|
||||
|
||||
gtk_widget_queue_resize (self->widget);
|
||||
}
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
#include "gtk/gtktypes.h"
|
||||
|
||||
#include "gtk/gtklistitemfactoryprivate.h"
|
||||
#include "gtk/gtklistitemfactory.h"
|
||||
#include "gtk/gtkrbtreeprivate.h"
|
||||
#include "gtk/gtkselectionmodel.h"
|
||||
|
||||
|
@ -22,11 +22,26 @@
|
||||
|
||||
#include "gtklistitem.h"
|
||||
|
||||
#include "gtklistitemmanagerprivate.h"
|
||||
#include "gtklistitemwidgetprivate.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
GtkListItem * gtk_list_item_new (const char *css_name);
|
||||
struct _GtkListItem
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GtkListItemWidget *owner; /* has a reference */
|
||||
|
||||
GObject *item;
|
||||
GtkWidget *child;
|
||||
guint position;
|
||||
|
||||
guint activatable : 1;
|
||||
guint selectable : 1;
|
||||
guint selected : 1;
|
||||
};
|
||||
|
||||
GtkListItem * gtk_list_item_new (GtkListItemWidget *owner);
|
||||
|
||||
void gtk_list_item_set_item (GtkListItem *self,
|
||||
gpointer item);
|
||||
|
426
gtk/gtklistitemwidget.c
Normal file
426
gtk/gtklistitemwidget.c
Normal file
@ -0,0 +1,426 @@
|
||||
/*
|
||||
* Copyright © 2018 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 "gtklistitemwidgetprivate.h"
|
||||
|
||||
#include "gtkbinlayout.h"
|
||||
#include "gtkcssnodeprivate.h"
|
||||
#include "gtkeventcontrollerfocus.h"
|
||||
#include "gtkgestureclick.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtklistitemfactoryprivate.h"
|
||||
#include "gtklistitemprivate.h"
|
||||
#include "gtkmain.h"
|
||||
#include "gtkwidget.h"
|
||||
#include "gtkwidgetprivate.h"
|
||||
|
||||
enum
|
||||
{
|
||||
ACTIVATE_SIGNAL,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GtkListItemWidget, gtk_list_item_widget, GTK_TYPE_WIDGET)
|
||||
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
static void
|
||||
gtk_list_item_widget_activate_signal (GtkListItemWidget *self)
|
||||
{
|
||||
if (!self->item->activatable)
|
||||
return;
|
||||
|
||||
gtk_widget_activate_action (GTK_WIDGET (self),
|
||||
"list.activate-item",
|
||||
"u",
|
||||
self->item->position);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_list_item_widget_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction)
|
||||
{
|
||||
GtkListItemWidget *self = GTK_LIST_ITEM_WIDGET (widget);
|
||||
|
||||
/* The idea of this function is the following:
|
||||
* 1. If any child can take focus, do not ever attempt
|
||||
* to take focus.
|
||||
* 2. Otherwise, if this item is selectable or activatable,
|
||||
* allow focusing this widget.
|
||||
*
|
||||
* This makes sure every item in a list is focusable for
|
||||
* activation and selection handling, but no useless widgets
|
||||
* get focused and moving focus is as fast as possible.
|
||||
*/
|
||||
if (self->item && self->item->child)
|
||||
{
|
||||
if (gtk_widget_get_focus_child (widget))
|
||||
return FALSE;
|
||||
if (gtk_widget_child_focus (self->item->child, direction))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (gtk_widget_is_focus (widget))
|
||||
return FALSE;
|
||||
|
||||
if (!gtk_widget_get_can_focus (widget) ||
|
||||
!self->item->selectable)
|
||||
return FALSE;
|
||||
|
||||
return gtk_widget_grab_focus (widget);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_list_item_widget_grab_focus (GtkWidget *widget)
|
||||
{
|
||||
GtkListItemWidget *self = GTK_LIST_ITEM_WIDGET (widget);
|
||||
|
||||
if (self->item->child && gtk_widget_grab_focus (self->item->child))
|
||||
return TRUE;
|
||||
|
||||
return GTK_WIDGET_CLASS (gtk_list_item_widget_parent_class)->grab_focus (widget);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_item_widget_dispose (GObject *object)
|
||||
{
|
||||
GtkListItemWidget *self = GTK_LIST_ITEM_WIDGET (object);
|
||||
|
||||
if (self->item)
|
||||
{
|
||||
if (self->item->item)
|
||||
gtk_list_item_factory_unbind (self->factory, self->item);
|
||||
gtk_list_item_factory_teardown (self->factory, self->item);
|
||||
self->item->owner = NULL;
|
||||
g_clear_object (&self->item);
|
||||
}
|
||||
g_clear_object (&self->factory);
|
||||
|
||||
G_OBJECT_CLASS (gtk_list_item_widget_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_item_widget_select_action (GtkWidget *widget,
|
||||
const char *action_name,
|
||||
GVariant *parameter)
|
||||
{
|
||||
GtkListItemWidget *self = GTK_LIST_ITEM_WIDGET (widget);
|
||||
gboolean modify, extend;
|
||||
|
||||
if (!self->item->selectable)
|
||||
return;
|
||||
|
||||
g_variant_get (parameter, "(bb)", &modify, &extend);
|
||||
|
||||
gtk_widget_activate_action (GTK_WIDGET (self),
|
||||
"list.select-item",
|
||||
"(ubb)",
|
||||
self->item->position, modify, extend);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_item_widget_class_init (GtkListItemWidgetClass *klass)
|
||||
{
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
klass->activate_signal = gtk_list_item_widget_activate_signal;
|
||||
|
||||
widget_class->focus = gtk_list_item_widget_focus;
|
||||
widget_class->grab_focus = gtk_list_item_widget_grab_focus;
|
||||
|
||||
gobject_class->dispose = gtk_list_item_widget_dispose;
|
||||
|
||||
signals[ACTIVATE_SIGNAL] =
|
||||
g_signal_new (I_("activate-keybinding"),
|
||||
G_OBJECT_CLASS_TYPE (gobject_class),
|
||||
G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
|
||||
G_STRUCT_OFFSET (GtkListItemWidgetClass, activate_signal),
|
||||
NULL, NULL,
|
||||
NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
widget_class->activate_signal = signals[ACTIVATE_SIGNAL];
|
||||
|
||||
/**
|
||||
* GtkListItem|listitem.select:
|
||||
* @modify: %TRUE to toggle the existing selection, %FALSE to select
|
||||
* @extend: %TRUE to extend the selection
|
||||
*
|
||||
* Changes selection if the item is selectable.
|
||||
* If the item is not selectable, nothing happens.
|
||||
*
|
||||
* This function will emit the list.select-item action and the resulting
|
||||
* behavior, in particular the interpretation of @modify and @extend
|
||||
* depends on the view containing this listitem. See for example
|
||||
* GtkListView|list.select-item or GtkGridView|list.select-item.
|
||||
*/
|
||||
gtk_widget_class_install_action (widget_class,
|
||||
"listitem.select",
|
||||
"(bb)",
|
||||
gtk_list_item_widget_select_action);
|
||||
|
||||
gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_Return, 0,
|
||||
"activate-keybinding", 0);
|
||||
gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_ISO_Enter, 0,
|
||||
"activate-keybinding", 0);
|
||||
gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_KP_Enter, 0,
|
||||
"activate-keybinding", 0);
|
||||
|
||||
/* note that some of these may get overwritten by child widgets,
|
||||
* such as GtkTreeExpander */
|
||||
gtk_widget_class_add_binding_action (widget_class, GDK_KEY_space, 0,
|
||||
"listitem.select", "(bb)", TRUE, FALSE);
|
||||
gtk_widget_class_add_binding_action (widget_class, GDK_KEY_space, GDK_CONTROL_MASK,
|
||||
"listitem.select", "(bb)", TRUE, FALSE);
|
||||
gtk_widget_class_add_binding_action (widget_class, GDK_KEY_space, GDK_SHIFT_MASK,
|
||||
"listitem.select", "(bb)", TRUE, FALSE);
|
||||
gtk_widget_class_add_binding_action (widget_class, GDK_KEY_space, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
|
||||
"listitem.select", "(bb)", TRUE, FALSE);
|
||||
gtk_widget_class_add_binding_action (widget_class, GDK_KEY_KP_Space, 0,
|
||||
"listitem.select", "(bb)", TRUE, FALSE);
|
||||
gtk_widget_class_add_binding_action (widget_class, GDK_KEY_KP_Space, GDK_CONTROL_MASK,
|
||||
"listitem.select", "(bb)", TRUE, FALSE);
|
||||
gtk_widget_class_add_binding_action (widget_class, GDK_KEY_KP_Space, GDK_SHIFT_MASK,
|
||||
"listitem.select", "(bb)", TRUE, FALSE);
|
||||
gtk_widget_class_add_binding_action (widget_class, GDK_KEY_KP_Space, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
|
||||
"listitem.select", "(bb)", TRUE, FALSE);
|
||||
|
||||
/* This gets overwritten by gtk_list_item_widget_new() but better safe than sorry */
|
||||
gtk_widget_class_set_css_name (widget_class, I_("row"));
|
||||
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_item_widget_click_gesture_pressed (GtkGestureClick *gesture,
|
||||
int n_press,
|
||||
double x,
|
||||
double y,
|
||||
GtkListItemWidget *self)
|
||||
{
|
||||
GtkWidget *widget = GTK_WIDGET (self);
|
||||
|
||||
if (!self->item->selectable && !self->item->activatable)
|
||||
{
|
||||
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_DENIED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->item->selectable)
|
||||
{
|
||||
GdkModifierType state;
|
||||
GdkEvent *event;
|
||||
gboolean extend, modify;
|
||||
|
||||
event = gtk_gesture_get_last_event (GTK_GESTURE (gesture),
|
||||
gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture)));
|
||||
state = gdk_event_get_modifier_state (event);
|
||||
extend = (state & GDK_SHIFT_MASK) != 0;
|
||||
modify = (state & GDK_CONTROL_MASK) != 0;
|
||||
|
||||
gtk_widget_activate_action (GTK_WIDGET (self),
|
||||
"list.select-item",
|
||||
"(ubb)",
|
||||
self->item->position, modify, extend);
|
||||
}
|
||||
|
||||
if (self->item->activatable)
|
||||
{
|
||||
if (n_press == 2)
|
||||
{
|
||||
gtk_widget_activate_action (GTK_WIDGET (self),
|
||||
"list.activate-item",
|
||||
"u",
|
||||
self->item->position);
|
||||
}
|
||||
}
|
||||
|
||||
gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_ACTIVE, FALSE);
|
||||
|
||||
if (gtk_widget_get_focus_on_click (widget))
|
||||
gtk_widget_grab_focus (widget);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_item_widget_enter_cb (GtkEventControllerFocus *controller,
|
||||
GtkListItemWidget *self)
|
||||
{
|
||||
GtkWidget *widget = GTK_WIDGET (self);
|
||||
|
||||
gtk_widget_activate_action (widget,
|
||||
"list.scroll-to-item",
|
||||
"u",
|
||||
self->item->position);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_item_widget_click_gesture_released (GtkGestureClick *gesture,
|
||||
int n_press,
|
||||
double x,
|
||||
double y,
|
||||
GtkListItemWidget *self)
|
||||
{
|
||||
gtk_widget_unset_state_flags (GTK_WIDGET (self), GTK_STATE_FLAG_ACTIVE);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_item_widget_click_gesture_canceled (GtkGestureClick *gesture,
|
||||
GdkEventSequence *sequence,
|
||||
GtkListItemWidget *self)
|
||||
{
|
||||
gtk_widget_unset_state_flags (GTK_WIDGET (self), GTK_STATE_FLAG_ACTIVE);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_item_widget_init (GtkListItemWidget *self)
|
||||
{
|
||||
GtkEventController *controller;
|
||||
GtkGesture *gesture;
|
||||
|
||||
gtk_widget_set_focusable (GTK_WIDGET (self), TRUE);
|
||||
|
||||
gesture = gtk_gesture_click_new ();
|
||||
gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (gesture),
|
||||
GTK_PHASE_BUBBLE);
|
||||
gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (gesture),
|
||||
FALSE);
|
||||
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture),
|
||||
GDK_BUTTON_PRIMARY);
|
||||
g_signal_connect (gesture, "pressed",
|
||||
G_CALLBACK (gtk_list_item_widget_click_gesture_pressed), self);
|
||||
g_signal_connect (gesture, "released",
|
||||
G_CALLBACK (gtk_list_item_widget_click_gesture_released), self);
|
||||
g_signal_connect (gesture, "cancel",
|
||||
G_CALLBACK (gtk_list_item_widget_click_gesture_canceled), self);
|
||||
gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (gesture));
|
||||
|
||||
controller = gtk_event_controller_focus_new ();
|
||||
g_signal_connect (controller, "enter", G_CALLBACK (gtk_list_item_widget_enter_cb), self);
|
||||
gtk_widget_add_controller (GTK_WIDGET (self), controller);
|
||||
|
||||
self->item = gtk_list_item_new (self);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
gtk_list_item_widget_new (GtkListItemFactory *factory,
|
||||
const char *css_name)
|
||||
{
|
||||
GtkListItemWidget *result;
|
||||
|
||||
g_return_val_if_fail (css_name != NULL, NULL);
|
||||
|
||||
result = g_object_new (GTK_TYPE_LIST_ITEM_WIDGET,
|
||||
"css-name", css_name,
|
||||
NULL);
|
||||
if (factory)
|
||||
{
|
||||
result->factory = g_object_ref (factory);
|
||||
|
||||
gtk_list_item_factory_setup (factory, result->item);
|
||||
}
|
||||
|
||||
return GTK_WIDGET (result);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_list_item_widget_bind (GtkListItemWidget *self,
|
||||
guint position,
|
||||
gpointer item,
|
||||
gboolean selected)
|
||||
{
|
||||
if (self->factory)
|
||||
gtk_list_item_factory_bind (self->factory, self->item, position, item, selected);
|
||||
|
||||
if (selected)
|
||||
gtk_widget_set_state_flags (GTK_WIDGET (self), GTK_STATE_FLAG_SELECTED, FALSE);
|
||||
else
|
||||
gtk_widget_unset_state_flags (GTK_WIDGET (self), GTK_STATE_FLAG_SELECTED);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_list_item_widget_rebind (GtkListItemWidget *self,
|
||||
guint position,
|
||||
gpointer item,
|
||||
gboolean selected)
|
||||
{
|
||||
if (self->factory)
|
||||
gtk_list_item_factory_rebind (self->factory, self->item, position, item, selected);
|
||||
|
||||
if (selected)
|
||||
gtk_widget_set_state_flags (GTK_WIDGET (self), GTK_STATE_FLAG_SELECTED, FALSE);
|
||||
else
|
||||
gtk_widget_unset_state_flags (GTK_WIDGET (self), GTK_STATE_FLAG_SELECTED);
|
||||
|
||||
gtk_css_node_invalidate (gtk_widget_get_css_node (GTK_WIDGET (self)), GTK_CSS_CHANGE_ANIMATIONS);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_list_item_widget_update (GtkListItemWidget *self,
|
||||
guint position,
|
||||
gboolean selected)
|
||||
{
|
||||
if (self->factory)
|
||||
gtk_list_item_factory_update (self->factory, self->item, position, selected);
|
||||
|
||||
if (selected)
|
||||
gtk_widget_set_state_flags (GTK_WIDGET (self), GTK_STATE_FLAG_SELECTED, FALSE);
|
||||
else
|
||||
gtk_widget_unset_state_flags (GTK_WIDGET (self), GTK_STATE_FLAG_SELECTED);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
gtk_list_item_widget_unbind (GtkListItemWidget *self)
|
||||
{
|
||||
if (self->factory)
|
||||
gtk_list_item_factory_unbind (self->factory, self->item);
|
||||
|
||||
gtk_widget_unset_state_flags (GTK_WIDGET (self), GTK_STATE_FLAG_SELECTED);
|
||||
|
||||
gtk_css_node_invalidate (gtk_widget_get_css_node (GTK_WIDGET (self)), GTK_CSS_CHANGE_ANIMATIONS);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_list_item_widget_add_child (GtkListItemWidget *self,
|
||||
GtkWidget *child)
|
||||
{
|
||||
gtk_widget_set_parent (child, GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
void
|
||||
gtk_list_item_widget_remove_child (GtkListItemWidget *self,
|
||||
GtkWidget *child)
|
||||
{
|
||||
gtk_widget_unparent (child);
|
||||
}
|
||||
|
||||
guint
|
||||
gtk_list_item_widget_get_position (GtkListItemWidget *self)
|
||||
{
|
||||
return self->item->position;
|
||||
}
|
||||
|
||||
gpointer
|
||||
gtk_list_item_widget_get_item (GtkListItemWidget *self)
|
||||
{
|
||||
return self->item->item;
|
||||
}
|
||||
|
81
gtk/gtklistitemwidgetprivate.h
Normal file
81
gtk/gtklistitemwidgetprivate.h
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright © 2018 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>
|
||||
*/
|
||||
|
||||
#ifndef __GTK_LIST_ITEM_WIDGET_PRIVATE_H__
|
||||
#define __GTK_LIST_ITEM_WIDGET_PRIVATE_H__
|
||||
|
||||
#include "gtklistitemfactory.h"
|
||||
#include "gtkwidget.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_LIST_ITEM_WIDGET (gtk_list_item_widget_get_type ())
|
||||
#define GTK_LIST_ITEM_WIDGET(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_LIST_ITEM_WIDGET, GtkListItemWidget))
|
||||
#define GTK_LIST_ITEM_WIDGET_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_LIST_ITEM_WIDGET, GtkListItemWidgetClass))
|
||||
#define GTK_IS_LIST_ITEM_WIDGET(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_LIST_ITEM_WIDGET))
|
||||
#define GTK_IS_LIST_ITEM_WIDGET_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_LIST_ITEM_WIDGET))
|
||||
#define GTK_LIST_ITEM_WIDGET_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_LIST_ITEM_WIDGET, GtkListItemWidgetClass))
|
||||
|
||||
typedef struct _GtkListItemWidget GtkListItemWidget;
|
||||
typedef struct _GtkListItemWidgetClass GtkListItemWidgetClass;
|
||||
|
||||
struct _GtkListItemWidget
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
|
||||
GtkListItemFactory *factory;
|
||||
GtkListItem *item;
|
||||
};
|
||||
|
||||
struct _GtkListItemWidgetClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
|
||||
void (* activate_signal) (GtkListItemWidget *self);
|
||||
};
|
||||
|
||||
GType gtk_list_item_widget_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GtkWidget * gtk_list_item_widget_new (GtkListItemFactory *factory,
|
||||
const char *css_name);
|
||||
|
||||
void gtk_list_item_widget_bind (GtkListItemWidget *self,
|
||||
guint position,
|
||||
gpointer item,
|
||||
gboolean selected);
|
||||
void gtk_list_item_widget_rebind (GtkListItemWidget *self,
|
||||
guint position,
|
||||
gpointer item,
|
||||
gboolean selected);
|
||||
void gtk_list_item_widget_update (GtkListItemWidget *self,
|
||||
guint position,
|
||||
gboolean selected);
|
||||
void gtk_list_item_widget_unbind (GtkListItemWidget *self);
|
||||
|
||||
void gtk_list_item_widget_add_child (GtkListItemWidget *self,
|
||||
GtkWidget *child);
|
||||
void gtk_list_item_widget_remove_child (GtkListItemWidget *self,
|
||||
GtkWidget *child);
|
||||
|
||||
guint gtk_list_item_widget_get_position (GtkListItemWidget *self);
|
||||
gpointer gtk_list_item_widget_get_item (GtkListItemWidget *self);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_LIST_ITEM_WIDGET_PRIVATE_H__ */
|
@ -281,6 +281,7 @@ gtk_public_sources = files([
|
||||
'gtklistitem.c',
|
||||
'gtklistitemfactory.c',
|
||||
'gtklistitemmanager.c',
|
||||
'gtklistitemwidget.c',
|
||||
'gtklistlistmodel.c',
|
||||
'gtkliststore.c',
|
||||
'gtklistview.c',
|
||||
|
@ -493,8 +493,6 @@ setup_widget (GtkListItem *list_item,
|
||||
RowData *data;
|
||||
|
||||
data = g_slice_new0 (RowData);
|
||||
g_signal_connect (list_item, "notify::item", G_CALLBACK (row_data_notify_item), data);
|
||||
g_object_set_data_full (G_OBJECT (list_item), "row-data", data, row_data_free);
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
|
||||
gtk_list_item_set_child (list_item, box);
|
||||
@ -516,6 +514,9 @@ setup_widget (GtkListItem *list_item,
|
||||
gtk_label_set_max_width_chars (GTK_LABEL (data->name), 25);
|
||||
gtk_label_set_ellipsize (GTK_LABEL (data->name), PANGO_ELLIPSIZE_END);
|
||||
gtk_box_append (GTK_BOX (box), data->name);
|
||||
|
||||
g_signal_connect (list_item, "notify::item", G_CALLBACK (row_data_notify_item), data);
|
||||
g_object_set_data_full (G_OBJECT (list_item), "row-data", data, row_data_free);
|
||||
}
|
||||
|
||||
static GListModel *
|
||||
|
Loading…
Reference in New Issue
Block a user