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

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

(trunk) rephrase "tracker returned..." to "tracker gave..." which is equally expressive but saves a little space on the status line

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