[libdazzle] example: add some basic document handling to example app
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libdazzle] example: add some basic document handling to example app
- Date: Sat, 17 Jun 2017 22:58:55 +0000 (UTC)
commit 82f749af97944e6e1a76684f1a68e5e1b326ae59
Author: Christian Hergert <chergert redhat com>
Date: Sat Jun 17 15:58:40 2017 -0700
example: add some basic document handling to example app
This is just going to be a stupid little text editor to demo some things
and allow us to test stuff in a non-trivial fashion.
examples/app/example-application.h | 5 +-
examples/app/example-document-view.c | 126 +++++++++++++++++++++++++++++++++
examples/app/example-document-view.h | 15 ++++
examples/app/example-document-view.ui | 16 ++++
examples/app/example-document.c | 109 ++++++++++++++++++++++++++++
examples/app/example-document.h | 13 ++++
examples/app/example-window.c | 111 +++++++++++++++++++++++++----
examples/app/example-window.h | 12 ++--
examples/app/example-window.ui | 48 ++++++++++---
examples/app/example.gresources.xml | 1 +
examples/app/meson.build | 4 +
11 files changed, 425 insertions(+), 35 deletions(-)
---
diff --git a/examples/app/example-application.h b/examples/app/example-application.h
index 8ad96f7..2b8d624 100644
--- a/examples/app/example-application.h
+++ b/examples/app/example-application.h
@@ -1,5 +1,4 @@
-#ifndef EXAMPLE_APPLICATION_H
-#define EXAMPLE_APPLICATION_H
+#pragma once
#include <dazzle.h>
@@ -10,5 +9,3 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (ExampleApplication, example_application, EXAMPLE, APPLICATION, DzlApplication)
G_END_DECLS
-
-#endif /* EXAMPLE_APPLICATION_H */
diff --git a/examples/app/example-document-view.c b/examples/app/example-document-view.c
new file mode 100644
index 0000000..dd9e1cf
--- /dev/null
+++ b/examples/app/example-document-view.c
@@ -0,0 +1,126 @@
+#include "example-document-view.h"
+
+struct _ExampleDocumentView
+{
+ GtkBin parent_instance;
+
+ GtkTextView *text_view;
+
+ ExampleDocument *document;
+};
+
+enum {
+ PROP_0,
+ PROP_DOCUMENT,
+ N_PROPS
+};
+
+G_DEFINE_TYPE (ExampleDocumentView, example_document_view, GTK_TYPE_BIN)
+
+static GParamSpec *properties [N_PROPS];
+
+static void
+example_document_view_set_document (ExampleDocumentView *self,
+ ExampleDocument *document)
+{
+ g_assert (EXAMPLE_IS_DOCUMENT_VIEW (self));
+ g_assert (!document || EXAMPLE_IS_DOCUMENT (document));
+
+ if (g_set_object (&self->document, document))
+ {
+ gtk_text_view_set_buffer (self->text_view, GTK_TEXT_BUFFER (document));
+ }
+}
+
+static void
+example_document_view_grab_focus (GtkWidget *widget)
+{
+ ExampleDocumentView *self = EXAMPLE_DOCUMENT_VIEW (widget);
+
+ gtk_widget_grab_focus (GTK_WIDGET (self->text_view));
+}
+
+static void
+example_document_view_finalize (GObject *object)
+{
+ ExampleDocumentView *self = (ExampleDocumentView *)object;
+
+ g_clear_object (&self->document);
+
+ G_OBJECT_CLASS (example_document_view_parent_class)->finalize (object);
+}
+
+static void
+example_document_view_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ ExampleDocumentView *self = EXAMPLE_DOCUMENT_VIEW (object);
+
+ switch (prop_id)
+ {
+ case PROP_DOCUMENT:
+ g_value_set_object (value, self->document);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+example_document_view_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ ExampleDocumentView *self = EXAMPLE_DOCUMENT_VIEW (object);
+
+ switch (prop_id)
+ {
+ case PROP_DOCUMENT:
+ example_document_view_set_document (self, g_value_get_object (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+example_document_view_class_init (ExampleDocumentViewClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ object_class->finalize = example_document_view_finalize;
+ object_class->get_property = example_document_view_get_property;
+ object_class->set_property = example_document_view_set_property;
+
+ widget_class->grab_focus = example_document_view_grab_focus;
+
+ properties [PROP_DOCUMENT] =
+ g_param_spec_object ("document",
+ "Document",
+ "The document to be viewed",
+ EXAMPLE_TYPE_DOCUMENT,
+ (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_properties (object_class, N_PROPS, properties);
+
+ gtk_widget_class_set_template_from_resource (widget_class,
"/org/gnome/example/ui/example-document-view.ui");
+ gtk_widget_class_bind_template_child (widget_class, ExampleDocumentView, text_view);
+}
+
+static void
+example_document_view_init (ExampleDocumentView *self)
+{
+ gtk_widget_init_template (GTK_WIDGET (self));
+}
+
+GtkWidget *
+example_document_view_new (void)
+{
+ return g_object_new (EXAMPLE_TYPE_DOCUMENT, NULL);
+}
diff --git a/examples/app/example-document-view.h b/examples/app/example-document-view.h
new file mode 100644
index 0000000..41fa8b0
--- /dev/null
+++ b/examples/app/example-document-view.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include <gtk/gtk.h>
+
+#include "example-document.h"
+
+G_BEGIN_DECLS
+
+#define EXAMPLE_TYPE_DOCUMENT_VIEW (example_document_view_get_type())
+
+G_DECLARE_FINAL_TYPE (ExampleDocumentView, example_document_view, EXAMPLE, DOCUMENT_VIEW, GtkBin)
+
+GtkWidget *example_document_view_new (void);
+
+G_END_DECLS
diff --git a/examples/app/example-document-view.ui b/examples/app/example-document-view.ui
new file mode 100644
index 0000000..fe3ebb3
--- /dev/null
+++ b/examples/app/example-document-view.ui
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="ExampleDocumentView" parent="GtkBin">
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">true</property>
+ <child>
+ <object class="GtkTextView" id="text_view">
+ <property name="monospace">true</property>
+ <property name="visible">true</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/examples/app/example-document.c b/examples/app/example-document.c
new file mode 100644
index 0000000..822de47
--- /dev/null
+++ b/examples/app/example-document.c
@@ -0,0 +1,109 @@
+#include "example-document.h"
+
+struct _ExampleDocument
+{
+ GtkTextBuffer parent_instance;
+ gchar *title;
+};
+
+enum {
+ PROP_0,
+ PROP_TITLE,
+ N_PROPS
+};
+
+G_DEFINE_TYPE (ExampleDocument, example_document, GTK_TYPE_TEXT_BUFFER)
+
+static guint last_untitled;
+static GParamSpec *properties [N_PROPS];
+
+static void
+example_document_constructed (GObject *object)
+{
+ ExampleDocument *self = (ExampleDocument *)object;
+
+ if (self->title == NULL)
+ self->title = g_strdup_printf ("Untitled Document %u", ++last_untitled);
+
+ G_OBJECT_CLASS (example_document_parent_class)->constructed (object);
+}
+
+static void
+example_document_finalize (GObject *object)
+{
+ ExampleDocument *self = (ExampleDocument *)object;
+
+ g_clear_pointer (&self->title, g_free);
+
+ G_OBJECT_CLASS (example_document_parent_class)->finalize (object);
+}
+
+static void
+example_document_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ ExampleDocument *self = EXAMPLE_DOCUMENT (object);
+
+ switch (prop_id)
+ {
+ case PROP_TITLE:
+ g_value_set_string (value, self->title);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+example_document_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ ExampleDocument *self = EXAMPLE_DOCUMENT (object);
+
+ switch (prop_id)
+ {
+ case PROP_TITLE:
+ g_free (self->title);
+ self->title = g_value_dup_string (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+example_document_class_init (ExampleDocumentClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = example_document_finalize;
+ object_class->constructed = example_document_constructed;
+ object_class->get_property = example_document_get_property;
+ object_class->set_property = example_document_set_property;
+
+ properties [PROP_TITLE] =
+ g_param_spec_string ("title",
+ "Title",
+ "The title of the document",
+ NULL,
+ (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_properties (object_class, N_PROPS, properties);
+}
+
+static void
+example_document_init (ExampleDocument *self)
+{
+}
+
+ExampleDocument *
+example_document_new (void)
+{
+ return g_object_new (EXAMPLE_TYPE_DOCUMENT, NULL);
+}
diff --git a/examples/app/example-document.h b/examples/app/example-document.h
new file mode 100644
index 0000000..e24815c
--- /dev/null
+++ b/examples/app/example-document.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define EXAMPLE_TYPE_DOCUMENT (example_document_get_type())
+
+G_DECLARE_FINAL_TYPE (ExampleDocument, example_document, EXAMPLE, DOCUMENT, GtkTextBuffer)
+
+ExampleDocument *example_document_new (void);
+
+G_END_DECLS
diff --git a/examples/app/example-window.c b/examples/app/example-window.c
index 7b2d331..3951a1f 100644
--- a/examples/app/example-window.c
+++ b/examples/app/example-window.c
@@ -7,35 +7,118 @@
struct _ExampleWindow
{
- GtkWindow parent_instance;
+ GtkApplicationWindow parent_instance;
DzlDockBin *dockbin;
+ GtkNotebook *notebook;
+ DzlEmptyState *empty_state;
+ GtkStack *stack;
};
-G_DEFINE_TYPE (ExampleWindow, example_window, GTK_TYPE_WINDOW)
+G_DEFINE_TYPE (ExampleWindow, example_window, GTK_TYPE_APPLICATION_WINDOW)
static const DzlShortcutEntry shortcuts[] = {
{ "com.example.window.NewDoc", NULL, N_("Editing"), N_("Documents"), N_("New Document"), N_("Create a new
document") },
{ "com.example.window.CloseDoc", NULL, N_("Editing"), N_("Documents"), N_("Close Document"), N_("Close the
current document") },
};
+ExampleDocumentView *
+example_window_get_current_document_view (ExampleWindow *self)
+{
+ gint page;
+
+ g_assert (EXAMPLE_IS_WINDOW (self));
+
+ page = gtk_notebook_get_current_page (self->notebook);
+
+ if (page == -1)
+ return NULL;
+
+ return EXAMPLE_DOCUMENT_VIEW (gtk_notebook_get_nth_page (self->notebook, page));
+}
+
+static GtkWidget *
+new_label (ExampleDocument *document)
+{
+ GtkWidget *box;
+ GtkWidget *label;
+ GtkWidget *button;
+
+ box = g_object_new (GTK_TYPE_BOX,
+ "visible", TRUE,
+ "spacing", 3,
+ NULL);
+ label = g_object_new (GTK_TYPE_LABEL,
+ "xalign", 0.0f,
+ "visible", TRUE,
+ NULL);
+ g_object_bind_property (document, "title", label, "label", G_BINDING_SYNC_CREATE);
+ button = g_object_new (GTK_TYPE_BUTTON,
+ "action-name", "win.close-document",
+ "visible", TRUE,
+ "child", g_object_new (GTK_TYPE_IMAGE,
+ "visible", TRUE,
+ "icon-name", "window-close-symbolic",
+ "icon-size", GTK_ICON_SIZE_MENU,
+ NULL),
+ NULL);
+ dzl_gtk_widget_add_style_class (button, "flat");
+ dzl_gtk_widget_add_style_class (button, "image-button");
+ gtk_container_add (GTK_CONTAINER (box), label);
+ gtk_container_add (GTK_CONTAINER (box), button);
+
+ return box;
+}
+
static void
-new_document_cb (ExampleWindow *self,
+new_document_cb (GSimpleAction *action,
+ GVariant *param,
gpointer user_data)
{
+ ExampleWindow *self = user_data;
+ g_autoptr(ExampleDocument) document = NULL;
+ GtkWidget *view;
+ GtkWidget *label;
+ gint page;
+
g_assert (EXAMPLE_IS_WINDOW (self));
- g_print ("New document!\n");
+ document = example_document_new ();
+ view = g_object_new (EXAMPLE_TYPE_DOCUMENT_VIEW,
+ "visible", TRUE,
+ "document", document,
+ NULL);
+ label = new_label (document);
+
+ page = gtk_notebook_append_page (self->notebook, view, label);
+ gtk_notebook_set_current_page (self->notebook, page);
+ gtk_stack_set_visible_child (self->stack, GTK_WIDGET (self->notebook));
+ gtk_widget_grab_focus (view);
}
static void
-close_document_cb (ExampleWindow *self,
+close_document_cb (GSimpleAction *action,
+ GVariant *param,
gpointer user_data)
{
+ ExampleWindow *self = user_data;
+ ExampleDocumentView *view;
+
g_assert (EXAMPLE_IS_WINDOW (self));
- g_print ("Close document!\n");
+ view = example_window_get_current_document_view (self);
+
+ if (view != NULL)
+ gtk_widget_destroy (GTK_WIDGET (view));
+
+ if (gtk_notebook_get_n_pages (self->notebook) == 0)
+ gtk_stack_set_visible_child (self->stack, GTK_WIDGET (self->empty_state));
}
+static const GActionEntry actions[] = {
+ { "new-document", new_document_cb },
+ { "close-document", close_document_cb },
+};
+
static void
example_window_class_init (ExampleWindowClass *klass)
{
@@ -43,6 +126,9 @@ example_window_class_init (ExampleWindowClass *klass)
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/example/ui/example-window.ui");
gtk_widget_class_bind_template_child (widget_class, ExampleWindow, dockbin);
+ gtk_widget_class_bind_template_child (widget_class, ExampleWindow, notebook);
+ gtk_widget_class_bind_template_child (widget_class, ExampleWindow, empty_state);
+ gtk_widget_class_bind_template_child (widget_class, ExampleWindow, stack);
}
static void
@@ -57,20 +143,15 @@ example_window_init (ExampleWindow *self)
dzl_shortcut_manager_set_theme_name (NULL, "default");
- dzl_shortcut_controller_add_command_callback (controller,
- "com.example.window.NewDoc",
- NULL,
- (GtkCallback) new_document_cb, NULL, NULL);
-
- dzl_shortcut_controller_add_command_callback (controller,
- "com.example.window.CloseDoc",
- NULL,
- (GtkCallback) close_document_cb, NULL, NULL);
+ dzl_shortcut_controller_add_command_action (controller, "com.example.window.NewDoc", NULL,
"win.new-document");
+ dzl_shortcut_controller_add_command_action (controller, "com.example.window.CloseDoc", NULL,
"win.close-document");
g_signal_connect_swapped (self,
"key-press-event",
G_CALLBACK (dzl_shortcut_manager_handle_event),
dzl_shortcut_manager_get_default ());
+
+ g_action_map_add_action_entries (G_ACTION_MAP (self), actions, G_N_ELEMENTS (actions), self);
}
GtkWidget *
diff --git a/examples/app/example-window.h b/examples/app/example-window.h
index f848403..c25d27a 100644
--- a/examples/app/example-window.h
+++ b/examples/app/example-window.h
@@ -1,16 +1,16 @@
-#ifndef EXAMPLE_WINDOW_H
-#define EXAMPLE_WINDOW_H
+#pragma once
#include <gtk/gtk.h>
+#include "example-document-view.h"
+
G_BEGIN_DECLS
#define EXAMPLE_TYPE_WINDOW (example_window_get_type())
-G_DECLARE_FINAL_TYPE (ExampleWindow, example_window, EXAMPLE, WINDOW, GtkWindow)
+G_DECLARE_FINAL_TYPE (ExampleWindow, example_window, EXAMPLE, WINDOW, GtkApplicationWindow)
-GtkWidget *example_window_new (void);
+GtkWidget *example_window_new (void);
+ExampleDocumentView *example_window_get_current_document_view (ExampleWindow *self);
G_END_DECLS
-
-#endif /* EXAMPLE_WINDOW_H */
diff --git a/examples/app/example-window.ui b/examples/app/example-window.ui
index ea02939..28198bd 100644
--- a/examples/app/example-window.ui
+++ b/examples/app/example-window.ui
@@ -1,25 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
- <template class="ExampleWindow" parent="GtkWindow">
+ <template class="ExampleWindow" parent="GtkApplicationWindow">
+ <child type="titlebar">
+ <object class="GtkHeaderBar" id="header_bar">
+ <property name="show-close-button">true</property>
+ <property name="visible">true</property>
+ <child>
+ <object class="GtkButton">
+ <property name="action-name">win.new-document</property>
+ <property name="visible">true</property>
+ <child>
+ <object class="GtkImage">
+ <property name="icon-name">document-new-symbolic</property>
+ <property name="visible">true</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="pack-type">start</property>
+ </packing>
+ </child>
+ </object>
+ </child>
<child>
<object class="DzlDockBin" id="dockbin">
<property name="visible">true</property>
<child>
- <object class="GtkNotebook" id="notebook">
+ <object class="GtkStack" id="stack">
<property name="expand">true</property>
+ <property name="transition-type">crossfade</property>
<property name="visible">true</property>
<child>
- <object class="GtkScrolledWindow">
+ <object class="DzlEmptyState" id="empty_state">
+ <property name="icon-name">document-new-symbolic</property>
+ <property name="pixel-size">128</property>
+ <property name="title" translatable="yes">No documents are open</property>
+ <property name="subtitle" translatable="yes">Open a document to see it’s contents</property>
+ <property name="visible">true</property>
+ </object>
+ <packing>
+ <property name="name">empty_state</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkNotebook" id="notebook">
<property name="visible">true</property>
- <child>
- <object class="GtkTextView">
- <property name="monospace">true</property>
- <property name="visible">true</property>
- </object>
- </child>
</object>
<packing>
- <property name="tab-label">Document 1</property>
+ <property name="name">notebook</property>
</packing>
</child>
</object>
diff --git a/examples/app/example.gresources.xml b/examples/app/example.gresources.xml
index 955a67d..5675300 100644
--- a/examples/app/example.gresources.xml
+++ b/examples/app/example.gresources.xml
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/gnome/example/ui">
+ <file>example-document-view.ui</file>
<file>example-window.ui</file>
</gresource>
diff --git a/examples/app/meson.build b/examples/app/meson.build
index 4b52352..dca5a96 100644
--- a/examples/app/meson.build
+++ b/examples/app/meson.build
@@ -7,6 +7,10 @@ example_resources = gnome.compile_resources(
example_application_sources = [
'example-application.c',
'example-application.h',
+ 'example-document.c',
+ 'example-document.h',
+ 'example-document-view.c',
+ 'example-document-view.h',
'example-window.c',
'example-window.h',
'main.c',
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]