[gnome-builder/wip/commands] command-bar: incremental work on command bar implementation
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/commands] command-bar: incremental work on command bar implementation
- Date: Tue, 7 Oct 2014 20:37:51 +0000 (UTC)
commit c9803ddbaeb436cdaaa776513c6e922076fec167
Author: Christian Hergert <christian hergert me>
Date: Tue Oct 7 13:37:41 2014 -0700
command-bar: incremental work on command bar implementation
Lot's to do still, but it's actually starting to look like a command bar
now.
I want to have long running tasks have a spinner on the left. If it is
complete, it should have a close button to remove it from the history.
(maybe?) is that even worth it?
Still needs more design, etc.
src/commands/gb-command-bar-item.c | 200 +++++++++++++++++++++++++++++
src/commands/gb-command-bar-item.h | 60 +++++++++
src/commands/gb-command-bar.c | 69 +++++++++-
src/commands/gb-commands-internal.c | 9 +-
src/gnome-builder.mk | 2 +
src/resources/css/builder.Adwaita.css | 16 +++
src/resources/gnome-builder.gresource.xml | 1 +
src/resources/ui/gb-command-bar-item.ui | 59 +++++++++
src/resources/ui/gb-command-bar.ui | 15 ++-
9 files changed, 422 insertions(+), 9 deletions(-)
---
diff --git a/src/commands/gb-command-bar-item.c b/src/commands/gb-command-bar-item.c
new file mode 100644
index 0000000..812a5d4
--- /dev/null
+++ b/src/commands/gb-command-bar-item.c
@@ -0,0 +1,200 @@
+/* gb-command-bar-item.c
+ *
+ * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ *
+ * 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 <glib/gi18n.h>
+
+#include "gb-command-bar-item.h"
+
+struct _GbCommandBarItemPrivate
+{
+ GbCommandTask *task;
+
+ GtkWidget *command_text;
+ GtkWidget *result_text;
+ GtkWidget *equal_label;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (GbCommandBarItem, gb_command_bar_item, GTK_TYPE_BIN)
+
+enum {
+ PROP_0,
+ PROP_TASK,
+ LAST_PROP
+};
+
+static GParamSpec *gParamSpecs [LAST_PROP];
+
+GtkWidget *
+gb_command_bar_item_new (GbCommandTask *task)
+{
+ return g_object_new (GB_TYPE_COMMAND_BAR_ITEM,
+ "task", task,
+ NULL);
+}
+
+/**
+ * gb_command_bar_item_get_result:
+ * @item: A #GbCommandBarItem.
+ *
+ * Retrieves the result text widget so it can be used in the command bar
+ * sizing group.
+ *
+ * Returns: (transfer none): The result text widget.
+ */
+GtkWidget *
+gb_command_bar_item_get_result (GbCommandBarItem *item)
+{
+ g_return_val_if_fail (GB_IS_COMMAND_BAR_ITEM (item), NULL);
+
+ return item->priv->result_text;
+}
+
+GbCommandTask *
+gb_command_bar_item_get_task (GbCommandBarItem *item)
+{
+ g_return_val_if_fail (GB_IS_COMMAND_BAR_ITEM (item), NULL);
+
+ return item->priv->task;
+}
+
+static gboolean
+string_to_boolean (GBinding *binding,
+ const GValue *from_value,
+ GValue *to_value,
+ gpointer user_data)
+{
+ g_value_set_boolean (to_value, !!g_value_get_string (from_value));
+ return TRUE;
+}
+
+void
+gb_command_bar_item_set_task (GbCommandBarItem *item,
+ GbCommandTask *task)
+{
+ g_return_val_if_fail (GB_IS_COMMAND_BAR_ITEM (item), NULL);
+ g_return_val_if_fail (GB_IS_COMMAND_TASK (task), NULL);
+
+ if (item->priv->task != task)
+ {
+ if (item->priv->task)
+ g_clear_object (&item->priv->task);
+
+ if (task)
+ {
+ item->priv->task = g_object_ref (task);
+ g_object_bind_property (task, "command-text",
+ item->priv->command_text, "label",
+ G_BINDING_SYNC_CREATE);
+ g_object_bind_property (task, "result-text",
+ item->priv->result_text, "label",
+ G_BINDING_SYNC_CREATE);
+ g_object_bind_property_full (task, "result-text",
+ item->priv->equal_label, "visible",
+ G_BINDING_SYNC_CREATE,
+ string_to_boolean,
+ NULL, NULL, NULL);
+ }
+
+ g_object_notify_by_pspec (G_OBJECT (item), gParamSpecs [PROP_TASK]);
+ }
+}
+
+static void
+gb_command_bar_item_dispose (GObject *object)
+{
+ GbCommandBarItemPrivate *priv = GB_COMMAND_BAR_ITEM (object)->priv;
+
+ g_clear_object (&priv->task);
+
+ G_OBJECT_CLASS (gb_command_bar_item_parent_class)->dispose (object);
+}
+
+static void
+gb_command_bar_item_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GbCommandBarItem *self = GB_COMMAND_BAR_ITEM (object);
+
+ switch (prop_id)
+ {
+ case PROP_TASK:
+ g_value_set_object (value, gb_command_bar_item_get_task (self));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gb_command_bar_item_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GbCommandBarItem *self = GB_COMMAND_BAR_ITEM (object);
+
+ switch (prop_id)
+ {
+ case PROP_TASK:
+ gb_command_bar_item_set_task (self, g_value_get_object (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gb_command_bar_item_class_init (GbCommandBarItemClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ object_class->dispose = gb_command_bar_item_dispose;
+ object_class->get_property = gb_command_bar_item_get_property;
+ object_class->set_property = gb_command_bar_item_set_property;
+
+ gtk_widget_class_set_template_from_resource (widget_class,
+ "/org/gnome/builder/ui/gb-command-bar-item.ui");
+
+ gtk_widget_class_bind_template_child_private (widget_class, GbCommandBarItem, command_text);
+ gtk_widget_class_bind_template_child_private (widget_class, GbCommandBarItem, result_text);
+ gtk_widget_class_bind_template_child_private (widget_class, GbCommandBarItem, equal_label);
+
+ gParamSpecs [PROP_TASK] =
+ g_param_spec_object ("task",
+ _("Task"),
+ _("The task to be visualized in the item."),
+ GB_TYPE_COMMAND_TASK,
+ (G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (object_class, PROP_TASK,
+ gParamSpecs [PROP_TASK]);
+}
+
+static void
+gb_command_bar_item_init (GbCommandBarItem *self)
+{
+ self->priv = gb_command_bar_item_get_instance_private (self);
+
+ gtk_widget_init_template (GTK_WIDGET (self));
+}
diff --git a/src/commands/gb-command-bar-item.h b/src/commands/gb-command-bar-item.h
new file mode 100644
index 0000000..7f0043f
--- /dev/null
+++ b/src/commands/gb-command-bar-item.h
@@ -0,0 +1,60 @@
+/* gb-command-bar-item.h
+ *
+ * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ *
+ * 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 GB_COMMAND_BAR_ITEM_H
+#define GB_COMMAND_BAR_ITEM_H
+
+#include <gtk/gtk.h>
+
+#include "gb-command-task.h"
+
+G_BEGIN_DECLS
+
+#define GB_TYPE_COMMAND_BAR_ITEM (gb_command_bar_item_get_type())
+#define GB_COMMAND_BAR_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_COMMAND_BAR_ITEM,
GbCommandBarItem))
+#define GB_COMMAND_BAR_ITEM_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_COMMAND_BAR_ITEM,
GbCommandBarItem const))
+#define GB_COMMAND_BAR_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GB_TYPE_COMMAND_BAR_ITEM,
GbCommandBarItemClass))
+#define GB_IS_COMMAND_BAR_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GB_TYPE_COMMAND_BAR_ITEM))
+#define GB_IS_COMMAND_BAR_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GB_TYPE_COMMAND_BAR_ITEM))
+#define GB_COMMAND_BAR_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GB_TYPE_COMMAND_BAR_ITEM,
GbCommandBarItemClass))
+
+typedef struct _GbCommandBarItem GbCommandBarItem;
+typedef struct _GbCommandBarItemClass GbCommandBarItemClass;
+typedef struct _GbCommandBarItemPrivate GbCommandBarItemPrivate;
+
+struct _GbCommandBarItem
+{
+ GtkBin parent;
+
+ /*< private >*/
+ GbCommandBarItemPrivate *priv;
+};
+
+struct _GbCommandBarItemClass
+{
+ GtkBinClass parent;
+};
+
+GType gb_command_bar_item_get_type (void) G_GNUC_CONST;
+GtkWidget *gb_command_bar_item_new (GbCommandTask *task);
+GbCommandTask *gb_command_bar_item_get_task (GbCommandBarItem *item);
+GtkWidget *gb_command_bar_item_get_result (GbCommandBarItem *item);
+
+G_END_DECLS
+
+#endif /* GB_COMMAND_BAR_ITEM_H */
diff --git a/src/commands/gb-command-bar.c b/src/commands/gb-command-bar.c
index 31475d5..58efc75 100644
--- a/src/commands/gb-command-bar.c
+++ b/src/commands/gb-command-bar.c
@@ -16,13 +16,18 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <glib/gi18n.h>
+
+#include "gb-animation.h"
#include "gb-command.h"
#include "gb-command-bar.h"
+#include "gb-command-bar-item.h"
#include "gb-command-manager.h"
#include "gb-string.h"
struct _GbCommandBarPrivate
{
+ GtkSizeGroup *result_size_group;
GtkEntry *entry;
GtkFrame *frame;
GtkListBox *list_box;
@@ -70,15 +75,34 @@ static void
gb_command_bar_push_task (GbCommandBar *bar,
GbCommandTask *task)
{
- const gchar *command_text;
- const gchar *result_text;
+ GtkAdjustment *vadj;
+ GdkFrameClock *frame_clock;
+ GtkWidget *item;
+ GtkWidget *result_widget;
+ gdouble upper;
g_return_if_fail (GB_IS_COMMAND_BAR (bar));
g_return_if_fail (GB_IS_COMMAND_TASK (task));
- command_text = gb_command_task_get_command_text (task);
- result_text = gb_command_task_get_result_text (task);
- g_print (" %s = %s\n", command_text, result_text);
+ item = g_object_new (GB_TYPE_COMMAND_BAR_ITEM,
+ "task", task,
+ "visible", TRUE,
+ NULL);
+ gtk_container_add (GTK_CONTAINER (bar->priv->list_box), item);
+
+ result_widget = gb_command_bar_item_get_result (GB_COMMAND_BAR_ITEM (item));
+ gtk_size_group_add_widget (bar->priv->result_size_group, result_widget);
+
+ vadj = gtk_list_box_get_adjustment (bar->priv->list_box);
+ upper = gtk_adjustment_get_upper (vadj);
+ frame_clock = gtk_widget_get_frame_clock (GTK_WIDGET (bar->priv->list_box));
+
+ gb_object_animate (vadj,
+ GB_ANIMATION_EASE_IN_CUBIC,
+ 250,
+ frame_clock,
+ "value", upper,
+ NULL);
}
static void
@@ -119,8 +143,10 @@ gb_command_bar_on_entry_activate (GbCommandBar *bar,
g_clear_object (&command);
g_clear_pointer (¶meters, g_variant_unref);
}
+ else
+ gb_command_bar_hide (bar);
- gb_command_bar_hide (bar);
+ gtk_entry_set_text (bar->priv->entry, "");
}
static gboolean
@@ -166,12 +192,38 @@ gb_command_bar_on_entry_key_press_event (GbCommandBar *bar,
}
static void
+update_header_func (GtkListBoxRow *row,
+ GtkListBoxRow *before,
+ gpointer user_data)
+{
+ if (before)
+ {
+ GtkWidget *sep;
+
+ sep = g_object_new (GTK_TYPE_SEPARATOR,
+ "orientation", GTK_ORIENTATION_HORIZONTAL,
+ "visible", TRUE,
+ NULL);
+ gtk_list_box_row_set_header (row, sep);
+ }
+}
+
+static void
gb_command_bar_constructed (GObject *object)
{
GbCommandBar *bar = (GbCommandBar *)object;
+ GtkWidget *placeholder;
G_OBJECT_CLASS (gb_command_bar_parent_class)->constructed (object);
+ placeholder = g_object_new (GTK_TYPE_LABEL,
+ "visible", TRUE,
+ "label", _("Use the entry below to execute a command"),
+ NULL);
+ gtk_style_context_add_class (gtk_widget_get_style_context (placeholder),
+ "gb-command-bar-placeholder");
+ gtk_list_box_set_placeholder (bar->priv->list_box, placeholder);
+
g_signal_connect_object (bar->priv->entry,
"activate",
G_CALLBACK (gb_command_bar_on_entry_activate),
@@ -189,6 +241,9 @@ gb_command_bar_constructed (GObject *object)
G_CALLBACK (gb_command_bar_on_entry_key_press_event),
bar,
G_CONNECT_SWAPPED);
+
+ gtk_list_box_set_header_func (bar->priv->list_box, update_header_func,
+ NULL, NULL);
}
static void
@@ -215,12 +270,12 @@ gb_command_bar_class_init (GbCommandBarClass *klass)
gtk_widget_class_bind_template_child_private (widget_class, GbCommandBar, frame);
gtk_widget_class_bind_template_child_private (widget_class, GbCommandBar, list_box);
gtk_widget_class_bind_template_child_private (widget_class, GbCommandBar, scroller);
+ gtk_widget_class_bind_template_child_private (widget_class, GbCommandBar, result_size_group);
}
static void
gb_command_bar_init (GbCommandBar *self)
{
self->priv = gb_command_bar_get_instance_private (self);
-
gtk_widget_init_template (GTK_WIDGET (self));
}
diff --git a/src/commands/gb-commands-internal.c b/src/commands/gb-commands-internal.c
index 4b81030..5dfbca1 100644
--- a/src/commands/gb-commands-internal.c
+++ b/src/commands/gb-commands-internal.c
@@ -120,6 +120,7 @@ text_command_execute (GbCommand *command,
GbEditorDocument *document;
GbWorkspace *workspace;
GbEditorTab *tab;
+ GbCommandTask *result;
g_return_val_if_fail (GB_IS_COMMAND (command), NULL);
g_return_val_if_fail (GB_IS_WORKBENCH (workbench), NULL);
@@ -139,7 +140,13 @@ text_command_execute (GbCommand *command,
text_command->command (command, parameters, tab, document);
- return NULL;
+ result = g_object_new (GB_TYPE_COMMAND_TASK,
+ "active", FALSE,
+ "command-text", text_command->name,
+ "progress", 1.0,
+ NULL);
+
+ return result;
}
static TextCommand gTextCommands[] = {
diff --git a/src/gnome-builder.mk b/src/gnome-builder.mk
index 17360b2..bae3c18 100644
--- a/src/gnome-builder.mk
+++ b/src/gnome-builder.mk
@@ -13,6 +13,8 @@ libgnome_builder_la_SOURCES = \
src/commands/gb-command.h \
src/commands/gb-command-bar.c \
src/commands/gb-command-bar.h \
+ src/commands/gb-command-bar-item.c \
+ src/commands/gb-command-bar-item.h \
src/commands/gb-command-manager.c \
src/commands/gb-command-manager.h \
src/commands/gb-command-task.c \
diff --git a/src/resources/css/builder.Adwaita.css b/src/resources/css/builder.Adwaita.css
index 5e64594..83efc88 100644
--- a/src/resources/css/builder.Adwaita.css
+++ b/src/resources/css/builder.Adwaita.css
@@ -155,3 +155,19 @@ GtkEntry.gb-command-bar {
padding: 6px;
font-family: Monospace;
}
+GtkLabel.gb-command-bar-placeholder {
+ font-size: 1.2em;
+ font-weight: bold;
+ color: shade (@theme_base_color, 0.5);
+}
+GbCommandBarItem .gb-command-bar-item-command {
+ font-size: 1.1em;
+}
+GbCommandBarItem .gb-command-bar-item-result {
+ font-size: 1.1em;
+}
+GbCommandBarItem .gb-command-bar-item-equal {
+ font-size: 1.2em;
+ font-weight: bold;
+ color: shade (@theme_base_color, 0.5);
+}
diff --git a/src/resources/gnome-builder.gresource.xml b/src/resources/gnome-builder.gresource.xml
index 710cbd7..dfc84c5 100644
--- a/src/resources/gnome-builder.gresource.xml
+++ b/src/resources/gnome-builder.gresource.xml
@@ -18,6 +18,7 @@
<file>snippets/chdr.snippets</file>
<file>ui/gb-command-bar.ui</file>
+ <file>ui/gb-command-bar-item.ui</file>
<file>ui/gb-devhelp-tab.ui</file>
<file>ui/gb-editor-tab.ui</file>
<file>ui/gb-preferences-window.ui</file>
diff --git a/src/resources/ui/gb-command-bar-item.ui b/src/resources/ui/gb-command-bar-item.ui
new file mode 100644
index 0000000..4171a24
--- /dev/null
+++ b/src/resources/ui/gb-command-bar-item.ui
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.8 -->
+ <template class="GbCommandBarItem" parent="GtkBin">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="border_width">6</property>
+ <child>
+ <object class="GtkBox" id="box">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="vexpand">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkSpinner" id="spinner">
+ <property name="visible">False</property>
+ <property name="can_focus">False</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="command_text">
+ <property name="visible">True</property>
+ <property name="xalign">0.0</property>
+ <property name="hexpand">True</property>
+ <property name="can_focus">False</property>
+ <property name="selectable">True</property>
+ <style>
+ <class name="gb-command-bar-item-command"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="equal_label">
+ <property name="visible">True</property>
+ <property name="hexpand">False</property>
+ <property name="can_focus">False</property>
+ <property name="label">=</property>
+ <property name="selectable">False</property>
+ <style>
+ <class name="gb-command-bar-item-equal"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="result_text">
+ <property name="visible">True</property>
+ <property name="xalign">0.0</property>
+ <property name="hexpand">False</property>
+ <property name="can_focus">False</property>
+ <property name="selectable">True</property>
+ <style>
+ <class name="gb-command-bar-item-result"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/src/resources/ui/gb-command-bar.ui b/src/resources/ui/gb-command-bar.ui
index 6949dc1..6f1f149 100644
--- a/src/resources/ui/gb-command-bar.ui
+++ b/src/resources/ui/gb-command-bar.ui
@@ -20,12 +20,15 @@
<property name="orientation">vertical</property>
<child>
<object class="GtkScrolledWindow" id="scroller">
- <property name="visible">False</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="visible">True</property>
<property name="expand">True</property>
+ <property name="height_request">325</property>
<child>
<object class="GtkListBox" id="list_box">
<property name="visible">True</property>
<property name="expand">True</property>
+ <property name="selection_mode">GTK_SELECTION_NONE</property>
</object>
<style>
<class name="view"/>
@@ -34,10 +37,17 @@
</object>
</child>
<child>
+ <object class="GtkSeparator" id="hsep1">
+ <property name="orientation">horizontal</property>
+ <property name="visible">True</property>
+ </object>
+ </child>
+ <child>
<object class="GtkEntry" id="entry">
<property name="visible">True</property>
<property name="expand">False</property>
<property name="valign">end</property>
+ <property name="has_frame">False</property>
<style>
<class name="gb-command-bar"/>
</style>
@@ -48,4 +58,7 @@
</object>
</child>
</template>
+ <object class="GtkSizeGroup" id="result_size_group">
+ <property name="mode">GTK_SIZE_GROUP_HORIZONTAL</property>
+ </object>
</interface>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]