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

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

(gtk trunk) #628: Show thumbnails next to torrents

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