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