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

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

(gtk) fix main window formatting error for torrents whose local data's being verified

File size: 34.7 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#if 1
407    const double verified = torStat->haveValid / (double)info->totalSize;
408    const double unverified = torStat->haveUnchecked / (double)info->totalSize;
409    const double unavailable = ( torStat->desiredSize
410                       - torStat->desiredAvailable ) / (double)info->totalSize;
411    const double unwanted = ( info->totalSize
412                            - torStat->desiredSize ) / (double)info->totalSize;
413#else /* for testing */
414    const double verified = 0.5;
415    const double unverified = 0.1;
416    const double unavailable = 0.1;
417    const double unwanted = 0.1;
418#endif
419    const double missing = 1.0 - verified - unverified - unavailable - unwanted;
420    const int verifiedWidth = (int)( verified * area->width );
421    const int unverifiedWidth = (int)( unverified * area->width );
422    const int unavailableWidth = (int)( unavailable * area->width );
423    const int unwantedWidth = (int)( unwanted * area->width );
424    const int missingWidth = (int)( missing * area->width );
425
426    const gboolean isActive = torStat->status == TR_STATUS_DOWNLOAD
427                           || torStat->status == TR_STATUS_DONE
428                           || torStat->status == TR_STATUS_SEED;
429    const gboolean isChecking = torStat->status == TR_STATUS_CHECK
430                             || torStat->status == TR_STATUS_CHECK_WAIT;
431
432    int x = area->x;
433    int w = 0;
434    GdkGC * gc = gdk_gc_new( drawable );
435    GdkRectangle rect = *area;
436
437    if(( w = verifiedWidth )) {
438        const GdkColor * colors;
439        if( !isActive )
440            colors = self->priv->color_paused;
441        else if( torStat->status == TR_STATUS_DOWNLOAD )
442            colors = self->priv->color_verified;
443        else
444            colors = self->priv->color_seeding;
445        rect.x = x;
446        rect.width = w;
447        fillRect( self, gc, drawable, &rect, colors, 2 );
448        x += w;
449    }
450
451    if(( w = unverifiedWidth )) {
452        const GdkColor * colors = isActive ? self->priv->color_verifying
453                                           : self->priv->color_paused;
454        rect.x = x;
455        rect.width = w;
456        fillRect( self, gc, drawable, &rect, colors, 2 );
457        x += w;
458    }
459
460    if(( w = missingWidth )) {
461        rect.x = x;
462        rect.width = w;
463        fillRect( self, gc, drawable, &rect, self->priv->color_missing, 2 );
464        x += w;
465    }
466
467    if(( w = unwantedWidth )) {
468        rect.x = x;
469        rect.width = w;
470        fillRect( self, gc, drawable, &rect, self->priv->color_unwanted, 2 );
471        x += w;
472    }
473
474    if(( w = unavailableWidth )) {
475        const GdkColor * colors = isActive && self->priv->show_unavailable
476                                ? self->priv->color_unavailable
477                                : self->priv->color_missing;
478        rect.x = x;
479        rect.width = w;
480        fillRect( self, gc, drawable, &rect, colors, 2 );
481        x += w;
482    }
483
484    if( isChecking ) {
485        const int checkedWidth = torStat->recheckProgress * area->width;
486        const int h2 = area->height / 2;
487        rect = *area;
488        rect.y += h2;
489        rect.height -= h2;
490        fillRect( self, gc, drawable, &rect, self->priv->color_missing, 2 );
491        rect.width = checkedWidth;
492        fillRect( self, gc, drawable, &rect, self->priv->color_verifying, 2 );
493    }
494
495    gtk_paint_shadow( gtk_widget_get_style( widget ),
496                      drawable,
497                      GTK_STATE_NORMAL,
498                      GTK_SHADOW_IN,
499                      NULL,
500                      widget,
501                      NULL,
502                      area->x, area->y, area->width, area->height );
503
504    gdk_gc_unref( gc );
505}
506
507static void
508torrent_cell_renderer_render( GtkCellRenderer      * cell,
509                              GdkDrawable          * window,
510                              GtkWidget            * widget,
511                              GdkRectangle         * background_area,
512                              GdkRectangle         * cell_area UNUSED,
513                              GdkRectangle         * expose_area UNUSED,
514                              GtkCellRendererState   flags)
515{
516    TorrentCellRenderer * self = TORRENT_CELL_RENDERER( cell );
517    if( self && self->priv->tor )
518    {
519        const tr_torrent * tor = self->priv->tor;
520        const tr_info * info = tr_torrentInfo( tor );
521        const char * name = info->name;
522        const tr_stat * torStat = tr_torrentStatCached( (tr_torrent*)tor );
523        GdkRectangle my_bg;
524        GdkRectangle my_cell;
525        GdkRectangle my_expose;
526        int xpad, ypad;
527        int w, h;
528        struct TorrentCellRendererPrivate * p = self->priv;
529        GtkCellRenderer * text_renderer = torStat->error != 0
530            ? p->text_renderer_err
531            : p->text_renderer;
532
533        g_object_get( self, "xpad", &xpad, "ypad", &ypad, NULL );
534
535        my_bg = *background_area; 
536        my_bg.x += xpad;
537        my_bg.y += ypad;
538        my_bg.width -= xpad*2;
539        my_cell = my_expose = my_bg;
540
541        /* above the progressbar */
542        if( !p->minimal )
543        {
544            char * progressString = getProgressString( info, torStat );
545            char * str = g_markup_printf_escaped( "<b>%s</b>\n<small>%s</small>",
546                                                  name, progressString );
547            g_object_set( text_renderer, "markup", str,
548                                            "ellipsize", PANGO_ELLIPSIZE_NONE,
549                                            NULL );
550            gtk_cell_renderer_get_size( text_renderer,
551                                        widget, NULL, NULL, NULL, &w, &h );
552            my_bg.height     = 
553            my_cell.height   =
554            my_expose.height = h;
555            g_object_set( text_renderer, "ellipsize", PANGO_ELLIPSIZE_END,
556                                            NULL );
557            gtk_cell_renderer_render( text_renderer,
558                                      window, widget,
559                                      &my_bg, &my_cell, &my_expose, flags );
560            my_bg.y += h;
561            my_cell.y += h;
562            my_expose.y += h;
563
564            g_free( str );
565            g_free( progressString );
566        }
567        else
568        {
569            char * statusStr = getShortStatusString( torStat );
570            char * str = g_markup_printf_escaped( "<small>%s</small>", statusStr );
571            int w1, w2, h1, h2, tmp_h;
572            GdkRectangle tmp_bg, tmp_cell, tmp_expose;
573
574            /* get the dimensions for the name */
575            g_object_set( text_renderer, "text", name,
576                                         "ellipsize", PANGO_ELLIPSIZE_NONE,
577                                         NULL );
578            gtk_cell_renderer_get_size( text_renderer,
579                                        widget, NULL, NULL, NULL, &w1, &h1 );
580
581            /* get the dimensions for the short status string */
582            g_object_set( text_renderer, "markup", str,
583                                         "ellipsize", PANGO_ELLIPSIZE_NONE,
584                                         NULL );
585            gtk_cell_renderer_get_size( text_renderer,
586                                        widget, NULL, NULL, NULL, &w2, &h2 );
587
588            tmp_h = MAX( h1, h2 );
589
590            /* short status */
591            tmp_bg.x = my_bg.width - w2;
592            tmp_bg.y = my_bg.y + (h2-h1)/2;
593            tmp_bg.width = w2;
594            tmp_bg.height = tmp_h;
595            tmp_expose = tmp_cell = tmp_bg;
596            g_object_set( text_renderer, "markup", str,
597                                         "ellipsize", PANGO_ELLIPSIZE_END,
598                                         NULL );
599            gtk_cell_renderer_render( text_renderer,
600                                      window, widget,
601                                      &tmp_bg, &tmp_cell, &tmp_expose, flags );
602
603            /* name */
604            tmp_bg.x = my_bg.x;
605            tmp_bg.width = my_bg.width - w2 - GUI_PAD_BIG;
606            tmp_expose = tmp_cell = tmp_bg;
607            g_object_set( text_renderer, "text", name,
608                                         "ellipsize", PANGO_ELLIPSIZE_END,
609                                         NULL );
610            gtk_cell_renderer_render( text_renderer,
611                                      window, widget,
612                                      &tmp_bg, &tmp_cell, &tmp_expose, flags );
613
614            my_bg.y = tmp_bg.y + tmp_bg.height;
615            my_cell.y = tmp_cell.y + tmp_cell.height;
616            my_expose.y += tmp_expose.y + tmp_cell.height;
617
618            g_free( str );
619            g_free( statusStr );
620        }
621
622        /* the progressbar */
623        my_cell.height = p->bar_height;
624        drawRegularBar( self, info, torStat, window, widget, &my_cell );
625        my_bg.y     += my_cell.height;
626        my_cell.y   += my_cell.height;
627        my_expose.y += my_cell.height;
628
629        /* below progressbar */
630        if( !p->minimal )
631        {
632            char * statusString = getStatusString( torStat );
633            char * str = g_markup_printf_escaped( "<small>%s</small>",
634                                                  statusString );
635            g_object_set( text_renderer, "markup", str,
636                                         "ellipsize", PANGO_ELLIPSIZE_END,
637                                         NULL );
638            gtk_cell_renderer_get_size( text_renderer,
639                                        widget, NULL, NULL, NULL, &w, &h );
640            my_bg.height      =
641            my_cell.height    =
642            my_expose.height  = h;
643            gtk_cell_renderer_render( text_renderer,
644                                      window, widget,
645                                      &my_bg, &my_cell, &my_expose, flags );
646
647            g_free( str );
648            g_free( statusString );
649        }
650    }
651}
652
653static void
654v2c( GdkColor * color, const GValue * value )
655{
656    gdk_color_parse( g_value_get_string( value ), color );
657}
658
659static void
660torrent_cell_renderer_set_property( GObject      * object,
661                                    guint          property_id,
662                                    const GValue * v,
663                                    GParamSpec   * pspec)
664{
665    TorrentCellRenderer * self = TORRENT_CELL_RENDERER( object );
666    struct TorrentCellRendererPrivate * p = self->priv;
667
668    switch( property_id )
669    {
670        case P_COLOR_MISSING:       v2c( &p->color_missing[0],     v ); break;
671        case P_COLOR_MISSING_2:     v2c( &p->color_missing[1],     v ); break;
672        case P_COLOR_UNWANTED:      v2c( &p->color_unwanted[0],    v ); break;
673        case P_COLOR_UNWANTED_2:    v2c( &p->color_unwanted[1],    v ); break;
674        case P_COLOR_PAUSED:        v2c( &p->color_paused[0],      v ); break;
675        case P_COLOR_PAUSED_2:      v2c( &p->color_paused[1],      v ); break;
676        case P_COLOR_VERIFIED:      v2c( &p->color_verified[0],    v ); break;
677        case P_COLOR_VERIFIED_2:    v2c( &p->color_verified[1],    v ); break;
678        case P_COLOR_UNAVAILABLE:   v2c( &p->color_unavailable[0], v ); break;
679        case P_COLOR_UNAVAILABLE_2: v2c( &p->color_unavailable[1], v ); break;
680        case P_COLOR_VERIFYING:     v2c( &p->color_verifying[0],   v ); break;
681        case P_COLOR_VERIFYING_2:   v2c( &p->color_verifying[1],   v ); break;
682        case P_COLOR_SEEDING:       v2c( &p->color_seeding[0],     v ); break;
683        case P_COLOR_SEEDING_2:     v2c( &p->color_seeding[1],     v ); break;
684        case P_TORRENT:     p->tor = g_value_get_pointer( v ); break;
685        case P_BAR_HEIGHT:  p->bar_height = g_value_get_int( v ); break;
686        case P_MINIMAL:     p->minimal  = g_value_get_boolean( v ); break;
687        case P_GRADIENT:    p->gradient = g_value_get_boolean( v ); break;
688        case P_SHOW_UNAVAILABLE:
689                            p->show_unavailable = g_value_get_boolean( v ); break;
690        default:
691            G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, pspec );
692            break;
693    }
694}
695
696static void
697c2v( GValue * value, const GdkColor * color )
698{
699    char buf[16];
700    g_snprintf( buf, sizeof(buf), "#%2.2x%2.2x%2.2x",
701                (color->red >> 8) & 0xff,
702                (color->green >> 8) & 0xff,
703                (color->blue >> 8) & 0xff );
704    g_value_set_string( value, buf );
705}
706
707static void
708torrent_cell_renderer_get_property( GObject      * object,
709                                    guint          property_id,
710                                    GValue       * v,
711                                    GParamSpec   * pspec)
712{
713    const TorrentCellRenderer * self = TORRENT_CELL_RENDERER( object );
714    struct TorrentCellRendererPrivate * p = self->priv;
715
716    switch( property_id )
717    {
718        case P_COLOR_MISSING:       c2v( v, &p->color_missing[0] ); break;
719        case P_COLOR_MISSING_2:     c2v( v, &p->color_missing[1] ); break;
720        case P_COLOR_UNWANTED:      c2v( v, &p->color_unwanted[0] ); break;
721        case P_COLOR_UNWANTED_2:    c2v( v, &p->color_unwanted[1] ); break;
722        case P_COLOR_PAUSED:        c2v( v, &p->color_paused[0] ); break;
723        case P_COLOR_PAUSED_2:      c2v( v, &p->color_paused[1] ); break;
724        case P_COLOR_VERIFIED:      c2v( v, &p->color_verified[0] ); break;
725        case P_COLOR_VERIFIED_2:    c2v( v, &p->color_verified[1] ); break;
726        case P_COLOR_UNAVAILABLE:   c2v( v, &p->color_unavailable[0] ); break;
727        case P_COLOR_UNAVAILABLE_2: c2v( v, &p->color_unavailable[1] ); break;
728        case P_COLOR_VERIFYING:     c2v( v, &p->color_verifying[0] ); break;
729        case P_COLOR_VERIFYING_2:   c2v( v, &p->color_verifying[1] ); break;
730        case P_COLOR_SEEDING:       c2v( v, &p->color_seeding[0] ); break;
731        case P_COLOR_SEEDING_2:     c2v( v, &p->color_seeding[1] ); break;
732        case P_TORRENT:     g_value_set_pointer( v, p->tor ); break;
733        case P_BAR_HEIGHT:  g_value_set_int( v, p->bar_height ); break;
734        case P_MINIMAL:     g_value_set_boolean( v, p->minimal ); break;
735        case P_GRADIENT:    g_value_set_boolean( v, p->gradient ); break;
736        case P_SHOW_UNAVAILABLE:
737                            g_value_set_boolean( v, p->show_unavailable ); break;
738        default:
739            G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, pspec );
740            break;
741    }
742}
743
744static void
745torrent_cell_renderer_dispose( GObject * o )
746{
747    TorrentCellRenderer * r = TORRENT_CELL_RENDERER( o );
748    GObjectClass * parent;
749
750    if( r && r->priv )
751    {
752        g_object_unref( G_OBJECT( r->priv->text_renderer ) );
753        g_object_unref( G_OBJECT( r->priv->text_renderer_err ) );
754        r->priv = NULL;
755    }
756
757    parent = g_type_class_peek( g_type_parent( TORRENT_CELL_RENDERER_TYPE ) );
758    parent->dispose( o );
759}
760
761static void
762torrent_cell_renderer_class_init( TorrentCellRendererClass * klass )
763{
764    GObjectClass * gobject_class = G_OBJECT_CLASS( klass );
765    GtkCellRendererClass * cell_class = GTK_CELL_RENDERER_CLASS( klass );
766
767    g_type_class_add_private( klass,
768                              sizeof(struct TorrentCellRendererPrivate) );
769
770    parent_class = (GtkCellRendererClass*) g_type_class_peek_parent( klass );
771
772    cell_class->render = torrent_cell_renderer_render;
773    cell_class->get_size = torrent_cell_renderer_get_size;
774    gobject_class->set_property = torrent_cell_renderer_set_property;
775    gobject_class->get_property = torrent_cell_renderer_get_property;
776    gobject_class->dispose = torrent_cell_renderer_dispose;
777
778    g_object_class_install_property( gobject_class, P_TORRENT,
779        g_param_spec_pointer( "torrent", NULL, "tr_torrent*",
780                              G_PARAM_READWRITE ) );
781
782    g_object_class_install_property( gobject_class, P_BAR_HEIGHT,
783        g_param_spec_int( "bar-height", NULL, "Bar Height",
784                          1, INT_MAX, DEFAULT_BAR_HEIGHT, G_PARAM_READWRITE ) );
785
786    g_object_class_install_property( gobject_class, P_MINIMAL,
787        g_param_spec_boolean( "minimal", NULL, "Minimal Mode",
788                              FALSE, G_PARAM_READWRITE ) );
789
790    g_object_class_install_property( gobject_class, P_GRADIENT,
791        g_param_spec_boolean( "gradient", NULL, "Render Progress as a Gradient",
792                              TRUE, G_PARAM_READWRITE ) );
793
794    g_object_class_install_property( gobject_class, P_SHOW_UNAVAILABLE,
795        g_param_spec_boolean( "unavailable", NULL, "Show Unavailable",
796                              FALSE, G_PARAM_READWRITE ) );
797
798    g_object_class_install_property( gobject_class, P_COLOR_MISSING,
799        g_param_spec_string( "missing-color", NULL, "Color for Missing Data",
800                             DEFAULT_COLOR_MISSING, G_PARAM_READWRITE ) );
801
802    g_object_class_install_property( gobject_class, P_COLOR_MISSING,
803        g_param_spec_string( "missing-color-2", NULL, "Gradient Color for Missing Data",
804                             DEFAULT_COLOR_MISSING_2, G_PARAM_READWRITE ) );
805
806    g_object_class_install_property( gobject_class, P_COLOR_UNWANTED,
807        g_param_spec_string( "unwanted-color", NULL, "Color for Unwanted Data",
808                             DEFAULT_COLOR_UNWANTED, G_PARAM_READWRITE ) );
809
810    g_object_class_install_property( gobject_class, P_COLOR_UNWANTED_2,
811        g_param_spec_string( "unwanted-color-2", NULL, "Gradient Color for Unwanted Data",
812                             DEFAULT_COLOR_UNWANTED_2, G_PARAM_READWRITE ) );
813
814    g_object_class_install_property( gobject_class, P_COLOR_PAUSED,
815        g_param_spec_string( "paused-color", NULL, "Color for Paused Data",
816                             DEFAULT_COLOR_PAUSED, G_PARAM_READWRITE ) );
817
818    g_object_class_install_property( gobject_class, P_COLOR_PAUSED_2,
819        g_param_spec_string( "paused-color-2", NULL, "Gradient Color for Paused Data",
820                             DEFAULT_COLOR_PAUSED_2, G_PARAM_READWRITE ) );
821
822    g_object_class_install_property( gobject_class, P_COLOR_VERIFIED,
823        g_param_spec_string( "verified-color", NULL, "Color for Verified Data",
824                             DEFAULT_COLOR_VERIFIED, G_PARAM_READWRITE ) );
825
826    g_object_class_install_property( gobject_class, P_COLOR_VERIFIED_2,
827        g_param_spec_string( "verified-color-2", NULL, "Gradient Color for Verified Data",
828                             DEFAULT_COLOR_VERIFIED_2, G_PARAM_READWRITE ) );
829
830    g_object_class_install_property( gobject_class, P_COLOR_UNAVAILABLE,
831        g_param_spec_string( "unavailable-color", NULL, "Color for Unavailable Data",
832                             DEFAULT_COLOR_UNAVAILABLE, G_PARAM_READWRITE ) );
833
834    g_object_class_install_property( gobject_class, P_COLOR_UNAVAILABLE_2,
835        g_param_spec_string( "unavailable-color-2", NULL, "Gradient Color for Unavailable Data",
836                             DEFAULT_COLOR_UNAVAILABLE_2, G_PARAM_READWRITE ) );
837
838    g_object_class_install_property( gobject_class, P_COLOR_VERIFYING,
839        g_param_spec_string( "verifying-color", NULL, "Color for Verifying Data",
840                             DEFAULT_COLOR_VERIFYING, G_PARAM_READWRITE ) );
841
842    g_object_class_install_property( gobject_class, P_COLOR_VERIFYING_2,
843        g_param_spec_string( "verifying-color-2", NULL, "Gradient Color for Verifying Data",
844                             DEFAULT_COLOR_VERIFYING_2, G_PARAM_READWRITE ) );
845
846    g_object_class_install_property( gobject_class, P_COLOR_SEEDING,
847        g_param_spec_string( "seeding-color", NULL, "Color for Seeding Data",
848                             DEFAULT_COLOR_SEEDING, G_PARAM_READWRITE ) );
849
850    g_object_class_install_property( gobject_class, P_COLOR_SEEDING_2,
851        g_param_spec_string( "seeding-color-2", NULL, "Second Color for Seeding Data",
852                             DEFAULT_COLOR_SEEDING_2, G_PARAM_READWRITE ) );
853}
854
855static void
856torrent_cell_renderer_init( GTypeInstance * instance, gpointer g_class UNUSED )
857{
858    TorrentCellRenderer * self = TORRENT_CELL_RENDERER( instance );
859    struct TorrentCellRendererPrivate * p;
860   
861    p = self->priv = G_TYPE_INSTANCE_GET_PRIVATE( self,
862                         TORRENT_CELL_RENDERER_TYPE,
863                         struct TorrentCellRendererPrivate );
864
865    p->tor = NULL;
866    p->text_renderer = gtk_cell_renderer_text_new( );
867    p->text_renderer_err = gtk_cell_renderer_text_new(  );
868    g_object_set( p->text_renderer_err, "foreground", "red", NULL );
869    tr_object_ref_sink( p->text_renderer );
870    tr_object_ref_sink( p->text_renderer_err );
871
872    p->gradient = TRUE;
873    p->show_unavailable = TRUE;
874    p->bar_height = DEFAULT_BAR_HEIGHT;
875
876    gdk_color_parse( DEFAULT_COLOR_VERIFIED,      &p->color_verified[0] );
877    gdk_color_parse( DEFAULT_COLOR_VERIFIED_2,    &p->color_verified[1] );
878    gdk_color_parse( DEFAULT_COLOR_MISSING,       &p->color_missing[0] );
879    gdk_color_parse( DEFAULT_COLOR_MISSING_2,     &p->color_missing[1] );
880    gdk_color_parse( DEFAULT_COLOR_UNWANTED,      &p->color_unwanted[0] );
881    gdk_color_parse( DEFAULT_COLOR_UNWANTED_2,    &p->color_unwanted[1] );
882    gdk_color_parse( DEFAULT_COLOR_UNAVAILABLE,   &p->color_unavailable[0] );
883    gdk_color_parse( DEFAULT_COLOR_UNAVAILABLE_2, &p->color_unavailable[1] );
884    gdk_color_parse( DEFAULT_COLOR_VERIFYING,     &p->color_verifying[0] );
885    gdk_color_parse( DEFAULT_COLOR_VERIFYING_2,   &p->color_verifying[1] );
886    gdk_color_parse( DEFAULT_COLOR_SEEDING,       &p->color_seeding[0] );
887    gdk_color_parse( DEFAULT_COLOR_SEEDING_2,     &p->color_seeding[1] );
888    gdk_color_parse( DEFAULT_COLOR_PAUSED,        &p->color_paused[0] );
889    gdk_color_parse( DEFAULT_COLOR_PAUSED_2,      &p->color_paused[1] );
890}
891
892GType
893torrent_cell_renderer_get_type( void )
894{
895    static GType type = 0;
896
897    if( !type )
898    {
899        static const GTypeInfo info =
900        {
901            sizeof( TorrentCellRendererClass ),
902            NULL, /* base_init */
903            NULL, /* base_finalize */
904            (GClassInitFunc)torrent_cell_renderer_class_init,
905            NULL, /* class_finalize */
906            NULL, /* class_data */
907            sizeof( TorrentCellRenderer ),
908            0, /* n_preallocs */
909            (GInstanceInitFunc)torrent_cell_renderer_init,
910            NULL
911        };
912
913        type = g_type_register_static( GTK_TYPE_CELL_RENDERER,
914                                       "TorrentCellRenderer",
915                                       &info, (GTypeFlags)0 );
916    }
917
918    return type;
919}
920
921GtkCellRenderer *
922torrent_cell_renderer_new( void )
923{
924    return (GtkCellRenderer *) g_object_new( TORRENT_CELL_RENDERER_TYPE, NULL );
925}
Note: See TracBrowser for help on using the repository browser.