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

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

(trunk gtk) fix #2292: wrong speed in bottom bar

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