source: branches/1.0x/gtk/torrent-cell-renderer.c @ 4963

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

(gtk 1.0x) #550: by default, use tango colors in the main window

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