source: trunk/gtk/torrent-cell-renderer.c @ 5048

Last change on this file since 5048 was 5048, checked in by charles, 14 years ago

(gtk) #703: better handling of rtl locales

File size: 34.9 KB
Line 
1/*
2 * This file Copyright (C) 2007-2008 Charles Kerr <charles@rebelbase.com>
3 *
4 * This file is licensed by the GPL version 2.  Works owned by the
5 * Transmission project are granted a special exemption to clause 2(b)
6 * so that the bulk of its code can remain under the MIT license.
7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
9 *
10 * $Id:$
11 */
12
13#include "assert.h"
14#include <gtk/gtk.h>
15#include <gtk/gtkcellrenderertext.h>
16#include <glib/gi18n.h>
17#include <libtransmission/transmission.h>
18#include "hig.h"
19#include "torrent-cell-renderer.h"
20#include "tr_torrent.h"
21#include "util.h"
22
23enum
24{
25    P_TORRENT = 1,
26    P_BAR_HEIGHT,
27    P_MINIMAL,
28    P_SHOW_UNAVAILABLE,
29    P_GRADIENT,
30    P_COLOR_VERIFIED,
31    P_COLOR_VERIFIED_2,
32    P_COLOR_MISSING,
33    P_COLOR_MISSING_2,
34    P_COLOR_UNWANTED,
35    P_COLOR_UNWANTED_2,
36    P_COLOR_UNAVAILABLE,
37    P_COLOR_UNAVAILABLE_2,
38    P_COLOR_PAUSED,
39    P_COLOR_PAUSED_2,
40    P_COLOR_VERIFYING,
41    P_COLOR_VERIFYING_2,
42    P_COLOR_SEEDING,
43    P_COLOR_SEEDING_2
44};
45
46#define DEFAULT_BAR_HEIGHT 12
47
48#define DEFAULT_COLOR_VERIFIED       "#729fcf"
49#define DEFAULT_COLOR_VERIFIED_2     "#204a87"
50
51#define DEFAULT_COLOR_SEEDING        "#8ae234"
52#define DEFAULT_COLOR_SEEDING_2      "#4e9a06"
53
54#define DEFAULT_COLOR_MISSING        "#eeeeec" /* aluminum 1 */
55#define DEFAULT_COLOR_MISSING_2      "#babdb6" /* aluminum 3 */
56
57#define DEFAULT_COLOR_UNWANTED       "#babdb6" /* aluminum 3 */
58#define DEFAULT_COLOR_UNWANTED_2     "#2e3436" /* aluminum 6 */
59
60#define DEFAULT_COLOR_UNAVAILABLE    "#ef2929"
61#define DEFAULT_COLOR_UNAVAILABLE_2  "#a40000"
62
63#define DEFAULT_COLOR_PAUSED         "#d3d7cf" /* aluminum 2 */
64#define DEFAULT_COLOR_PAUSED_2       "#555753" /* aluminum 5 */
65
66#define DEFAULT_COLOR_VERIFYING      "#fce94f"
67#define DEFAULT_COLOR_VERIFYING_2    "#c4a000"
68
69/***
70****
71***/
72
73static char*
74getProgressString( const tr_info * info, const tr_stat * torStat )
75{
76    const int isDone = torStat->leftUntilDone == 0;
77    const uint64_t haveTotal = torStat->haveUnchecked + torStat->haveValid;
78    const int isSeed = torStat->haveValid >= info->totalSize;
79    char buf1[32], buf2[32], buf3[32], buf4[32];
80    char * str;
81
82    if( !isDone )
83        str = g_strdup_printf(
84                  _("%s of %s (%.2f%%)"),
85                  tr_strlsize( buf1, haveTotal, sizeof(buf1) ),
86                  tr_strlsize( buf2, torStat->desiredSize, sizeof(buf2) ),
87                  torStat->percentDone * 100.0 );
88    else if( !isSeed )
89        str = g_strdup_printf(
90                  _("%s of %s (%.2f%%), uploaded %s (Ratio: %s)"),
91                  tr_strlsize( buf1, haveTotal, sizeof(buf1) ),
92                  tr_strlsize( buf2, info->totalSize, sizeof(buf2) ),
93                  torStat->percentComplete * 100.0,
94                  tr_strlsize( buf3, torStat->uploadedEver, sizeof(buf3) ),
95                  tr_strlratio( buf4, torStat->ratio, sizeof( buf4 ) ) );
96    else
97        str = g_strdup_printf(
98                  _("%s, uploaded %s (Ratio: %s)"),
99                  tr_strlsize( buf1, info->totalSize, sizeof(buf1) ),
100                  tr_strlsize( buf2, torStat->uploadedEver, sizeof(buf2) ),
101                  tr_strlratio( buf3, torStat->ratio, sizeof( buf3 ) ) );
102
103    // add time when downloading
104    if( torStat->status == TR_STATUS_DOWNLOAD )
105    {
106        const int eta = torStat->eta;
107        GString * gstr = g_string_new( str );
108        g_string_append( gstr, " - " );
109        if( eta < 0 )
110            g_string_append( gstr, _( "Stalled" ) );
111        else {
112            char timestr[128];
113            tr_strltime( timestr, eta, sizeof( timestr ) );
114            g_string_append_printf( gstr, _( "%s remaining" ), timestr );
115        }
116        g_free( str );
117        str = g_string_free( gstr, FALSE );
118    }
119
120    return str;
121}
122
123static char*
124getShortTransferString( const tr_stat * torStat, char * buf, size_t buflen )
125{
126    char downStr[32], upStr[32];
127    const int haveDown = torStat->peersSendingToUs > 0;
128    const int haveUp = torStat->peersGettingFromUs > 0;
129
130    if( haveDown )
131        tr_strlspeed( downStr, torStat->rateDownload, sizeof(downStr) );
132    if( haveUp )
133        tr_strlspeed( upStr, torStat->rateUpload, sizeof(upStr) );
134
135    if( haveDown && haveUp )
136        g_snprintf( buf, buflen, _( "Down: %s, Up: %s"), downStr, upStr );
137    else if( haveDown )
138        g_snprintf( buf, buflen, _( "Down: %s" ), downStr );
139    else if( haveUp )
140        g_snprintf( buf, buflen, _( "Up: %s" ), upStr );
141    else
142        g_strlcpy( buf, _( "Idle" ), buflen );
143
144    return buf;
145}
146
147static char*
148getShortStatusString( const tr_stat * torStat )
149{
150    GString * gstr = g_string_new( NULL );
151
152    switch( torStat->status )
153    {
154        case TR_STATUS_STOPPED:
155            g_string_assign( gstr, _("Paused") );
156            break;
157
158        case TR_STATUS_CHECK_WAIT:
159            g_string_assign( gstr, _( "Waiting to Verify local data" ) );
160            break;
161
162        case TR_STATUS_CHECK:
163            g_string_append_printf( gstr, _("Verifying local data (%.1f%% tested)"),
164                                    torStat->recheckProgress * 100.0 );
165            break;
166
167        case TR_STATUS_DOWNLOAD:
168        case TR_STATUS_SEED:
169        case TR_STATUS_DONE: {
170            char buf[128];
171            if( torStat->status != TR_STATUS_DOWNLOAD ) {
172                tr_strlratio( buf, torStat->ratio, sizeof( buf ) );
173                g_string_append_printf( gstr, _("Ratio: %s, " ), buf );
174            }
175            getShortTransferString( torStat, buf, sizeof( buf ) );
176            g_string_append( gstr, buf );
177            break;
178        }
179
180        default:
181            break;
182    }
183
184    return g_string_free( gstr, FALSE );
185}
186
187static char*
188getStatusString( const tr_stat * torStat )
189{
190    const int isActive = torStat->status != TR_STATUS_STOPPED;
191    const int isChecking = torStat->status == TR_STATUS_CHECK
192                        || torStat->status == TR_STATUS_CHECK_WAIT;
193
194    GString * gstr = g_string_new( NULL );
195
196    if( torStat->error )
197    {
198        g_string_assign( gstr, torStat->errorString );
199    }
200    else switch( torStat->status )
201    {
202        case TR_STATUS_STOPPED:
203        case TR_STATUS_CHECK_WAIT:
204        case TR_STATUS_CHECK: {
205            char * pch = getShortStatusString( torStat );
206            g_string_assign( gstr, pch );
207            g_free( pch );
208            break;
209        }
210
211        case TR_STATUS_DOWNLOAD:
212            g_string_append_printf( gstr,
213                ngettext( "Downloading from %d of %d connected peer",
214                          "Downloading from %d of %d connected peers",
215                          torStat->peersConnected ),
216                torStat->peersSendingToUs,
217                torStat->peersConnected );
218            break;
219
220        case TR_STATUS_DONE:
221        case TR_STATUS_SEED:
222            g_string_append_printf( gstr,
223                ngettext( "Seeding to %d of %d connected peer",
224                          "Seeding to %d of %d connected peers",
225                          torStat->peersConnected ),
226                torStat->peersGettingFromUs,
227                torStat->peersConnected );
228            break;
229    }
230
231    if( isActive && !isChecking )
232    {
233        char buf[256];
234        getShortTransferString( torStat, buf, sizeof(buf) );
235        g_string_append_printf( gstr, " - %s", buf );
236    }
237
238    return g_string_free( gstr, FALSE );
239}
240
241/***
242****
243***/
244
245static GtkCellRendererClass * parent_class = NULL;
246
247struct TorrentCellRendererPrivate
248{
249    tr_torrent * tor;
250    GtkCellRenderer * text_renderer;
251    GtkCellRenderer * text_renderer_err;
252    int bar_height;
253    gboolean minimal;
254    gboolean show_unavailable;
255    gboolean gradient;
256    GdkColor color_paused[2];
257    GdkColor color_verified[2];
258    GdkColor color_verifying[2];
259    GdkColor color_missing[2];
260    GdkColor color_unwanted[2];
261    GdkColor color_unavailable[2];
262    GdkColor color_seeding[2];
263};
264
265static void
266torrent_cell_renderer_get_size( GtkCellRenderer  * cell,
267                                GtkWidget        * widget,
268                                GdkRectangle     * cell_area,
269                                gint             * x_offset,
270                                gint             * y_offset,
271                                gint             * width,
272                                gint             * height)
273{
274    TorrentCellRenderer * self = TORRENT_CELL_RENDERER( cell );
275    int xpad, ypad;
276    g_object_get( self, "xpad", &xpad, "ypad", &ypad, NULL );
277
278    if( self && self->priv->tor )
279    {
280        const tr_torrent * tor = self->priv->tor;
281        const tr_info * info = tr_torrentInfo( tor );
282        const char * name = info->name;
283        const tr_stat * torStat = tr_torrentStatCached( (tr_torrent*)tor );
284        char * str;
285        int w=0, h=0;
286        struct TorrentCellRendererPrivate * p = self->priv;
287        GtkCellRenderer * text_renderer = torStat->error != 0
288            ? p->text_renderer_err
289            : p->text_renderer;
290
291        g_object_set( text_renderer, "ellipsize", PANGO_ELLIPSIZE_NONE, NULL );
292
293        /* above the progressbar */
294        if( p->minimal )
295        {
296            int w1, w2, h1, h2;
297            char * shortStatus = getShortStatusString( torStat );
298            g_object_set( text_renderer, "text", name, NULL );
299            gtk_cell_renderer_get_size( text_renderer,
300                                        widget, NULL, NULL, NULL, &w1, &h1 );
301            str = g_markup_printf_escaped( "<small>%s</small>", shortStatus );
302            g_object_set( text_renderer, "markup", str, NULL );
303            gtk_cell_renderer_get_size( text_renderer,
304                                        widget, NULL, NULL, NULL, &w2, &h2 );
305            h += MAX( h1, h2 );
306            w = MAX( w, w1+GUI_PAD_BIG+w2 );
307            g_free( str );
308            g_free( shortStatus );
309        }
310        else
311        {
312            int w1, h1;
313            char * progressString = getProgressString( info, torStat );
314            str = g_markup_printf_escaped( "<b>%s</b>\n<small>%s</small>",
315                                           name, progressString );
316            g_object_set( text_renderer, "markup", str, NULL );
317            gtk_cell_renderer_get_size( text_renderer,
318                                        widget, NULL, NULL, NULL, &w1, &h1 );
319            h += h1;
320            w = MAX( w, w1 );
321            g_free( str );
322            g_free( progressString );
323        }
324
325        /* below the progressbar */
326        if( !p->minimal )
327        {
328            int w1, h1;
329            char * statusString = getStatusString( torStat );
330            str = g_markup_printf_escaped( "<small>%s</small>", statusString );
331            g_object_set( text_renderer, "markup", str, NULL );
332            gtk_cell_renderer_get_size( text_renderer,
333                                        widget, NULL, NULL, NULL, &w1, &h1 );
334            h += h1;
335            w = MAX( w, w1 );
336            g_free( str );
337            g_free( statusString );
338        }
339
340        h += p->bar_height;
341
342        if( cell_area ) {
343            if( x_offset ) *x_offset = 0;
344            if( y_offset ) {
345                *y_offset = 0.5 * (cell_area->height - (h + (2 * ypad)));
346                *y_offset = MAX( *y_offset, 0 );
347            }
348        }
349
350        *width = w + xpad*2;
351        *height = h + ypad*2;
352    }
353}
354
355static void
356fillRect( TorrentCellRenderer * self,
357          GdkGC               * gc,
358          GdkDrawable         * drawable,
359          const GdkRectangle  * area_in,
360          const GdkColor      * colors,
361          size_t                n_colors )
362{
363    const int drawGradient = self->priv->gradient && ( n_colors > 1 );
364    assert( n_colors==1 || n_colors==2 );
365
366    if( !drawGradient )
367    {
368        gdk_gc_set_rgb_fg_color( gc, colors );
369        gdk_draw_rectangle( drawable, gc, TRUE,
370                            area_in->x, area_in->y,
371                            area_in->width, area_in->height );
372    }
373    else
374    {
375        int i;
376        const int steps = area_in->height;
377        const int step_height = area_in->height / steps;
378        const int r_inc = ((int)colors[1].red   - (int)colors[0].red) / steps;
379        const int g_inc = ((int)colors[1].green - (int)colors[0].green) / steps;
380        const int b_inc = ((int)colors[1].blue  - (int)colors[0].blue) / steps;
381
382        GdkRectangle area = *area_in;
383        GdkColor color = colors[0];
384     
385        area.height = step_height;
386        for( i=0; i<steps; ++i ) {
387            gdk_gc_set_rgb_fg_color( gc, &color );
388            gdk_draw_rectangle( drawable, gc, TRUE,
389                                area.x, area.y, area.width, area.height );
390            area.y += step_height;
391            color.red   += r_inc;
392            color.green += g_inc;
393            color.blue  += b_inc;
394        }
395    }
396}
397
398static void
399drawRegularBar( TorrentCellRenderer * self,
400                const tr_info       * info,
401                const tr_stat       * torStat,
402                GdkDrawable         * drawable,
403                GtkWidget           * widget,
404                const GdkRectangle  * area )
405{
406    const gboolean rtl = gtk_widget_get_direction( widget ) == GTK_TEXT_DIR_RTL;
407#if 1
408    const double verified = torStat->haveValid / (double)info->totalSize;
409    const double unverified = torStat->haveUnchecked / (double)info->totalSize;
410    const double unavailable = ( torStat->desiredSize
411                       - torStat->desiredAvailable ) / (double)info->totalSize;
412    const double unwanted = ( info->totalSize
413                            - torStat->desiredSize ) / (double)info->totalSize;
414#else /* for testing */
415    const double verified = 0.5;
416    const double unverified = 0.1;
417    const double unavailable = 0.1;
418    const double unwanted = 0.1;
419#endif
420    const double missing = 1.0 - verified - unverified - unavailable - unwanted;
421    const int verifiedWidth = (int)( verified * area->width );
422    const int unverifiedWidth = (int)( unverified * area->width );
423    const int unavailableWidth = (int)( unavailable * area->width );
424    const int unwantedWidth = (int)( unwanted * area->width );
425    const int missingWidth = (int)( missing * area->width );
426
427    const gboolean isActive = torStat->status == TR_STATUS_DOWNLOAD
428                           || torStat->status == TR_STATUS_DONE
429                           || torStat->status == TR_STATUS_SEED;
430    const gboolean isChecking = torStat->status == TR_STATUS_CHECK
431                             || torStat->status == TR_STATUS_CHECK_WAIT;
432
433    int x = rtl ? area->x + area->width : area->x;
434    int w = 0;
435    GdkGC * gc = gdk_gc_new( drawable );
436    GdkRectangle rect = *area;
437
438    if(( w = verifiedWidth )) {
439        const GdkColor * colors;
440        if( !isActive )
441            colors = self->priv->color_paused;
442        else if( torStat->status == TR_STATUS_DOWNLOAD )
443            colors = self->priv->color_verified;
444        else
445            colors = self->priv->color_seeding;
446        rect.width = w;
447        rect.x = rtl ? x-w : x;
448        fillRect( self, gc, drawable, &rect, colors, 2 );
449        x += rtl ? -w : w;
450    }
451
452    if(( w = unverifiedWidth )) {
453        const GdkColor * colors = isActive ? self->priv->color_verifying
454                                           : self->priv->color_paused;
455        rect.width = w;
456        rect.x = rtl ? x-w : x;
457        fillRect( self, gc, drawable, &rect, colors, 2 );
458        x += rtl ? -w : w;
459    }
460
461    if(( w = missingWidth )) {
462        rect.width = w;
463        rect.x = rtl ? x-w : x;
464        fillRect( self, gc, drawable, &rect, self->priv->color_missing, 2 );
465        x += rtl ? -w : w;
466    }
467
468    if(( w = unwantedWidth )) {
469        rect.width = w;
470        rect.x = rtl ? x-w : x;
471        fillRect( self, gc, drawable, &rect, self->priv->color_unwanted, 2 );
472        x += rtl ? -w : w;
473    }
474
475    if(( w = unavailableWidth )) {
476        const GdkColor * colors = isActive && self->priv->show_unavailable
477                                ? self->priv->color_unavailable
478                                : self->priv->color_missing;
479        rect.width = w;
480        rect.x = rtl ? x-w : x;
481        fillRect( self, gc, drawable, &rect, colors, 2 );
482        x += rtl ? -w : w;
483    }
484
485    if( isChecking ) {
486        const int checkedWidth = torStat->recheckProgress * area->width;
487        const int h2 = area->height / 2;
488        rect = *area;
489        rect.y += h2;
490        rect.height -= h2;
491        fillRect( self, gc, drawable, &rect, self->priv->color_missing, 2 );
492        rect.width = checkedWidth;
493        fillRect( self, gc, drawable, &rect, self->priv->color_verifying, 2 );
494    }
495
496    gtk_paint_shadow( gtk_widget_get_style( widget ),
497                      drawable,
498                      GTK_STATE_NORMAL,
499                      GTK_SHADOW_IN,
500                      NULL,
501                      widget,
502                      NULL,
503                      area->x, area->y, area->width, area->height );
504
505    gdk_gc_unref( gc );
506}
507
508static void
509torrent_cell_renderer_render( GtkCellRenderer      * cell,
510                              GdkDrawable          * window,
511                              GtkWidget            * widget,
512                              GdkRectangle         * background_area,
513                              GdkRectangle         * cell_area UNUSED,
514                              GdkRectangle         * expose_area UNUSED,
515                              GtkCellRendererState   flags)
516{
517    TorrentCellRenderer * self = TORRENT_CELL_RENDERER( cell );
518    if( self && self->priv->tor )
519    {
520        const tr_torrent * tor = self->priv->tor;
521        const tr_info * info = tr_torrentInfo( tor );
522        const char * name = info->name;
523        const tr_stat * torStat = tr_torrentStatCached( (tr_torrent*)tor );
524        GdkRectangle my_bg;
525        GdkRectangle my_cell;
526        GdkRectangle my_expose;
527        int xpad, ypad;
528        int w, h;
529        struct TorrentCellRendererPrivate * p = self->priv;
530        GtkCellRenderer * text_renderer = torStat->error != 0
531            ? p->text_renderer_err
532            : p->text_renderer;
533
534        g_object_get( self, "xpad", &xpad, "ypad", &ypad, NULL );
535
536        my_bg = *background_area; 
537        my_bg.x += xpad;
538        my_bg.y += ypad;
539        my_bg.width -= xpad*2;
540        my_cell = my_expose = my_bg;
541
542        /* above the progressbar */
543        if( !p->minimal )
544        {
545            char * progressString = getProgressString( info, torStat );
546            char * str = g_markup_printf_escaped( "<b>%s</b>\n<small>%s</small>",
547                                                  name, progressString );
548            g_object_set( text_renderer, "markup", str,
549                                            "ellipsize", PANGO_ELLIPSIZE_NONE,
550                                            NULL );
551            gtk_cell_renderer_get_size( text_renderer,
552                                        widget, NULL, NULL, NULL, &w, &h );
553            my_bg.height     = 
554            my_cell.height   =
555            my_expose.height = h;
556            g_object_set( text_renderer, "ellipsize", PANGO_ELLIPSIZE_END,
557                                            NULL );
558            gtk_cell_renderer_render( text_renderer,
559                                      window, widget,
560                                      &my_bg, &my_cell, &my_expose, flags );
561            my_bg.y += h;
562            my_cell.y += h;
563            my_expose.y += h;
564
565            g_free( str );
566            g_free( progressString );
567        }
568        else
569        {
570            char * statusStr = getShortStatusString( torStat );
571            char * str = g_markup_printf_escaped( "<small>%s</small>", statusStr );
572            int w1, w2, h1, h2, tmp_h;
573            GdkRectangle tmp_bg, tmp_cell, tmp_expose;
574
575            /* get the dimensions for the name */
576            g_object_set( text_renderer, "text", name,
577                                         "ellipsize", PANGO_ELLIPSIZE_NONE,
578                                         NULL );
579            gtk_cell_renderer_get_size( text_renderer,
580                                        widget, NULL, NULL, NULL, &w1, &h1 );
581
582            /* get the dimensions for the short status string */
583            g_object_set( text_renderer, "markup", str,
584                                         "ellipsize", PANGO_ELLIPSIZE_NONE,
585                                         NULL );
586            gtk_cell_renderer_get_size( text_renderer,
587                                        widget, NULL, NULL, NULL, &w2, &h2 );
588
589            tmp_h = MAX( h1, h2 );
590
591            /* short status */
592            tmp_bg.x = my_bg.width - w2;
593            tmp_bg.y = my_bg.y + (h2-h1)/2;
594            tmp_bg.width = w2;
595            tmp_bg.height = tmp_h;
596            tmp_expose = tmp_cell = tmp_bg;
597            g_object_set( text_renderer, "markup", str,
598                                         "ellipsize", PANGO_ELLIPSIZE_END,
599                                         NULL );
600            gtk_cell_renderer_render( text_renderer,
601                                      window, widget,
602                                      &tmp_bg, &tmp_cell, &tmp_expose, flags );
603
604            /* name */
605            tmp_bg.x = my_bg.x;
606            tmp_bg.width = my_bg.width - w2 - GUI_PAD_BIG;
607            tmp_expose = tmp_cell = tmp_bg;
608            g_object_set( text_renderer, "text", name,
609                                         "ellipsize", PANGO_ELLIPSIZE_END,
610                                         NULL );
611            gtk_cell_renderer_render( text_renderer,
612                                      window, widget,
613                                      &tmp_bg, &tmp_cell, &tmp_expose, flags );
614
615            my_bg.y = tmp_bg.y + tmp_bg.height;
616            my_cell.y = tmp_cell.y + tmp_cell.height;
617            my_expose.y += tmp_expose.y + tmp_cell.height;
618
619            g_free( str );
620            g_free( statusStr );
621        }
622
623        /* the progressbar */
624        my_cell.height = p->bar_height;
625        drawRegularBar( self, info, torStat, window, widget, &my_cell );
626        my_bg.y     += my_cell.height;
627        my_cell.y   += my_cell.height;
628        my_expose.y += my_cell.height;
629
630        /* below progressbar */
631        if( !p->minimal )
632        {
633            char * statusString = getStatusString( torStat );
634            char * str = g_markup_printf_escaped( "<small>%s</small>",
635                                                  statusString );
636            g_object_set( text_renderer, "markup", str,
637                                         "ellipsize", PANGO_ELLIPSIZE_END,
638                                         NULL );
639            gtk_cell_renderer_get_size( text_renderer,
640                                        widget, NULL, NULL, NULL, &w, &h );
641            my_bg.height      =
642            my_cell.height    =
643            my_expose.height  = h;
644            gtk_cell_renderer_render( text_renderer,
645                                      window, widget,
646                                      &my_bg, &my_cell, &my_expose, flags );
647
648            g_free( str );
649            g_free( statusString );
650        }
651    }
652}
653
654static void
655v2c( GdkColor * color, const GValue * value )
656{
657    gdk_color_parse( g_value_get_string( value ), color );
658}
659
660static void
661torrent_cell_renderer_set_property( GObject      * object,
662                                    guint          property_id,
663                                    const GValue * v,
664                                    GParamSpec   * pspec)
665{
666    TorrentCellRenderer * self = TORRENT_CELL_RENDERER( object );
667    struct TorrentCellRendererPrivate * p = self->priv;
668
669    switch( property_id )
670    {
671        case P_COLOR_MISSING:       v2c( &p->color_missing[0],     v ); break;
672        case P_COLOR_MISSING_2:     v2c( &p->color_missing[1],     v ); break;
673        case P_COLOR_UNWANTED:      v2c( &p->color_unwanted[0],    v ); break;
674        case P_COLOR_UNWANTED_2:    v2c( &p->color_unwanted[1],    v ); break;
675        case P_COLOR_PAUSED:        v2c( &p->color_paused[0],      v ); break;
676        case P_COLOR_PAUSED_2:      v2c( &p->color_paused[1],      v ); break;
677        case P_COLOR_VERIFIED:      v2c( &p->color_verified[0],    v ); break;
678        case P_COLOR_VERIFIED_2:    v2c( &p->color_verified[1],    v ); break;
679        case P_COLOR_UNAVAILABLE:   v2c( &p->color_unavailable[0], v ); break;
680        case P_COLOR_UNAVAILABLE_2: v2c( &p->color_unavailable[1], v ); break;
681        case P_COLOR_VERIFYING:     v2c( &p->color_verifying[0],   v ); break;
682        case P_COLOR_VERIFYING_2:   v2c( &p->color_verifying[1],   v ); break;
683        case P_COLOR_SEEDING:       v2c( &p->color_seeding[0],     v ); break;
684        case P_COLOR_SEEDING_2:     v2c( &p->color_seeding[1],     v ); break;
685        case P_TORRENT:     p->tor = g_value_get_pointer( v ); break;
686        case P_BAR_HEIGHT:  p->bar_height = g_value_get_int( v ); break;
687        case P_MINIMAL:     p->minimal  = g_value_get_boolean( v ); break;
688        case P_GRADIENT:    p->gradient = g_value_get_boolean( v ); break;
689        case P_SHOW_UNAVAILABLE:
690                            p->show_unavailable = g_value_get_boolean( v ); break;
691        default:
692            G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, pspec );
693            break;
694    }
695}
696
697static void
698c2v( GValue * value, const GdkColor * color )
699{
700    char buf[16];
701    g_snprintf( buf, sizeof(buf), "#%2.2x%2.2x%2.2x",
702                (color->red >> 8) & 0xff,
703                (color->green >> 8) & 0xff,
704                (color->blue >> 8) & 0xff );
705    g_value_set_string( value, buf );
706}
707
708static void
709torrent_cell_renderer_get_property( GObject      * object,
710                                    guint          property_id,
711                                    GValue       * v,
712                                    GParamSpec   * pspec)
713{
714    const TorrentCellRenderer * self = TORRENT_CELL_RENDERER( object );
715    struct TorrentCellRendererPrivate * p = self->priv;
716
717    switch( property_id )
718    {
719        case P_COLOR_MISSING:       c2v( v, &p->color_missing[0] ); break;
720        case P_COLOR_MISSING_2:     c2v( v, &p->color_missing[1] ); break;
721        case P_COLOR_UNWANTED:      c2v( v, &p->color_unwanted[0] ); break;
722        case P_COLOR_UNWANTED_2:    c2v( v, &p->color_unwanted[1] ); break;
723        case P_COLOR_PAUSED:        c2v( v, &p->color_paused[0] ); break;
724        case P_COLOR_PAUSED_2:      c2v( v, &p->color_paused[1] ); break;
725        case P_COLOR_VERIFIED:      c2v( v, &p->color_verified[0] ); break;
726        case P_COLOR_VERIFIED_2:    c2v( v, &p->color_verified[1] ); break;
727        case P_COLOR_UNAVAILABLE:   c2v( v, &p->color_unavailable[0] ); break;
728        case P_COLOR_UNAVAILABLE_2: c2v( v, &p->color_unavailable[1] ); break;
729        case P_COLOR_VERIFYING:     c2v( v, &p->color_verifying[0] ); break;
730        case P_COLOR_VERIFYING_2:   c2v( v, &p->color_verifying[1] ); break;
731        case P_COLOR_SEEDING:       c2v( v, &p->color_seeding[0] ); break;
732        case P_COLOR_SEEDING_2:     c2v( v, &p->color_seeding[1] ); break;
733        case P_TORRENT:     g_value_set_pointer( v, p->tor ); break;
734        case P_BAR_HEIGHT:  g_value_set_int( v, p->bar_height ); break;
735        case P_MINIMAL:     g_value_set_boolean( v, p->minimal ); break;
736        case P_GRADIENT:    g_value_set_boolean( v, p->gradient ); break;
737        case P_SHOW_UNAVAILABLE:
738                            g_value_set_boolean( v, p->show_unavailable ); break;
739        default:
740            G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, pspec );
741            break;
742    }
743}
744
745static void
746torrent_cell_renderer_dispose( GObject * o )
747{
748    TorrentCellRenderer * r = TORRENT_CELL_RENDERER( o );
749    GObjectClass * parent;
750
751    if( r && r->priv )
752    {
753        g_object_unref( G_OBJECT( r->priv->text_renderer ) );
754        g_object_unref( G_OBJECT( r->priv->text_renderer_err ) );
755        r->priv = NULL;
756    }
757
758    parent = g_type_class_peek( g_type_parent( TORRENT_CELL_RENDERER_TYPE ) );
759    parent->dispose( o );
760}
761
762static void
763torrent_cell_renderer_class_init( TorrentCellRendererClass * klass )
764{
765    GObjectClass * gobject_class = G_OBJECT_CLASS( klass );
766    GtkCellRendererClass * cell_class = GTK_CELL_RENDERER_CLASS( klass );
767
768    g_type_class_add_private( klass,
769                              sizeof(struct TorrentCellRendererPrivate) );
770
771    parent_class = (GtkCellRendererClass*) g_type_class_peek_parent( klass );
772
773    cell_class->render = torrent_cell_renderer_render;
774    cell_class->get_size = torrent_cell_renderer_get_size;
775    gobject_class->set_property = torrent_cell_renderer_set_property;
776    gobject_class->get_property = torrent_cell_renderer_get_property;
777    gobject_class->dispose = torrent_cell_renderer_dispose;
778
779    g_object_class_install_property( gobject_class, P_TORRENT,
780        g_param_spec_pointer( "torrent", NULL, "tr_torrent*",
781                              G_PARAM_READWRITE ) );
782
783    g_object_class_install_property( gobject_class, P_BAR_HEIGHT,
784        g_param_spec_int( "bar-height", NULL, "Bar Height",
785                          1, INT_MAX, DEFAULT_BAR_HEIGHT, G_PARAM_READWRITE ) );
786
787    g_object_class_install_property( gobject_class, P_MINIMAL,
788        g_param_spec_boolean( "minimal", NULL, "Minimal Mode",
789                              FALSE, G_PARAM_READWRITE ) );
790
791    g_object_class_install_property( gobject_class, P_GRADIENT,
792        g_param_spec_boolean( "gradient", NULL, "Render Progress as a Gradient",
793                              TRUE, G_PARAM_READWRITE ) );
794
795    g_object_class_install_property( gobject_class, P_SHOW_UNAVAILABLE,
796        g_param_spec_boolean( "unavailable", NULL, "Show Unavailable",
797                              FALSE, G_PARAM_READWRITE ) );
798
799    g_object_class_install_property( gobject_class, P_COLOR_MISSING,
800        g_param_spec_string( "missing-color", NULL, "Color for Missing Data",
801                             DEFAULT_COLOR_MISSING, G_PARAM_READWRITE ) );
802
803    g_object_class_install_property( gobject_class, P_COLOR_MISSING,
804        g_param_spec_string( "missing-color-2", NULL, "Gradient Color for Missing Data",
805                             DEFAULT_COLOR_MISSING_2, G_PARAM_READWRITE ) );
806
807    g_object_class_install_property( gobject_class, P_COLOR_UNWANTED,
808        g_param_spec_string( "unwanted-color", NULL, "Color for Unwanted Data",
809                             DEFAULT_COLOR_UNWANTED, G_PARAM_READWRITE ) );
810
811    g_object_class_install_property( gobject_class, P_COLOR_UNWANTED_2,
812        g_param_spec_string( "unwanted-color-2", NULL, "Gradient Color for Unwanted Data",
813                             DEFAULT_COLOR_UNWANTED_2, G_PARAM_READWRITE ) );
814
815    g_object_class_install_property( gobject_class, P_COLOR_PAUSED,
816        g_param_spec_string( "paused-color", NULL, "Color for Paused Data",
817                             DEFAULT_COLOR_PAUSED, G_PARAM_READWRITE ) );
818
819    g_object_class_install_property( gobject_class, P_COLOR_PAUSED_2,
820        g_param_spec_string( "paused-color-2", NULL, "Gradient Color for Paused Data",
821                             DEFAULT_COLOR_PAUSED_2, G_PARAM_READWRITE ) );
822
823    g_object_class_install_property( gobject_class, P_COLOR_VERIFIED,
824        g_param_spec_string( "verified-color", NULL, "Color for Verified Data",
825                             DEFAULT_COLOR_VERIFIED, G_PARAM_READWRITE ) );
826
827    g_object_class_install_property( gobject_class, P_COLOR_VERIFIED_2,
828        g_param_spec_string( "verified-color-2", NULL, "Gradient Color for Verified Data",
829                             DEFAULT_COLOR_VERIFIED_2, G_PARAM_READWRITE ) );
830
831    g_object_class_install_property( gobject_class, P_COLOR_UNAVAILABLE,
832        g_param_spec_string( "unavailable-color", NULL, "Color for Unavailable Data",
833                             DEFAULT_COLOR_UNAVAILABLE, G_PARAM_READWRITE ) );
834
835    g_object_class_install_property( gobject_class, P_COLOR_UNAVAILABLE_2,
836        g_param_spec_string( "unavailable-color-2", NULL, "Gradient Color for Unavailable Data",
837                             DEFAULT_COLOR_UNAVAILABLE_2, G_PARAM_READWRITE ) );
838
839    g_object_class_install_property( gobject_class, P_COLOR_VERIFYING,
840        g_param_spec_string( "verifying-color", NULL, "Color for Verifying Data",
841                             DEFAULT_COLOR_VERIFYING, G_PARAM_READWRITE ) );
842
843    g_object_class_install_property( gobject_class, P_COLOR_VERIFYING_2,
844        g_param_spec_string( "verifying-color-2", NULL, "Gradient Color for Verifying Data",
845                             DEFAULT_COLOR_VERIFYING_2, G_PARAM_READWRITE ) );
846
847    g_object_class_install_property( gobject_class, P_COLOR_SEEDING,
848        g_param_spec_string( "seeding-color", NULL, "Color for Seeding Data",
849                             DEFAULT_COLOR_SEEDING, G_PARAM_READWRITE ) );
850
851    g_object_class_install_property( gobject_class, P_COLOR_SEEDING_2,
852        g_param_spec_string( "seeding-color-2", NULL, "Second Color for Seeding Data",
853                             DEFAULT_COLOR_SEEDING_2, G_PARAM_READWRITE ) );
854}
855
856static void
857torrent_cell_renderer_init( GTypeInstance * instance, gpointer g_class UNUSED )
858{
859    TorrentCellRenderer * self = TORRENT_CELL_RENDERER( instance );
860    struct TorrentCellRendererPrivate * p;
861   
862    p = self->priv = G_TYPE_INSTANCE_GET_PRIVATE( self,
863                         TORRENT_CELL_RENDERER_TYPE,
864                         struct TorrentCellRendererPrivate );
865
866    p->tor = NULL;
867    p->text_renderer = gtk_cell_renderer_text_new( );
868    p->text_renderer_err = gtk_cell_renderer_text_new(  );
869    g_object_set( p->text_renderer_err, "foreground", "red", NULL );
870    tr_object_ref_sink( p->text_renderer );
871    tr_object_ref_sink( p->text_renderer_err );
872
873    p->gradient = TRUE;
874    p->show_unavailable = TRUE;
875    p->bar_height = DEFAULT_BAR_HEIGHT;
876
877    gdk_color_parse( DEFAULT_COLOR_VERIFIED,      &p->color_verified[0] );
878    gdk_color_parse( DEFAULT_COLOR_VERIFIED_2,    &p->color_verified[1] );
879    gdk_color_parse( DEFAULT_COLOR_MISSING,       &p->color_missing[0] );
880    gdk_color_parse( DEFAULT_COLOR_MISSING_2,     &p->color_missing[1] );
881    gdk_color_parse( DEFAULT_COLOR_UNWANTED,      &p->color_unwanted[0] );
882    gdk_color_parse( DEFAULT_COLOR_UNWANTED_2,    &p->color_unwanted[1] );
883    gdk_color_parse( DEFAULT_COLOR_UNAVAILABLE,   &p->color_unavailable[0] );
884    gdk_color_parse( DEFAULT_COLOR_UNAVAILABLE_2, &p->color_unavailable[1] );
885    gdk_color_parse( DEFAULT_COLOR_VERIFYING,     &p->color_verifying[0] );
886    gdk_color_parse( DEFAULT_COLOR_VERIFYING_2,   &p->color_verifying[1] );
887    gdk_color_parse( DEFAULT_COLOR_SEEDING,       &p->color_seeding[0] );
888    gdk_color_parse( DEFAULT_COLOR_SEEDING_2,     &p->color_seeding[1] );
889    gdk_color_parse( DEFAULT_COLOR_PAUSED,        &p->color_paused[0] );
890    gdk_color_parse( DEFAULT_COLOR_PAUSED_2,      &p->color_paused[1] );
891}
892
893GType
894torrent_cell_renderer_get_type( void )
895{
896    static GType type = 0;
897
898    if( !type )
899    {
900        static const GTypeInfo info =
901        {
902            sizeof( TorrentCellRendererClass ),
903            NULL, /* base_init */
904            NULL, /* base_finalize */
905            (GClassInitFunc)torrent_cell_renderer_class_init,
906            NULL, /* class_finalize */
907            NULL, /* class_data */
908            sizeof( TorrentCellRenderer ),
909            0, /* n_preallocs */
910            (GInstanceInitFunc)torrent_cell_renderer_init,
911            NULL
912        };
913
914        type = g_type_register_static( GTK_TYPE_CELL_RENDERER,
915                                       "TorrentCellRenderer",
916                                       &info, (GTypeFlags)0 );
917    }
918
919    return type;
920}
921
922GtkCellRenderer *
923torrent_cell_renderer_new( void )
924{
925    return (GtkCellRenderer *) g_object_new( TORRENT_CELL_RENDERER_TYPE, NULL );
926}
Note: See TracBrowser for help on using the repository browser.