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

Last change on this file since 8003 was 8003, checked in by charles, 13 years ago

(trunk gtk) #628: tweak r7996 a little bit to play nicer on older versions of gtk+

  • Property svn:keywords set to Date Rev Author Id
File size: 30.1 KB
Line 
1/*
2 * This file Copyright (C) 2007-2009 Charles Kerr <charles@transmissionbt.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: torrent-cell-renderer.c 8003 2009-03-03 17:58:25Z charles $
11 */
12
13#include "assert.h"
14#include <string.h> /* strcmp */
15#include <gtk/gtk.h>
16#include <glib/gi18n.h>
17#include <libtransmission/transmission.h>
18#include "hig.h"
19#include "icons.h"
20#include "torrent-cell-renderer.h"
21#include "tr-torrent.h"
22#include "util.h"
23
24/* #define TEST_RTL */
25
26enum
27{
28    P_TORRENT = 1,
29    P_BAR_HEIGHT,
30    P_MINIMAL
31};
32
33#define DEFAULT_BAR_HEIGHT 12
34#define SMALL_SCALE 0.9
35#define MINIMAL_ICON_SIZE GTK_ICON_SIZE_MENU
36#define FULL_ICON_SIZE GTK_ICON_SIZE_DND
37
38/***
39****
40***/
41
42static char*
43getProgressString( const tr_torrent * tor,
44                   const tr_info    * info,
45                   const tr_stat    * torStat )
46{
47    const int      isDone = torStat->leftUntilDone == 0;
48    const uint64_t haveTotal = torStat->haveUnchecked + torStat->haveValid;
49    const int      isSeed = torStat->haveValid >= info->totalSize;
50    char           buf1[32], buf2[32], buf3[32], buf4[32];
51    char *         str;
52    double         seedRatio; 
53    gboolean       hasSeedRatio;
54
55    if( !isDone )
56    {
57        str = g_strdup_printf(
58            /* %1$s is how much we've got,
59               %2$s is how much we'll have when done,
60               %3$.2f%% is a percentage of the two */
61            _( "%1$s of %2$s (%3$.2f%%)" ),
62            tr_strlsize( buf1, haveTotal, sizeof( buf1 ) ),
63            tr_strlsize( buf2, torStat->sizeWhenDone, sizeof( buf2 ) ),
64            torStat->percentDone * 100.0 );
65    }
66    else if( !isSeed )
67    {
68        str = g_strdup_printf(
69            /* %1$s is how much we've got,
70               %2$s is the torrent's total size,
71               %3$.2f%% is a percentage of the two,
72               %4$s is how much we've uploaded,
73               %5$s is our upload-to-download ratio */
74            _( "%1$s of %2$s (%3$.2f%%), uploaded %4$s (Ratio: %5$s)" ),
75            tr_strlsize( buf1, haveTotal, sizeof( buf1 ) ),
76            tr_strlsize( buf2, info->totalSize, sizeof( buf2 ) ),
77            torStat->percentComplete * 100.0,
78            tr_strlsize( buf3, torStat->uploadedEver, sizeof( buf3 ) ),
79            tr_strlratio( buf4, torStat->ratio, sizeof( buf4 ) ) );
80    }
81    else if(( hasSeedRatio = tr_torrentGetSeedRatio( tor, &seedRatio )))
82    {
83        str = g_strdup_printf(
84            /* %1$s is the torrent's total size,
85               %2$s is how much we've uploaded,
86               %3$s is our upload-to-download ratio,
87               $4$s is the ratio we want to reach before we stop uploading */
88            _( "%1$s, uploaded %2$s (Ratio: %3$s Goal: %4$s)" ),
89            tr_strlsize( buf1, info->totalSize, sizeof( buf1 ) ),
90            tr_strlsize( buf2, torStat->uploadedEver, sizeof( buf2 ) ),
91            tr_strlratio( buf3, torStat->ratio, sizeof( buf3 ) ),
92            tr_strlratio( buf4, seedRatio, sizeof( buf4 ) ) );
93    }
94    else /* seeding w/o a ratio */
95    {
96        str = g_strdup_printf(
97            /* %1$s is the torrent's total size,
98               %2$s is how much we've uploaded,
99               %3$s is our upload-to-download ratio */
100            _( "%1$s, uploaded %2$s (Ratio: %3$s)" ),
101            tr_strlsize( buf1, info->totalSize, sizeof( buf1 ) ),
102            tr_strlsize( buf2, torStat->uploadedEver, sizeof( buf2 ) ),
103            tr_strlratio( buf3, torStat->ratio, sizeof( buf3 ) ) );
104    }
105
106    /* add time when downloading */
107    if( hasSeedRatio || ( torStat->activity == TR_STATUS_DOWNLOAD ) )
108    {
109        const int eta = torStat->eta;
110        GString * gstr = g_string_new( str );
111        g_string_append( gstr, " - " );
112        if( eta < 0 )
113            g_string_append( gstr, _( "Remaining time unknown" ) );
114        else
115        {
116            char timestr[128];
117            tr_strltime( timestr, eta, sizeof( timestr ) );
118            /* time remaining */
119            g_string_append_printf( gstr, _( "%s remaining" ), timestr );
120        }
121        g_free( str );
122        str = g_string_free( gstr, FALSE );
123    }
124
125    return str;
126}
127
128static char*
129getShortTransferString( const tr_stat * torStat,
130                        char *          buf,
131                        size_t          buflen )
132{
133    char      downStr[32], upStr[32];
134    const int haveDown = torStat->peersSendingToUs > 0;
135    const int haveUp = torStat->peersGettingFromUs > 0;
136
137    if( haveDown )
138        tr_strlspeed( downStr, torStat->pieceDownloadSpeed, sizeof( downStr ) );
139    if( haveUp )
140        tr_strlspeed( upStr, torStat->pieceUploadSpeed, sizeof( upStr ) );
141
142    if( haveDown && haveUp )
143        /* Translators: "speed|" is here for disambiguation.  Please remove it from your translation.
144           %1$s is the download speed
145           %2$s is the upload speed */
146        g_snprintf( buf, buflen, Q_(
147                        "speed|Down: %1$s, Up: %2$s" ), downStr, upStr );
148    else if( haveDown )
149        /* download speed */
150        g_snprintf( buf, buflen, _( "Down: %s" ), downStr );
151    else if( haveUp )
152        /* upload speed */
153        g_snprintf( buf, buflen, _( "Up: %s" ), upStr );
154    else
155        /* the torrent isn't uploading or downloading */
156        g_strlcpy( buf, _( "Idle" ), buflen );
157
158    return buf;
159}
160
161static char*
162getShortStatusString( const tr_stat * torStat )
163{
164    GString * gstr = g_string_new( NULL );
165
166    switch( torStat->activity )
167    {
168        case TR_STATUS_STOPPED:
169            g_string_assign( gstr, _( "Paused" ) );
170            break;
171
172        case TR_STATUS_CHECK_WAIT:
173            g_string_assign( gstr, _( "Waiting to verify local data" ) );
174            break;
175
176        case TR_STATUS_CHECK:
177            g_string_append_printf( gstr,
178                                    _(
179                                        "Verifying local data (%.1f%% tested)" ),
180                                    torStat->recheckProgress * 100.0 );
181            break;
182
183        case TR_STATUS_DOWNLOAD:
184        case TR_STATUS_SEED:
185        {
186            char buf[128];
187            if( torStat->activity != TR_STATUS_DOWNLOAD )
188            {
189                tr_strlratio( buf, torStat->ratio, sizeof( buf ) );
190                g_string_append_printf( gstr, _( "Ratio: %s" ), buf );
191                g_string_append( gstr, ", " );
192            }
193            getShortTransferString( torStat, buf, sizeof( buf ) );
194            g_string_append( gstr, buf );
195            break;
196        }
197
198        default:
199            break;
200    }
201
202    return g_string_free( gstr, FALSE );
203}
204
205static char*
206getStatusString( const tr_stat * torStat )
207{
208    const int isActive = torStat->activity != TR_STATUS_STOPPED;
209    const int isChecking = torStat->activity == TR_STATUS_CHECK
210                        || torStat->activity == TR_STATUS_CHECK_WAIT;
211
212    GString * gstr = g_string_new( NULL );
213
214    if( torStat->error )
215    {
216        g_string_assign( gstr, torStat->errorString );
217    }
218    else switch( torStat->activity )
219        {
220            case TR_STATUS_STOPPED:
221            case TR_STATUS_CHECK_WAIT:
222            case TR_STATUS_CHECK:
223            {
224                char * pch = getShortStatusString( torStat );
225                g_string_assign( gstr, pch );
226                g_free( pch );
227                break;
228            }
229
230            case TR_STATUS_DOWNLOAD:
231                g_string_append_printf( gstr,
232                    ngettext( "Downloading from %1$'d of %2$'d connected peer",
233                              "Downloading from %1$'d of %2$'d connected peers",
234                              torStat->peersConnected ),
235                    torStat->peersSendingToUs +
236                    torStat->webseedsSendingToUs,
237                    torStat->peersConnected +
238                    torStat->webseedsSendingToUs );
239                break;
240
241            case TR_STATUS_SEED:
242                g_string_append_printf( gstr,
243                    ngettext( "Seeding to %1$'d of %2$'d connected peer",
244                              "Seeding to %1$'d of %2$'d connected peers",
245                              torStat->peersConnected ),
246                    torStat->peersGettingFromUs,
247                    torStat->peersConnected );
248                break;
249        }
250
251    if( isActive && !isChecking )
252    {
253        char buf[256];
254        getShortTransferString( torStat, buf, sizeof( buf ) );
255        g_string_append_printf( gstr, " - %s", buf );
256    }
257
258    return g_string_free( gstr, FALSE );
259}
260
261/***
262****
263***/
264
265static GtkCellRendererClass * parent_class = NULL;
266
267struct TorrentCellRendererPrivate
268{
269    tr_torrent       * tor;
270    GtkCellRenderer  * text_renderer;
271    GtkCellRenderer  * text_renderer_err;
272    GtkCellRenderer  * progress_renderer;
273    GtkCellRenderer  * icon_renderer;
274    int                bar_height;
275    gboolean           minimal;
276};
277
278/***
279****
280***/
281
282static GdkPixbuf*
283get_icon( const tr_torrent * tor, GtkIconSize icon_size, GtkWidget * for_widget )
284{
285    const char * mime_type;
286    const tr_info * info = tr_torrentInfo( tor );
287
288    /* a very basic cache, but hits about 80% of the time... */
289    static GdkPixbuf   * prev_icon = NULL;
290    static GtkWidget   * prev_widget = NULL;
291    static const char  * prev_mime_type = NULL;
292    static GtkIconSize   prev_size = 0;
293
294    if( info->fileCount > 1 )
295        mime_type = DIRECTORY_MIME_TYPE;
296    else
297        mime_type = get_mime_type_from_filename( info->files[0].name );
298
299    if( ( for_widget == prev_widget ) && ( prev_size == icon_size ) && !strcmp( prev_mime_type, mime_type ) )
300        return prev_icon;
301
302    prev_mime_type = mime_type;
303    prev_size = icon_size;
304    prev_widget = for_widget;
305    prev_icon = get_mime_type_icon( mime_type, icon_size, for_widget );
306    return prev_icon;
307}
308
309static GtkCellRenderer*
310get_text_renderer( const tr_stat * st, TorrentCellRenderer * r )
311{
312    return st->error ? r->priv->text_renderer_err : r->priv->text_renderer;
313}
314
315/***
316****
317***/
318
319static void
320get_size_minimal( TorrentCellRenderer * cell,
321                  GtkWidget           * widget,
322                  gint                * width,
323                  gint                * height )
324{
325    int w, h;
326    GdkRectangle icon_area;
327    GdkRectangle name_area;
328    GdkRectangle stat_area;
329    const char * name;
330    char * status;
331    GdkPixbuf * icon;
332    GtkCellRenderer * text_renderer;
333
334    struct TorrentCellRendererPrivate * p = cell->priv;
335    const tr_torrent * tor = p->tor;
336    const tr_stat * st = tr_torrentStatCached( (tr_torrent*)tor );
337
338    icon = get_icon( tor, MINIMAL_ICON_SIZE, widget );
339    name = tr_torrentInfo( tor )->name;
340    status = getShortStatusString( st );
341
342    /* get the idealized cell dimensions */
343    g_object_set( p->icon_renderer, "pixbuf", icon, NULL );
344    gtk_cell_renderer_get_size( p->icon_renderer, widget, NULL, NULL, NULL, &w, &h );
345    icon_area.width = w;
346    icon_area.height = h;
347    text_renderer = get_text_renderer( st, cell );
348    g_object_set( text_renderer, "text", name, "ellipsize", PANGO_ELLIPSIZE_NONE,  "scale", 1.0, NULL );
349    gtk_cell_renderer_get_size( text_renderer, widget, NULL, NULL, NULL, &w, &h );
350    name_area.width = w;
351    name_area.height = h;
352    g_object_set( text_renderer, "text", status, "scale", SMALL_SCALE, NULL );
353    gtk_cell_renderer_get_size( text_renderer, widget, NULL, NULL, NULL, &w, &h );
354    stat_area.width = w;
355    stat_area.height = h;
356   
357    /**
358    *** LAYOUT
359    **/
360
361    if( width != NULL )
362        *width = cell->parent.xpad * 2 + icon_area.width + GUI_PAD + name_area.width + GUI_PAD + stat_area.width;
363    if( height != NULL )
364        *height = cell->parent.ypad * 2 + name_area.height + p->bar_height;
365
366    /* cleanup */
367    g_free( status );
368    g_object_unref( icon );
369}
370
371#define MAX3(a,b,c) MAX(a,MAX(b,c))
372
373static void
374get_size_full( TorrentCellRenderer * cell,
375               GtkWidget           * widget,
376               gint                * width,
377               gint                * height )
378{
379    int w, h;
380    GdkRectangle icon_area;
381    GdkRectangle name_area;
382    GdkRectangle stat_area;
383    GdkRectangle prog_area;
384    const char * name;
385    char * status;
386    char * progress;
387    GdkPixbuf * icon;
388    GtkCellRenderer * text_renderer;
389
390    struct TorrentCellRendererPrivate * p = cell->priv;
391    const tr_torrent * tor = p->tor;
392    const tr_stat * st = tr_torrentStatCached( (tr_torrent*)tor );
393    const tr_info * inf = tr_torrentInfo( tor );
394
395    icon = get_icon( tor, FULL_ICON_SIZE, widget );
396    name = inf->name;
397    status = getStatusString( st );
398    progress = getProgressString( tor, inf, st );
399
400    /* get the idealized cell dimensions */
401    g_object_set( p->icon_renderer, "pixbuf", icon, NULL );
402    gtk_cell_renderer_get_size( p->icon_renderer, widget, NULL, NULL, NULL, &w, &h );
403    icon_area.width = w;
404    icon_area.height = h;
405    text_renderer = get_text_renderer( st, cell );
406    g_object_set( text_renderer, "text", name, "weight", PANGO_WEIGHT_BOLD, "scale", 1.0, "ellipsize", PANGO_ELLIPSIZE_NONE, NULL );
407    gtk_cell_renderer_get_size( text_renderer, widget, NULL, NULL, NULL, &w, &h );
408    name_area.width = w;
409    name_area.height = h;
410    g_object_set( text_renderer, "text", progress, "weight", PANGO_WEIGHT_NORMAL, "scale", SMALL_SCALE, NULL );
411    gtk_cell_renderer_get_size( text_renderer, widget, NULL, NULL, NULL, &w, &h );
412    prog_area.width = w;
413    prog_area.height = h;
414    g_object_set( text_renderer, "text", status, NULL );
415    gtk_cell_renderer_get_size( text_renderer, widget, NULL, NULL, NULL, &w, &h );
416    stat_area.width = w;
417    stat_area.height = h;
418   
419    /**
420    *** LAYOUT
421    **/
422
423    if( width != NULL )
424        *width = cell->parent.xpad * 2 + icon_area.width + GUI_PAD + MAX3( name_area.width, prog_area.width, stat_area.width );
425    if( height != NULL )
426        *height = cell->parent.ypad * 2 + name_area.height + prog_area.height + GUI_PAD_SMALL + p->bar_height + GUI_PAD_SMALL + stat_area.height;
427
428    /* cleanup */
429    g_free( status );
430    g_free( progress );
431    g_object_unref( icon );
432}
433
434
435static void
436torrent_cell_renderer_get_size( GtkCellRenderer  * cell,
437                                GtkWidget        * widget,
438                                GdkRectangle     * cell_area,
439                                gint             * x_offset,
440                                gint             * y_offset,
441                                gint             * width,
442                                gint             * height )
443{
444    TorrentCellRenderer * self = TORRENT_CELL_RENDERER( cell );
445
446    if( self && self->priv->tor )
447    {
448        struct TorrentCellRendererPrivate * p = self->priv;
449        int w, h;
450
451        if( p->minimal )
452            get_size_minimal( TORRENT_CELL_RENDERER( cell ), widget, &w, &h );
453        else
454            get_size_full( TORRENT_CELL_RENDERER( cell ), widget, &w, &h );
455
456        if( width )
457            *width = w;
458
459        if( height )
460            *height = h;
461
462        if( cell_area ) {
463            if( x_offset ) *x_offset = 0;
464            if( y_offset ) {
465                *y_offset = 0.5 * ( cell_area->height - ( h + ( 2 * cell->ypad ) ) );
466                *y_offset = MAX( *y_offset, 0 );
467            }
468        }
469    }
470}
471
472static void
473render_minimal( TorrentCellRenderer   * cell,
474                GdkDrawable           * window,
475                GtkWidget             * widget,
476                GdkRectangle          * background_area,
477                GdkRectangle          * cell_area UNUSED,
478                GdkRectangle          * expose_area UNUSED,
479                GtkCellRendererState    flags )
480{
481    int w, h;
482    GdkRectangle icon_area;
483    GdkRectangle name_area;
484    GdkRectangle stat_area;
485    GdkRectangle prog_area;
486    GdkRectangle fill_area;
487    const char * name;
488    char * status;
489    GdkPixbuf * icon;
490    GtkCellRenderer * text_renderer;
491
492    struct TorrentCellRendererPrivate * p = cell->priv;
493    const tr_torrent * tor = p->tor;
494    const tr_stat * st = tr_torrentStatCached( (tr_torrent*)tor );
495    const gboolean active = st->activity != TR_STATUS_STOPPED;
496    const double percentDone = MAX( 0.0, st->percentDone );
497
498    icon = get_icon( tor, MINIMAL_ICON_SIZE, widget );
499    name = tr_torrentInfo( tor )->name;
500    status = getShortStatusString( st );
501
502    /* get the cell dimensions */
503    g_object_set( p->icon_renderer, "pixbuf", icon, NULL );
504    gtk_cell_renderer_get_size( p->icon_renderer, widget, NULL, NULL, NULL, &w, &h );
505    icon_area.width = w;
506    icon_area.height = h;
507    text_renderer = get_text_renderer( st, cell );
508    g_object_set( text_renderer, "text", name, "ellipsize", PANGO_ELLIPSIZE_NONE, "scale", 1.0, NULL );
509    gtk_cell_renderer_get_size( text_renderer, widget, NULL, NULL, NULL, &w, &h );
510    name_area.width = w;
511    name_area.height = h;
512    g_object_set( text_renderer, "text", status, "scale", SMALL_SCALE, NULL );
513    gtk_cell_renderer_get_size( text_renderer, widget, NULL, NULL, NULL, &w, &h );
514    stat_area.width = w;
515    stat_area.height = h;
516
517    /**
518    *** LAYOUT
519    **/
520
521    fill_area = *background_area;
522    fill_area.x += cell->parent.xpad;
523    fill_area.y += cell->parent.ypad;
524    fill_area.width -= cell->parent.xpad * 2;
525    fill_area.height -= cell->parent.ypad * 2;
526
527    /* icon */
528    icon_area.x = fill_area.x;
529    icon_area.y = fill_area.y + ( fill_area.height - icon_area.height ) / 2;
530
531    /* short status (right justified) */
532    stat_area.x = fill_area.x + fill_area.width - stat_area.width;
533    stat_area.y = fill_area.y + ( name_area.height - stat_area.height ) / 2;
534
535    /* name */
536    name_area.x = icon_area.x + icon_area.width + GUI_PAD;
537    name_area.y = fill_area.y;
538    name_area.width = stat_area.x - GUI_PAD - name_area.x;
539
540    /* progressbar */
541    prog_area.x = name_area.x;
542    prog_area.y = name_area.y + name_area.height;
543    prog_area.width = name_area.width + GUI_PAD + stat_area.width;
544    prog_area.height = p->bar_height;
545
546    /**
547    *** RENDER
548    **/
549   
550    g_object_set( p->icon_renderer, "pixbuf", icon, "sensitive", active, NULL );
551    gtk_cell_renderer_render( p->icon_renderer, window, widget, &icon_area, &icon_area, &icon_area, flags );
552    g_object_set( text_renderer, "text", status, "scale", SMALL_SCALE, "sensitive", active, "ellipsize", PANGO_ELLIPSIZE_END, NULL );
553    gtk_cell_renderer_render( text_renderer, window, widget, &stat_area, &stat_area, &stat_area, flags );
554    g_object_set( text_renderer, "text", name, "scale", 1.0, NULL );
555    gtk_cell_renderer_render( text_renderer, window, widget, &name_area, &name_area, &name_area, flags );
556    g_object_set( p->progress_renderer, "value", (int)(percentDone*100.0), "text", "", "sensitive", active, NULL );
557    gtk_cell_renderer_render( p->progress_renderer, window, widget, &prog_area, &prog_area, &prog_area, flags );
558
559    /* cleanup */
560    g_free( status );
561    g_object_unref( icon );
562}
563
564static void
565render_full( TorrentCellRenderer   * cell,
566             GdkDrawable           * window,
567             GtkWidget             * widget,
568             GdkRectangle          * background_area,
569             GdkRectangle          * cell_area UNUSED,
570             GdkRectangle          * expose_area UNUSED,
571             GtkCellRendererState    flags )
572{
573    int w, h;
574    GdkRectangle fill_area;
575    GdkRectangle icon_area;
576    GdkRectangle name_area;
577    GdkRectangle stat_area;
578    GdkRectangle prog_area;
579    GdkRectangle prct_area;
580    const char * name;
581    char * status;
582    char * progress;
583    GdkPixbuf * icon;
584    GtkCellRenderer * text_renderer;
585
586    struct TorrentCellRendererPrivate * p = cell->priv;
587    const tr_torrent * tor = p->tor;
588    const tr_stat * st = tr_torrentStatCached( (tr_torrent*)tor );
589    const tr_info * inf = tr_torrentInfo( tor );
590    const gboolean active = st->activity != TR_STATUS_STOPPED;
591    const double percentDone = MAX( 0.0, st->percentDone );
592
593    icon = get_icon( tor, FULL_ICON_SIZE, widget );
594    name = inf->name;
595    status = getStatusString( st );
596    progress = getProgressString( tor, inf, st );
597
598    /* get the idealized cell dimensions */
599    g_object_set( p->icon_renderer, "pixbuf", icon, NULL );
600    gtk_cell_renderer_get_size( p->icon_renderer, widget, NULL, NULL, NULL, &w, &h );
601    icon_area.width = w;
602    icon_area.height = h;
603    text_renderer = get_text_renderer( st, cell );
604    g_object_set( text_renderer, "text", name, "weight", PANGO_WEIGHT_BOLD, "ellipsize", PANGO_ELLIPSIZE_NONE, "scale", 1.0, NULL );
605    gtk_cell_renderer_get_size( text_renderer, widget, NULL, NULL, NULL, &w, &h );
606    name_area.width = w;
607    name_area.height = h;
608    g_object_set( text_renderer, "text", progress, "weight", PANGO_WEIGHT_NORMAL, "scale", SMALL_SCALE, NULL );
609    gtk_cell_renderer_get_size( text_renderer, widget, NULL, NULL, NULL, &w, &h );
610    prog_area.width = w;
611    prog_area.height = h;
612    g_object_set( text_renderer, "text", status, NULL );
613    gtk_cell_renderer_get_size( text_renderer, widget, NULL, NULL, NULL, &w, &h );
614    stat_area.width = w;
615    stat_area.height = h;
616   
617    /**
618    *** LAYOUT
619    **/
620
621    fill_area = *background_area;
622    fill_area.x += cell->parent.xpad;
623    fill_area.y += cell->parent.ypad;
624    fill_area.width -= cell->parent.xpad * 2;
625    fill_area.height -= cell->parent.ypad * 2;
626
627    /* icon */
628    icon_area.x = fill_area.x;
629    icon_area.y = fill_area.y + ( fill_area.height - icon_area.height ) / 2;
630
631    /* name */
632    name_area.x = icon_area.x + icon_area.width + GUI_PAD;
633    name_area.y = fill_area.y;
634    name_area.width = fill_area.width - GUI_PAD - icon_area.width - GUI_PAD_SMALL;
635
636    /* prog */
637    prog_area.x = name_area.x;
638    prog_area.y = name_area.y + name_area.height;
639    prog_area.width = name_area.width;
640
641    /* progressbar */
642    prct_area.x = prog_area.x;
643    prct_area.y = prog_area.y + prog_area.height + GUI_PAD_SMALL;
644    prct_area.width = prog_area.width;
645    prct_area.height = p->bar_height;
646
647    /* status */
648    stat_area.x = prct_area.x;
649    stat_area.y = prct_area.y + prct_area.height + GUI_PAD_SMALL;
650    stat_area.width = prct_area.width;
651
652    /**
653    *** RENDER
654    **/
655   
656    g_object_set( p->icon_renderer, "pixbuf", icon, "sensitive", active, NULL );
657    gtk_cell_renderer_render( p->icon_renderer, window, widget, &icon_area, &icon_area, &icon_area, flags );
658    g_object_set( text_renderer, "text", name, "scale", 1.0, "sensitive", active, "ellipsize", PANGO_ELLIPSIZE_END, "weight", PANGO_WEIGHT_BOLD, NULL );
659    gtk_cell_renderer_render( text_renderer, window, widget, &name_area, &name_area, &name_area, flags );
660    g_object_set( text_renderer, "text", progress, "scale", SMALL_SCALE, "weight", PANGO_WEIGHT_NORMAL, NULL );
661    gtk_cell_renderer_render( text_renderer, window, widget, &prog_area, &prog_area, &prog_area, flags );
662    g_object_set( p->progress_renderer, "value", (int)(percentDone*100.0), "text", "", "sensitive", active, NULL );
663    gtk_cell_renderer_render( p->progress_renderer, window, widget, &prct_area, &prct_area, &prct_area, flags );
664    g_object_set( text_renderer, "text", status, NULL );
665    gtk_cell_renderer_render( text_renderer, window, widget, &stat_area, &stat_area, &stat_area, flags );
666
667    /* cleanup */
668    g_free( status );
669    g_free( progress );
670    g_object_unref( icon );
671}
672
673static void
674torrent_cell_renderer_render( GtkCellRenderer       * cell,
675                              GdkDrawable           * window,
676                              GtkWidget             * widget,
677                              GdkRectangle          * background_area,
678                              GdkRectangle          * cell_area,
679                              GdkRectangle          * expose_area,
680                              GtkCellRendererState    flags )
681{
682    TorrentCellRenderer * self = TORRENT_CELL_RENDERER( cell );
683
684#ifdef TEST_RTL
685    GtkTextDirection      real_dir = gtk_widget_get_direction( widget );
686    gtk_widget_set_direction( widget, GTK_TEXT_DIR_RTL );
687#endif
688
689    if( self && self->priv->tor )
690    {
691        struct TorrentCellRendererPrivate * p = self->priv;
692        if( p->minimal )
693            render_minimal( self, window, widget, background_area, cell_area, expose_area, flags );
694        else
695            render_full( self, window, widget, background_area, cell_area, expose_area, flags );
696    }
697
698#ifdef TEST_RTL
699    gtk_widget_set_direction( widget, real_dir );
700#endif
701}
702
703static void
704torrent_cell_renderer_set_property( GObject *      object,
705                                    guint          property_id,
706                                    const GValue * v,
707                                    GParamSpec *   pspec )
708{
709    TorrentCellRenderer *               self = TORRENT_CELL_RENDERER(
710        object );
711    struct TorrentCellRendererPrivate * p = self->priv;
712
713    switch( property_id )
714    {
715        case P_TORRENT:
716            p->tor = g_value_get_pointer( v ); break;
717
718        case P_BAR_HEIGHT:
719            p->bar_height = g_value_get_int( v ); break;
720
721        case P_MINIMAL:
722            p->minimal  = g_value_get_boolean( v ); break;
723
724        default:
725            G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, pspec );
726            break;
727    }
728}
729
730static void
731torrent_cell_renderer_get_property( GObject *    object,
732                                    guint        property_id,
733                                    GValue *     v,
734                                    GParamSpec * pspec )
735{
736    const TorrentCellRenderer *         self = TORRENT_CELL_RENDERER(
737        object );
738    struct TorrentCellRendererPrivate * p = self->priv;
739
740    switch( property_id )
741    {
742        case P_TORRENT:
743            g_value_set_pointer( v, p->tor ); break;
744
745        case P_BAR_HEIGHT:
746            g_value_set_int( v, p->bar_height ); break;
747
748        case P_MINIMAL:
749            g_value_set_boolean( v, p->minimal ); break;
750
751        default:
752            G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, pspec );
753            break;
754    }
755}
756
757static void
758torrent_cell_renderer_dispose( GObject * o )
759{
760    TorrentCellRenderer * r = TORRENT_CELL_RENDERER( o );
761    GObjectClass *        parent;
762
763    if( r && r->priv )
764    {
765        g_object_unref( G_OBJECT( r->priv->text_renderer ) );
766        g_object_unref( G_OBJECT( r->priv->text_renderer_err ) );
767        g_object_unref( G_OBJECT( r->priv->progress_renderer ) );
768        g_object_unref( G_OBJECT( r->priv->icon_renderer ) );
769        r->priv = NULL;
770    }
771
772    parent = g_type_class_peek( g_type_parent( TORRENT_CELL_RENDERER_TYPE ) );
773    parent->dispose( o );
774}
775
776static void
777torrent_cell_renderer_class_init( TorrentCellRendererClass * klass )
778{
779    GObjectClass *         gobject_class = G_OBJECT_CLASS( klass );
780    GtkCellRendererClass * cell_class = GTK_CELL_RENDERER_CLASS( klass );
781
782    g_type_class_add_private( klass,
783                             sizeof( struct TorrentCellRendererPrivate ) );
784
785    parent_class = (GtkCellRendererClass*) g_type_class_peek_parent( klass );
786
787    cell_class->render = torrent_cell_renderer_render;
788    cell_class->get_size = torrent_cell_renderer_get_size;
789    gobject_class->set_property = torrent_cell_renderer_set_property;
790    gobject_class->get_property = torrent_cell_renderer_get_property;
791    gobject_class->dispose = torrent_cell_renderer_dispose;
792
793    g_object_class_install_property( gobject_class, P_TORRENT,
794                                    g_param_spec_pointer( "torrent", NULL,
795                                                          "tr_torrent*",
796                                                          G_PARAM_READWRITE ) );
797
798    g_object_class_install_property( gobject_class, P_BAR_HEIGHT,
799                                    g_param_spec_int( "bar-height", NULL,
800                                                      "Bar Height",
801                                                      1, INT_MAX,
802                                                      DEFAULT_BAR_HEIGHT,
803                                                      G_PARAM_READWRITE ) );
804
805    g_object_class_install_property( gobject_class, P_MINIMAL,
806                                    g_param_spec_boolean( "minimal", NULL,
807                                                          "Minimal Mode",
808                                                          FALSE,
809                                                          G_PARAM_READWRITE ) );
810}
811
812static void
813torrent_cell_renderer_init( GTypeInstance *  instance,
814                            gpointer g_class UNUSED )
815{
816    TorrentCellRenderer *               self = TORRENT_CELL_RENDERER(
817        instance );
818    struct TorrentCellRendererPrivate * p;
819
820    p = self->priv = G_TYPE_INSTANCE_GET_PRIVATE(
821            self,
822            TORRENT_CELL_RENDERER_TYPE,
823            struct
824            TorrentCellRendererPrivate );
825
826    p->tor = NULL;
827    p->text_renderer = gtk_cell_renderer_text_new( );
828    g_object_set( p->text_renderer, "xpad", 0, "ypad", 0, NULL );
829    p->text_renderer_err = gtk_cell_renderer_text_new(  );
830    g_object_set( p->text_renderer_err, "xpad", 0, "ypad", 0, NULL );
831    p->progress_renderer = gtk_cell_renderer_progress_new(  );
832    p->icon_renderer = gtk_cell_renderer_pixbuf_new(  );
833    g_object_set( p->text_renderer_err, "foreground", "red", NULL );
834    tr_object_ref_sink( p->text_renderer );
835    tr_object_ref_sink( p->text_renderer_err );
836    tr_object_ref_sink( p->progress_renderer );
837    tr_object_ref_sink( p->icon_renderer );
838
839    p->bar_height = DEFAULT_BAR_HEIGHT;
840}
841
842GType
843torrent_cell_renderer_get_type( void )
844{
845    static GType type = 0;
846
847    if( !type )
848    {
849        static const GTypeInfo info =
850        {
851            sizeof( TorrentCellRendererClass ),
852            NULL,                                            /* base_init */
853            NULL,                                            /* base_finalize */
854            (GClassInitFunc)torrent_cell_renderer_class_init,
855            NULL,                                            /* class_finalize
856                                                               */
857            NULL,                                            /* class_data */
858            sizeof( TorrentCellRenderer ),
859            0,                                               /* n_preallocs */
860            (GInstanceInitFunc)torrent_cell_renderer_init,
861            NULL
862        };
863
864        type = g_type_register_static( GTK_TYPE_CELL_RENDERER,
865                                       "TorrentCellRenderer",
866                                       &info, (GTypeFlags)0 );
867    }
868
869    return type;
870}
871
872GtkCellRenderer *
873torrent_cell_renderer_new( void )
874{
875    return (GtkCellRenderer *) g_object_new( TORRENT_CELL_RENDERER_TYPE,
876                                             NULL );
877}
878
Note: See TracBrowser for help on using the repository browser.