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

Last change on this file since 10031 was 10031, checked in by charles, 12 years ago

(trunk) remove unnecessary #includes

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