1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * gimpcellrendererdashes.c
5  * Copyright (C) 2005 Sven Neumann <sven@gimp.org>
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  */
20 
21 #include <config.h>
22 
23 #include <gtk/gtk.h>
24 
25 #include "widgets-types.h"
26 
27 #include "core/gimpdashpattern.h"
28 
29 #include "gimpcellrendererdashes.h"
30 
31 
32 #define DASHES_WIDTH   96
33 #define DASHES_HEIGHT   4
34 
35 #define N_SEGMENTS     24
36 #define BLOCK_WIDTH    (DASHES_WIDTH / (2 * N_SEGMENTS))
37 
38 
39 enum
40 {
41   PROP_0,
42   PROP_PATTERN
43 };
44 
45 
46 static void gimp_cell_renderer_dashes_finalize     (GObject         *object);
47 static void gimp_cell_renderer_dashes_get_property (GObject         *object,
48                                                     guint            param_id,
49                                                     GValue          *value,
50                                                     GParamSpec      *pspec);
51 static void gimp_cell_renderer_dashes_set_property (GObject         *object,
52                                                     guint            param_id,
53                                                     const GValue    *value,
54                                                     GParamSpec      *pspec);
55 static void gimp_cell_renderer_dashes_get_size     (GtkCellRenderer *cell,
56                                                     GtkWidget       *widget,
57                                                     GdkRectangle    *rectangle,
58                                                     gint            *x_offset,
59                                                     gint            *y_offset,
60                                                     gint            *width,
61                                                     gint            *height);
62 static void gimp_cell_renderer_dashes_render       (GtkCellRenderer *cell,
63                                                     GdkWindow       *window,
64                                                     GtkWidget       *widget,
65                                                     GdkRectangle    *background_area,
66                                                     GdkRectangle    *cell_area,
67                                                     GdkRectangle    *expose_area,
68                                                     GtkCellRendererState flags);
69 
70 
G_DEFINE_TYPE(GimpCellRendererDashes,gimp_cell_renderer_dashes,GTK_TYPE_CELL_RENDERER)71 G_DEFINE_TYPE (GimpCellRendererDashes, gimp_cell_renderer_dashes,
72                GTK_TYPE_CELL_RENDERER)
73 
74 #define parent_class gimp_cell_renderer_dashes_parent_class
75 
76 
77 static void
78 gimp_cell_renderer_dashes_class_init (GimpCellRendererDashesClass *klass)
79 {
80   GObjectClass         *object_class = G_OBJECT_CLASS (klass);
81   GtkCellRendererClass *cell_class   = GTK_CELL_RENDERER_CLASS (klass);
82 
83   object_class->finalize     = gimp_cell_renderer_dashes_finalize;
84   object_class->get_property = gimp_cell_renderer_dashes_get_property;
85   object_class->set_property = gimp_cell_renderer_dashes_set_property;
86 
87   cell_class->get_size       = gimp_cell_renderer_dashes_get_size;
88   cell_class->render         = gimp_cell_renderer_dashes_render;
89 
90   g_object_class_install_property (object_class, PROP_PATTERN,
91                                    g_param_spec_boxed ("pattern", NULL, NULL,
92                                                        GIMP_TYPE_DASH_PATTERN,
93                                                        GIMP_PARAM_WRITABLE));
94 }
95 
96 static void
gimp_cell_renderer_dashes_init(GimpCellRendererDashes * dashes)97 gimp_cell_renderer_dashes_init (GimpCellRendererDashes *dashes)
98 {
99   dashes->segments = g_new0 (gboolean, N_SEGMENTS);
100 }
101 
102 static void
gimp_cell_renderer_dashes_finalize(GObject * object)103 gimp_cell_renderer_dashes_finalize (GObject *object)
104 {
105   GimpCellRendererDashes *dashes = GIMP_CELL_RENDERER_DASHES (object);
106 
107   g_free (dashes->segments);
108 
109   G_OBJECT_CLASS (parent_class)->finalize (object);
110 }
111 
112 static void
gimp_cell_renderer_dashes_get_property(GObject * object,guint param_id,GValue * value,GParamSpec * pspec)113 gimp_cell_renderer_dashes_get_property (GObject    *object,
114                                         guint       param_id,
115                                         GValue     *value,
116                                         GParamSpec *pspec)
117 {
118   G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
119 }
120 
121 static void
gimp_cell_renderer_dashes_set_property(GObject * object,guint param_id,const GValue * value,GParamSpec * pspec)122 gimp_cell_renderer_dashes_set_property (GObject      *object,
123                                         guint         param_id,
124                                         const GValue *value,
125                                         GParamSpec   *pspec)
126 {
127   GimpCellRendererDashes *dashes = GIMP_CELL_RENDERER_DASHES (object);
128 
129   switch (param_id)
130     {
131     case PROP_PATTERN:
132       gimp_dash_pattern_fill_segments (g_value_get_boxed (value),
133                                        dashes->segments, N_SEGMENTS);
134       break;
135 
136     default:
137       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
138       break;
139     }
140 }
141 
142 static void
gimp_cell_renderer_dashes_get_size(GtkCellRenderer * cell,GtkWidget * widget,GdkRectangle * cell_area,gint * x_offset,gint * y_offset,gint * width,gint * height)143 gimp_cell_renderer_dashes_get_size (GtkCellRenderer *cell,
144                                     GtkWidget       *widget,
145                                     GdkRectangle    *cell_area,
146                                     gint            *x_offset,
147                                     gint            *y_offset,
148                                     gint            *width,
149                                     gint            *height)
150 {
151   gfloat xalign, yalign;
152   gint   xpad, ypad;
153 
154   gtk_cell_renderer_get_alignment (cell, &xalign, &yalign);
155   gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
156 
157   if (cell_area)
158     {
159       if (x_offset)
160         {
161           gdouble align;
162 
163           align = ((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) ?
164                    1.0 - xalign : xalign);
165 
166           *x_offset = align * (cell_area->width - DASHES_WIDTH);
167           *x_offset = MAX (*x_offset, 0) + xpad;
168         }
169 
170       if (y_offset)
171         {
172           *y_offset = yalign * (cell_area->height - DASHES_HEIGHT);
173           *y_offset = MAX (*y_offset, 0) + ypad;
174         }
175     }
176   else
177     {
178       if (x_offset)
179         *x_offset = 0;
180 
181       if (y_offset)
182         *y_offset = 0;
183     }
184 
185   *width  = DASHES_WIDTH  + 2 * xpad;
186   *height = DASHES_HEIGHT + 2 * ypad;
187 }
188 
189 static void
gimp_cell_renderer_dashes_render(GtkCellRenderer * cell,GdkWindow * window,GtkWidget * widget,GdkRectangle * background_area,GdkRectangle * cell_area,GdkRectangle * expose_area,GtkCellRendererState flags)190 gimp_cell_renderer_dashes_render (GtkCellRenderer      *cell,
191                                   GdkWindow            *window,
192                                   GtkWidget            *widget,
193                                   GdkRectangle         *background_area,
194                                   GdkRectangle         *cell_area,
195                                   GdkRectangle         *expose_area,
196                                   GtkCellRendererState  flags)
197 {
198   GimpCellRendererDashes *dashes = GIMP_CELL_RENDERER_DASHES (cell);
199   GtkStyle               *style  = gtk_widget_get_style (widget);
200   GtkStateType            state;
201   gint                    xpad, ypad;
202   cairo_t                *cr;
203   gint                    width;
204   gint                    x, y;
205 
206   gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
207 
208   if (! gtk_cell_renderer_get_sensitive (cell))
209     {
210       state = GTK_STATE_INSENSITIVE;
211     }
212   else if ((flags & GTK_CELL_RENDERER_SELECTED) == GTK_CELL_RENDERER_SELECTED)
213     {
214       if (gtk_widget_has_focus (widget))
215         state = GTK_STATE_SELECTED;
216       else
217         state = GTK_STATE_ACTIVE;
218     }
219   else if ((flags & GTK_CELL_RENDERER_PRELIT) == GTK_CELL_RENDERER_PRELIT &&
220            gtk_widget_get_state (widget) == GTK_STATE_PRELIGHT)
221     {
222       state = GTK_STATE_PRELIGHT;
223     }
224   else
225     {
226       if (gtk_widget_is_sensitive (widget))
227         state = GTK_STATE_NORMAL;
228       else
229         state = GTK_STATE_INSENSITIVE;
230     }
231 
232   y = cell_area->y + (cell_area->height - DASHES_HEIGHT) / 2;
233   width = cell_area->width - 2 * xpad;
234 
235   cr = gdk_cairo_create (window);
236 
237   gdk_cairo_rectangle (cr, expose_area);
238   cairo_clip (cr);
239 
240   for (x = 0; x < width + BLOCK_WIDTH; x += BLOCK_WIDTH)
241     {
242       guint index = ((guint) x / BLOCK_WIDTH) % N_SEGMENTS;
243 
244       if (dashes->segments[index])
245         {
246           cairo_rectangle (cr,
247                            cell_area->x + xpad + x, y,
248                            MIN (BLOCK_WIDTH, width - x), DASHES_HEIGHT);
249         }
250     }
251 
252   gdk_cairo_set_source_color (cr, &style->text[state]);
253   cairo_fill (cr);
254 
255   cairo_destroy (cr);
256 }
257 
258 GtkCellRenderer *
gimp_cell_renderer_dashes_new(void)259 gimp_cell_renderer_dashes_new (void)
260 {
261   return g_object_new (GIMP_TYPE_CELL_RENDERER_DASHES, NULL);
262 }
263