print: Reimplement collate preview
authorMatthias Clasen <mclasen@redhat.com>
Thu, 8 Jun 2023 04:24:38 +0000 (00:24 -0400)
committerMatthias Clasen <mclasen@redhat.com>
Thu, 8 Jun 2023 23:51:28 +0000 (19:51 -0400)
Redo this with widgets instead of cairo drawing.
The new private widget is called GtkPageThumbnail.

gtk/print/gtkpagethumbnail.c [new file with mode: 0644]
gtk/print/gtkpagethumbnailprivate.h [new file with mode: 0644]
gtk/print/gtkprintunixdialog.c
gtk/print/meson.build
gtk/print/ui/gtkprintunixdialog.ui

diff --git a/gtk/print/gtkpagethumbnail.c b/gtk/print/gtkpagethumbnail.c
new file mode 100644 (file)
index 0000000..a77d4a6
--- /dev/null
@@ -0,0 +1,158 @@
+#include "config.h"
+
+#include "gtkpagethumbnailprivate.h"
+
+enum
+{
+  PROP_PAGE_NUM = 1,
+  NUM_PROPERTIES,
+};
+
+static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
+
+struct _GtkPageThumbnail
+{
+  GtkWidget parent_instance;
+
+  GtkWidget *label;
+  int page_num;
+};
+
+struct _GtkPageThumbnailClass
+{
+  GtkWidgetClass parent_class;
+};
+
+G_DEFINE_TYPE (GtkPageThumbnail, gtk_page_thumbnail, GTK_TYPE_WIDGET)
+
+static void
+gtk_page_thumbnail_init (GtkPageThumbnail *self)
+{
+  self->label = gtk_inscription_new ("0");
+  gtk_widget_set_parent (self->label, GTK_WIDGET (self));
+  gtk_inscription_set_min_chars (GTK_INSCRIPTION (self->label), 1);
+  gtk_inscription_set_nat_chars (GTK_INSCRIPTION (self->label), 1);
+}
+
+static void
+gtk_page_thumbnail_dispose (GObject *object)
+{
+  GtkPageThumbnail *self = GTK_PAGE_THUMBNAIL (object);
+
+  g_clear_pointer (&self->label, gtk_widget_unparent);
+
+  G_OBJECT_CLASS (gtk_page_thumbnail_parent_class)->dispose (object);
+}
+
+static void
+gtk_page_thumbnail_set_property (GObject      *object,
+                                 guint         prop_id,
+                                 const GValue *value,
+                                 GParamSpec   *pspec)
+{
+  GtkPageThumbnail *self = GTK_PAGE_THUMBNAIL (object);
+
+  switch (prop_id)
+    {
+    case PROP_PAGE_NUM:
+      gtk_page_thumbnail_set_page_num (self, g_value_get_int (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_page_thumbnail_get_property (GObject     *object,
+                                 guint        prop_id,
+                                 GValue      *value,
+                                 GParamSpec  *pspec)
+{
+  GtkPageThumbnail *self = GTK_PAGE_THUMBNAIL (object);
+
+  switch (prop_id)
+    {
+    case PROP_PAGE_NUM:
+      g_value_set_int (value, self->page_num);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_page_thumbnail_size_allocate (GtkWidget *widget,
+                                  int        width,
+                                  int        height,
+                                  int        baseline)
+{
+  GtkPageThumbnail *self = GTK_PAGE_THUMBNAIL (widget);
+  GtkRequisition nat;
+  GtkAllocation alloc;
+
+  gtk_widget_get_preferred_size (self->label, NULL, &nat);
+  alloc.x = width - nat.width;
+  alloc.y = height - nat.height;
+  alloc.width = nat.width;
+  alloc.height = nat.height;
+  gtk_widget_size_allocate (self->label, &alloc, -1);
+}
+
+static void
+gtk_page_thumbnail_class_init (GtkPageThumbnailClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
+
+  object_class->dispose = gtk_page_thumbnail_dispose;
+  object_class->set_property = gtk_page_thumbnail_set_property;
+  object_class->get_property = gtk_page_thumbnail_get_property;
+
+  widget_class->size_allocate = gtk_page_thumbnail_size_allocate;
+
+  properties[PROP_PAGE_NUM] =
+      g_param_spec_int ("page-num", NULL, NULL,
+                        0, G_MAXINT, 0, G_PARAM_READWRITE);
+
+  g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
+
+  gtk_widget_class_set_css_name (widget_class, "page-thumbnail");
+}
+
+GtkPageThumbnail *
+gtk_page_thumbnail_new (void)
+{
+  return g_object_new (GTK_TYPE_PAGE_THUMBNAIL, NULL);
+}
+
+void
+gtk_page_thumbnail_set_page_num (GtkPageThumbnail *self,
+                                 int               page_num)
+{
+  g_return_if_fail (GTK_IS_PAGE_THUMBNAIL (self));
+  g_return_if_fail (page_num >= 0);
+  char text[64];
+
+  if (self->page_num == page_num)
+    return;
+
+  self->page_num = page_num;
+
+  g_snprintf (text, sizeof (text), "%d", self->page_num);
+
+  gtk_inscription_set_text (GTK_INSCRIPTION (self->label), text);
+  gtk_widget_queue_draw (GTK_WIDGET (self));
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PAGE_NUM]);
+}
+
+int
+gtk_page_thumbnail_get_page_num (GtkPageThumbnail *self)
+{
+  g_return_val_if_fail (GTK_IS_PAGE_THUMBNAIL (self), 0);
+
+  return self->page_num;
+}
diff --git a/gtk/print/gtkpagethumbnailprivate.h b/gtk/print/gtkpagethumbnailprivate.h
new file mode 100644 (file)
index 0000000..f30a4fd
--- /dev/null
@@ -0,0 +1,12 @@
+#pragma once
+
+#include <gtk/gtk.h>
+
+#define GTK_TYPE_PAGE_THUMBNAIL (gtk_page_thumbnail_get_type ())
+G_DECLARE_FINAL_TYPE (GtkPageThumbnail, gtk_page_thumbnail, GTK, PAGE_THUMBNAIL, GtkWidget)
+
+GtkPageThumbnail * gtk_page_thumbnail_new          (void);
+void               gtk_page_thumbnail_set_page_num (GtkPageThumbnail *self,
+                                                    int               page_num);
+int                gtk_page_thumbnail_get_page_num (GtkPageThumbnail *self);
+
index 5c1c587bb52dbe1c66ff6c36a3789eecd3301e84..36639a30972cc84ffc89cba0b2ecd947bbad6095 100644 (file)
@@ -40,6 +40,7 @@
 #include "gtkprinterprivate.h"
 #include "gtkprinteroptionwidgetprivate.h"
 #include "gtkprintutilsprivate.h"
+#include "gtkpagethumbnailprivate.h"
 
 
 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
@@ -147,11 +148,6 @@ static void     update_print_at_entry_sensitivity  (GtkWidget          *button,
                                                    GtkPrintUnixDialog *dialog);
 static void     update_print_at_option             (GtkPrintUnixDialog *dialog);
 static void     update_dialog_from_capabilities    (GtkPrintUnixDialog *dialog);
-static void     draw_collate                       (GtkDrawingArea     *da,
-                                                   cairo_t            *cr,
-                                                    int                 width,
-                                                    int                 height,
-                                                    gpointer            data);
 static gboolean is_printer_active                  (gpointer            item,
                                                     gpointer            data);
 static  int     default_printer_list_sort_func     (gconstpointer        a,
@@ -258,7 +254,11 @@ struct _GtkPrintUnixDialog
   GtkWidget *copies_spin;
   GtkWidget *collate_check;
   GtkWidget *reverse_check;
-  GtkWidget *collate_image;
+  GtkWidget *page_collate_preview;
+  GtkWidget *page_a1;
+  GtkWidget *page_a2;
+  GtkWidget *page_b1;
+  GtkWidget *page_b2;
   GtkWidget *page_layout_preview;
   GtkWidget *scale_spin;
   GtkWidget *page_set_combo;
@@ -351,12 +351,48 @@ is_default_printer (GtkPrintUnixDialog *dialog,
    return gtk_printer_is_default (printer);
 }
 
+static const char *css_data = ""
+  "page-thumbnail {\n"
+  "  border: 1px solid #e6e5e4;\n"
+  "  background: white;\n"
+  "}\n"
+  "page-thumbnail > label {\n"
+  "  font-family: Sans;\n"
+  "  font-size: 9pt;\n"
+  "  color: #2e3436;\n"
+  "}\n";
+
+static void
+ensure_fallback_style (void)
+{
+  GdkDisplay *display;
+  GtkCssProvider *provider;
+
+  display = gdk_display_get_default ();
+  if (!display)
+    return;
+
+  provider = gtk_css_provider_new ();
+
+  gtk_css_provider_load_from_string (provider, css_data);
+
+  gtk_style_context_add_provider_for_display (display,
+                                              GTK_STYLE_PROVIDER (provider),
+                                              GTK_STYLE_PROVIDER_PRIORITY_FALLBACK);
+
+  g_object_unref (provider);
+}
+
 static void
 gtk_print_unix_dialog_class_init (GtkPrintUnixDialogClass *class)
 {
   GObjectClass *object_class;
   GtkWidgetClass *widget_class;
 
+  ensure_fallback_style ();
+
+  g_type_ensure (GTK_TYPE_PAGE_THUMBNAIL);
+
   object_class = (GObjectClass *) class;
   widget_class = (GtkWidgetClass *) class;
 
@@ -477,7 +513,11 @@ gtk_print_unix_dialog_class_init (GtkPrintUnixDialogClass *class)
   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, copies_spin);
   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, collate_check);
   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, reverse_check);
-  gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, collate_image);
+  gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, page_collate_preview);
+  gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, page_a1);
+  gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, page_a2);
+  gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, page_b1);
+  gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, page_b2);
   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, page_layout_preview);
   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, scale_spin);
   gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, page_set_combo);
@@ -857,20 +897,13 @@ gtk_print_unix_dialog_init (GtkPrintUnixDialog *dialog)
 
   gtk_print_load_custom_papers (dialog->custom_paper_list);
 
-  gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (dialog->collate_image),
-                                  draw_collate,
-                                  dialog, NULL);
   gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (dialog->page_layout_preview),
                                   draw_page,
                                   dialog, NULL);
-
-  gtk_css_node_set_name (gtk_widget_get_css_node (dialog->collate_image), g_quark_from_static_string ("drawing"));
   gtk_css_node_set_name (gtk_widget_get_css_node (dialog->page_layout_preview), g_quark_from_static_string ("drawing"));
 
   dialog->collate_paper_node = gtk_css_node_new();
   gtk_css_node_set_name (dialog->collate_paper_node, g_quark_from_static_string ("paper"));
-  gtk_css_node_set_parent (dialog->collate_paper_node,
-                           gtk_widget_get_css_node (dialog->collate_image));
   g_object_unref (dialog->collate_paper_node);
 
   dialog->page_layout_paper_node = gtk_css_node_new();
@@ -1914,107 +1947,31 @@ static void
 update_collate_icon (GtkToggleButton    *toggle_button,
                      GtkPrintUnixDialog *dialog)
 {
-  gtk_widget_queue_draw (dialog->collate_image);
-}
-
-static void
-paint_page (GtkPrintUnixDialog *dialog,
-            GtkWidget  *widget,
-            cairo_t    *cr,
-            int         x,
-            int         y,
-            const char *text,
-            int         text_x)
-{
-  GtkCssStyle *style;
-  int width, height;
-  int text_y;
-  GdkRGBA color;
-  GtkSnapshot *snapshot;
-  GskRenderNode *node;
-  GtkCssBoxes boxes;
-
-  width = 20;
-  height = 26;
-  text_y = 21;
-
-  style = gtk_css_node_get_style (dialog->collate_paper_node);
-
-  snapshot = gtk_snapshot_new ();
-  gtk_css_boxes_init_border_box (&boxes, style, x, y, width, height);
-  gtk_css_style_snapshot_background (&boxes, snapshot);
-  gtk_css_style_snapshot_border (&boxes, snapshot);
-
-  node = gtk_snapshot_free_to_node (snapshot);
-  if (node)
-    {
-      gsk_render_node_draw (node, cr);
-      gsk_render_node_unref (node);
-    }
-
-  color = *gtk_css_color_value_get_rgba (style->core->color);
-  gdk_cairo_set_source_rgba (cr, &color);
-
-  cairo_select_font_face (cr, "Sans",
-                          CAIRO_FONT_SLANT_NORMAL,
-                          CAIRO_FONT_WEIGHT_NORMAL);
-  cairo_set_font_size (cr, 9);
-  cairo_move_to (cr, x + text_x, y + text_y);
-  cairo_show_text (cr, text);
-}
-
-static void
-draw_collate (GtkDrawingArea *da,
-              cairo_t        *cr,
-              int             width,
-              int             height,
-              gpointer        data)
-{
-  GtkPrintUnixDialog *dialog = GTK_PRINT_UNIX_DIALOG (data);
-  GtkWidget *widget = GTK_WIDGET (da);
-  gboolean collate, reverse, rtl;
+  gboolean collate;
+  gboolean reverse;
   int copies;
-  int text_x;
-  int x, y, x1, x2, p1, p2;
 
   collate = dialog_get_collate (dialog);
   reverse = dialog_get_reverse (dialog);
   copies = dialog_get_n_copies (dialog);
 
-  rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
-
-  x = (width - 30) / 2;
-  y = (height - 36) / 2;
-  if (rtl)
+  if (collate)
     {
-      x1 = x;
-      x2 = x - 36;
-      p1 = 0;
-      p2 = 10;
-      text_x = 4;
+      gtk_page_thumbnail_set_page_num (GTK_PAGE_THUMBNAIL (dialog->page_a1), reverse ? 1 : 2);
+      gtk_page_thumbnail_set_page_num (GTK_PAGE_THUMBNAIL (dialog->page_a2), reverse ? 2 : 1);
+      gtk_page_thumbnail_set_page_num (GTK_PAGE_THUMBNAIL (dialog->page_b1), reverse ? 1 : 2);
+      gtk_page_thumbnail_set_page_num (GTK_PAGE_THUMBNAIL (dialog->page_b2), reverse ? 2 : 1);
     }
   else
     {
-      x1 = x;
-      x2 = x + 36;
-      p1 = 10;
-      p2 = 0;
-      text_x = 11;
-    }
-
-  if (copies == 1)
-    {
-      paint_page (dialog, widget, cr, x1 + p1, y, reverse ? "1" : "2", text_x);
-      paint_page (dialog, widget, cr, x1 + p2, y + 10, reverse ? "2" : "1", text_x);
+      gtk_page_thumbnail_set_page_num (GTK_PAGE_THUMBNAIL (dialog->page_a1), reverse ? 2 : 1);
+      gtk_page_thumbnail_set_page_num (GTK_PAGE_THUMBNAIL (dialog->page_a2), reverse ? 2 : 1);
+      gtk_page_thumbnail_set_page_num (GTK_PAGE_THUMBNAIL (dialog->page_b1), reverse ? 1 : 2);
+      gtk_page_thumbnail_set_page_num (GTK_PAGE_THUMBNAIL (dialog->page_b2), reverse ? 1 : 2);
     }
-  else
-    {
-      paint_page (dialog, widget, cr, x1 + p1, y, collate == reverse ? "1" : "2", text_x);
-      paint_page (dialog, widget, cr, x1 + p2, y + 10, reverse ? "2" : "1", text_x);
 
-      paint_page (dialog, widget, cr, x2 + p1, y, reverse ? "1" : "2", text_x);
-      paint_page (dialog, widget, cr, x2 + p2, y + 10, collate == reverse ? "2" : "1", text_x);
-    }
+  gtk_widget_set_visible (dialog->page_b1, copies > 1);
+  gtk_widget_set_visible (dialog->page_b2, copies > 1);
 }
 
 static gboolean
@@ -2264,7 +2221,7 @@ dialog_get_collate (GtkPrintUnixDialog *dialog)
 {
   if (gtk_widget_is_sensitive (dialog->collate_check))
     return gtk_check_button_get_active (GTK_CHECK_BUTTON (dialog->collate_check));
-  return FALSE;
+  return TRUE;
 }
 
 static void
index a5263da99d20ec396a6dcca9ca51bcaaa08821fc..f113877a5ea2e1d432712a70c15b37ebd1fae88d 100644 (file)
@@ -31,6 +31,7 @@ if os_unix
   gtk_unix_print_sources += files([
     'gtkcustompaperunixdialog.c',
     'gtkpagesetupunixdialog.c',
+    'gtkpagethumbnail.c',
     'gtkprintbackend.c',
     'gtkprinter.c',
     'gtkprinteroption.c',
index d27c585ea2c4a925ed731e62816236f081f674cd..5233cea309762b116ea42adfc0983ade74ccbf76 100644 (file)
                                       </object>
                                     </child>
                                     <child>
-                                      <object class="GtkDrawingArea" id="collate_image">
-                                        <property name="content-width">70</property>
-                                        <property name="content-height">50</property>
+                                      <object class="GtkFixed" id="page_collate_preview">
+                                        <child>
+                                          <object class="GtkPageThumbnail" id="page_a1">
+                                            <property name="page-num">1</property>
+                                            <property name="width-request">32</property>
+                                            <property name="height-request">40</property>
+                                            <layout>
+                                              <property name="transform">translate(17, 0)</property>
+                                            </layout>
+                                          </object>
+                                        </child>
+                                        <child>
+                                          <object class="GtkPageThumbnail" id="page_a2">
+                                            <property name="page-num">2</property>
+                                            <property name="width-request">32</property>
+                                            <property name="height-request">40</property>
+                                            <layout>
+                                              <property name="transform">translate(0, 17)</property>
+                                            </layout>
+                                          </object>
+                                        </child>
+                                        <child>
+                                          <object class="GtkPageThumbnail" id="page_b1">
+                                            <property name="page-num">1</property>
+                                            <property name="width-request">32</property>
+                                            <property name="height-request">40</property>
+                                            <layout>
+                                              <property name="transform">translate(73, 0)</property>
+                                            </layout>
+                                          </object>
+                                        </child>
+                                        <child>
+                                          <object class="GtkPageThumbnail" id="page_b2">
+                                            <property name="page-num">2</property>
+                                            <property name="width-request">32</property>
+                                            <property name="height-request">40</property>
+                                            <layout>
+                                              <property name="transform">translate(56, 17)</property>
+                                            </layout>
+                                          </object>
+                                        </child>
                                         <layout>
                                           <property name="column">1</property>
                                           <property name="row">1</property>