diff options
author | Robert Ancell <robert.ancell@canonical.com> | 2018-11-19 11:30:41 +1300 |
---|---|---|
committer | Georges Basile Stavracas Neto <georges.stavracas@gmail.com> | 2019-02-04 13:56:41 +0000 |
commit | 18007a17c156fd15adda2fe44c7c6edd9d1bb380 (patch) | |
tree | 6e6a5714ff211e640cfec26154348a78b729a1c5 /panels/region | |
parent | 4d5626d066e8794351a879bc63f3b0a819b363f6 (diff) | |
download | gnome-control-center-18007a17c156fd15adda2fe44c7c6edd9d1bb380.tar.gz |
region: Make rows reorderable with drag and drop
Drop toolbar - all functionality is now in rows.
This matches the new designs in
https://gitlab.gnome.org/Teams/Design/settings-mockups/blob/master/region-and-language/region-and-language.png
Diffstat (limited to 'panels/region')
-rw-r--r-- | panels/region/cc-input-row.c | 105 | ||||
-rw-r--r-- | panels/region/cc-input-row.h | 3 | ||||
-rw-r--r-- | panels/region/cc-input-row.ui | 92 | ||||
-rw-r--r-- | panels/region/cc-region-panel.c | 128 | ||||
-rw-r--r-- | panels/region/cc-region-panel.ui | 76 |
5 files changed, 196 insertions, 208 deletions
diff --git a/panels/region/cc-input-row.c b/panels/region/cc-input-row.c index 66d4f01ee..eadc20443 100644 --- a/panels/region/cc-input-row.c +++ b/panels/region/cc-input-row.c @@ -25,9 +25,12 @@ struct _CcInputRow CcInputSource *source; + GtkEventBox *drag_handle; GtkLabel *name_label; GtkButton *remove_button; GtkButton *settings_button; + + GtkListBox *drag_widget; }; G_DEFINE_TYPE (CcInputRow, cc_input_row, GTK_TYPE_LIST_BOX_ROW) @@ -36,6 +39,7 @@ enum { SIGNAL_SHOW_SETTINGS, SIGNAL_SHOW_LAYOUT, + SIGNAL_MOVE_ROW, SIGNAL_REMOVE_ROW, SIGNAL_LAST }; @@ -43,6 +47,72 @@ enum static guint signals[SIGNAL_LAST] = { 0, }; static void +drag_begin_cb (CcInputRow *self, + GdkDragContext *drag_context) +{ + GtkAllocation alloc; + gint x = 0, y = 0; + + gtk_widget_get_allocation (GTK_WIDGET (self), &alloc); + + gdk_window_get_device_position (gtk_widget_get_window (GTK_WIDGET (self)), + gdk_drag_context_get_device (drag_context), + &x, &y, NULL); + + self->drag_widget = GTK_LIST_BOX (gtk_list_box_new ()); + gtk_widget_show (GTK_WIDGET (self->drag_widget)); + gtk_widget_set_size_request (GTK_WIDGET (self->drag_widget), alloc.width, alloc.height); + CcInputRow *drag_row = cc_input_row_new (self->source); + gtk_widget_show (GTK_WIDGET (drag_row)); + gtk_container_add (GTK_CONTAINER (self->drag_widget), GTK_WIDGET (drag_row)); + gtk_list_box_drag_highlight_row (self->drag_widget, GTK_LIST_BOX_ROW (drag_row)); + + gtk_drag_set_icon_widget (drag_context, GTK_WIDGET (self->drag_widget), x - alloc.x, y - alloc.y); +} + +static void +drag_end_cb (CcInputRow *self) +{ + g_clear_pointer ((GtkWidget **) &self->drag_widget, gtk_widget_destroy); +} + +static void +drag_data_get_cb (CcInputRow *self, + GdkDragContext *context, + GtkSelectionData *selection_data, + guint info, + guint time_) +{ + gtk_selection_data_set (selection_data, + gdk_atom_intern_static_string ("GTK_LIST_BOX_ROW"), + 32, + (const guchar *)&self, + sizeof (gpointer)); +} + +static void +drag_data_received_cb (CcInputRow *self, + GdkDragContext *context, + gint x, + gint y, + GtkSelectionData *selection_data, + guint info, + guint time_) +{ + CcInputRow *source; + + source = *((CcInputRow **) gtk_selection_data_get_data (selection_data)); + + if (source == self) + return; + + g_signal_emit (source, + signals[SIGNAL_MOVE_ROW], + 0, + self); +} + +static void settings_button_clicked_cb (CcInputRow *self) { g_signal_emit (self, @@ -86,10 +156,15 @@ cc_input_row_class_init (CcInputRowClass *klass) gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/region/cc-input-row.ui"); - gtk_widget_class_bind_template_child (widget_class, CcInputRow, remove_button); + gtk_widget_class_bind_template_child (widget_class, CcInputRow, drag_handle); gtk_widget_class_bind_template_child (widget_class, CcInputRow, name_label); + gtk_widget_class_bind_template_child (widget_class, CcInputRow, remove_button); gtk_widget_class_bind_template_child (widget_class, CcInputRow, settings_button); + gtk_widget_class_bind_template_callback (widget_class, drag_data_get_cb); + gtk_widget_class_bind_template_callback (widget_class, drag_begin_cb); + gtk_widget_class_bind_template_callback (widget_class, drag_end_cb); + gtk_widget_class_bind_template_callback (widget_class, drag_data_received_cb); gtk_widget_class_bind_template_callback (widget_class, layout_button_clicked_cb); gtk_widget_class_bind_template_callback (widget_class, settings_button_clicked_cb); gtk_widget_class_bind_template_callback (widget_class, remove_button_clicked_cb); @@ -114,6 +189,16 @@ cc_input_row_class_init (CcInputRowClass *klass) G_TYPE_NONE, 0); + signals[SIGNAL_MOVE_ROW] = + g_signal_new ("move-row", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + NULL, + G_TYPE_NONE, + 1, CC_TYPE_INPUT_ROW); + signals[SIGNAL_REMOVE_ROW] = g_signal_new ("remove-row", G_TYPE_FROM_CLASS (object_class), @@ -125,10 +210,18 @@ cc_input_row_class_init (CcInputRowClass *klass) 0); } +static GtkTargetEntry entries[] = +{ + { "GTK_LIST_BOX_ROW", GTK_TARGET_SAME_APP, 0 } +}; + void cc_input_row_init (CcInputRow *self) { gtk_widget_init_template (GTK_WIDGET (self)); + + gtk_drag_source_set (GTK_WIDGET (self->drag_handle), GDK_BUTTON1_MASK, entries, 1, GDK_ACTION_MOVE); + gtk_drag_dest_set (GTK_WIDGET (self), GTK_DEST_DEFAULT_ALL, entries, 1, GDK_ACTION_MOVE); } static void @@ -168,3 +261,13 @@ cc_input_row_set_removable (CcInputRow *self, g_return_if_fail (CC_IS_INPUT_ROW (self)); gtk_widget_set_sensitive (GTK_WIDGET (self->remove_button), removable); } + +void +cc_input_row_set_draggable (CcInputRow *self, + gboolean draggable) +{ + if (draggable) + gtk_drag_source_set (GTK_WIDGET (self->drag_handle), GDK_BUTTON1_MASK, entries, 1, GDK_ACTION_MOVE); + else + gtk_drag_source_unset (GTK_WIDGET (self->drag_handle)); +} diff --git a/panels/region/cc-input-row.h b/panels/region/cc-input-row.h index 1200b09ea..5d78337e6 100644 --- a/panels/region/cc-input-row.h +++ b/panels/region/cc-input-row.h @@ -34,4 +34,7 @@ CcInputSource *cc_input_row_get_source (CcInputRow *row); void cc_input_row_set_removable (CcInputRow *row, gboolean removable); +void cc_input_row_set_draggable (CcInputRow *row, + gboolean draggable); + G_END_DECLS diff --git a/panels/region/cc-input-row.ui b/panels/region/cc-input-row.ui index 1f7c893f7..cbc99f922 100644 --- a/panels/region/cc-input-row.ui +++ b/panels/region/cc-input-row.ui @@ -4,59 +4,75 @@ <template class="CcInputRow" parent="GtkListBoxRow"> <property name="visible">True</property> <property name="can-focus">False</property> + <property name="selectable">False</property> + <signal name="drag_data_received" handler="drag_data_received_cb" object="CcInputRow" swapped="yes"/> <child> - <object class="GtkBox"> + <object class="GtkEventBox" id="drag_handle"> <property name="visible">True</property> - <property name="border-width">12</property> - <property name="spacing">12</property> + <signal name="drag_data_get" handler="drag_data_get_cb" object="CcInputRow" swapped="yes"/> + <signal name="drag_begin" handler="drag_begin_cb" object="CcInputRow" swapped="yes"/> + <signal name="drag_end" handler="drag_end_cb" object="CcInputRow" swapped="yes"/> <child> - <object class="GtkLabel" id="name_label"> + <object class="GtkBox"> <property name="visible">True</property> - <property name="xalign">0.0</property> - <property name="hexpand">True</property> - </object> - </child> - <child> - <object class="GtkButton" id="settings_button"> - <property name="visible">False</property> - <signal name="clicked" handler="settings_button_clicked_cb" object="CcInputRow" swapped="yes"/> - <style> - <class name="image-button"/> - </style> + <property name="border-width">12</property> + <property name="spacing">12</property> <child> <object class="GtkImage"> <property name="visible">True</property> - <property name="icon_name">emblem-system-symbolic</property> + <property name="icon_name">open-menu-symbolic</property> </object> </child> - </object> - </child> - <child> - <object class="GtkButton" id="remove_button"> - <property name="visible">True</property> - <signal name="clicked" handler="layout_button_clicked_cb" object="CcInputRow" swapped="yes"/> - <style> - <class name="image-button"/> - </style> <child> - <object class="GtkImage"> + <object class="GtkLabel" id="name_label"> <property name="visible">True</property> - <property name="icon_name">view-layout-symbolic</property> + <property name="xalign">0.0</property> + <property name="hexpand">True</property> </object> </child> - </object> - </child> - <child> - <object class="GtkButton"> - <property name="visible">True</property> - <signal name="clicked" handler="remove_button_clicked_cb" object="CcInputRow" swapped="yes"/> - <style> - <class name="image-button"/> - </style> <child> - <object class="GtkImage"> + <object class="GtkButton" id="settings_button"> + <property name="visible">False</property> + <signal name="clicked" handler="settings_button_clicked_cb" object="CcInputRow" swapped="yes"/> + <style> + <class name="image-button"/> + </style> + <child> + <object class="GtkImage"> + <property name="visible">True</property> + <property name="icon_name">emblem-system-symbolic</property> + </object> + </child> + </object> + </child> + <child> + <object class="GtkButton"> + <property name="visible">True</property> + <signal name="clicked" handler="layout_button_clicked_cb" object="CcInputRow" swapped="yes"/> + <style> + <class name="image-button"/> + </style> + <child> + <object class="GtkImage"> + <property name="visible">True</property> + <property name="icon_name">view-layout-symbolic</property> + </object> + </child> + </object> + </child> + <child> + <object class="GtkButton" id="remove_button"> <property name="visible">True</property> - <property name="icon_name">edit-delete-symbolic</property> + <signal name="clicked" handler="remove_button_clicked_cb" object="CcInputRow" swapped="yes"/> + <style> + <class name="image-button"/> + </style> + <child> + <object class="GtkImage"> + <property name="visible">True</property> + <property name="icon_name">edit-delete-symbolic</property> + </object> + </child> </object> </child> </object> diff --git a/panels/region/cc-region-panel.c b/panels/region/cc-region-panel.c index e4d6f1833..5310339be 100644 --- a/panels/region/cc-region-panel.c +++ b/panels/region/cc-region-panel.c @@ -72,8 +72,6 @@ struct _CcRegionPanel { GtkListBox *language_list; GtkListBoxRow *language_row; GtkFrame *language_section_frame; - GtkButton *move_down_input_button; - GtkButton *move_up_input_button; GtkLabel *next_source; GtkLabel *next_source_label; GtkListBoxRow *no_inputs_row; @@ -114,24 +112,26 @@ CC_PANEL_REGISTER (CcRegionPanel, cc_region_panel) typedef struct { CcRegionPanel *panel; - CcInputRow *row; - gint offset; + CcInputRow *source; + CcInputRow *dest; } RowData; static RowData * -row_data_new (CcRegionPanel *panel, CcInputRow *row, gint offset) +row_data_new (CcRegionPanel *panel, CcInputRow *source, CcInputRow *dest) { RowData *data = g_malloc0 (sizeof (RowData)); data->panel = panel; - data->row = g_object_ref (row); - data->offset = offset; + data->source = g_object_ref (source); + if (dest != NULL) + data->dest = g_object_ref (dest); return data; } static void row_data_free (RowData *data) { - g_object_unref (data->row); + g_clear_object (&data->source); + g_clear_object (&data->dest); g_free (data); } @@ -764,6 +764,16 @@ row_layout_cb (CcRegionPanel *self, g_spawn_command_line_async (commandline, NULL); } +static void move_input (CcRegionPanel *self, CcInputRow *source, CcInputRow *dest); + +static void +row_moved_cb (CcRegionPanel *self, + CcInputRow *dest_row, + CcInputRow *row) +{ + move_input (self, row, dest_row); +} + static void remove_input (CcRegionPanel *self, CcInputRow *row); static void @@ -792,6 +802,7 @@ update_input_rows (CcRegionPanel *self) row = CC_INPUT_ROW (l->data); cc_input_row_set_removable (row, n_input_rows > 1); + cc_input_row_set_draggable (row, n_input_rows > 1); } } @@ -807,6 +818,7 @@ add_input_row (CcRegionPanel *self, CcInputSource *source) gtk_size_group_add_widget (self->input_size_group, GTK_WIDGET (row)); g_signal_connect_object (row, "show-settings", G_CALLBACK (row_settings_cb), self, G_CONNECT_SWAPPED); g_signal_connect_object (row, "show-layout", G_CALLBACK (row_layout_cb), self, G_CONNECT_SWAPPED); + g_signal_connect_object (row, "move-row", G_CALLBACK (row_moved_cb), self, G_CONNECT_SWAPPED); g_signal_connect_object (row, "remove-row", G_CALLBACK (row_removed_cb), self, G_CONNECT_SWAPPED); gtk_list_box_insert (GTK_LIST_BOX (self->input_list), GTK_WIDGET (row), gtk_list_box_row_get_index (self->add_input_row)); update_input_rows (self); @@ -914,33 +926,6 @@ input_sources_changed (CcRegionPanel *self, } static void -update_buttons (CcRegionPanel *self) -{ - CcInputRow *selected; - g_autoptr(GList) children = NULL; - guint n_rows; - - children = gtk_container_get_children (GTK_CONTAINER (self->input_list)); - n_rows = g_list_length (children); - - selected = CC_INPUT_ROW (gtk_list_box_get_selected_row (self->input_list)); - if (selected == NULL) { - gtk_widget_set_sensitive (GTK_WIDGET (self->move_up_input_button), FALSE); - gtk_widget_set_sensitive (GTK_WIDGET (self->move_down_input_button), FALSE); - } else { - gint index; - - index = gtk_list_box_row_get_index (GTK_LIST_BOX_ROW (selected)); - - gtk_widget_set_sensitive (GTK_WIDGET (self->move_up_input_button), index > 1); - gtk_widget_set_sensitive (GTK_WIDGET (self->move_down_input_button), index < n_rows - 1); - } - - gtk_widget_set_visible (GTK_WIDGET (self->options_button), - n_rows > 1 && !self->login); -} - -static void set_input_settings (CcRegionPanel *self) { GVariantBuilder builder; @@ -1006,7 +991,6 @@ show_input_chooser (CcRegionPanel *self) source = cc_input_chooser_get_source (chooser); if (source != NULL && get_row_by_source (self, source) == NULL) { add_input_row (self, source); - update_buttons (self); update_input (self); } } @@ -1072,7 +1056,6 @@ do_remove_input (CcRegionPanel *self, CcInputRow *row) cc_list_box_adjust_scrolling (self->input_list); - update_buttons (self); update_input (self); update_input_rows (self); } @@ -1082,7 +1065,7 @@ remove_input_permission_cb (GObject *source, GAsyncResult *res, gpointer user_da { RowData *data = user_data; if (permission_acquired (G_PERMISSION (source), res, "remove input")) - do_remove_input (data->panel, data->row); + do_remove_input (data->panel, data->source); } static void @@ -1096,31 +1079,24 @@ remove_input (CcRegionPanel *self, CcInputRow *row) g_permission_acquire_async (self->permission, self->cancellable, remove_input_permission_cb, - row_data_new (self, row, -1)); + row_data_new (self, row, NULL)); } } static void -do_move_input (CcRegionPanel *self, - CcInputRow *row, - gint offset) +do_move_input (CcRegionPanel *self, CcInputRow *source, CcInputRow *dest) { - gint idx; + gint dest_index; - idx = gtk_list_box_row_get_index (GTK_LIST_BOX_ROW (row)) + offset; + dest_index = gtk_list_box_row_get_index (GTK_LIST_BOX_ROW (dest)); - gtk_list_box_unselect_row (self->input_list, GTK_LIST_BOX_ROW (row)); - - g_object_ref (row); - gtk_container_remove (GTK_CONTAINER (self->input_list), GTK_WIDGET (row)); - gtk_list_box_insert (self->input_list, GTK_WIDGET (row), idx); - g_object_unref (row); - - gtk_list_box_select_row (self->input_list, GTK_LIST_BOX_ROW (row)); + g_object_ref (source); + gtk_container_remove (GTK_CONTAINER (self->input_list), GTK_WIDGET (source)); + gtk_list_box_insert (self->input_list, GTK_WIDGET (source), dest_index); + g_object_unref (source); cc_list_box_adjust_scrolling (self->input_list); - update_buttons (self); update_input (self); } @@ -1129,23 +1105,23 @@ move_input_permission_cb (GObject *source, GAsyncResult *res, gpointer user_data { RowData *data = user_data; if (permission_acquired (G_PERMISSION (source), res, "move input")) - do_move_input (data->panel, data->row, data->offset); + do_move_input (data->panel, data->source, data->dest); } static void move_input (CcRegionPanel *self, - CcInputRow *row, - gint offset) + CcInputRow *source, + CcInputRow *dest) { if (!self->login) { - do_move_input (self, row, offset); + do_move_input (self, source, dest); } else if (g_permission_get_allowed (self->permission)) { - do_move_input (self, row, offset); + do_move_input (self, source, dest); } else if (g_permission_get_can_acquire (self->permission)) { g_permission_acquire_async (self->permission, self->cancellable, move_input_permission_cb, - row_data_new (self, row, offset)); + row_data_new (self, source, dest)); } } @@ -1158,30 +1134,6 @@ input_row_activated_cb (CcRegionPanel *self, GtkListBoxRow *row) } static void -move_selected_input_up (CcRegionPanel *self) -{ - GtkListBoxRow *selected; - - selected = gtk_list_box_get_selected_row (GTK_LIST_BOX (self->input_list)); - if (selected == NULL) - return; - - move_input (self, CC_INPUT_ROW (selected), -1); -} - -static void -move_selected_input_down (CcRegionPanel *self) -{ - GtkListBoxRow *selected; - - selected = gtk_list_box_get_selected_row (GTK_LIST_BOX (self->input_list)); - if (selected == NULL) - return; - - move_input (self, CC_INPUT_ROW (selected), 1); -} - -static void update_shortcut_label (GtkLabel *label, const gchar *value) { @@ -1274,19 +1226,14 @@ setup_input_section (CcRegionPanel *self) cc_list_box_setup_scrolling (self->input_list, 5); - gtk_list_box_set_selection_mode (self->input_list, - GTK_SELECTION_SINGLE); gtk_list_box_set_header_func (self->input_list, cc_list_box_update_header_func, NULL, NULL); - g_signal_connect_object (self->input_list, "row-selected", - G_CALLBACK (update_buttons), self, G_CONNECT_SWAPPED); g_signal_connect_object (self->input_settings, "changed::" KEY_INPUT_SOURCES, G_CALLBACK (input_sources_changed), self, G_CONNECT_SWAPPED); add_input_sources_from_settings (self); - update_buttons (self); g_object_bind_property (self->previous_source, "visible", self->previous_source_label, "visible", @@ -1514,7 +1461,6 @@ login_changed (CcRegionPanel *self) add_input_sources_from_settings (self); update_language_label (self); - update_buttons (self); } static void @@ -1623,8 +1569,6 @@ cc_region_panel_class_init (CcRegionPanelClass * klass) gtk_widget_class_bind_template_child (widget_class, CcRegionPanel, language_list); gtk_widget_class_bind_template_child (widget_class, CcRegionPanel, language_row); gtk_widget_class_bind_template_child (widget_class, CcRegionPanel, language_section_frame); - gtk_widget_class_bind_template_child (widget_class, CcRegionPanel, move_down_input_button); - gtk_widget_class_bind_template_child (widget_class, CcRegionPanel, move_up_input_button); gtk_widget_class_bind_template_child (widget_class, CcRegionPanel, next_source); gtk_widget_class_bind_template_child (widget_class, CcRegionPanel, next_source_label); gtk_widget_class_bind_template_child (widget_class, CcRegionPanel, no_inputs_row); @@ -1638,8 +1582,6 @@ cc_region_panel_class_init (CcRegionPanelClass * klass) gtk_widget_class_bind_template_callback (widget_class, input_row_activated_cb); gtk_widget_class_bind_template_callback (widget_class, restart_now); - gtk_widget_class_bind_template_callback (widget_class, move_selected_input_up); - gtk_widget_class_bind_template_callback (widget_class, move_selected_input_down); } static void diff --git a/panels/region/cc-region-panel.ui b/panels/region/cc-region-panel.ui index 242793e1f..728ee8f16 100644 --- a/panels/region/cc-region-panel.ui +++ b/panels/region/cc-region-panel.ui @@ -293,82 +293,6 @@ </child> </object> </child> - <child> - <object class="GtkToolbar"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="toolbar_style">icons</property> - <property name="show_arrow">False</property> - <property name="icon_size">1</property> - <style> - <class name="inline-toolbar"/> - </style> - <child> - <object class="GtkSeparatorToolItem"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="draw">False</property> - </object> - <packing> - <property name="expand">True</property> - </packing> - </child> - <child> - <object class="GtkToolItem"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <child> - <object class="GtkBox"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <child> - <object class="GtkButton" id="move_up_input_button"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <signal name="clicked" handler="move_selected_input_up" object="CcRegionPanel" swapped="yes"/> - <child internal-child="accessible"> - <object class="AtkObject"> - <property name="accessible-name" translatable="yes">Move input source up</property> - </object> - </child> - <child> - <object class="GtkImage"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="icon_name">go-up-symbolic</property> - <property name="icon-size">1</property> - </object> - </child> - </object> - </child> - <child> - <object class="GtkButton" id="move_down_input_button"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <signal name="clicked" handler="move_selected_input_down" object="CcRegionPanel" swapped="yes"/> - <child internal-child="accessible"> - <object class="AtkObject"> - <property name="accessible-name" translatable="yes">Move input source down</property> - </object> - </child> - <child> - <object class="GtkImage"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="icon_name">go-down-symbolic</property> - <property name="icon-size">1</property> - </object> - </child> - </object> - </child> - </object> - </child> - </object> - </child> - </object> - </child> </object> </child> <child> |