1 | /* trcellrenderertorrent.c |
---|
2 | * Copyright (C) 2002 Naba Kumar <kh_naba@users.sourceforge.net> |
---|
3 | * heavily modified by Jörgen Scheibengruber <mfcn@gmx.de> |
---|
4 | * heavily modified by Marco Pesenti Gritti <marco@gnome.org> |
---|
5 | * heavily modified by Josh Elsasser <josh@elsasser.org> for transmission |
---|
6 | * |
---|
7 | * This library is free software; you can redistribute it and/or |
---|
8 | * modify it under the terms of the GNU Library General Public |
---|
9 | * License as published by the Free Software Foundation; either |
---|
10 | * version 2 of the License, or (at your option) any later version. |
---|
11 | * |
---|
12 | * This library 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 GNU |
---|
15 | * Library General Public License for more details. |
---|
16 | * |
---|
17 | * You should have received a copy of the GNU Library General Public |
---|
18 | * License along with this library; if not, write to the |
---|
19 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
---|
20 | * Boston, MA 02111-1307, USA. |
---|
21 | */ |
---|
22 | /* |
---|
23 | * Modified by the GTK+ Team and others 1997-2004. See the AUTHORS |
---|
24 | * file for a list of people on the GTK+ Team. See the ChangeLog |
---|
25 | * files for a list of changes. These files are distributed with |
---|
26 | * GTK+ at ftp://ftp.gtk.org/pub/gtk/. |
---|
27 | */ |
---|
28 | |
---|
29 | #include <gtk/gtk.h> |
---|
30 | |
---|
31 | #include "trcellrenderertorrent.h" |
---|
32 | #include "util.h" |
---|
33 | |
---|
34 | enum { PROP_0, PROP_VALUE, PROP_TEXT, PROP_LABEL }; |
---|
35 | |
---|
36 | struct _TrCellRendererTorrentPrivate { |
---|
37 | gfloat value; |
---|
38 | gchar *text; |
---|
39 | PangoAttrList *text_attrs; |
---|
40 | gchar *label; |
---|
41 | PangoAttrList *label_attrs; |
---|
42 | GtkStyle *style; |
---|
43 | }; |
---|
44 | |
---|
45 | static void |
---|
46 | finalize(GObject *object); |
---|
47 | static void |
---|
48 | get_property(GObject *obj, guint id, GValue *value, GParamSpec *spec); |
---|
49 | static void |
---|
50 | set_property(GObject *obj, guint id, const GValue *value, GParamSpec *spec); |
---|
51 | static void |
---|
52 | get_size(GtkCellRenderer *cell, GtkWidget *widget, GdkRectangle *area, |
---|
53 | gint *xoff, gint *yoff, gint *width, gint *height); |
---|
54 | static void |
---|
55 | render(GtkCellRenderer *cell, GdkWindow *window, GtkWidget *widget, |
---|
56 | GdkRectangle *bg, GdkRectangle *area, GdkRectangle *exp, guint flags); |
---|
57 | |
---|
58 | |
---|
59 | G_DEFINE_TYPE(TrCellRendererTorrent, tr_cell_renderer_torrent, GTK_TYPE_CELL_RENDERER); |
---|
60 | |
---|
61 | static void |
---|
62 | tr_cell_renderer_torrent_class_init (TrCellRendererTorrentClass *klass) { |
---|
63 | GObjectClass *object_class = G_OBJECT_CLASS (klass); |
---|
64 | GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass); |
---|
65 | |
---|
66 | object_class->finalize = finalize; |
---|
67 | object_class->get_property = get_property; |
---|
68 | object_class->set_property = set_property; |
---|
69 | |
---|
70 | cell_class->get_size = get_size; |
---|
71 | cell_class->render = render; |
---|
72 | |
---|
73 | g_object_class_install_property( |
---|
74 | object_class, PROP_VALUE, |
---|
75 | g_param_spec_float("value", "Value", "Value of the torrent bar", |
---|
76 | 0.0, 1.0, 0.0, G_PARAM_READWRITE)); |
---|
77 | |
---|
78 | g_object_class_install_property( |
---|
79 | object_class, PROP_TEXT, |
---|
80 | g_param_spec_string ("text", "Text", "Text under the torrent bar", |
---|
81 | /* XXX should I have NULL or "" here, and is initial strdup needed? */ |
---|
82 | NULL, G_PARAM_READWRITE)); |
---|
83 | |
---|
84 | g_object_class_install_property( |
---|
85 | object_class, PROP_LABEL, |
---|
86 | g_param_spec_string ("label", "Label", "Text on the torrent bar", |
---|
87 | NULL, G_PARAM_READWRITE)); |
---|
88 | |
---|
89 | g_type_class_add_private (object_class, |
---|
90 | sizeof (TrCellRendererTorrentPrivate)); |
---|
91 | } |
---|
92 | |
---|
93 | static void |
---|
94 | tr_cell_renderer_torrent_init(TrCellRendererTorrent *tcell) { |
---|
95 | tcell->priv = G_TYPE_INSTANCE_GET_PRIVATE( |
---|
96 | tcell, GTK_TYPE_CELL_RENDERER_TORRENT, TrCellRendererTorrentPrivate); |
---|
97 | tcell->priv->value = 0.0; |
---|
98 | tcell->priv->text = g_strdup(""); |
---|
99 | tcell->priv->text_attrs = NULL; |
---|
100 | tcell->priv->label = g_strdup(""); |
---|
101 | tcell->priv->text_attrs = NULL; |
---|
102 | tcell->priv->style = NULL; |
---|
103 | } |
---|
104 | |
---|
105 | GtkCellRenderer* |
---|
106 | tr_cell_renderer_torrent_new(void) { |
---|
107 | return g_object_new (GTK_TYPE_CELL_RENDERER_TORRENT, NULL); |
---|
108 | } |
---|
109 | |
---|
110 | /* XXX need to do this better somehow */ |
---|
111 | void |
---|
112 | tr_cell_renderer_torrent_reset_style(TrCellRendererTorrent *tor) { |
---|
113 | if(NULL != tor->priv->style) { |
---|
114 | gtk_style_detach(tor->priv->style); |
---|
115 | gtk_style_unref(tor->priv->style); |
---|
116 | tor->priv->style = NULL; |
---|
117 | } |
---|
118 | } |
---|
119 | |
---|
120 | static void |
---|
121 | finalize(GObject *object) { |
---|
122 | TrCellRendererTorrent *tcell = TR_CELL_RENDERER_TORRENT(object); |
---|
123 | |
---|
124 | g_free(tcell->priv->text); |
---|
125 | g_free(tcell->priv->label); |
---|
126 | |
---|
127 | if(NULL != tcell->priv->text_attrs) |
---|
128 | pango_attr_list_unref(tcell->priv->text_attrs); |
---|
129 | if(NULL != tcell->priv->label_attrs) |
---|
130 | pango_attr_list_unref(tcell->priv->label_attrs); |
---|
131 | if(NULL != tcell->priv->style) { |
---|
132 | gtk_style_detach(tcell->priv->style); |
---|
133 | gtk_style_unref(tcell->priv->style); |
---|
134 | } |
---|
135 | |
---|
136 | G_OBJECT_CLASS (tr_cell_renderer_torrent_parent_class)->finalize(object); |
---|
137 | } |
---|
138 | |
---|
139 | static void |
---|
140 | get_property(GObject *object, guint id, GValue *value, GParamSpec *pspec) { |
---|
141 | TrCellRendererTorrent *tcell = TR_CELL_RENDERER_TORRENT (object); |
---|
142 | |
---|
143 | switch (id) { |
---|
144 | case PROP_VALUE: |
---|
145 | g_value_set_float (value, tcell->priv->value); |
---|
146 | break; |
---|
147 | case PROP_TEXT: |
---|
148 | g_value_set_string (value, tcell->priv->text); |
---|
149 | break; |
---|
150 | case PROP_LABEL: |
---|
151 | g_value_set_string (value, tcell->priv->label); |
---|
152 | break; |
---|
153 | default: |
---|
154 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, id, pspec); |
---|
155 | } |
---|
156 | } |
---|
157 | |
---|
158 | static void |
---|
159 | set_property(GObject *obj, guint id, const GValue *value, GParamSpec *spec) { |
---|
160 | TrCellRendererTorrent *tcell = TR_CELL_RENDERER_TORRENT(obj); |
---|
161 | gchar **prop = NULL; |
---|
162 | PangoAttrList **attrs = NULL; |
---|
163 | /*GError *err = NULL;*/ |
---|
164 | const gchar *markup; |
---|
165 | |
---|
166 | switch(id) { |
---|
167 | case PROP_VALUE: |
---|
168 | tcell->priv->value = g_value_get_float(value); |
---|
169 | break; |
---|
170 | |
---|
171 | case PROP_TEXT: |
---|
172 | prop = &tcell->priv->text; |
---|
173 | attrs = &tcell->priv->text_attrs; |
---|
174 | /* fallthrough */ |
---|
175 | |
---|
176 | case PROP_LABEL: |
---|
177 | if(PROP_LABEL == id) { |
---|
178 | prop = &tcell->priv->label; |
---|
179 | attrs = &tcell->priv->label_attrs; |
---|
180 | } |
---|
181 | |
---|
182 | if(NULL == (markup = g_value_get_string(value))) |
---|
183 | markup = ""; |
---|
184 | |
---|
185 | g_free(*prop); |
---|
186 | if(NULL != *attrs) |
---|
187 | pango_attr_list_unref(*attrs); |
---|
188 | |
---|
189 | *prop = g_strdup(markup); |
---|
190 | |
---|
191 | /* |
---|
192 | if(pango_parse_markup(markup, -1, 0, attrs, prop, NULL, &err)) |
---|
193 | break; |
---|
194 | |
---|
195 | g_warning ("Failed to parse markup: %s", err->message); |
---|
196 | g_error_free(err); |
---|
197 | */ |
---|
198 | break; |
---|
199 | |
---|
200 | default: |
---|
201 | G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, id, spec); |
---|
202 | } |
---|
203 | } |
---|
204 | |
---|
205 | static void |
---|
206 | get_size(GtkCellRenderer *cell, GtkWidget *widget, GdkRectangle *area, |
---|
207 | gint *xoff, gint *yoff, gint *width, gint *height) { |
---|
208 | TrCellRendererTorrent *tcell = TR_CELL_RENDERER_TORRENT(cell); |
---|
209 | /* XXX do I have to unref the context? */ |
---|
210 | PangoLayout *layout = pango_layout_new(gtk_widget_get_pango_context(widget)); |
---|
211 | PangoRectangle rect; |
---|
212 | gint h = cell->ypad * 2; |
---|
213 | gint w1, w2; |
---|
214 | |
---|
215 | pango_layout_set_markup(layout, tcell->priv->label, -1); |
---|
216 | pango_layout_get_pixel_extents(layout, NULL, &rect); |
---|
217 | w1 = rect.width; |
---|
218 | h += rect.height; |
---|
219 | |
---|
220 | pango_layout_set_markup(layout, tcell->priv->text, -1); |
---|
221 | pango_layout_get_pixel_extents(layout, NULL, &rect); |
---|
222 | w2 = rect.width; |
---|
223 | h += rect.height; |
---|
224 | |
---|
225 | if(NULL != xoff) |
---|
226 | *xoff = 0; |
---|
227 | if(NULL != yoff) |
---|
228 | *yoff = (area->height - h) / 2; |
---|
229 | if(NULL != width) |
---|
230 | *width = MAX(w1, w2) + cell->xpad * 2; |
---|
231 | if(NULL != height) |
---|
232 | *height = h; |
---|
233 | |
---|
234 | g_object_unref(layout); |
---|
235 | } |
---|
236 | |
---|
237 | #define RECTARGS(rect) (rect).x, (rect).y, (rect).width, (rect).height |
---|
238 | |
---|
239 | static void |
---|
240 | render(GtkCellRenderer *cell, GdkWindow *window, GtkWidget *widget, |
---|
241 | GdkRectangle *bg SHUTUP, GdkRectangle *area, GdkRectangle *exp SHUTUP, |
---|
242 | guint flags) { |
---|
243 | TrCellRendererTorrent *tcell = TR_CELL_RENDERER_TORRENT(cell); |
---|
244 | PangoContext *ctx = gtk_widget_get_pango_context(widget); |
---|
245 | PangoLayout *llayout, *tlayout; |
---|
246 | PangoRectangle lrect, trect; |
---|
247 | GdkRectangle bar, complete, text; |
---|
248 | gboolean rtl; |
---|
249 | GtkStyle *style; |
---|
250 | |
---|
251 | /* try to use the style for GtkProgressBar */ |
---|
252 | if(NULL == tcell->priv->style) |
---|
253 | if(NULL != (tcell->priv->style = gtk_rc_get_style_by_paths( |
---|
254 | gtk_widget_get_settings(widget), NULL, NULL, |
---|
255 | gtk_progress_bar_get_type()))) |
---|
256 | tcell->priv->style = gtk_style_attach(gtk_style_ref(tcell->priv->style), |
---|
257 | window); |
---|
258 | style = (NULL == tcell->priv->style ? widget->style : tcell->priv->style); |
---|
259 | |
---|
260 | rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL; |
---|
261 | |
---|
262 | /* get the text layouts */ |
---|
263 | llayout = pango_layout_new(ctx); |
---|
264 | /* XXX cache parsed markup? */ |
---|
265 | pango_layout_set_markup(llayout, tcell->priv->label, -1); |
---|
266 | pango_layout_get_pixel_extents(llayout, NULL, &lrect); |
---|
267 | tlayout = pango_layout_new(ctx); |
---|
268 | pango_layout_set_markup(tlayout, tcell->priv->text, -1); |
---|
269 | pango_layout_get_pixel_extents (tlayout, NULL, &trect); |
---|
270 | |
---|
271 | /* set up the dimensions for the bar */ |
---|
272 | bar.x = area->x + cell->xpad; |
---|
273 | bar.y = area->y + cell->ypad + |
---|
274 | (area->height - lrect.height - trect.height) / 2; |
---|
275 | bar.width = area->width - cell->xpad * 2; |
---|
276 | bar.height = lrect.height; |
---|
277 | |
---|
278 | /* set up the dimensions for the complete portion of the bar */ |
---|
279 | complete.x = bar.x + style->xthickness; |
---|
280 | complete.y = bar.y + style->ythickness; |
---|
281 | complete.width = (bar.width - style->xthickness * 2) * tcell->priv->value; |
---|
282 | complete.height = bar.height - style->ythickness * 2; |
---|
283 | if(rtl) |
---|
284 | complete.x += bar.width - (complete.width + style->xthickness * 2); |
---|
285 | |
---|
286 | /* set up the dimensions for the text under the bar */ |
---|
287 | text.x = bar.x; |
---|
288 | text.y = bar.y + bar.height; |
---|
289 | text.width = bar.width; |
---|
290 | text.height = area->height - bar.height; |
---|
291 | if(rtl && text.width > trect.width) |
---|
292 | text.x += text.width - trect.width; |
---|
293 | |
---|
294 | /* draw the background of the bar */ |
---|
295 | if(complete.width < bar.width) |
---|
296 | gtk_paint_box(style, window, GTK_STATE_NORMAL, GTK_SHADOW_IN, |
---|
297 | NULL, widget, "trough", RECTARGS(bar)); |
---|
298 | |
---|
299 | /* draw the complete portion of the bar */ |
---|
300 | if(0 < complete.width) |
---|
301 | gtk_paint_box(style, window, GTK_STATE_PRELIGHT, GTK_SHADOW_OUT, |
---|
302 | NULL, widget, "bar", RECTARGS(complete)); |
---|
303 | |
---|
304 | /* draw the text under the bar */ |
---|
305 | gtk_paint_layout(widget->style, window, (GTK_CELL_RENDERER_SELECTED & flags ? |
---|
306 | GTK_STATE_SELECTED : GTK_STATE_NORMAL), FALSE, &text, |
---|
307 | widget, "cellrenderertext", text.x, text.y, tlayout); |
---|
308 | |
---|
309 | /* free memory */ |
---|
310 | g_object_unref(llayout); |
---|
311 | g_object_unref(tlayout); |
---|
312 | } |
---|