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 | |
26 | G_DEFINE_TYPE (GtkCssImageScaled, _gtk_css_image_scaled, GTK_TYPE_CSS_IMAGE) |
27 | |
28 | static int |
29 | gtk_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 | |
36 | static int |
37 | gtk_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 | |
44 | static double |
45 | gtk_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 | |
52 | static void |
53 | gtk_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 | |
64 | static void |
65 | gtk_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 | |
82 | static void |
83 | gtk_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 | |
99 | static GtkCssImage * |
100 | gtk_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 | |
146 | typedef struct |
147 | { |
148 | GPtrArray *images; |
149 | GArray *scales; |
150 | } GtkCssImageScaledParseData; |
151 | |
152 | static guint |
153 | gtk_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 | |
176 | static gboolean |
177 | gtk_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 | |
206 | static gboolean |
207 | gtk_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 | |
215 | static 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 | |
233 | static void |
234 | _gtk_css_image_scaled_init (GtkCssImageScaled *image_scaled) |
235 | { |
236 | } |
237 | |