source: trunk/gtk/tr_cell_renderer_progress.c @ 1125

Last change on this file since 1125 was 760, checked in by joshe, 15 years ago

Change all my 2-clause BSD licenses to the same MIT/X11 license as libtransmission.

  • Property svn:keywords set to Date Rev Author Id
File size: 10.2 KB
Line 
1/******************************************************************************
2 * $Id: tr_cell_renderer_progress.c 760 2006-08-13 00:26:52Z livings124 $
3 *
4 * Copyright (c) 2006 Transmission authors and contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *****************************************************************************/
24
25#include <gtk/gtk.h>
26#include <glib/gi18n.h>
27
28#include "tr_cell_renderer_progress.h"
29#include "transmission.h"
30#include "util.h"
31
32enum {
33  P_TEXT = 1,
34  P_MARKUP,
35  P_SPACER,
36  P_PROG,
37};
38
39static void
40class_init(gpointer gclass, gpointer gdata);
41static void
42init(GTypeInstance *instance, gpointer gclass);
43static void
44set_property(GObject *obj, guint id, const GValue *val, GParamSpec *pspec);
45static void
46get_property(GObject *obj, guint id, GValue *val, GParamSpec *pspec);
47static void
48dispose(GObject *obj);
49static void
50finalize(GObject *obj);
51static void
52get_size(GtkCellRenderer *rend, GtkWidget *widget, GdkRectangle *cell,
53         gint *xoff, gint *yoff, gint *width, gint *height);
54static void
55render(GtkCellRenderer *rend, GdkWindow *win, GtkWidget *widget,
56       GdkRectangle *bg, GdkRectangle *cell, GdkRectangle *expose,
57       GtkCellRendererState flags);
58static GtkStyle *
59getstyle(TrCellRendererProgress *self, GtkWidget *wid, GdkWindow *win);
60
61GType
62tr_cell_renderer_progress_get_type(void) {
63  static GType type = 0;
64
65  if(0 == type) {
66    static const GTypeInfo info = {
67      sizeof (TrCellRendererProgressClass),
68      NULL,   /* base_init */
69      NULL,   /* base_finalize */
70      class_init,   /* class_init */
71      NULL,   /* class_finalize */
72      NULL,   /* class_data */
73      sizeof (TrCellRendererProgress),
74      0,      /* n_preallocs */
75      init, /* instance_init */
76      NULL,
77    };
78    type = g_type_register_static(GTK_TYPE_CELL_RENDERER,
79                                  "TrCellRendererProgressType", &info, 0);
80  }
81  return type;
82}
83
84static void
85class_init(gpointer gclass, gpointer gdata SHUTUP) {
86  GObjectClass *gobjclass = G_OBJECT_CLASS(gclass);
87  GtkCellRendererClass *rendclass = GTK_CELL_RENDERER_CLASS(gclass);
88  GParamSpec *pspec;
89
90  gobjclass->set_property = set_property;
91  gobjclass->get_property = get_property;
92  gobjclass->dispose      = dispose;
93  gobjclass->finalize     = finalize;
94  rendclass->get_size     = get_size;
95  rendclass->render       = render;
96
97  pspec = g_param_spec_string("markup", "Markup", "Marked up text to render",
98                              NULL, G_PARAM_READWRITE);
99  g_object_class_install_property(gobjclass, P_MARKUP, pspec);
100
101  pspec = g_param_spec_string("bar-sizing", "Bar sizing",
102                              "Text to determine size of progress bar",
103                              NULL, G_PARAM_READWRITE);
104  g_object_class_install_property(gobjclass, P_SPACER, pspec);
105
106  pspec = g_param_spec_float("progress", "Progress", "Progress",
107                             0.0, 1.0, 0.0, G_PARAM_READWRITE);
108  g_object_class_install_property(gobjclass, P_PROG, pspec);
109}
110
111static void
112init(GTypeInstance *instance, gpointer gclass SHUTUP) {
113  TrCellRendererProgress *self = (TrCellRendererProgress *)instance;
114
115  self->rend      = gtk_cell_renderer_text_new();
116  self->style     = NULL;
117  self->text      = NULL;
118  self->spacer    = NULL;
119  self->barwidth  = -1;
120  self->barheight = -1;
121  self->progress  = 0.0;
122  self->disposed  = FALSE;
123
124  g_object_ref(self->rend);
125  gtk_object_sink(GTK_OBJECT(self->rend));
126}
127
128static void
129set_property(GObject *obj, guint id, const GValue *val,
130                                   GParamSpec *pspec) {
131  TrCellRendererProgress *self = (TrCellRendererProgress*)obj;
132
133  if(self->disposed)
134    return;
135
136  switch(id) {
137    case P_MARKUP:
138      g_free(self->text);
139      self->text = g_value_dup_string(val);
140      g_object_set_property(G_OBJECT(self->rend), "markup", val);
141      break;
142    case P_SPACER:
143      g_free(self->spacer);
144      self->spacer    = g_value_dup_string(val);
145      self->barwidth  = -1;
146      self->barheight = -1;
147      break;
148    case P_PROG:
149      self->progress = g_value_get_float(val);
150      break;
151    default:
152      G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, id, pspec);
153      break;
154  }
155}
156
157static void
158get_property(GObject *obj, guint id, GValue *val,
159                                   GParamSpec *pspec) {
160  TrCellRendererProgress *self = (TrCellRendererProgress*)obj;
161
162  if(self->disposed)
163    return;
164
165  switch(id) {
166    case P_MARKUP:
167      g_value_set_string(val, self->text);
168      break;
169    case P_SPACER:
170      g_value_set_string(val, self->spacer);
171      break;
172    case P_PROG:
173      g_value_set_float(val, self->progress);
174      break;
175    default:
176      G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, id, pspec);
177      break;
178  }
179}
180
181static void
182dispose(GObject *obj) {
183  GObjectClass *parent =
184    g_type_class_peek(g_type_parent(TR_CELL_RENDERER_PROGRESS_TYPE));
185  TrCellRendererProgress *self = (TrCellRendererProgress*)obj;
186
187  if(self->disposed)
188    return;
189  self->disposed = TRUE;
190
191  g_object_unref(self->rend);
192  tr_cell_renderer_progress_reset_style(self);
193
194  /* Chain up to the parent class */
195  parent->dispose(obj);
196}
197
198static void
199finalize(GObject *obj) {
200  GObjectClass *parent =
201    g_type_class_peek(g_type_parent(TR_CELL_RENDERER_PROGRESS_TYPE));
202  TrCellRendererProgress *self = (TrCellRendererProgress*)obj;
203
204  g_free(self->text);
205  g_free(self->spacer);
206
207  /* Chain up to the parent class */
208  parent->finalize(obj);
209}
210
211GtkCellRenderer *
212tr_cell_renderer_progress_new(void) {
213  return g_object_new(TR_CELL_RENDERER_PROGRESS_TYPE, NULL);
214}
215
216static void
217get_size(GtkCellRenderer *rend, GtkWidget *wid, GdkRectangle *cell,
218         gint *xoff, gint *yoff, gint *width, gint *height) {
219  TrCellRendererProgress *self;
220  GdkRectangle rect;
221  int xpad, ypad;
222
223  TR_IS_CELL_RENDERER_PROGRESS(rend);
224  self = TR_CELL_RENDERER_PROGRESS(rend);
225
226  /* calculate and cache minimum bar width and height */
227  if(0 > self->barwidth || 0 > self->barheight) {
228    xpad = self->rend->xpad;
229    ypad = self->rend->ypad;
230    g_object_set(self->rend, "markup", self->spacer, "xpad", 0, "ypad", 0,
231                 NULL);
232    gtk_cell_renderer_get_size(self->rend, wid, NULL, NULL, NULL,
233                               &self->barwidth, &self->barheight);
234    g_object_set(self->rend, "markup", self->text, "xpad", xpad, "ypad", ypad,
235                 NULL);
236  }
237
238  /* get the text size */
239  if(NULL != cell) {
240    rect = *cell;
241    rect.height -= self->barheight;
242    cell = &rect;
243  }
244  gtk_cell_renderer_get_size(self->rend, wid, cell, xoff, yoff, width, height);
245
246  if(NULL != width && self->barwidth > *width)
247    *width = self->barwidth;
248  if(NULL != height)
249    *height += self->barheight + (NULL == yoff ? 0 : *yoff);
250}
251
252static void
253render(GtkCellRenderer *rend, GdkWindow *win, GtkWidget *wid, GdkRectangle *bg,
254       GdkRectangle *cell, GdkRectangle *expose, GtkCellRendererState flags) {
255  TrCellRendererProgress *self;
256  GdkRectangle rect, full, empty;
257  GtkStyle *style;
258
259  TR_IS_CELL_RENDERER_PROGRESS(rend);
260  self = TR_CELL_RENDERER_PROGRESS(rend);
261
262  style = getstyle(self, wid, win);
263
264  /* make sure we have a cached bar width */
265  if(0 > self->barwidth || 0 > self->barheight)
266    get_size(rend, wid, NULL, NULL, NULL, NULL, NULL);
267  g_assert(0 < self->barwidth && 0 < self->barheight);
268
269  /* set up the dimensions for the bar and text */
270  rect         = *cell;
271  rect.x      += rend->xpad + style->xthickness;
272  rect.y      += rend->ypad + style->ythickness;
273  rect.width  -= (rend->xpad + style->xthickness) * 2;
274  rect.height -= (rend->ypad + style->ythickness) * 2;
275  empty        = rect;
276  empty.height = self->barheight;
277  full         = empty;
278  full.x      += style->xthickness;
279  full.y      += style->ythickness;
280  full.width  -= style->xthickness * 2;
281  full.height -= style->ythickness * 2;
282  rect.y      += self->barheight;
283  rect.height -= self->barheight;
284
285  /* draw the bar background */
286  gtk_paint_box(style, win, GTK_STATE_NORMAL, GTK_SHADOW_IN, NULL, wid,
287                "trough", empty.x, empty.y, empty.width, empty.height);
288
289  /* figure the width of the complete portion of the bar */
290  if(PANGO_DIRECTION_RTL ==
291     pango_context_get_base_dir(gtk_widget_get_pango_context(wid)))
292    full.x += full.width - (full.width * self->progress);
293  full.width *= self->progress;
294
295  /* draw the complete portion of the bar */
296  if(0 < full.width)
297    gtk_paint_box(style, win, GTK_STATE_PRELIGHT, GTK_SHADOW_OUT, NULL,
298                  wid, "bar", full.x, full.y, full.width, full.height);
299
300  /* draw the text */
301  if(0 < rect.height)
302    gtk_cell_renderer_render(self->rend, win, wid, bg, &rect, expose, flags);
303}
304
305/* ugly hack to get the style for GtkProgressBar */
306static GtkStyle *
307getstyle(TrCellRendererProgress *self, GtkWidget *wid, GdkWindow *win) {
308  if(NULL == self->style) {
309    self->style = gtk_rc_get_style_by_paths(gtk_widget_get_settings(wid), NULL,
310                                            NULL, GTK_TYPE_PROGRESS_BAR);
311    if(NULL != self->style)
312      self->style = gtk_style_attach(gtk_style_ref(self->style), win);
313  }
314
315  return (NULL == self->style ? wid->style : self->style);
316}
317
318/* hack to make the GtkProgressBar style hack work when the theme changes */
319void
320tr_cell_renderer_progress_reset_style(TrCellRendererProgress *self) {
321  TR_IS_CELL_RENDERER_PROGRESS(self);
322
323  if(NULL != self->style) {
324    gtk_style_detach(self->style);
325    gtk_style_unref(self->style);
326    self->style = NULL;
327  }
328}
Note: See TracBrowser for help on using the repository browser.