1/*
2 * Copyright (c) 2014 Benjamin Otte <ottte@gnome.org>
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 "cellrenderergraph.h"
21
22#include "graphdata.h"
23
24#include "gtksnapshot.h"
25#include "gtkstylecontext.h"
26
27enum {
28 PROP_0,
29 PROP_DATA,
30 PROP_MINIMUM,
31 PROP_MAXIMUM
32};
33
34struct _GtkCellRendererGraphPrivate
35{
36 GtkGraphData *data;
37 double minimum;
38 double maximum;
39};
40
41G_DEFINE_TYPE_WITH_PRIVATE (GtkCellRendererGraph, gtk_cell_renderer_graph, GTK_TYPE_CELL_RENDERER)
42
43static void
44gtk_cell_renderer_graph_dispose (GObject *object)
45{
46 GtkCellRendererGraph *graph = GTK_CELL_RENDERER_GRAPH (object);
47 GtkCellRendererGraphPrivate *priv = graph->priv;
48
49 g_clear_object (&priv->data);
50
51 G_OBJECT_CLASS (gtk_cell_renderer_graph_parent_class)->dispose (object);
52}
53
54static void
55gtk_cell_renderer_graph_get_property (GObject *object,
56 guint param_id,
57 GValue *value,
58 GParamSpec *pspec)
59{
60 GtkCellRendererGraph *cell = GTK_CELL_RENDERER_GRAPH (object);
61 GtkCellRendererGraphPrivate *priv = cell->priv;
62
63 switch (param_id)
64 {
65 case PROP_DATA:
66 g_value_set_object (value, v_object: priv->data);
67 break;
68 case PROP_MINIMUM:
69 g_value_set_double (value, v_double: priv->minimum);
70 break;
71 case PROP_MAXIMUM:
72 g_value_set_double (value, v_double: priv->maximum);
73 break;
74 default:
75 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
76 }
77}
78
79static void
80gtk_cell_renderer_graph_set_property (GObject *object,
81 guint param_id,
82 const GValue *value,
83 GParamSpec *pspec)
84{
85 GtkCellRendererGraph *cell = GTK_CELL_RENDERER_GRAPH (object);
86 GtkCellRendererGraphPrivate *priv = cell->priv;
87
88 switch (param_id)
89 {
90 case PROP_DATA:
91 if (priv->data != g_value_get_object (value))
92 {
93 if (priv->data)
94 g_object_unref (object: priv->data);
95 priv->data = g_value_dup_object (value);
96 g_object_notify_by_pspec (object, pspec);
97 }
98 break;
99 case PROP_MINIMUM:
100 if (priv->minimum != g_value_get_double (value))
101 {
102 priv->minimum = g_value_get_double (value);
103 g_object_notify_by_pspec (object, pspec);
104 }
105 break;
106 case PROP_MAXIMUM:
107 if (priv->maximum != g_value_get_double (value))
108 {
109 priv->maximum = g_value_get_double (value);
110 g_object_notify_by_pspec (object, pspec);
111 }
112 break;
113 default:
114 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
115 }
116}
117
118#define MIN_HEIGHT 24
119#define MIN_WIDTH (3 * MIN_HEIGHT)
120
121static void
122gtk_cell_renderer_graph_get_preferred_width (GtkCellRenderer *cell,
123 GtkWidget *widget,
124 int *minimum,
125 int *natural)
126{
127 int xpad, size;
128
129 g_object_get (object: cell, first_property_name: "xpad", &xpad, NULL);
130
131 size = MIN_WIDTH + 2 * xpad;
132
133 if (minimum != NULL)
134 *minimum = size;
135 if (natural != NULL)
136 *natural = size;
137}
138
139static void
140gtk_cell_renderer_graph_get_preferred_height (GtkCellRenderer *cell,
141 GtkWidget *widget,
142 int *minimum,
143 int *natural)
144{
145 int ypad, size;
146
147 g_object_get (object: cell, first_property_name: "ypad", &ypad, NULL);
148
149 size = MIN_HEIGHT + 2 * ypad;
150
151 if (minimum != NULL)
152 *minimum = size;
153 if (natural != NULL)
154 *natural = size;
155}
156
157static void
158gtk_cell_renderer_graph_snapshot (GtkCellRenderer *cell,
159 GtkSnapshot *snapshot,
160 GtkWidget *widget,
161 const GdkRectangle *background_area,
162 const GdkRectangle *cell_area,
163 GtkCellRendererState flags)
164{
165 GtkCellRendererGraph *graph = GTK_CELL_RENDERER_GRAPH (cell);
166 GtkCellRendererGraphPrivate *priv = graph->priv;
167 GtkStyleContext *context;
168 double minimum, maximum, diff;
169 double x, y, width, height;
170 int xpad, ypad;
171 cairo_t *cr;
172 GdkRGBA color;
173 guint i, n;
174
175#define LINE_WIDTH 1.0
176
177 if (priv->data == NULL)
178 return;
179
180 g_object_get (object: cell,
181 first_property_name: "xpad", &xpad,
182 "ypad", &ypad,
183 NULL);
184
185 if (priv->minimum == -G_MAXDOUBLE)
186 minimum = gtk_graph_data_get_minimum (data: priv->data);
187 else
188 minimum = priv->minimum;
189
190 if (priv->maximum == G_MAXDOUBLE)
191 maximum = gtk_graph_data_get_maximum (data: priv->data);
192 else
193 maximum = priv->maximum;
194
195 diff = maximum - minimum;
196
197 context = gtk_widget_get_style_context (widget);
198 gtk_style_context_get_color (context, color: &color);
199
200 cr = gtk_snapshot_append_cairo (snapshot,
201 bounds: &GRAPHENE_RECT_INIT (
202 background_area->x, background_area->y,
203 background_area->width, background_area->height
204 ));
205
206 cairo_set_line_width (cr, width: 1.0);
207
208 x = background_area->x + xpad + LINE_WIDTH / 2.0;
209 y = background_area->y + ypad + LINE_WIDTH / 2.0;
210 width = background_area->width - 2 * xpad - LINE_WIDTH;
211 height = background_area->height - 2 * ypad - LINE_WIDTH;
212
213 cairo_move_to (cr, x, y: y + height);
214
215 if (diff > 0)
216 {
217 n = gtk_graph_data_get_n_values (data: priv->data);
218 for (i = 0; i < n; i++)
219 {
220 double val = gtk_graph_data_get_value (data: priv->data, i);
221
222 val = (val - minimum) / diff;
223 val = y + height - val * height;
224
225 cairo_line_to (cr, x: x + width * i / (n - 1), y: val);
226 }
227 }
228
229 cairo_line_to (cr, x: x + width, y: y + height);
230 cairo_close_path (cr);
231
232 gdk_cairo_set_source_rgba (cr, rgba: &color);
233 cairo_stroke_preserve (cr);
234
235 color.alpha *= 0.2;
236 gdk_cairo_set_source_rgba (cr, rgba: &color);
237 cairo_fill (cr);
238
239 cairo_destroy (cr);
240}
241
242static void
243gtk_cell_renderer_graph_class_init (GtkCellRendererGraphClass *klass)
244{
245 GObjectClass *object_class = G_OBJECT_CLASS (klass);
246 GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
247
248 object_class->dispose = gtk_cell_renderer_graph_dispose;
249 object_class->get_property = gtk_cell_renderer_graph_get_property;
250 object_class->set_property = gtk_cell_renderer_graph_set_property;
251
252 cell_class->get_preferred_width = gtk_cell_renderer_graph_get_preferred_width;
253 cell_class->get_preferred_height = gtk_cell_renderer_graph_get_preferred_height;
254 cell_class->snapshot = gtk_cell_renderer_graph_snapshot;
255
256 g_object_class_install_property (oclass: object_class,
257 property_id: PROP_DATA,
258 pspec: g_param_spec_object (name: "data",
259 nick: "Data",
260 blurb: "The data to display",
261 GTK_TYPE_GRAPH_DATA,
262 flags: G_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
263
264 g_object_class_install_property (oclass: object_class,
265 property_id: PROP_MINIMUM,
266 pspec: g_param_spec_double (name: "minimum",
267 nick: "Minimum",
268 blurb: "Minimum value to use (or -G_MAXDOUBLE for graph's value",
269 minimum: -G_MAXDOUBLE, G_MAXDOUBLE, default_value: -G_MAXDOUBLE,
270 flags: G_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
271
272 g_object_class_install_property (oclass: object_class,
273 property_id: PROP_MINIMUM,
274 pspec: g_param_spec_double (name: "maximum",
275 nick: "Maximum",
276 blurb: "Maximum value to use (or G_MAXDOUBLE for graph's value",
277 minimum: -G_MAXDOUBLE, G_MAXDOUBLE, G_MAXDOUBLE,
278 flags: G_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
279}
280
281static void
282gtk_cell_renderer_graph_init (GtkCellRendererGraph *cell)
283{
284 cell->priv = gtk_cell_renderer_graph_get_instance_private (self: cell);
285
286 cell->priv->minimum = -G_MAXDOUBLE;
287 cell->priv->maximum = G_MAXDOUBLE;
288}
289
290GtkCellRenderer *
291gtk_cell_renderer_graph_new (void)
292{
293 return g_object_new (GTK_TYPE_CELL_RENDERER_GRAPH, NULL);
294}
295

source code of gtk/gtk/inspector/cellrenderergraph.c