[dia/dia-next: 34/59] Use a seperate custom widget to pick sheets



commit c0f46e1d9ee86b1da36412b1f1f4f597883debbb
Author: Zander Brown <zbrown gnome org>
Date:   Fri Dec 28 23:01:30 2018 +0000

    Use a seperate custom widget to pick sheets
    
    Sheet is now DiaSheet and is a GObject

 app/Makefile.am                       |   8 +-
 app/menus.c                           |  19 ---
 app/sheets.h                          |   2 +-
 app/sheets_dialog.c                   |   4 +-
 app/sheets_dialog_callbacks.c         |   4 +-
 app/toolbox.c                         | 237 ++++++++++------------------------
 app/toolbox.h                         |   5 +-
 app/widgets/dia-sheet-chooser.c       | 226 ++++++++++++++++++++++++++++++++
 app/widgets/dia-sheet-chooser.h       |  35 +++++
 data/dia-sheet-chooser-popover.ui     |  68 ++++++++++
 lib/dia-line-style-selector-popover.c |  17 ---
 lib/dia_dirs.c                        |  17 +++
 lib/dia_dirs.h                        |   2 +
 lib/diatypes.h                        |   1 -
 lib/sheet.c                           |  46 ++++---
 lib/sheet.h                           |  20 ++-
 lib/widgets/dialist.c                 |   4 +-
 plug-ins/python/pydia-sheet.c         |   2 +-
 plug-ins/python/pydia-sheet.h         |   2 +-
 19 files changed, 473 insertions(+), 246 deletions(-)
---
diff --git a/app/Makefile.am b/app/Makefile.am
index 8b474176..4d8f74c7 100644
--- a/app/Makefile.am
+++ b/app/Makefile.am
@@ -141,6 +141,8 @@ dia_core_files = \
        handle_ops.h \
        interface.c \
        interface.h \
+       widgets/dia-sheet-chooser.c \
+       widgets/dia-sheet-chooser.h \
        toolbox.c \
        toolbox.h \
        dia-app-icons.h \
@@ -172,12 +174,6 @@ dia_core_files = \
        plugin-manager.h \
        dia-props.c \
        dia-props.h \
-       gtkwrapbox.h \
-       gtkwrapbox.c \
-       gtkhwrapbox.h \
-       gtkhwrapbox.c \
-       gtkvwrapbox.h \
-       gtkvwrapbox.c \
        cursor.c \
        cursor.h \
        splash.c \
diff --git a/app/menus.c b/app/menus.c
index 01d1eb0b..cdf63f87 100644
--- a/app/menus.c
+++ b/app/menus.c
@@ -60,8 +60,6 @@ create_integrated_ui_toolbar (void);
 
 static void add_plugin_actions (GtkUIManager *ui_manager, const char *base_path);
 
-gchar *build_ui_filename (const gchar* name);
-
 /* Active/inactive state is set in diagram_update_menu_sensitivity()
  * in diagram.c */
 
@@ -742,23 +740,6 @@ add_plugin_actions (GtkUIManager *ui_manager, const gchar *base_path)
   }
 }
 
-gchar*
-build_ui_filename (const gchar* name)
-{
-  gchar* uifile;
-
-  if (g_getenv ("DIA_BASE_PATH") != NULL) {
-    /* a small hack cause the final destination and the local path differ */
-    const gchar* p = strrchr (name, '/');
-    if (p != NULL)
-      name = p+1;
-    uifile = g_build_filename (g_getenv ("DIA_BASE_PATH"), "data", name, NULL);
-  } else
-    uifile = dia_get_data_directory (name);
-
-  return uifile;
-}
-
 /*!
  * Not sure why this service is not provided by GTK+. 
  * We are passing tooltips into the actions (especially recent file menu).
diff --git a/app/sheets.h b/app/sheets.h
index d0fc3b5b..d3d0b914 100644
--- a/app/sheets.h
+++ b/app/sheets.h
@@ -55,7 +55,7 @@ struct _SheetObjectMod
 
 struct _SheetMod
 {
-  Sheet sheet;
+  DiaSheet sheet;
   
   enum { SHEETMOD_TYPE_NORMAL,
          SHEETMOD_TYPE_UNASSIGNED } type;      /* reserved for future use */
diff --git a/app/sheets_dialog.c b/app/sheets_dialog.c
index e67378a5..865ecfee 100644
--- a/app/sheets_dialog.c
+++ b/app/sheets_dialog.c
@@ -47,6 +47,7 @@
 
 #include "intl.h"
 #include "persistence.h"
+#include "dia_dirs.h"
 
 static void
 sheets_dialog_destroyed (GtkWidget *widget, gpointer user_data)
@@ -57,9 +58,6 @@ sheets_dialog_destroyed (GtkWidget *widget, gpointer user_data)
   g_object_set_data (G_OBJECT(widget), "_sheet_dialogs_builder", NULL);
 }
 
-/* FIXME: header? */
-gchar *build_ui_filename (const gchar* name);
-
 static GtkBuilder *
 builder_new_from_file (const char *filename)
 {
diff --git a/app/sheets_dialog_callbacks.c b/app/sheets_dialog_callbacks.c
index d079fbb2..a8f07b7a 100644
--- a/app/sheets_dialog_callbacks.c
+++ b/app/sheets_dialog_callbacks.c
@@ -865,7 +865,7 @@ on_sheets_new_dialog_button_ok_clicked (GtkButton       *button,
       entry = lookup_widget(sheets_new_dialog, "entry_sheet_description");
       sheet_descrip = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1);
 
-      sheet = g_new0(Sheet, 1);
+      sheet = g_object_new (DIA_TYPE_SHEET, NULL);
       sheet->name = sheet_name;
       sheet->filename = "";
       sheet->description = sheet_descrip;
@@ -1797,7 +1797,7 @@ on_sheets_dialog_button_apply_clicked  (GtkButton       *button,
       sheet_object_mods_list = sm->sheet.objects;
       sm->sheet.objects = NULL;
       /* we have to transfer 'permanent' memory */
-      new_sheet = g_new0 (Sheet, 1);
+      new_sheet = g_object_new (DIA_TYPE_SHEET, NULL);
       *new_sheet = sm->sheet;
       register_sheet(new_sheet);
 
diff --git a/app/toolbox.c b/app/toolbox.c
index 2657aa09..50ab4df3 100644
--- a/app/toolbox.c
+++ b/app/toolbox.c
@@ -26,6 +26,7 @@
 #include "sheet.h"
 #include "dia-colour-area.h"
 #include "dia-line-width-area.h"
+#include "widgets/dia-sheet-chooser.h"
 #include "intl.h"
 #include "message.h"
 #include "object.h"
@@ -60,9 +61,6 @@ static GtkTargetEntry toolbox_target_table[] =
 static guint toolbox_n_targets = (sizeof (toolbox_target_table) /
                                  sizeof (toolbox_target_table[0]));
 
-static GtkWidget *sheet_option_menu;
-static GtkWidget *sheet_wbox;
-
 GtkWidget *modify_tool_button;
 gchar *interface_current_sheet_name;
 static GSList *tool_group = NULL;
@@ -245,20 +243,15 @@ static void
 fill_sheet_wbox (DiaToolbox *self, DiaSheet *sheet)
 {
   int i = 0;
-  int rows;
   GSList *tmp;
   GtkWidget *first_button = NULL;
-
-  gtk_container_foreach(GTK_CONTAINER(sheet_wbox),
-                       (GtkCallback)gtk_widget_destroy, NULL);
-  tool_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(tool_widgets[0]));
+  gtk_container_foreach (GTK_CONTAINER (self->items),
+                         (GtkCallback) gtk_widget_destroy, NULL);
+  tool_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (tool_widgets[0]));
 
   /* Remember sheet 'name' for 'Sheets and Objects' dialog */
   interface_current_sheet_name = sheet->name;
 
-  /* set the aspect ratio on the wbox */
-  rows = ceil(g_slist_length(sheet->objects) / (double)COLUMNS);
-  if (rows<1) rows = 1;
   for (tmp = sheet->objects; tmp != NULL; tmp = tmp->next) {
     SheetObject *sheet_obj = tmp->data;
     GdkPixbuf *pixbuf = NULL;
@@ -273,22 +266,22 @@ fill_sheet_wbox (DiaToolbox *self, DiaSheet *sheet)
       
       pixbuf = gdk_pixbuf_new_from_file(sheet_obj->pixmap_file, &gerror);
       if (pixbuf != NULL) {
-          int width = gdk_pixbuf_get_width (pixbuf);
-          int height = gdk_pixbuf_get_height (pixbuf);
-          if (width > 22 && prefs.fixed_icon_size) {
-           GdkPixbuf *cropped;
-           g_warning ("Shape icon '%s' size wrong, cropped.", sheet_obj->pixmap_file);
-           cropped = gdk_pixbuf_new_subpixbuf (pixbuf, 
-                                              (width - 22) / 2, height > 22 ? (height - 22) / 2 : 0, 
-                                              22, height > 22 ? 22 : height);
-           g_object_unref (pixbuf);
-           pixbuf = cropped;
-         }
+        int width = gdk_pixbuf_get_width (pixbuf);
+        int height = gdk_pixbuf_get_height (pixbuf);
+        if (width > 22 && prefs.fixed_icon_size) {
+          GdkPixbuf *cropped;
+          g_warning ("Shape icon '%s' size wrong, cropped.", sheet_obj->pixmap_file);
+          cropped = gdk_pixbuf_new_subpixbuf (pixbuf, 
+                                            (width - 22) / 2, height > 22 ? (height - 22) / 2 : 0, 
+                    22, height > 22 ? 22 : height);
+          g_object_unref (pixbuf);
+          pixbuf = cropped;
+        }
       } else {
-          pixbuf = gdk_pixbuf_new_from_xpm_data (missing);
+        pixbuf = gdk_pixbuf_new_from_xpm_data (missing);
 
-          message_warning("failed to load icon for file\n %s\n cause=%s",
-                          sheet_obj->pixmap_file,gerror?gerror->message:"[NULL]");
+        message_warning("failed to load icon for file\n %s\n cause=%s",
+                        sheet_obj->pixmap_file,gerror?gerror->message:"[NULL]");
       }
     } else {
       DiaObjectType *type;
@@ -307,15 +300,13 @@ fill_sheet_wbox (DiaToolbox *self, DiaSheet *sheet)
     tool_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (button));
 
     gtk_container_add (GTK_CONTAINER (button), image);
-    gtk_widget_show(image);
-
-    gtk_grid_attach (GTK_GRID (self->items), button, i % COLUMNS, i / COLUMNS, 1, 1);
-    gtk_widget_show(button);
+    gtk_widget_show (image);
 
     if (sheet_obj->line_break) {
-      g_message ("Got a line break!");
-      i += i % COLUMNS;
+      i += COLUMNS - (i % COLUMNS);
     }
+    gtk_grid_attach (GTK_GRID (self->items), button, i % COLUMNS, i / COLUMNS, 1, 1);
+    gtk_widget_show (button);
 
     data = g_new(ToolButtonData, 1);
     data->type = CREATE_OBJECT_TOOL;
@@ -346,148 +337,59 @@ fill_sheet_wbox (DiaToolbox *self, DiaSheet *sheet)
 }
 
 static void
-sheet_option_menu_changed (GtkListBox    *box,
-                           GtkListBoxRow *row,
-                           DiaToolbox    *self)
-{
-  char *string;
-  DiaSheet *sheet;
-
-  g_return_if_fail (DIA_IS_LIST_ITEM (row));
-
-  string = dia_list_item_get_value (DIA_LIST_ITEM (row));
-  sheet = get_sheet_by_name (string);
-
-  if (sheet == NULL) {
-    message_warning (_("No sheet named %s"), string);
-  } else {
-    persistence_set_string ("last-sheet-selected", string);
-    fill_sheet_wbox (self, sheet);
-  }
-  g_free (string);
-}
-
-static int
-cmp_names (const void *a, const void *b)
-{
-  return g_utf8_collate(gettext( (gchar *)a ), gettext( (gchar *)b ));
-}
-
-static GList *
-get_sheet_names()
-{
-  GSList *tmp;
-  GList *names = NULL;
-  for (tmp = get_sheets_list(); tmp != NULL; tmp = tmp->next) {
-    DiaSheet *sheet = tmp->data;
-    names = g_list_append(names, sheet->name);
-  }
-  /* Already sorted in lib/ but here we sort by the localized (display-)name */
-  return g_list_sort (names, cmp_names);
-}
-
-#define DIA_TYPE_SHEET_META (dia_sheet_meta_get_type ())
-G_DECLARE_FINAL_TYPE (DiaSheetMeta, dia_sheet_meta, DIA, SHEET_META, GObject)
-
-struct _DiaSheetMeta {
-  GObject parent;
-  gchar *name;
-};
-
-G_DEFINE_TYPE (DiaSheetMeta, dia_sheet_meta, G_TYPE_OBJECT)
-
-static void
-dia_sheet_meta_class_init (DiaSheetMetaClass *klass)
-{
-
-}
-
-static void
-dia_sheet_meta_init (DiaSheetMeta *self)
-{
-  
-}
-
-static GtkWidget *
-render_row (gpointer item, gpointer user_data)
+sheet_selected (DiaSheetChooser *chooser,
+                DiaSheet        *sheet,
+                DiaToolbox      *self)
 {
-  GtkWidget *tmp = dia_list_item_new_with_label (DIA_SHEET_META (item)->name);
-  gtk_widget_show_all (tmp);
-  return tmp;
+  persistence_set_string ("last-sheet-selected", DIA_SHEET (sheet)->name);
+  fill_sheet_wbox (self, sheet);
 }
 
 static void
 create_sheet_dropdown_menu (DiaToolbox *self)
 {
-  GListStore *sheets = g_list_store_new (DIA_TYPE_SHEET_META);
-  GList *sheet_names = get_sheet_names();
-  DiaSheetMeta *meta;
-  GList *l;
-  GtkWidget *popover;
-  GtkWidget *frame;
-  GtkWidget *wrap;
-  GtkWidget *list;
-
-  if (sheet_option_menu != NULL) {
-    gtk_container_remove (GTK_CONTAINER (self), sheet_option_menu);
-    sheet_option_menu = NULL;
-  }
-
-  meta = g_object_new (DIA_TYPE_SHEET_META, NULL);
-  meta->name = "Assorted";
-  g_list_store_append (sheets, meta);
-
-  meta = g_object_new (DIA_TYPE_SHEET_META, NULL);
-  meta->name = "Flowchart";
-  g_list_store_append (sheets, meta);
-
-  meta = g_object_new (DIA_TYPE_SHEET_META, NULL);
-  meta->name = "UML";
-  g_list_store_append (sheets, meta);
-
-  for (l = sheet_names; l != NULL; l = l->next) {
-    meta = g_object_new (DIA_TYPE_SHEET_META, NULL);
-    meta->name = l->data;
-    g_list_store_append (sheets, meta);
+  GSList *sheets = get_sheets_list();
+  GSList *l;
+  GtkWidget *button;
+  DiaSheet *tmp;
+
+  self->sheets = g_list_store_new (DIA_TYPE_SHEET);
+
+  /* TODO: Handle this & translations better */
+  tmp = get_sheet_by_name ("Assorted");
+  g_object_set_data (G_OBJECT (tmp), "dia-list-top", GINT_TO_POINTER (TRUE));
+  g_list_store_append (self->sheets, tmp);
+  tmp = get_sheet_by_name ("Flowchart");
+  g_object_set_data (G_OBJECT (tmp), "dia-list-top", GINT_TO_POINTER (TRUE));
+  g_list_store_append (self->sheets, tmp);
+  tmp = get_sheet_by_name ("UML");
+  g_object_set_data (G_OBJECT (tmp), "dia-list-top", GINT_TO_POINTER (TRUE));
+  g_list_store_append (self->sheets, tmp);
+
+  for (l = sheets; l != NULL; l = l->next) {
+    if (g_strcmp0 (DIA_SHEET (l->data)->name, "Assorted") == 0 ||
+        g_strcmp0 (DIA_SHEET (l->data)->name, "Flowchart") == 0 ||
+        g_strcmp0 (DIA_SHEET (l->data)->name, "UML") == 0) {
+      continue;
+    }
+    g_list_store_append (self->sheets, DIA_SHEET (l->data));
   }
 
-  popover = gtk_popover_new (NULL);
-  frame = gtk_frame_new (NULL);
-  gtk_container_add (GTK_CONTAINER (popover), frame);
-  wrap = g_object_new (GTK_TYPE_SCROLLED_WINDOW,
-                       "min-content-width", 200,
-                       "min-content-height", 200,
-                       NULL);
-  gtk_container_add (GTK_CONTAINER (frame), wrap);
-  list = gtk_list_box_new ();
-  gtk_container_add (GTK_CONTAINER (wrap), list);
-  gtk_widget_show_all (frame);
-
-  gtk_list_box_set_selection_mode (GTK_LIST_BOX (list), GTK_SELECTION_SINGLE);
-  gtk_list_box_bind_model (GTK_LIST_BOX (list), G_LIST_MODEL (sheets), render_row, NULL, NULL);
-
-  // TODO: Display selected, Show recent on top, Persistance
-  sheet_option_menu = gtk_menu_button_new ();
-  gtk_menu_button_set_popover (GTK_MENU_BUTTON (sheet_option_menu), popover);
-
-  g_signal_connect (G_OBJECT (list), "row-selected",
-                    G_CALLBACK(sheet_option_menu_changed), self);
-  gtk_box_pack_start (GTK_BOX (self), sheet_option_menu, FALSE, FALSE, 0);
-  gtk_widget_show(sheet_option_menu);
+  button = dia_sheet_chooser_new ();
+  g_signal_connect (G_OBJECT (button), "sheet-selected",
+                    G_CALLBACK (sheet_selected), self);
+  dia_sheet_chooser_set_model (DIA_SHEET_CHOOSER (button), G_LIST_MODEL (self->sheets));
+  gtk_box_pack_start (GTK_BOX (self), button, FALSE, FALSE, 0);
+  gtk_widget_show (button);
 }
 
 static void
 create_sheets (DiaToolbox *self)
 {
-  GtkWidget *separator;
   GtkWidget *swin;
   gchar *sheetname;
   DiaSheet *sheet;
   
-  separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
-  gtk_box_pack_start (GTK_BOX (self), separator, FALSE, FALSE, 0);
-  gtk_widget_show (separator);
-
   create_sheet_dropdown_menu (self);
 
   swin = gtk_scrolled_window_new (NULL, NULL);
@@ -498,24 +400,20 @@ create_sheets (DiaToolbox *self)
   gtk_box_pack_start (GTK_BOX (self), swin, FALSE, FALSE, 0);
   gtk_widget_show (swin);
 
-  self->items = gtk_grid_new ();
+  self->items = g_object_new (GTK_TYPE_GRID,
+                              "column-homogeneous", TRUE,
+                              "column-spacing", 4,
+                              "row-spacing", 4,
+                              NULL);
   gtk_container_add (GTK_CONTAINER (swin), self->items);
   gtk_widget_show (self->items);
 
   sheetname = persistence_register_string ("last-sheet-selected", _("Flowchart"));
   sheet = get_sheet_by_name (sheetname);
-  if (sheet == NULL) {
-    /* Couldn't find it */
-  } else {
+  if (sheet != NULL) {
     fill_sheet_wbox (self, sheet);
-    /* TODO: dia_dynamic_menu_select_entry(DIA_DYNAMIC_MENU(sheet_option_menu),
-                                 sheetname); */
   }
   g_free (sheetname);
-
-  separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
-  gtk_box_pack_end (GTK_BOX (self), separator, FALSE, FALSE, 0);
-  gtk_widget_show (separator);
 }
 
 static void
@@ -789,8 +687,11 @@ dia_toolbox_class_init (DiaToolboxClass *class)
 static void
 dia_toolbox_init (DiaToolbox *self)
 {
-  gtk_orientable_set_orientation (GTK_ORIENTABLE (self), GTK_ORIENTATION_VERTICAL);
-  gtk_box_set_spacing (GTK_BOX (self), 9);
+  g_object_set (G_OBJECT (self),
+                "orientation", GTK_ORIENTATION_VERTICAL,
+                "spacing", 8,
+                "margin", 8,
+                NULL);
   gtk_widget_show (GTK_WIDGET (self));
 
   create_tools (self);
diff --git a/app/toolbox.h b/app/toolbox.h
index 1b6bf966..60c1f600 100644
--- a/app/toolbox.h
+++ b/app/toolbox.h
@@ -8,8 +8,9 @@ G_DECLARE_FINAL_TYPE (DiaToolbox, dia_toolbox, DIA, TOOLBOX, GtkBox)
 struct _DiaToolbox {
   GtkBox parent;
 
-  GtkWidget *tools;
-  GtkWidget *items;
+  GtkWidget  *tools;
+  GtkWidget  *items;
+  GListStore *sheets;
 };
 
 typedef struct _ToolButton ToolButton;
diff --git a/app/widgets/dia-sheet-chooser.c b/app/widgets/dia-sheet-chooser.c
new file mode 100644
index 00000000..d28739b9
--- /dev/null
+++ b/app/widgets/dia-sheet-chooser.c
@@ -0,0 +1,226 @@
+#include <gtk/gtk.h>
+
+#include "dia-sheet-chooser.h"
+#include "dia_dirs.h"
+
+G_DEFINE_TYPE (DiaSheetChooserPopover, dia_sheet_chooser_popover, GTK_TYPE_POPOVER)
+
+enum {
+  SHEET_SELECTED,
+  LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+static guint popover_signals[LAST_SIGNAL] = { 0 };
+
+static void
+dia_sheet_chooser_popover_class_init (DiaSheetChooserPopoverClass *klass)
+{
+  GFile *template_file;
+  GBytes *template;
+  GError *err = NULL;
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  popover_signals[SHEET_SELECTED] = g_signal_new ("sheet-selected",
+                                                  G_TYPE_FROM_CLASS (klass),
+                                                  G_SIGNAL_RUN_FIRST,
+                                                  0, NULL, NULL, NULL,
+                                                  G_TYPE_NONE, 1,
+                                                  DIA_TYPE_SHEET);
+
+  /* TODO: Use GResource */
+  template_file = g_file_new_for_path (build_ui_filename ("ui/dia-sheet-chooser-popover.ui"));
+  template = g_file_load_bytes (template_file, NULL, NULL, &err);
+
+  if (err)
+    g_critical ("Failed to load template: %s", err->message);
+
+  gtk_widget_class_set_template (widget_class, template);
+  gtk_widget_class_bind_template_child (widget_class, DiaSheetChooserPopover, list);
+  gtk_widget_class_bind_template_child (widget_class, DiaSheetChooserPopover, filter);
+
+  g_object_unref (template_file);
+}
+
+static GtkWidget *
+render_row (gpointer item, gpointer user_data)
+{
+  GtkWidget *row;
+  GtkWidget *box;
+  GtkWidget *name;
+  GtkWidget *desc;
+
+  row = gtk_list_box_row_new ();
+  /* TODO: Let's avoid the trap of set_data */
+  g_object_set_data (G_OBJECT (row), "dia-sheet", item);
+  g_object_set_data (G_OBJECT (row),
+                     "dia-list-top",
+                     g_object_get_data (G_OBJECT (item), "dia-list-top"));
+  gtk_widget_set_tooltip_markup (row,
+                                 g_strdup_printf ("<b>%s</b>\n%s",
+                                                  DIA_SHEET (item)->name,
+                                                  DIA_SHEET (item)->description));
+  gtk_widget_show (row);
+
+  box = g_object_new (GTK_TYPE_BOX,
+                      "orientation", GTK_ORIENTATION_VERTICAL,
+                      "spacing", 2,
+                      "margin", 4,
+                      NULL);
+  gtk_container_add (GTK_CONTAINER (row), box);
+  gtk_widget_show (box);
+
+  name = g_object_new (GTK_TYPE_LABEL,
+                       "label", DIA_SHEET (item)->name,
+                       "xalign", 0.0,
+                       "ellipsize", PANGO_ELLIPSIZE_END,
+                       "max-width-chars", 25,
+                       NULL);
+  gtk_widget_show (name);
+  gtk_box_pack_start (GTK_BOX (box), name, FALSE, FALSE, 0);
+
+  desc = g_object_new (GTK_TYPE_LABEL,
+                       "label", DIA_SHEET (item)->description,
+                       "xalign", 0.0,
+                       "ellipsize", PANGO_ELLIPSIZE_END,
+                       "max-width-chars", 25,
+                       NULL);
+  gtk_style_context_add_class (gtk_widget_get_style_context (desc),
+                               GTK_STYLE_CLASS_DIM_LABEL);
+  gtk_widget_show (desc);
+  gtk_box_pack_start (GTK_BOX (box), desc, FALSE, FALSE, 0);
+
+  return row;
+}
+
+static void
+header_func (GtkListBoxRow *row,
+             GtkListBoxRow *before,
+             gpointer user_data)
+{
+  gboolean last = FALSE;
+  gboolean this = FALSE;
+
+  if (before)
+    last = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (before), "dia-list-top"));
+  this = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (row), "dia-list-top"));
+
+  if (last && !this) {
+    GtkWidget *sep = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
+    gtk_widget_show (sep);
+    gtk_list_box_row_set_header (row, sep);
+  }
+}
+
+static void
+sheet_selected (GtkListBox             *box,
+                GtkListBoxRow          *row,
+                DiaSheetChooserPopover *self)
+{
+  DiaSheet *sheet = g_object_get_data (G_OBJECT (row), "dia-sheet");
+
+  g_signal_emit_by_name (G_OBJECT (self), "sheet-selected", sheet);
+}
+
+static void
+sheet_activated (GtkListBox             *box,
+                 GtkListBoxRow          *row,
+                 DiaSheetChooserPopover *self)
+{
+  gtk_popover_popdown (GTK_POPOVER (self));
+}
+
+static void
+dia_sheet_chooser_popover_init (DiaSheetChooserPopover *self)
+{
+  gtk_widget_init_template (GTK_WIDGET (self));
+
+  gtk_list_box_set_header_func (GTK_LIST_BOX (self->list),
+                                header_func, NULL, NULL);
+
+  g_signal_connect (G_OBJECT (self->list), "row-selected",
+                    G_CALLBACK (sheet_selected), self);
+  g_signal_connect (G_OBJECT (self->list), "row-activated",
+                    G_CALLBACK (sheet_activated), self);
+}
+
+void
+dia_sheet_chooser_popover_set_model (DiaSheetChooserPopover *self,
+                                     GListModel             *model)
+{
+  gtk_list_box_bind_model (GTK_LIST_BOX (self->list),
+                           G_LIST_MODEL (model),
+                           render_row, NULL, NULL);
+}
+
+GtkWidget *
+dia_sheet_chooser_popover_new ()
+{
+  return g_object_new (DIA_TYPE_SHEET_CHOOSER_POPOVER, NULL);
+}
+
+G_DEFINE_TYPE (DiaSheetChooser, dia_sheet_chooser, GTK_TYPE_MENU_BUTTON)
+
+static void
+propagate (DiaSheetChooserPopover *chooser,
+           DiaSheet               *sheet,
+           DiaSheetChooser        *self)
+{
+  gtk_label_set_label (GTK_LABEL (self->label), sheet->name);
+
+  g_signal_emit_by_name (G_OBJECT (self), "sheet-selected", sheet);
+}
+
+static void
+dia_sheet_chooser_class_init (DiaSheetChooserClass *klass)
+{
+  signals[SHEET_SELECTED] = g_signal_new ("sheet-selected",
+                                          G_TYPE_FROM_CLASS (klass),
+                                          G_SIGNAL_RUN_FIRST,
+                                          0, NULL, NULL, NULL,
+                                          G_TYPE_NONE, 1,
+                                          DIA_TYPE_SHEET);
+}
+
+static void
+dia_sheet_chooser_init (DiaSheetChooser *self)
+{
+  GtkWidget *box;
+  GtkWidget *arrow;
+
+  box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 16);
+  gtk_widget_show (box);
+  gtk_container_add (GTK_CONTAINER (self), box);
+
+  self->label = g_object_new (GTK_TYPE_LABEL,
+                              "label", "[NONE]",
+                              "ellipsize", PANGO_ELLIPSIZE_END,
+                              "max-width-chars", 14,
+                              "xalign", 0.0,
+                              NULL);
+  gtk_widget_show (self->label);
+  gtk_box_pack_start (GTK_BOX (box), self->label, TRUE, TRUE, 0);
+
+  arrow = gtk_image_new_from_icon_name ("pan-down-symbolic", GTK_ICON_SIZE_BUTTON);
+  gtk_widget_show (arrow);
+  gtk_box_pack_end (GTK_BOX (box), arrow, FALSE, FALSE, 0);
+
+  self->popover = dia_sheet_chooser_popover_new ();
+  g_signal_connect (G_OBJECT (self->popover), "sheet-selected",
+                    G_CALLBACK (propagate), self);
+  gtk_menu_button_set_popover (GTK_MENU_BUTTON (self), self->popover);
+}
+
+void
+dia_sheet_chooser_set_model (DiaSheetChooser *self,
+                             GListModel      *model)
+{
+  dia_sheet_chooser_popover_set_model (DIA_SHEET_CHOOSER_POPOVER (self->popover),
+                                       model);
+}
+
+GtkWidget *
+dia_sheet_chooser_new ()
+{
+  return g_object_new (DIA_TYPE_SHEET_CHOOSER, NULL);
+}
diff --git a/app/widgets/dia-sheet-chooser.h b/app/widgets/dia-sheet-chooser.h
new file mode 100644
index 00000000..a37c0116
--- /dev/null
+++ b/app/widgets/dia-sheet-chooser.h
@@ -0,0 +1,35 @@
+#include <gtk/gtk.h>
+
+#include "sheet.h"
+
+G_BEGIN_DECLS
+
+#define DIA_TYPE_SHEET_CHOOSER_POPOVER (dia_sheet_chooser_popover_get_type ())
+G_DECLARE_FINAL_TYPE (DiaSheetChooserPopover, dia_sheet_chooser_popover, DIA, SHEET_CHOOSER_POPOVER, 
GtkPopover)
+
+struct _DiaSheetChooserPopover {
+  GtkPopover parent;
+
+  GtkWidget  *filter;
+  GtkWidget  *list;
+};
+
+void       dia_sheet_chooser_popover_set_model (DiaSheetChooserPopover *self,
+                                                GListModel             *model);
+
+
+#define DIA_TYPE_SHEET_CHOOSER (dia_sheet_chooser_get_type ())
+G_DECLARE_FINAL_TYPE (DiaSheetChooser, dia_sheet_chooser, DIA, SHEET_CHOOSER, GtkMenuButton)
+
+struct _DiaSheetChooser {
+  GtkMenuButton parent;
+
+  GtkWidget *label;
+  GtkWidget *popover;
+};
+
+GtkWidget *dia_sheet_chooser_new               ();
+void       dia_sheet_chooser_set_model         (DiaSheetChooser *self,
+                                                GListModel      *model);
+
+G_END_DECLS
\ No newline at end of file
diff --git a/data/dia-sheet-chooser-popover.ui b/data/dia-sheet-chooser-popover.ui
new file mode 100644
index 00000000..0317086b
--- /dev/null
+++ b/data/dia-sheet-chooser-popover.ui
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface>
+  <requires lib="gtk+" version="3.20"/>
+  <template class="DiaSheetChooserPopover" parent="GtkPopover">
+    <property name="can_focus">False</property>
+    <child>
+      <object class="GtkBox">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="margin_left">8</property>
+        <property name="margin_right">8</property>
+        <property name="margin_top">8</property>
+        <property name="margin_bottom">8</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">8</property>
+        <child>
+          <object class="GtkSearchEntry" id="filter">
+            <property name="visible">True</property>
+            <property name="sensitive">False</property>
+            <property name="can_focus">True</property>
+            <property name="primary_icon_name">edit-find-symbolic</property>
+            <property name="primary_icon_activatable">False</property>
+            <property name="primary_icon_sensitive">False</property>
+            <property name="secondary_icon_tooltip_text" translatable="yes">TODO: Add filter</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkScrolledWindow">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="hscrollbar_policy">never</property>
+            <property name="shadow_type">etched-in</property>
+            <property name="min_content_width">200</property>
+            <property name="min_content_height">200</property>
+            <property name="max_content_width">300</property>
+            <property name="max_content_height">300</property>
+            <property name="propagate_natural_width">True</property>
+            <property name="propagate_natural_height">True</property>
+            <child>
+              <object class="GtkViewport">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="shadow_type">none</property>
+                <child>
+                  <object class="GtkListBox" id="list">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/lib/dia-line-style-selector-popover.c b/lib/dia-line-style-selector-popover.c
index a04cb049..3e0d153c 100644
--- a/lib/dia-line-style-selector-popover.c
+++ b/lib/dia-line-style-selector-popover.c
@@ -23,23 +23,6 @@ enum {
 
 static guint signals[LAST_SIGNAL] = { 0 };
 
-static gchar*
-build_ui_filename (const gchar* name)
-{
-  gchar* uifile;
-
-  if (g_getenv ("DIA_BASE_PATH") != NULL) {
-    /* a small hack cause the final destination and the local path differ */
-    const gchar* p = strrchr (name, '/');
-    if (p != NULL)
-      name = p+1;
-    uifile = g_build_filename (g_getenv ("DIA_BASE_PATH"), "data", name, NULL);
-  } else
-    uifile = dia_get_data_directory (name);
-
-  return uifile;
-}
-
 GtkWidget *
 dia_line_style_selector_popover_new ()
 {
diff --git a/lib/dia_dirs.c b/lib/dia_dirs.c
index 99e8590c..65abe8ef 100644
--- a/lib/dia_dirs.c
+++ b/lib/dia_dirs.c
@@ -367,3 +367,20 @@ dia_absolutize_filename (const gchar *master, const gchar *slave)
   g_free (path);
   return result;
 }
+
+gchar*
+build_ui_filename (const gchar* name)
+{
+  gchar* uifile;
+
+  if (g_getenv ("DIA_BASE_PATH") != NULL) {
+    /* a small hack cause the final destination and the local path differ */
+    const gchar* p = strrchr (name, '/');
+    if (p != NULL)
+      name = p+1;
+    uifile = g_build_filename (g_getenv ("DIA_BASE_PATH"), "data", name, NULL);
+  } else
+    uifile = dia_get_data_directory (name);
+
+  return uifile;
+}
diff --git a/lib/dia_dirs.h b/lib/dia_dirs.h
index c0cbff05..52c01bd4 100644
--- a/lib/dia_dirs.h
+++ b/lib/dia_dirs.h
@@ -38,4 +38,6 @@ gchar *dia_absolutize_filename (const gchar *master, const gchar *slave);
 gchar *dia_get_canonical_path (const gchar *path);
 const gchar *dia_message_filename (const gchar *filename);
 
+gchar *build_ui_filename (const gchar* name);
+
 #endif /* DIA_DIRS_H */
diff --git a/lib/diatypes.h b/lib/diatypes.h
index 64ed4f80..4ae01b69 100644
--- a/lib/diatypes.h
+++ b/lib/diatypes.h
@@ -157,7 +157,6 @@ typedef struct _PropDescSArrayExtra PropDescSArrayExtra;
 typedef struct _PropOffset PropOffset;
 
 /* In sheet.h: */
-typedef struct _Sheet Sheet;
 typedef struct _SheetObject SheetObject;
 
 /* In text.h: */
diff --git a/lib/sheet.c b/lib/sheet.c
index 698b750f..378c535c 100644
--- a/lib/sheet.c
+++ b/lib/sheet.c
@@ -41,15 +41,29 @@
 #include "object-alias.h"
 #include "dia_dirs.h"
 
+G_DEFINE_TYPE (DiaSheet, dia_sheet, G_TYPE_OBJECT)
+
 static GSList *sheets = NULL;
 
-Sheet *
-new_sheet(char *name, gchar *description, char *filename, SheetScope scope,
-          Sheet *shadowing)
+static void
+dia_sheet_class_init (DiaSheetClass *klass)
+{
+
+}
+
+static void
+dia_sheet_init (DiaSheet *self)
+{
+  
+}
+
+DiaSheet *
+dia_sheet_new (char *name, gchar *description, char *filename, SheetScope scope,
+          DiaSheet *shadowing)
 {
-  Sheet *sheet;
+  DiaSheet *sheet;
 
-  sheet = g_new(Sheet, 1);
+  sheet = g_object_new (DIA_TYPE_SHEET, NULL);
 
   sheet->name = g_strdup(name);
   sheet->description = g_strdup(description);
@@ -62,7 +76,7 @@ new_sheet(char *name, gchar *description, char *filename, SheetScope scope,
 }
 
 void
-sheet_prepend_sheet_obj(Sheet *sheet, SheetObject *obj)
+sheet_prepend_sheet_obj(DiaSheet *sheet, SheetObject *obj)
 {
   DiaObjectType *type;
 
@@ -77,7 +91,7 @@ sheet_prepend_sheet_obj(Sheet *sheet, SheetObject *obj)
 }
 
 void
-sheet_append_sheet_obj(Sheet *sheet, SheetObject *obj)
+sheet_append_sheet_obj(DiaSheet *sheet, SheetObject *obj)
 {
   DiaObjectType *type;
 
@@ -92,7 +106,7 @@ sheet_append_sheet_obj(Sheet *sheet, SheetObject *obj)
 }
 
 void
-register_sheet(Sheet *sheet)
+register_sheet(DiaSheet *sheet)
 {
   sheets = g_slist_append(sheets, (gpointer) sheet);
 }
@@ -114,8 +128,8 @@ static void load_register_sheet(const gchar *directory,const gchar *filename,
 static gint
 dia_sheet_sort_callback(gconstpointer a, gconstpointer b)
 {
-  return g_utf8_collate(gettext( ((Sheet *)(a))->name ),
-                       gettext( ((Sheet *)(b))->name ));
+  return g_utf8_collate(gettext( ((DiaSheet *)(a))->name ),
+                       gettext( ((DiaSheet *)(b))->name ));
 }
 
 void
@@ -205,12 +219,12 @@ load_register_sheet(const gchar *dirname, const gchar *filename,
   gchar *name = NULL, *description = NULL;
   int name_score = -1;
   int descr_score = -1;
-  Sheet *sheet = NULL;
+  DiaSheet *sheet = NULL;
   GSList *sheetp;
   gboolean set_line_break = FALSE;
   gboolean name_is_gmalloced = FALSE;
-  Sheet *shadowing = NULL;
-  Sheet *shadowing_sheet = NULL;
+  DiaSheet *shadowing = NULL;
+  DiaSheet *shadowing_sheet = NULL;
 
   /* the XML fun begins here. */
 
@@ -302,12 +316,12 @@ load_register_sheet(const gchar *dirname, const gchar *filename,
   sheetp = get_sheets_list();
   while (sheetp)
   {
-    if (sheetp->data && !strcmp(((Sheet *)(sheetp->data))->name, name)) 
+    if (sheetp->data && !strcmp(((DiaSheet *)(sheetp->data))->name, name)) 
     {
       struct stat first_file, this_file;
       int stat_ret;
       
-      stat_ret = g_stat(((Sheet *)(sheetp->data))->filename, &first_file);
+      stat_ret = g_stat(((DiaSheet *)(sheetp->data))->filename, &first_file);
       g_assert(!stat_ret);
 
       stat_ret = g_stat(filename, &this_file);
@@ -340,7 +354,7 @@ load_register_sheet(const gchar *dirname, const gchar *filename,
     sheetp = g_slist_next(sheetp);
   }
 
-  sheet = new_sheet(name, description, g_strdup(filename), scope, shadowing);
+  sheet = dia_sheet_new(name, description, g_strdup(filename), scope, shadowing);
 
   if (shadowing_sheet)
     shadowing_sheet->shadowing = sheet;                   /* Hilarious :-) */
diff --git a/lib/sheet.h b/lib/sheet.h
index 2c47aed0..8b9b2405 100644
--- a/lib/sheet.h
+++ b/lib/sheet.h
@@ -19,6 +19,7 @@
 #define SHEET_H
 
 #include <glib.h>
+#include <glib-object.h>
 
 #include "diatypes.h"
 
@@ -43,13 +44,18 @@ typedef enum
 }
 SheetScope;
 
-struct _Sheet {
+#define DIA_TYPE_SHEET (dia_sheet_get_type ())
+G_DECLARE_FINAL_TYPE (DiaSheet, dia_sheet, DIA, SHEET, GObject)
+
+struct _DiaSheet {
+  GObject parent;
+
   char *name;
   char *description;
   char *filename;
 
   SheetScope scope;
-  Sheet *shadowing;           /* If (scope == USER), the system sheet that this
+  DiaSheet *shadowing;           /* If (scope == USER), the system sheet that this
                                  user sheet is shadowing.
                                  If (scope == SYSTEM), there has been a name
                                  collision between a system sheet and a user
@@ -60,11 +66,11 @@ struct _Sheet {
   GSList *objects; /* list of SheetObject */
 };
 
-Sheet *new_sheet(char *name, char *description, char *filename,
-                 SheetScope scope, Sheet *shadowing);
-void sheet_prepend_sheet_obj(Sheet *sheet, SheetObject *type);
-void sheet_append_sheet_obj(Sheet *sheet, SheetObject *type);
-void register_sheet(Sheet *sheet);
+DiaSheet *dia_sheet_new (char *name, char *description, char *filename,
+                 SheetScope scope, DiaSheet *shadowing);
+void sheet_prepend_sheet_obj(DiaSheet *sheet, SheetObject *type);
+void sheet_append_sheet_obj(DiaSheet *sheet, SheetObject *type);
+void register_sheet(DiaSheet *sheet);
 GSList *get_sheets_list(void);
 
 void load_all_sheets(void);
diff --git a/lib/widgets/dialist.c b/lib/widgets/dialist.c
index 6383ec68..05396893 100644
--- a/lib/widgets/dialist.c
+++ b/lib/widgets/dialist.c
@@ -514,7 +514,7 @@ dia_list_item_get_value (DiaListItem* self)
   g_return_val_if_fail (self != NULL, NULL);
 
   label = ((DiaListItemPrivate *) dia_list_item_get_instance_private (self))->label;
-  result = gtk_label_get_label (GTK_LABEL (label));
+  result = g_strdup (gtk_label_get_label (GTK_LABEL (label)));
 
   return result;
 }
@@ -528,7 +528,7 @@ dia_list_item_set_value (DiaListItem* self,
   g_return_if_fail (self != NULL);
 
   label = ((DiaListItemPrivate *) dia_list_item_get_instance_private (self))->label;
-  gtk_label_set_label (GTK_LABEL (label), value);
+  gtk_label_set_label (GTK_LABEL (label), g_strdup (value));
 
   g_object_notify_by_pspec ((GObject *) self, dia_list_item_properties[DIA_LIST_ITEM_VALUE_PROPERTY]);
 }
diff --git a/plug-ins/python/pydia-sheet.c b/plug-ins/python/pydia-sheet.c
index 91f3414a..ef877ecc 100644
--- a/plug-ins/python/pydia-sheet.c
+++ b/plug-ins/python/pydia-sheet.c
@@ -25,7 +25,7 @@
 #include <structmember.h> /* PyMemberDef */
 
 PyObject *
-PyDiaSheet_New(Sheet *sheet)
+PyDiaSheet_New(DiaSheet *sheet)
 {
     PyDiaSheet *self;
 
diff --git a/plug-ins/python/pydia-sheet.h b/plug-ins/python/pydia-sheet.h
index 84addc76..5b811605 100644
--- a/plug-ins/python/pydia-sheet.h
+++ b/plug-ins/python/pydia-sheet.h
@@ -6,7 +6,7 @@
 
 typedef struct {
     PyObject_HEAD
-    Sheet *sheet;
+    DiaSheet *sheet;
 } PyDiaSheet;
 
 extern PyTypeObject PyDiaSheet_Type;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]