mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-30 15:31:34 +00:00
Added gtk_cell_area_activate_cell() and some cell editing management
Now: - The current edit cell and editable widget in use can be fetched with properties and accessors - gtk_cell_area_activate_cell() handles bookkeeping of the currently edited cell, starting the editing of a cell, activating a cell etc - Exported signals are available on GtkCellArea: "editing-started", "editing-canceled", "editing-done", "remove-editable". - Upon receiving GDK_KEY_Escape current editing gets canceled.
This commit is contained in:
parent
017f637a76
commit
cbe1154e51
@ -117,6 +117,20 @@ static void cell_attribute_free (CellAttribute *attribute);
|
||||
static gint cell_attribute_find (CellAttribute *cell_attribute,
|
||||
const gchar *attribute);
|
||||
|
||||
/* Internal signal emissions */
|
||||
static void gtk_cell_area_editing_started (GtkCellArea *area,
|
||||
GtkCellRenderer *renderer,
|
||||
GtkCellEditable *editable);
|
||||
static void gtk_cell_area_editing_canceled (GtkCellArea *area,
|
||||
GtkCellRenderer *renderer);
|
||||
static void gtk_cell_area_editing_done (GtkCellArea *area,
|
||||
GtkCellRenderer *renderer,
|
||||
GtkCellEditable *editable);
|
||||
static void gtk_cell_area_remove_editable (GtkCellArea *area,
|
||||
GtkCellRenderer *renderer,
|
||||
GtkCellEditable *editable);
|
||||
|
||||
|
||||
/* Struct to pass data along while looping over
|
||||
* cell renderers to apply attributes
|
||||
*/
|
||||
@ -144,7 +158,15 @@ struct _GtkCellAreaPrivate
|
||||
* of gtk_cell_area_apply_attributes() */
|
||||
gchar *current_path;
|
||||
|
||||
/* Current cell being edited and editable widget used */
|
||||
GtkCellEditable *edit_widget;
|
||||
GtkCellRenderer *edited_cell;
|
||||
|
||||
/* Signal connections to the editable widget */
|
||||
gulong editing_done_id;
|
||||
gulong remove_widget_id;
|
||||
|
||||
/* Currently focused cell */
|
||||
GtkCellRenderer *focus_cell;
|
||||
guint can_focus : 1;
|
||||
|
||||
@ -157,12 +179,16 @@ enum {
|
||||
PROP_CELL_MARGIN_TOP,
|
||||
PROP_CELL_MARGIN_BOTTOM,
|
||||
PROP_FOCUS_CELL,
|
||||
PROP_EDITED_CELL
|
||||
PROP_EDITED_CELL,
|
||||
PROP_EDIT_WIDGET
|
||||
};
|
||||
|
||||
enum {
|
||||
SIGNAL_FOCUS_LEAVE,
|
||||
SIGNAL_EDITING_STARTED,
|
||||
SIGNAL_EDITING_CANCELED,
|
||||
SIGNAL_EDITING_DONE,
|
||||
SIGNAL_REMOVE_EDITABLE,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
@ -200,6 +226,12 @@ gtk_cell_area_init (GtkCellArea *area)
|
||||
priv->cell_border.bottom = 0;
|
||||
|
||||
priv->focus_cell = NULL;
|
||||
priv->edited_cell = NULL;
|
||||
priv->edit_widget = NULL;
|
||||
priv->can_focus = FALSE;
|
||||
|
||||
priv->editing_done_id = 0;
|
||||
priv->remove_widget_id = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -255,6 +287,38 @@ gtk_cell_area_class_init (GtkCellAreaClass *class)
|
||||
GTK_TYPE_CELL_EDITABLE,
|
||||
G_TYPE_STRING);
|
||||
|
||||
cell_area_signals[SIGNAL_EDITING_CANCELED] =
|
||||
g_signal_new (I_("editing-canceled"),
|
||||
G_OBJECT_CLASS_TYPE (object_class),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
0, /* No class closure here */
|
||||
NULL, NULL,
|
||||
_gtk_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE, 1,
|
||||
GTK_TYPE_CELL_RENDERER);
|
||||
|
||||
cell_area_signals[SIGNAL_EDITING_DONE] =
|
||||
g_signal_new (I_("editing-done"),
|
||||
G_OBJECT_CLASS_TYPE (object_class),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
0, /* No class closure here */
|
||||
NULL, NULL,
|
||||
_gtk_marshal_VOID__OBJECT_OBJECT,
|
||||
G_TYPE_NONE, 2,
|
||||
GTK_TYPE_CELL_RENDERER,
|
||||
GTK_TYPE_CELL_EDITABLE);
|
||||
|
||||
cell_area_signals[SIGNAL_REMOVE_EDITABLE] =
|
||||
g_signal_new (I_("remove-editable"),
|
||||
G_OBJECT_CLASS_TYPE (object_class),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
0, /* No class closure here */
|
||||
NULL, NULL,
|
||||
_gtk_marshal_VOID__OBJECT_OBJECT,
|
||||
G_TYPE_NONE, 2,
|
||||
GTK_TYPE_CELL_RENDERER,
|
||||
GTK_TYPE_CELL_EDITABLE);
|
||||
|
||||
/* Properties */
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_CELL_MARGIN_LEFT,
|
||||
@ -318,6 +382,15 @@ gtk_cell_area_class_init (GtkCellAreaClass *class)
|
||||
GTK_TYPE_CELL_RENDERER,
|
||||
GTK_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_EDIT_WIDGET,
|
||||
g_param_spec_object
|
||||
("edit-widget",
|
||||
P_("Edit Widget"),
|
||||
P_("The widget currently editing the edited cell"),
|
||||
GTK_TYPE_CELL_RENDERER,
|
||||
GTK_PARAM_READWRITE));
|
||||
|
||||
/* Pool for Cell Properties */
|
||||
if (!cell_property_pool)
|
||||
cell_property_pool = g_param_spec_pool_new (FALSE);
|
||||
@ -427,6 +500,7 @@ gtk_cell_area_dispose (GObject *object)
|
||||
/* Remove any ref to a focused/edited cell */
|
||||
gtk_cell_area_set_focus_cell (GTK_CELL_AREA (object), NULL);
|
||||
gtk_cell_area_set_edited_cell (GTK_CELL_AREA (object), NULL);
|
||||
gtk_cell_area_set_edit_widget (GTK_CELL_AREA (object), NULL);
|
||||
|
||||
G_OBJECT_CLASS (gtk_cell_area_parent_class)->dispose (object);
|
||||
}
|
||||
@ -456,6 +530,12 @@ gtk_cell_area_set_property (GObject *object,
|
||||
case PROP_FOCUS_CELL:
|
||||
gtk_cell_area_set_focus_cell (area, (GtkCellRenderer *)g_value_get_object (value));
|
||||
break;
|
||||
case PROP_EDITED_CELL:
|
||||
gtk_cell_area_set_edited_cell (area, (GtkCellRenderer *)g_value_get_object (value));
|
||||
break;
|
||||
case PROP_EDIT_WIDGET:
|
||||
gtk_cell_area_set_edit_widget (area, (GtkCellEditable *)g_value_get_object (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@ -488,6 +568,12 @@ gtk_cell_area_get_property (GObject *object,
|
||||
case PROP_FOCUS_CELL:
|
||||
g_value_set_object (value, priv->focus_cell);
|
||||
break;
|
||||
case PROP_EDITED_CELL:
|
||||
g_value_set_object (value, priv->edited_cell);
|
||||
break;
|
||||
case PROP_EDIT_WIDGET:
|
||||
g_value_set_object (value, priv->edit_widget);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@ -517,61 +603,30 @@ gtk_cell_area_real_event (GtkCellArea *area,
|
||||
key_event->keyval == GDK_KEY_ISO_Enter ||
|
||||
key_event->keyval == GDK_KEY_KP_Enter))
|
||||
{
|
||||
/* Activate or Edit the currently focused cell */
|
||||
GtkCellRendererMode mode;
|
||||
GdkRectangle background_area;
|
||||
GdkRectangle inner_area;
|
||||
GdkRectangle background_area;
|
||||
|
||||
/* Get the allocation of the focused cell.
|
||||
*/
|
||||
gtk_cell_area_get_cell_allocation (area, iter, widget, priv->focus_cell,
|
||||
cell_area, &background_area);
|
||||
|
||||
/* Remove margins from the background area to produce the cell area.
|
||||
*/
|
||||
gtk_cell_area_inner_cell_area (area, &background_area, &inner_area);
|
||||
/* Activate or Edit the currently focused cell */
|
||||
if (gtk_cell_area_activate_cell (area, widget, priv->focus_cell, event,
|
||||
&background_area, flags))
|
||||
return TRUE;
|
||||
}
|
||||
else if (priv->edited_cell &&
|
||||
(key_event->keyval == GDK_KEY_Escape))
|
||||
{
|
||||
/* Cancel editing of the cell renderer */
|
||||
gtk_cell_renderer_stop_editing (priv->edited_cell, TRUE);
|
||||
|
||||
/* XXX Need to do some extra right-to-left casing either here
|
||||
* or inside the above called apis.
|
||||
*/
|
||||
/* Signal that editing has been canceled */
|
||||
gtk_cell_area_editing_canceled (area, priv->edited_cell);
|
||||
|
||||
g_object_get (priv->focus_cell, "mode", &mode, NULL);
|
||||
|
||||
if (mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
|
||||
{
|
||||
if (gtk_cell_renderer_activate (priv->focus_cell,
|
||||
event, widget,
|
||||
priv->current_path,
|
||||
&background_area,
|
||||
&inner_area,
|
||||
flags))
|
||||
return TRUE;
|
||||
}
|
||||
else if (mode == GTK_CELL_RENDERER_MODE_EDITABLE)
|
||||
{
|
||||
GtkCellEditable *editable_widget;
|
||||
|
||||
editable_widget =
|
||||
gtk_cell_renderer_start_editing (priv->focus_cell,
|
||||
event, widget,
|
||||
priv->current_path,
|
||||
&background_area,
|
||||
&inner_area,
|
||||
flags);
|
||||
|
||||
if (editable_widget != NULL)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_CELL_EDITABLE (editable_widget), FALSE);
|
||||
|
||||
gtk_cell_area_set_edited_cell (area, priv->focus_cell);
|
||||
|
||||
/* Signal that editing started so that callers can get
|
||||
* a handle on the editable_widget */
|
||||
gtk_cell_area_editing_started (area, priv->focus_cell, editable_widget);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
/* Remove any references to the editable widget */
|
||||
gtk_cell_area_set_edited_cell (area, NULL);
|
||||
gtk_cell_area_set_edit_widget (area, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1825,6 +1880,71 @@ gtk_cell_area_get_focus_cell (GtkCellArea *area)
|
||||
return priv->focus_cell;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************
|
||||
* API: Cell Activation/Editing *
|
||||
*************************************************************/
|
||||
static void
|
||||
gtk_cell_area_editing_started (GtkCellArea *area,
|
||||
GtkCellRenderer *renderer,
|
||||
GtkCellEditable *editable)
|
||||
{
|
||||
g_signal_emit (area, cell_area_signals[SIGNAL_EDITING_STARTED], 0,
|
||||
renderer, editable, area->priv->current_path);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_cell_area_editing_canceled (GtkCellArea *area,
|
||||
GtkCellRenderer *renderer)
|
||||
{
|
||||
g_signal_emit (area, cell_area_signals[SIGNAL_EDITING_CANCELED], 0, renderer);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_cell_area_editing_done (GtkCellArea *area,
|
||||
GtkCellRenderer *renderer,
|
||||
GtkCellEditable *editable)
|
||||
{
|
||||
g_signal_emit (area, cell_area_signals[SIGNAL_EDITING_DONE], 0, renderer, editable);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_cell_area_remove_editable (GtkCellArea *area,
|
||||
GtkCellRenderer *renderer,
|
||||
GtkCellEditable *editable)
|
||||
{
|
||||
g_signal_emit (area, cell_area_signals[SIGNAL_REMOVE_EDITABLE], 0, renderer, editable);
|
||||
}
|
||||
|
||||
static void
|
||||
cell_area_editing_done_cb (GtkCellEditable *editable,
|
||||
GtkCellArea *area)
|
||||
{
|
||||
GtkCellAreaPrivate *priv = area->priv;
|
||||
|
||||
g_assert (priv->edit_widget == editable);
|
||||
g_assert (priv->edited_cell != NULL);
|
||||
|
||||
gtk_cell_area_editing_done (area, priv->edited_cell, priv->edit_widget);
|
||||
}
|
||||
|
||||
static void
|
||||
cell_area_remove_widget_cb (GtkCellEditable *editable,
|
||||
GtkCellArea *area)
|
||||
{
|
||||
GtkCellAreaPrivate *priv = area->priv;
|
||||
|
||||
g_assert (priv->edit_widget == editable);
|
||||
g_assert (priv->edited_cell != NULL);
|
||||
|
||||
gtk_cell_area_remove_editable (area, priv->edited_cell, priv->edit_widget);
|
||||
|
||||
/* Now that we're done with editing the widget and it can be removed,
|
||||
* remove our references to the widget and disconnect handlers */
|
||||
gtk_cell_area_set_edited_cell (area, NULL);
|
||||
gtk_cell_area_set_edit_widget (area, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_cell_area_set_edited_cell (GtkCellArea *area,
|
||||
GtkCellRenderer *renderer)
|
||||
@ -1862,6 +1982,126 @@ gtk_cell_area_get_edited_cell (GtkCellArea *area)
|
||||
return priv->edited_cell;
|
||||
}
|
||||
|
||||
void
|
||||
gtk_cell_area_set_edit_widget (GtkCellArea *area,
|
||||
GtkCellEditable *editable)
|
||||
{
|
||||
GtkCellAreaPrivate *priv;
|
||||
|
||||
g_return_if_fail (GTK_IS_CELL_AREA (area));
|
||||
g_return_if_fail (editable == NULL || GTK_IS_CELL_EDITABLE (editable));
|
||||
|
||||
priv = area->priv;
|
||||
|
||||
if (priv->edit_widget != editable)
|
||||
{
|
||||
if (priv->edit_widget)
|
||||
{
|
||||
g_signal_handler_disconnect (priv->edit_widget, priv->editing_done_id);
|
||||
g_signal_handler_disconnect (priv->edit_widget, priv->remove_widget_id);
|
||||
|
||||
g_object_unref (priv->edit_widget);
|
||||
}
|
||||
|
||||
priv->edit_widget = editable;
|
||||
|
||||
if (priv->edit_widget)
|
||||
{
|
||||
priv->editing_done_id =
|
||||
g_signal_connect (priv->edit_widget, "editing-done",
|
||||
G_CALLBACK (cell_area_editing_done_cb), area);
|
||||
priv->remove_widget_id =
|
||||
g_signal_connect (priv->edit_widget, "remove-widget",
|
||||
G_CALLBACK (cell_area_remove_widget_cb), area);
|
||||
|
||||
g_object_ref (priv->edit_widget);
|
||||
}
|
||||
|
||||
g_object_notify (G_OBJECT (area), "edit-widget");
|
||||
}
|
||||
}
|
||||
|
||||
GtkCellEditable *
|
||||
gtk_cell_area_get_edit_widget (GtkCellArea *area)
|
||||
{
|
||||
GtkCellAreaPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
|
||||
|
||||
priv = area->priv;
|
||||
|
||||
return priv->edit_widget;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtk_cell_area_activate_cell (GtkCellArea *area,
|
||||
GtkWidget *widget,
|
||||
GtkCellRenderer *renderer,
|
||||
GdkEvent *event,
|
||||
const GdkRectangle *cell_area,
|
||||
GtkCellRendererState flags)
|
||||
{
|
||||
GtkCellRendererMode mode;
|
||||
GdkRectangle inner_area;
|
||||
GtkCellAreaPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
|
||||
g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
|
||||
g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), FALSE);
|
||||
g_return_val_if_fail (event != NULL, FALSE);
|
||||
g_return_val_if_fail (cell_area != NULL, FALSE);
|
||||
|
||||
priv = area->priv;
|
||||
|
||||
/* Remove margins from the background area to produce the cell area.
|
||||
*
|
||||
* XXX Maybe have to do some rtl mode treatment here...
|
||||
*/
|
||||
gtk_cell_area_inner_cell_area (area, cell_area, &inner_area);
|
||||
|
||||
g_object_get (renderer, "mode", &mode, NULL);
|
||||
|
||||
if (mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
|
||||
{
|
||||
if (gtk_cell_renderer_activate (renderer,
|
||||
event, widget,
|
||||
priv->current_path,
|
||||
cell_area,
|
||||
&inner_area,
|
||||
flags))
|
||||
return TRUE;
|
||||
}
|
||||
else if (mode == GTK_CELL_RENDERER_MODE_EDITABLE)
|
||||
{
|
||||
GtkCellEditable *editable_widget;
|
||||
|
||||
editable_widget =
|
||||
gtk_cell_renderer_start_editing (renderer,
|
||||
event, widget,
|
||||
priv->current_path,
|
||||
cell_area,
|
||||
&inner_area,
|
||||
flags);
|
||||
|
||||
if (editable_widget != NULL)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_CELL_EDITABLE (editable_widget), FALSE);
|
||||
|
||||
gtk_cell_area_set_edited_cell (area, renderer);
|
||||
gtk_cell_area_set_edit_widget (area, editable_widget);
|
||||
|
||||
/* Signal that editing started so that callers can get
|
||||
* a handle on the editable_widget */
|
||||
gtk_cell_area_editing_started (area, priv->focus_cell, editable_widget);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************
|
||||
* API: Margins *
|
||||
*************************************************************/
|
||||
@ -1969,25 +2209,9 @@ gtk_cell_area_set_cell_margin_bottom (GtkCellArea *area,
|
||||
}
|
||||
}
|
||||
|
||||
/* For convenience in area implementations */
|
||||
void
|
||||
gtk_cell_area_editing_started (GtkCellArea *area,
|
||||
GtkCellRenderer *renderer,
|
||||
GtkCellEditable *editable)
|
||||
{
|
||||
GtkCellAreaPrivate *priv;
|
||||
|
||||
g_return_if_fail (GTK_IS_CELL_AREA (area));
|
||||
|
||||
priv = area->priv;
|
||||
|
||||
g_signal_emit (area, cell_area_signals[SIGNAL_EDITING_STARTED], 0,
|
||||
renderer, editable, priv->current_path);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_cell_area_inner_cell_area (GtkCellArea *area,
|
||||
GdkRectangle *background_area,
|
||||
const GdkRectangle *background_area,
|
||||
GdkRectangle *cell_area)
|
||||
{
|
||||
GtkCellAreaPrivate *priv;
|
||||
|
@ -277,11 +277,21 @@ gboolean gtk_cell_area_get_can_focus (GtkCellArea
|
||||
void gtk_cell_area_set_focus_cell (GtkCellArea *area,
|
||||
GtkCellRenderer *renderer);
|
||||
GtkCellRenderer *gtk_cell_area_get_focus_cell (GtkCellArea *area);
|
||||
void gtk_cell_area_set_edited_cell (GtkCellArea *area,
|
||||
GtkCellRenderer *renderer);
|
||||
GtkCellRenderer *gtk_cell_area_get_edited_cell (GtkCellArea *area);
|
||||
|
||||
|
||||
/* Cell Activation/Editing */
|
||||
void gtk_cell_area_set_edited_cell (GtkCellArea *area,
|
||||
GtkCellRenderer *renderer);
|
||||
GtkCellRenderer *gtk_cell_area_get_edited_cell (GtkCellArea *area);
|
||||
void gtk_cell_area_set_edit_widget (GtkCellArea *area,
|
||||
GtkCellEditable *editable);
|
||||
GtkCellEditable *gtk_cell_area_get_edit_widget (GtkCellArea *area);
|
||||
gboolean gtk_cell_area_activate_cell (GtkCellArea *area,
|
||||
GtkWidget *widget,
|
||||
GtkCellRenderer *renderer,
|
||||
GdkEvent *event,
|
||||
const GdkRectangle *cell_area,
|
||||
GtkCellRendererState flags);
|
||||
|
||||
/* Margins */
|
||||
gint gtk_cell_area_get_cell_margin_left (GtkCellArea *area);
|
||||
@ -299,14 +309,9 @@ void gtk_cell_area_set_cell_margin_bottom (GtkCellArea
|
||||
|
||||
/* Functions for area implementations */
|
||||
|
||||
/* Signal that editing started on the area (fires the "editing-started" signal) */
|
||||
void gtk_cell_area_editing_started (GtkCellArea *area,
|
||||
GtkCellRenderer *renderer,
|
||||
GtkCellEditable *editable);
|
||||
|
||||
/* Distinguish the inner cell area from the whole requested area including margins */
|
||||
void gtk_cell_area_inner_cell_area (GtkCellArea *area,
|
||||
GdkRectangle *cell_area,
|
||||
const GdkRectangle *cell_area,
|
||||
GdkRectangle *inner_cell_area);
|
||||
|
||||
/* Request the size of a cell while respecting the cell margins (requests are margin inclusive) */
|
||||
|
Loading…
Reference in New Issue
Block a user