1/*
2 * Copyright © 2013 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.1 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 * Authors: Alexander Larsson <alexl@gnome.org>
18 */
19
20#include "config.h"
21
22#include "gtkcssimagescaledprivate.h"
23
24#include "gtkstyleproviderprivate.h"
25
26G_DEFINE_TYPE (GtkCssImageScaled, _gtk_css_image_scaled, GTK_TYPE_CSS_IMAGE)
27
28static int
29gtk_css_image_scaled_get_width (GtkCssImage *image)
30{
31 GtkCssImageScaled *scaled = GTK_CSS_IMAGE_SCALED (image);
32
33 return _gtk_css_image_get_width (image: scaled->images[0])/scaled->scales[0];
34}
35
36static int
37gtk_css_image_scaled_get_height (GtkCssImage *image)
38{
39 GtkCssImageScaled *scaled = GTK_CSS_IMAGE_SCALED (image);
40
41 return _gtk_css_image_get_height (image: scaled->images[0])/scaled->scales[0];
42}
43
44static double
45gtk_css_image_scaled_get_aspect_ratio (GtkCssImage *image)
46{
47 GtkCssImageScaled *scaled = GTK_CSS_IMAGE_SCALED (image);
48
49 return _gtk_css_image_get_aspect_ratio (image: scaled->images[0]);
50}
51
52static void
53gtk_css_image_scaled_snapshot (GtkCssImage *image,
54 GtkSnapshot *snapshot,
55 double width,
56 double height)
57{
58 GtkCssImageScaled *scaled = GTK_CSS_IMAGE_SCALED (image);
59
60 gtk_css_image_snapshot (image: scaled->images[0], snapshot, width, height);
61 // FIXME apply scale
62}
63
64static void
65gtk_css_image_scaled_print (GtkCssImage *image,
66 GString *string)
67{
68 GtkCssImageScaled *scaled = GTK_CSS_IMAGE_SCALED (image);
69 int i;
70
71 g_string_append (string, val: "-gtk-scaled(");
72 for (i = 0; i < scaled->n_images; i++)
73 {
74 _gtk_css_image_print (image: scaled->images[i], string);
75 g_string_append_printf (string, format: ",%d", scaled->scales[i]);
76 if (i != scaled->n_images - 1)
77 g_string_append (string, val: ",");
78 }
79 g_string_append (string, val: ")");
80}
81
82static void
83gtk_css_image_scaled_dispose (GObject *object)
84{
85 GtkCssImageScaled *scaled = GTK_CSS_IMAGE_SCALED (object);
86 int i;
87
88 for (i = 0; i < scaled->n_images; i++)
89 g_object_unref (object: scaled->images[i]);
90 g_free (mem: scaled->images);
91 scaled->images = NULL;
92 g_free (mem: scaled->scales);
93 scaled->scales = NULL;
94
95 G_OBJECT_CLASS (_gtk_css_image_scaled_parent_class)->dispose (object);
96}
97
98
99static GtkCssImage *
100gtk_css_image_scaled_compute (GtkCssImage *image,
101 guint property_id,
102 GtkStyleProvider *provider,
103 GtkCssStyle *style,
104 GtkCssStyle *parent_style)
105{
106 GtkCssImageScaled *scaled = GTK_CSS_IMAGE_SCALED (image);
107 int scale;
108 GtkCssImageScaled *res;
109 int i;
110 int best;
111
112 scale = gtk_style_provider_get_scale (provider);
113 scale = MAX(scale, 1);
114
115 best = 0;
116 for (i = 0; i < scaled->n_images; i++)
117 {
118 if (scaled->scales[i] == scale)
119 {
120 best = i;
121 break;
122 }
123 else if ((scaled->scales[best] < scaled->scales[i] && scaled->scales[i] < scale) ||
124 (scale < scaled->scales[i] && scaled->scales[i] < scaled->scales[best]) ||
125 (scaled->scales[best] < scale && scaled->scales[i] > scale))
126 {
127 best = i;
128 }
129 }
130
131 res = g_object_new (GTK_TYPE_CSS_IMAGE_SCALED, NULL);
132 res->n_images = 1;
133 res->images = g_new (GtkCssImage *, 1);
134 res->scales = g_new (int, 1);
135
136 res->images[0] = _gtk_css_image_compute (image: scaled->images[best],
137 property_id,
138 provider,
139 style,
140 parent_style);
141 res->scales[0] = scaled->scales[best];
142
143 return GTK_CSS_IMAGE (res);
144}
145
146typedef struct
147{
148 GPtrArray *images;
149 GArray *scales;
150} GtkCssImageScaledParseData;
151
152static guint
153gtk_css_image_scaled_parse_arg (GtkCssParser *parser,
154 guint arg,
155 gpointer data_)
156{
157 GtkCssImageScaledParseData *data = data_;
158 GtkCssImage *child;
159 int scale;
160
161 child = _gtk_css_image_new_parse (parser);
162 if (child == NULL)
163 return 0;
164
165 if (!gtk_css_parser_has_integer (self: parser))
166 scale = arg > 0 ? g_array_index (data->scales, int, arg - 1) + 1 : 1;
167 else if (!gtk_css_parser_consume_integer (self: parser, number: &scale))
168 return 0;
169
170 g_ptr_array_add (array: data->images, data: child);
171 g_array_append_val (data->scales, scale);
172
173 return 1;
174}
175
176static gboolean
177gtk_css_image_scaled_parse (GtkCssImage *image,
178 GtkCssParser *parser)
179{
180 GtkCssImageScaled *self = GTK_CSS_IMAGE_SCALED (image);
181 GtkCssImageScaledParseData data;
182
183 if (!gtk_css_parser_has_function (self: parser, name: "-gtk-scaled"))
184 {
185 gtk_css_parser_error_syntax (self: parser, format: "Expected '-gtk-scaled('");
186 return FALSE;
187 }
188
189 data.images = g_ptr_array_new_with_free_func (element_free_func: g_object_unref);
190 data.scales = g_array_new (FALSE, FALSE, element_size: sizeof (int));
191
192 if (!gtk_css_parser_consume_function (self: parser, min_args: 1, G_MAXUINT, parse_func: gtk_css_image_scaled_parse_arg, data: &data))
193 {
194 g_ptr_array_unref (array: data.images);
195 g_array_unref (array: data.scales);
196 return FALSE;
197 }
198
199 self->n_images = data.images->len;
200 self->images = (GtkCssImage **) g_ptr_array_free (array: data.images, FALSE);
201 self->scales = (int *) g_array_free (array: data.scales, FALSE);
202
203 return TRUE;
204}
205
206static gboolean
207gtk_css_image_scaled_is_computed (GtkCssImage *image)
208{
209 GtkCssImageScaled *self = GTK_CSS_IMAGE_SCALED (image);
210
211 return self->n_images == 1 &&
212 gtk_css_image_is_computed (image: self->images[0]);
213}
214
215static void
216_gtk_css_image_scaled_class_init (GtkCssImageScaledClass *klass)
217{
218 GtkCssImageClass *image_class = GTK_CSS_IMAGE_CLASS (klass);
219 GObjectClass *object_class = G_OBJECT_CLASS (klass);
220
221 image_class->get_width = gtk_css_image_scaled_get_width;
222 image_class->get_height = gtk_css_image_scaled_get_height;
223 image_class->get_aspect_ratio = gtk_css_image_scaled_get_aspect_ratio;
224 image_class->snapshot = gtk_css_image_scaled_snapshot;
225 image_class->parse = gtk_css_image_scaled_parse;
226 image_class->compute = gtk_css_image_scaled_compute;
227 image_class->print = gtk_css_image_scaled_print;
228 image_class->is_computed = gtk_css_image_scaled_is_computed;
229
230 object_class->dispose = gtk_css_image_scaled_dispose;
231}
232
233static void
234_gtk_css_image_scaled_init (GtkCssImageScaled *image_scaled)
235{
236}
237

source code of gtk/gtk/gtkcssimagescaled.c