[gnome-builder/wip/chergert/perspective] prefs: reflow preference groups
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/chergert/perspective] prefs: reflow preference groups
- Date: Sat, 5 Dec 2015 03:16:40 +0000 (UTC)
commit 7b869ca2aa18f676118fc7f8ab66a8057acf64dc
Author: Christian Hergert <chergert redhat com>
Date: Fri Dec 4 19:16:24 2015 -0800
prefs: reflow preference groups
This follows the updated design a bit closer, allowing for more efficient
use of larger screens (the typical case).
data/ui/ide-preferences-group.ui | 1 +
data/ui/ide-preferences-page.ui | 14 +-
libide/Makefile.am | 2 +
libide/preferences/ide-preferences-builtin.c | 14 +-
libide/preferences/ide-preferences-flow-box.c | 331 ++++++++++++++++++++
libide/preferences/ide-preferences-flow-box.h | 32 ++
libide/preferences/ide-preferences-group-private.h | 15 +
libide/preferences/ide-preferences-group.c | 27 +-
libide/preferences/ide-preferences-group.h | 5 +-
libide/preferences/ide-preferences-page.c | 14 +-
10 files changed, 410 insertions(+), 45 deletions(-)
---
diff --git a/data/ui/ide-preferences-group.ui b/data/ui/ide-preferences-group.ui
index 3a78994..04aac85 100644
--- a/data/ui/ide-preferences-group.ui
+++ b/data/ui/ide-preferences-group.ui
@@ -3,6 +3,7 @@
<!-- interface-requires gtk+ 3.18 -->
<template class="IdePreferencesGroup" parent="GtkBin">
<property name="vexpand">false</property>
+ <property name="halign">fill</property>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
diff --git a/data/ui/ide-preferences-page.ui b/data/ui/ide-preferences-page.ui
index 61f02bb..89a5e20 100644
--- a/data/ui/ide-preferences-page.ui
+++ b/data/ui/ide-preferences-page.ui
@@ -4,21 +4,11 @@
<template class="IdePreferencesPage" parent="GtkBin">
<child>
<object class="GtkScrolledWindow">
+ <property name="hscrollbar-policy">never</property>
<property name="visible">true</property>
<child>
- <object class="EggCenteringBin">
- <property name="max-width-request">550</property>
+ <object class="IdePreferencesFlowBox" id="box">
<property name="visible">true</property>
- <child>
- <object class="GtkBox" id="box">
- <property name="halign">center</property>
- <property name="margin">24</property>
- <property name="orientation">vertical</property>
- <property name="spacing">24</property>
- <property name="visible">true</property>
- <property name="width-request">550</property>
- </object>
- </child>
</object>
</child>
</object>
diff --git a/libide/Makefile.am b/libide/Makefile.am
index 3333fcd..65bcfef 100644
--- a/libide/Makefile.am
+++ b/libide/Makefile.am
@@ -335,6 +335,8 @@ libide_1_0_la_SOURCES = \
preferences/ide-preferences-bin-private.h \
preferences/ide-preferences-entry.c \
preferences/ide-preferences-entry.h \
+ preferences/ide-preferences-flow-box.c \
+ preferences/ide-preferences-flow-box.h \
preferences/ide-preferences-font-button.c \
preferences/ide-preferences-font-button.h \
preferences/ide-preferences-group.c \
diff --git a/libide/preferences/ide-preferences-builtin.c b/libide/preferences/ide-preferences-builtin.c
index 1cb9348..4d5e5aa 100644
--- a/libide/preferences/ide-preferences-builtin.c
+++ b/libide/preferences/ide-preferences-builtin.c
@@ -69,13 +69,11 @@ ide_preferences_builtin_register_appearance (IdePreferences *preferences)
ide_preferences_add_page (preferences, "appearance", _("Appearance"), 0);
- ide_preferences_add_list_group (preferences, "appearance", "basic", NULL, 0);
+ ide_preferences_add_list_group (preferences, "appearance", "basic", _("Themes"), 0);
ide_preferences_add_switch (preferences, "appearance", "basic", "org.gnome.builder", "night-mode", NULL,
NULL, _("Dark Theme"), _("Whether Builder should use a dark theme"), _("dark theme"), 0);
+ ide_preferences_add_switch (preferences, "appearance", "basic", "org.gnome.builder.editor",
"show-grid-lines", NULL, NULL, _("Grid Pattern"), _("Display a grid pattern underneath source code"), NULL,
0);
- ide_preferences_add_list_group (preferences, "appearance", "font", _("Font"), 100);
- ide_preferences_add_font_button (preferences, "appearance", "font", "org.gnome.builder.editor",
"font-name", _("Editor"), _("editor font monospace"), 0);
-
- ide_preferences_add_list_group (preferences, "appearance", "schemes", _("Themes"), 200);
+ ide_preferences_add_list_group (preferences, "appearance", "schemes", NULL, 100);
manager = gtk_source_style_scheme_manager_get_default ();
scheme_ids = gtk_source_style_scheme_manager_get_scheme_ids (manager);
@@ -93,8 +91,8 @@ ide_preferences_builtin_register_appearance (IdePreferences *preferences)
ide_preferences_add_radio (preferences, "appearance", "schemes", "org.gnome.builder.editor",
"style-scheme-name", NULL, variant_str, title, NULL, title, i);
}
- ide_preferences_add_list_group (preferences, "appearance", "background", NULL, 300);
- ide_preferences_add_switch (preferences, "appearance", "background", "org.gnome.builder.editor",
"show-grid-lines", NULL, NULL, _("Grid Pattern"), _("Display a grid pattern underneath source code"), NULL,
0);
+ ide_preferences_add_list_group (preferences, "appearance", "font", _("Font"), 200);
+ ide_preferences_add_font_button (preferences, "appearance", "font", "org.gnome.builder.editor",
"font-name", _("Editor"), _("editor font monospace"), 0);
}
static void
@@ -117,7 +115,7 @@ ide_preferences_builtin_register_editor (IdePreferences *preferences)
{
ide_preferences_add_page (preferences, "editor", _("Editor"), 100);
- ide_preferences_add_list_group (preferences, "editor", "position", NULL, 0);
+ ide_preferences_add_list_group (preferences, "editor", "position", _("Cursor"), 0);
ide_preferences_add_switch (preferences, "editor", "position", "org.gnome.builder.editor",
"restore-insert-mark", NULL, NULL, _("Restore cursor position"), _("Restore cursor position when a file is
reopened"), NULL, 0);
ide_preferences_add_spin_button (preferences, "editor", "position", "org.gnome.builder.editor",
"scroll-offset", NULL, _("Scroll Offset"), _("Minimum number of lines to keep above and below the cursor"),
NULL, 10);
diff --git a/libide/preferences/ide-preferences-flow-box.c b/libide/preferences/ide-preferences-flow-box.c
new file mode 100644
index 0000000..bd2ebc8
--- /dev/null
+++ b/libide/preferences/ide-preferences-flow-box.c
@@ -0,0 +1,331 @@
+/* ide-preferences-flow-box.c
+ *
+ * Copyright (C) 2015 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ide-preferences-flow-box.h"
+#include "ide-preferences-group.h"
+#include "ide-preferences-group-private.h"
+
+/**
+ * SECTION:ide-preferences-flow-box
+ *
+ * This is a custom container similar to flow box, but not quiet. It is
+ * meant to have multiple columns with preference items in it. We will
+ * try to reflow the groups based on a couple hueristics to make things
+ * more pleasant to look at.
+ */
+
+#define BORDER_WIDTH 32
+#define COLUMN_WIDTH 500
+#define COLUMN_SPACING 32
+#define ROW_SPACING 24
+
+struct _IdePreferencesFlowBox
+{
+ GtkBox parent_instance;
+
+ guint needs_reflow : 1;
+ guint max_columns : 3;
+
+ GPtrArray *columns;
+ GList *groups;
+};
+
+G_DEFINE_TYPE (IdePreferencesFlowBox, ide_preferences_flow_box, GTK_TYPE_BOX)
+
+static gint
+compare_group (gconstpointer a,
+ gconstpointer b)
+{
+ const IdePreferencesGroup *group_a = a;
+ const IdePreferencesGroup *group_b = b;
+
+ return group_a->priority - group_b->priority;
+}
+
+static gint
+find_next_column (IdePreferencesFlowBox *self,
+ IdePreferencesGroup *group,
+ gint last_column)
+{
+ gint i;
+ struct {
+ gint column;
+ gint height;
+ } shortest = { -1, 0 };
+
+ g_assert (IDE_IS_PREFERENCES_FLOW_BOX (self));
+ g_assert (IDE_IS_PREFERENCES_GROUP (group));
+ g_assert (last_column >= -1);
+ g_assert (self->columns->len > 0);
+
+ if (ide_preferences_group_get_title (group) == NULL)
+ return last_column == -1 ? 0 : last_column;
+
+ for (i = 0; i < self->columns->len; i++)
+ {
+ GtkBox *column = g_ptr_array_index (self->columns, i);
+ gint height;
+
+ gtk_widget_get_preferred_height (GTK_WIDGET (column), NULL, &height);
+
+ if (shortest.column == -1 || height < shortest.height)
+ {
+ shortest.height = height;
+ shortest.column = i;
+ }
+ }
+
+ return shortest.column;
+}
+
+static void
+ide_preferences_flow_box_reflow (IdePreferencesFlowBox *self)
+{
+ GtkAllocation alloc;
+ const GList *iter;
+ gint n_columns;
+ gint width;
+ gint spacing;
+ gint border_width;
+ gint last_column = -1;
+
+ g_assert (IDE_IS_PREFERENCES_FLOW_BOX (self));
+
+ self->needs_reflow = FALSE;
+
+ gtk_widget_get_allocation (GTK_WIDGET (self), &alloc);
+
+ /*
+ * Remove all groups from their containers, and add an extra reference
+ * until we have added the items back to a new box.
+ */
+ for (iter = self->groups; iter; iter = iter->next)
+ {
+ GtkWidget *group = iter->data;
+ GtkWidget *parent = gtk_widget_get_parent (group);
+
+ g_object_ref (group);
+
+ if (parent != NULL)
+ gtk_container_remove (GTK_CONTAINER (parent), group);
+ }
+
+ /*
+ * Now remove the containers.
+ */
+ while (self->columns->len > 0)
+ {
+ GtkWidget *box = g_ptr_array_index (self->columns, self->columns->len - 1);
+
+ gtk_container_remove (GTK_CONTAINER (self), box);
+ g_ptr_array_remove_index (self->columns, self->columns->len - 1);
+ }
+
+ g_assert (self->columns->len == 0);
+
+ /*
+ * Determine the number of containers we need based on column width and
+ * allocation width, taking border_width and spacing into account.
+ */
+ n_columns = 1;
+ spacing = gtk_box_get_spacing (GTK_BOX (self));
+ border_width = gtk_container_get_border_width (GTK_CONTAINER (self));
+ width = (border_width * 2) + COLUMN_WIDTH;
+
+ while (TRUE)
+ {
+ width += spacing;
+ width += COLUMN_WIDTH;
+
+ if (width <= alloc.width)
+ {
+ n_columns++;
+ continue;
+ }
+
+ break;
+ }
+
+ /*
+ * Limit ourselves to our max columns.
+ */
+ n_columns = MIN (n_columns, self->max_columns);
+
+ /*
+ * Add those columns, we'll add items to them after they are configured.
+ */
+ while (self->columns->len < n_columns)
+ {
+ GtkWidget *column;
+
+ column = g_object_new (GTK_TYPE_BOX,
+ "hexpand", FALSE,
+ "orientation", GTK_ORIENTATION_VERTICAL,
+ "spacing", ROW_SPACING,
+ "visible", TRUE,
+ "width-request", COLUMN_WIDTH,
+ NULL);
+ GTK_CONTAINER_CLASS (ide_preferences_flow_box_parent_class)->add (GTK_CONTAINER (self), column);
+ g_ptr_array_add (self->columns, column);
+ }
+
+ /*
+ * Now go through adding groups to columns based on the column with the
+ * shortest height. If the group does not have a title, it should be
+ * placed in the same column as the previous group.
+ */
+ for (iter = self->groups; iter; iter = iter->next)
+ {
+ IdePreferencesGroup *group = iter->data;
+ GtkBox *box;
+ gint column;
+
+ column = find_next_column (self, group, last_column);
+ g_assert (column >= 0);
+ g_assert (column < self->columns->len);
+
+ box = g_ptr_array_index (self->columns, column);
+ g_assert (GTK_IS_BOX (box));
+
+ gtk_container_add (GTK_CONTAINER (box), GTK_WIDGET (group));
+
+ last_column = column;
+ }
+
+ /*
+ * Now we can drop our extra reference to the groups.
+ */
+ g_list_foreach (self->groups, (GFunc)g_object_unref, NULL);
+}
+
+static void
+ide_preferences_flow_box_add_group (IdePreferencesFlowBox *self,
+ IdePreferencesGroup *group)
+{
+ g_assert (IDE_IS_PREFERENCES_FLOW_BOX (self));
+ g_assert (IDE_IS_PREFERENCES_GROUP (group));
+
+ self->groups = g_list_insert_sorted (self->groups, group, compare_group);
+ self->needs_reflow = TRUE;
+
+ gtk_widget_queue_allocate (GTK_WIDGET (self));
+}
+
+static void
+ide_preferences_flow_box_add (GtkContainer *container,
+ GtkWidget *child)
+{
+ IdePreferencesFlowBox *self = (IdePreferencesFlowBox *)container;
+
+ g_assert (IDE_IS_PREFERENCES_FLOW_BOX (self));
+ g_assert (IDE_IS_PREFERENCES_GROUP (child));
+
+ ide_preferences_flow_box_add_group (self, IDE_PREFERENCES_GROUP (child));
+}
+
+static void
+ide_preferences_flow_box_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ IdePreferencesFlowBox *self = (IdePreferencesFlowBox *)widget;
+ gint border_width;
+ gint min_width;
+ gint spacing;
+
+ g_assert (IDE_IS_PREFERENCES_FLOW_BOX (self));
+ g_assert (allocation != NULL);
+
+ border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
+ spacing = gtk_box_get_spacing (GTK_BOX (self));
+
+ min_width = (border_width * 2)
+ + (spacing * (self->columns->len - 1))
+ + (COLUMN_WIDTH * self->columns->len);
+
+ /*
+ * If we need to shrink our number of columns, or add another column,
+ * lets go through the reflow state.
+ */
+ if ((allocation->width < min_width) ||
+ ((allocation->width >= (min_width + spacing + COLUMN_WIDTH)) &&
+ (self->columns->len < self->max_columns)))
+ self->needs_reflow = TRUE;
+
+ GTK_WIDGET_CLASS (ide_preferences_flow_box_parent_class)->size_allocate (widget, allocation);
+
+ if (self->needs_reflow)
+ ide_preferences_flow_box_reflow (self);
+}
+
+static void
+ide_preferences_flow_box_get_preferred_width (GtkWidget *widget,
+ gint *min_width,
+ gint *nat_width)
+{
+ gint border_width;
+
+ g_assert (GTK_IS_WIDGET (widget));
+ g_assert (min_width != NULL);
+ g_assert (nat_width != NULL);
+
+ GTK_WIDGET_CLASS (ide_preferences_flow_box_parent_class)->get_preferred_width (widget, min_width,
nat_width);
+
+ border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
+
+ *min_width = (border_width * 2) + COLUMN_WIDTH;
+
+ if (*nat_width < *min_width)
+ *nat_width = *min_width;
+}
+
+static void
+ide_preferences_flow_box_finalize (GObject *object)
+{
+ IdePreferencesFlowBox *self = (IdePreferencesFlowBox *)object;
+
+ g_clear_pointer (&self->columns, g_ptr_array_unref);
+ g_clear_pointer (&self->groups, g_list_free);
+
+ G_OBJECT_CLASS (ide_preferences_flow_box_parent_class)->finalize (object);
+}
+
+static void
+ide_preferences_flow_box_class_init (IdePreferencesFlowBoxClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
+
+ object_class->finalize = ide_preferences_flow_box_finalize;
+
+ widget_class->size_allocate = ide_preferences_flow_box_size_allocate;
+ widget_class->get_preferred_width = ide_preferences_flow_box_get_preferred_width;
+
+ container_class->add = ide_preferences_flow_box_add;
+}
+
+static void
+ide_preferences_flow_box_init (IdePreferencesFlowBox *self)
+{
+ self->columns = g_ptr_array_new ();
+ self->max_columns = 2;
+
+ gtk_widget_set_hexpand (GTK_WIDGET (self), TRUE);
+ gtk_container_set_border_width (GTK_CONTAINER (self), BORDER_WIDTH);
+ gtk_box_set_spacing (GTK_BOX (self), COLUMN_SPACING);
+}
diff --git a/libide/preferences/ide-preferences-flow-box.h b/libide/preferences/ide-preferences-flow-box.h
new file mode 100644
index 0000000..49e763e
--- /dev/null
+++ b/libide/preferences/ide-preferences-flow-box.h
@@ -0,0 +1,32 @@
+/* ide-preferences-flow-box.h
+ *
+ * Copyright (C) 2015 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef IDE_PREFERENCES_FLOW_BOX_H
+#define IDE_PREFERENCES_FLOW_BOX_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_PREFERENCES_FLOW_BOX (ide_preferences_flow_box_get_type())
+
+G_DECLARE_FINAL_TYPE (IdePreferencesFlowBox, ide_preferences_flow_box, IDE, PREFERENCES_FLOW_BOX, GtkBox)
+
+G_END_DECLS
+
+#endif /* IDE_PREFERENCES_FLOW_BOX_H */
diff --git a/libide/preferences/ide-preferences-group-private.h
b/libide/preferences/ide-preferences-group-private.h
index 50d2c4d..2a52529 100644
--- a/libide/preferences/ide-preferences-group-private.h
+++ b/libide/preferences/ide-preferences-group-private.h
@@ -24,6 +24,21 @@
G_BEGIN_DECLS
+struct _IdePreferencesGroup
+{
+ GtkBin parent_instance;
+
+ gint priority;
+ guint is_list : 1;
+
+ GtkLabel *title;
+ GtkBox *box;
+ GtkListBox *list_box;
+ GtkFrame *list_box_frame;
+
+ GPtrArray *widgets;
+};
+
void _ide_preferences_group_set_map (IdePreferencesGroup *self,
GHashTable *map);
guint _ide_preferences_group_refilter (IdePreferencesGroup *self,
diff --git a/libide/preferences/ide-preferences-group.c b/libide/preferences/ide-preferences-group.c
index d826d17..46a37d7 100644
--- a/libide/preferences/ide-preferences-group.c
+++ b/libide/preferences/ide-preferences-group.c
@@ -21,21 +21,6 @@
#include "ide-preferences-group.h"
#include "ide-preferences-group-private.h"
-struct _IdePreferencesGroup
-{
- GtkBin parent_instance;
-
- gint priority;
- guint is_list : 1;
-
- GtkLabel *title;
- GtkBox *box;
- GtkListBox *list_box;
- GtkFrame *list_box_frame;
-
- GPtrArray *widgets;
-};
-
G_DEFINE_TYPE (IdePreferencesGroup, ide_preferences_group, GTK_TYPE_BIN)
enum {
@@ -74,6 +59,18 @@ ide_preferences_group_row_activated (IdePreferencesGroup *self,
gtk_widget_activate (child);
}
+const gchar *
+ide_preferences_group_get_title (IdePreferencesGroup *self)
+{
+ const gchar *title;
+
+ g_return_val_if_fail (IDE_IS_PREFERENCES_GROUP (self), NULL);
+
+ title = gtk_label_get_label (self->title);
+
+ return (!title || !*title) ? NULL : title;
+}
+
static void
ide_preferences_group_finalize (GObject *object)
{
diff --git a/libide/preferences/ide-preferences-group.h b/libide/preferences/ide-preferences-group.h
index c4b0be9..e4fe5f8 100644
--- a/libide/preferences/ide-preferences-group.h
+++ b/libide/preferences/ide-preferences-group.h
@@ -27,8 +27,9 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (IdePreferencesGroup, ide_preferences_group, IDE, PREFERENCES_GROUP, GtkBin)
-void ide_preferences_group_add (IdePreferencesGroup *self,
- GtkWidget *widget);
+void ide_preferences_group_add (IdePreferencesGroup *self,
+ GtkWidget *widget);
+const gchar *ide_preferences_group_get_title (IdePreferencesGroup *self);
G_END_DECLS
diff --git a/libide/preferences/ide-preferences-page.c b/libide/preferences/ide-preferences-page.c
index c2cf64e..5bb499b 100644
--- a/libide/preferences/ide-preferences-page.c
+++ b/libide/preferences/ide-preferences-page.c
@@ -18,6 +18,7 @@
#include <glib/gi18n.h>
+#include "ide-preferences-flow-box.h"
#include "ide-preferences-group.h"
#include "ide-preferences-group-private.h"
#include "ide-preferences-page.h"
@@ -25,12 +26,12 @@
struct _IdePreferencesPage
{
- GtkBin parent_instance;
+ GtkBin parent_instance;
- gint priority;
+ gint priority;
- GtkBox *box;
- GHashTable *groups_by_name;
+ IdePreferencesFlowBox *box;
+ GHashTable *groups_by_name;
};
enum {
@@ -129,7 +130,6 @@ ide_preferences_page_add_group (IdePreferencesPage *self,
IdePreferencesGroup *group)
{
gchar *name = NULL;
- gint position = -1;
g_return_if_fail (IDE_IS_PREFERENCES_PAGE (self));
g_return_if_fail (IDE_IS_PREFERENCES_GROUP (group));
@@ -144,9 +144,7 @@ ide_preferences_page_add_group (IdePreferencesPage *self,
g_hash_table_insert (self->groups_by_name, name, group);
- gtk_container_add_with_properties (GTK_CONTAINER (self->box), GTK_WIDGET (group),
- "position", position,
- NULL);
+ gtk_container_add (GTK_CONTAINER (self->box), GTK_WIDGET (group));
}
IdePreferencesGroup *
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]