1/* GTK - The GIMP Toolkit
2 * Copyright (C) 2012 Red Hat, Inc.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "config.h"
19
20#include "fontplane.h"
21
22enum {
23 PROP_0,
24 PROP_WEIGHT_ADJUSTMENT,
25 PROP_WIDTH_ADJUSTMENT
26};
27
28G_DEFINE_TYPE (GtkFontPlane, gtk_font_plane, GTK_TYPE_WIDGET)
29
30static double
31adjustment_get_normalized_value (GtkAdjustment *adj)
32{
33 return (gtk_adjustment_get_value (adjustment: adj) - gtk_adjustment_get_lower (adjustment: adj)) /
34 (gtk_adjustment_get_upper (adjustment: adj) - gtk_adjustment_get_lower (adjustment: adj));
35}
36
37static void
38val_to_xy (GtkFontPlane *plane,
39 int *x,
40 int *y)
41{
42 double u, v;
43 int width, height;
44
45 width = gtk_widget_get_allocated_width (GTK_WIDGET (plane));
46 height = gtk_widget_get_allocated_height (GTK_WIDGET (plane));
47
48 u = adjustment_get_normalized_value (adj: plane->width_adj);
49 v = adjustment_get_normalized_value (adj: plane->weight_adj);
50
51 *x = CLAMP (width * u, 0, width - 1);
52 *y = CLAMP (height * (1 - v), 0, height - 1);
53}
54
55static void
56plane_snapshot (GtkWidget *widget,
57 GtkSnapshot *snapshot)
58{
59 GtkFontPlane *plane = GTK_FONT_PLANE (widget);
60 int x, y;
61 int width, height;
62 cairo_t *cr;
63
64 val_to_xy (plane, x: &x, y: &y);
65 width = gtk_widget_get_allocated_width (widget);
66 height = gtk_widget_get_allocated_height (widget);
67
68 cr = gtk_snapshot_append_cairo (snapshot,
69 bounds: &GRAPHENE_RECT_INIT (0, 0, width, height));
70
71 cairo_set_source_rgb (cr, red: 0, green: 0, blue: 0);
72 cairo_rectangle (cr, x: 0, y: 0, width, height);
73 cairo_paint (cr);
74
75 cairo_move_to (cr, x: 0, y: y + 0.5);
76 cairo_line_to (cr, x: width, y: y + 0.5);
77
78 cairo_move_to (cr, x: x + 0.5, y: 0);
79 cairo_line_to (cr, x: x + 0.5, y: height);
80
81 if (gtk_widget_has_visible_focus (widget))
82 {
83 cairo_set_line_width (cr, width: 3.0);
84 cairo_set_source_rgba (cr, red: 1.0, green: 1.0, blue: 1.0, alpha: 0.6);
85 cairo_stroke_preserve (cr);
86
87 cairo_set_line_width (cr, width: 1.0);
88 cairo_set_source_rgba (cr, red: 0.0, green: 0.0, blue: 0.0, alpha: 0.8);
89 cairo_stroke (cr);
90 }
91 else
92 {
93 cairo_set_line_width (cr, width: 1.0);
94 cairo_set_source_rgba (cr, red: 0.8, green: 0.8, blue: 0.8, alpha: 0.8);
95 cairo_stroke (cr);
96 }
97
98 cairo_destroy (cr);
99}
100
101static void
102set_cross_cursor (GtkWidget *widget,
103 gboolean enabled)
104{
105 if (enabled)
106 gtk_widget_set_cursor_from_name (widget, name: "crosshair");
107 else
108 gtk_widget_set_cursor (widget, NULL);
109}
110
111static void
112adj_changed (GtkFontPlane *plane)
113{
114 gtk_widget_queue_draw (GTK_WIDGET (plane));
115}
116
117static void
118adjustment_set_normalized_value (GtkAdjustment *adj,
119 double val)
120{
121 gtk_adjustment_set_value (adjustment: adj,
122 value: gtk_adjustment_get_lower (adjustment: adj) +
123 val * (gtk_adjustment_get_upper (adjustment: adj) - gtk_adjustment_get_lower (adjustment: adj)));
124}
125
126static void
127update_value (GtkFontPlane *plane,
128 int x,
129 int y)
130{
131 GtkWidget *widget = GTK_WIDGET (plane);
132 double u, v;
133
134 u = CLAMP (x * (1.0 / gtk_widget_get_allocated_width (widget)), 0, 1);
135 v = CLAMP (1 - y * (1.0 / gtk_widget_get_allocated_height (widget)), 0, 1);
136
137 adjustment_set_normalized_value (adj: plane->width_adj, val: u);
138 adjustment_set_normalized_value (adj: plane->weight_adj, val: v);
139
140 gtk_widget_queue_draw (widget);
141}
142
143static void
144plane_drag_gesture_begin (GtkGestureDrag *gesture,
145 double start_x,
146 double start_y,
147 GtkFontPlane *plane)
148{
149 guint button;
150
151 button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
152
153 if (button != GDK_BUTTON_PRIMARY)
154 {
155 gtk_gesture_set_state (GTK_GESTURE (gesture), state: GTK_EVENT_SEQUENCE_DENIED);
156 return;
157 }
158
159 set_cross_cursor (GTK_WIDGET (plane), TRUE);
160 update_value (plane, x: start_x, y: start_y);
161 gtk_widget_grab_focus (GTK_WIDGET (plane));
162 gtk_gesture_set_state (GTK_GESTURE (gesture), state: GTK_EVENT_SEQUENCE_CLAIMED);
163}
164
165static void
166plane_drag_gesture_update (GtkGestureDrag *gesture,
167 double offset_x,
168 double offset_y,
169 GtkFontPlane *plane)
170{
171 double start_x, start_y;
172
173 gtk_gesture_drag_get_start_point (GTK_GESTURE_DRAG (gesture),
174 x: &start_x, y: &start_y);
175 update_value (plane, x: start_x + offset_x, y: start_y + offset_y);
176}
177
178static void
179plane_drag_gesture_end (GtkGestureDrag *gesture,
180 double offset_x,
181 double offset_y,
182 GtkFontPlane *plane)
183{
184 set_cross_cursor (GTK_WIDGET (plane), FALSE);
185}
186
187static void
188gtk_font_plane_init (GtkFontPlane *plane)
189{
190 GtkGesture *gesture;
191
192 gesture = gtk_gesture_drag_new ();
193 g_signal_connect (gesture, "drag-begin",
194 G_CALLBACK (plane_drag_gesture_begin), plane);
195 g_signal_connect (gesture, "drag-update",
196 G_CALLBACK (plane_drag_gesture_update), plane);
197 g_signal_connect (gesture, "drag-end",
198 G_CALLBACK (plane_drag_gesture_end), plane);
199 gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), button: 0);
200 gtk_widget_add_controller (GTK_WIDGET (plane), GTK_EVENT_CONTROLLER (gesture));
201}
202
203static void
204plane_finalize (GObject *object)
205{
206 GtkFontPlane *plane = GTK_FONT_PLANE (object);
207
208 g_clear_object (&plane->weight_adj);
209 g_clear_object (&plane->width_adj);
210
211 G_OBJECT_CLASS (gtk_font_plane_parent_class)->finalize (object);
212}
213
214static void
215plane_set_property (GObject *object,
216 guint prop_id,
217 const GValue *value,
218 GParamSpec *pspec)
219{
220 GtkFontPlane *plane = GTK_FONT_PLANE (object);
221 GtkAdjustment *adjustment;
222
223 switch (prop_id)
224 {
225 case PROP_WEIGHT_ADJUSTMENT:
226 adjustment = GTK_ADJUSTMENT (g_value_get_object (value));
227 if (adjustment)
228 {
229 plane->weight_adj = g_object_ref_sink (adjustment);
230 g_signal_connect_swapped (adjustment, "value-changed", G_CALLBACK (adj_changed), plane);
231 }
232 break;
233 case PROP_WIDTH_ADJUSTMENT:
234 adjustment = GTK_ADJUSTMENT (g_value_get_object (value));
235 if (adjustment)
236 {
237 plane->width_adj = g_object_ref_sink (adjustment);
238 g_signal_connect_swapped (adjustment, "value-changed", G_CALLBACK (adj_changed), plane);
239 }
240 break;
241 default:
242 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
243 break;
244 }
245}
246
247static void
248gtk_font_plane_class_init (GtkFontPlaneClass *class)
249{
250 GObjectClass *object_class = G_OBJECT_CLASS (class);
251 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
252
253 object_class->finalize = plane_finalize;
254 object_class->set_property = plane_set_property;
255
256 widget_class->snapshot = plane_snapshot;
257
258 g_object_class_install_property (oclass: object_class,
259 property_id: PROP_WEIGHT_ADJUSTMENT,
260 pspec: g_param_spec_object (name: "weight-adjustment",
261 NULL,
262 NULL,
263 GTK_TYPE_ADJUSTMENT,
264 flags: G_PARAM_WRITABLE |
265 G_PARAM_CONSTRUCT_ONLY));
266
267 g_object_class_install_property (oclass: object_class,
268 property_id: PROP_WIDTH_ADJUSTMENT,
269 pspec: g_param_spec_object (name: "width-adjustment",
270 NULL,
271 NULL,
272 GTK_TYPE_ADJUSTMENT,
273 flags: G_PARAM_WRITABLE |
274 G_PARAM_CONSTRUCT_ONLY));
275}
276
277GtkWidget *
278gtk_font_plane_new (GtkAdjustment *weight_adj,
279 GtkAdjustment *width_adj)
280{
281 return g_object_new (GTK_TYPE_FONT_PLANE,
282 first_property_name: "weight-adjustment", weight_adj,
283 "width-adjustment", width_adj,
284 NULL);
285}
286

source code of gtk/demos/gtk-demo/fontplane.c