maemo-ui-old/src/mmyth_epg_grid_widget.c
author renatofilho
Tue Sep 18 21:01:18 2007 +0100 (2007-09-18)
branchtrunk
changeset 853 c738c2ac1968
parent 754 cb885ee44618
permissions -rw-r--r--
[svn r859] removed flat to keep aspect ration
renatofilho@20
     1
#include <gtk/gtksignal.h>
renatofilho@20
     2
#include <gdk/gdkevents.h>
renatofilho@20
     3
#include <gdk/gdkkeysyms.h>
renatofilho@20
     4
renatofilho@20
     5
#include "mmyth_uicommon.h"
renatofilho@20
     6
#include "mmyth_epg_grid_widget.h"
renatofilho@20
     7
rosfran@245
     8
#include <gmyth/gmyth_util.h>
rosfran@245
     9
#include <gmyth/gmyth_epg.h>
renatofilho@20
    10
renatofilho@20
    11
#define PIXELS_HOUR 105
renatofilho@20
    12
#define PROGRAM_SEPARATION 2
renatofilho@20
    13
renatofilho@20
    14
enum {
renatofilho@754
    15
    SELECTION_UPDATED_SIGNAL,
renatofilho@754
    16
    LAST_SIGNAL
renatofilho@20
    17
};
renatofilho@20
    18
renatofilho@20
    19
struct _MMythEpgGridWidgetPrivate {
renatofilho@754
    20
    /*
renatofilho@754
    21
     * private widget components 
renatofilho@754
    22
     */
renatofilho@754
    23
    GtkWidget      *epg_channels_vbox;
renatofilho@754
    24
    GtkWidget      *epg_programs_vbox;
renatofilho@20
    25
renatofilho@754
    26
    GHashTable     *service_model_hash;
renatofilho@754
    27
renatofilho@754
    28
    /*
renatofilho@754
    29
     * guidegrid attributes 
renatofilho@754
    30
     */
renatofilho@754
    31
    gboolean        show_favorites;
renatofilho@754
    32
    gint            current_start_channel_id;
renatofilho@754
    33
renatofilho@754
    34
    GTimeVal       *current_start_time;
renatofilho@754
    35
    GTimeVal       *current_end_time;
renatofilho@754
    36
renatofilho@754
    37
    guint           selected_channel_index;
renatofilho@754
    38
renatofilho@754
    39
    /*
renatofilho@754
    40
     * GList of ProgramInfo for each Channel 
renatofilho@754
    41
     */
renatofilho@754
    42
    GList          *program_list[MAX_DISPLAY_CHANS];
renatofilho@754
    43
    GList          *channel_list;
renatofilho@754
    44
renatofilho@754
    45
    GMythEPG       *mmyth_epg;
rosfran@208
    46
rosfran@208
    47
    GMythBackendInfo *backend_info;
renatofilho@754
    48
renatofilho@754
    49
    gint            DISPLAY_CHANS;
renatofilho@20
    50
};
renatofilho@20
    51
renatofilho@754
    52
static void     mmyth_epg_grid_widget_class_init(MMythEpgGridWidgetClass *
renatofilho@754
    53
                                                 klass);
renatofilho@754
    54
static void     mmyth_epg_grid_widget_init(MMythEpgGridWidget * object);
renatofilho@754
    55
static void    
renatofilho@754
    56
mmyth_epg_grid_widget_private_init(MMythEpgGridWidgetPrivate * private);
renatofilho@754
    57
static void     mmyth_epg_grid_widget_mount_services(MMythEpgGridWidget *
renatofilho@754
    58
                                                     object,
renatofilho@754
    59
                                                     GTimeVal * start_time,
renatofilho@754
    60
                                                     GTimeVal * end_time);
renatofilho@754
    61
static void     mmyth_epg_grid_widget_mount_header(MMythEpgGridWidget *
renatofilho@754
    62
                                                   object);
renatofilho@754
    63
static void     mmyth_epg_grid_widget_clicked(GtkWidget * widget,
renatofilho@754
    64
                                              GdkEventExpose * event,
renatofilho@754
    65
                                              gpointer data);
renatofilho@754
    66
static GtkWidget *create_event_box_lbl(gchar * str, int width,
renatofilho@754
    67
                                       const GdkColor * bg_color,
renatofilho@754
    68
                                       const GdkColor * fg_color);
renatofilho@20
    69
renatofilho@754
    70
static void    
renatofilho@754
    71
mmyth_epg_grid_widget_fill_programinfos(MMythEpgGridWidgetPrivate *
renatofilho@754
    72
                                        private);
renatofilho@754
    73
static void    
renatofilho@754
    74
mmyth_epg_grid_widget_fill_program_row_infos(MMythEpgGridWidgetPrivate *
renatofilho@754
    75
                                             private, unsigned int chanNum,
renatofilho@754
    76
                                             unsigned int row);
renatofilho@20
    77
renatofilho@754
    78
static gint     mmyth_epg_grid_widget_signals[LAST_SIGNAL] = { 0 };
renatofilho@20
    79
renatofilho@754
    80
G_DEFINE_TYPE(MMythEpgGridWidget, mmyth_epg_grid_widget,
renatofilho@754
    81
              GTK_TYPE_EVENT_BOX)
renatofilho@754
    82
renatofilho@754
    83
    static void
renatofilho@754
    84
     
renatofilho@754
    85
        
renatofilho@754
    86
        
renatofilho@754
    87
        
renatofilho@754
    88
        
renatofilho@754
    89
        
renatofilho@754
    90
        
renatofilho@754
    91
        
renatofilho@754
    92
        
renatofilho@754
    93
        
renatofilho@754
    94
        
renatofilho@754
    95
        
renatofilho@754
    96
        
renatofilho@754
    97
          mmyth_epg_grid_widget_class_init(MMythEpgGridWidgetClass * klass)
renatofilho@20
    98
{
renatofilho@754
    99
    g_type_class_add_private(klass, sizeof(MMythEpgGridWidgetPrivate));
renatofilho@754
   100
renatofilho@754
   101
    mmyth_epg_grid_widget_signals[SELECTION_UPDATED_SIGNAL] =
renatofilho@754
   102
        g_signal_new("selection_updated", G_TYPE_FROM_CLASS(klass),
renatofilho@754
   103
                     G_SIGNAL_RUN_FIRST, 0, NULL, NULL,
renatofilho@754
   104
                     g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1,
renatofilho@20
   105
                     G_TYPE_POINTER);
renatofilho@20
   106
}
renatofilho@20
   107
renatofilho@754
   108
static void
renatofilho@754
   109
mmyth_epg_grid_widget_private_init(MMythEpgGridWidgetPrivate * private)
renatofilho@20
   110
{
renatofilho@754
   111
    time_t          cur_time;
renatofilho@20
   112
renatofilho@754
   113
    g_return_if_fail(private != NULL);
renatofilho@754
   114
renatofilho@754
   115
    private->epg_channels_vbox = NULL;
renatofilho@754
   116
    private->epg_programs_vbox = NULL;
renatofilho@754
   117
    private->service_model_hash = NULL;
renatofilho@20
   118
renatofilho@20
   119
    private->show_favorites = FALSE;
renatofilho@20
   120
    private->current_start_channel_id = -1;
renatofilho@20
   121
renatofilho@754
   122
    /*
renatofilho@754
   123
     * Selected the first diplayable channel initially 
renatofilho@754
   124
     */
renatofilho@20
   125
    private->selected_channel_index = 0;
renatofilho@754
   126
renatofilho@754
   127
    /*
renatofilho@754
   128
     * TODO fix the current start/end time 
renatofilho@754
   129
     */
renatofilho@754
   130
    private->current_start_time = g_new0(GTimeVal, 1);
rosfran@244
   131
    private->current_start_time->tv_sec = time(&cur_time);
rosfran@244
   132
renatofilho@754
   133
    private->current_end_time = g_new0(GTimeVal, 1);
rosfran@244
   134
    private->current_end_time->tv_sec = time(&cur_time) + 10800;
renatofilho@754
   135
renatofilho@20
   136
    private->DISPLAY_CHANS = MAX_DISPLAY_CHANS;
rosfran@208
   137
renatofilho@754
   138
    private->backend_info =
renatofilho@754
   139
        gmyth_backend_info_new_full("localhost", "mythtv", "mythtv",
renatofilho@754
   140
                                    "mythconverg", 6543);
rosfran@208
   141
renatofilho@20
   142
    // TODO: Close the epg and unref it in dispose call
renatofilho@754
   143
    private->mmyth_epg = gmyth_epg_new();
renatofilho@754
   144
    if (!gmyth_epg_connect(private->mmyth_epg, private->backend_info)) {
renatofilho@754
   145
        g_warning("[%s] Could not connect mysql handler to db",
renatofilho@754
   146
                  __FUNCTION__);
renatofilho@754
   147
        g_object_unref(private->mmyth_epg);
renatofilho@754
   148
        private->mmyth_epg = NULL;
renatofilho@20
   149
    }
renatofilho@20
   150
}
renatofilho@20
   151
renatofilho@20
   152
static void
renatofilho@754
   153
mmyth_epg_grid_widget_init(MMythEpgGridWidget * mmyth_epg_grid_widget)
renatofilho@20
   154
{
renatofilho@754
   155
    MMythEpgGridWidgetPrivate *private =
renatofilho@20
   156
        MMYTH_EPG_GRID_WIDGET_GET_PRIVATE(mmyth_epg_grid_widget);
renatofilho@754
   157
renatofilho@754
   158
    /*
renatofilho@754
   159
     * init private fields 
renatofilho@754
   160
     */
renatofilho@20
   161
    mmyth_epg_grid_widget_private_init(private);
renatofilho@20
   162
renatofilho@754
   163
    mmyth_epg_grid_widget->epg_view_model = NULL;
renatofilho@754
   164
    mmyth_epg_grid_widget->selected_grid_item = NULL;
renatofilho@20
   165
renatofilho@754
   166
    GtkWidget      *epg_event_box = GTK_WIDGET(mmyth_epg_grid_widget);
renatofilho@20
   167
    gtk_widget_modify_bg(epg_event_box, GTK_STATE_NORMAL, &main_bg_color);
renatofilho@754
   168
    gtk_widget_set_size_request(epg_event_box, 0, 125);
renatofilho@20
   169
renatofilho@754
   170
    GtkWidget      *epg_main_hbox = gtk_hbox_new(FALSE, 10);
renatofilho@754
   171
    gtk_container_set_border_width(GTK_CONTAINER(epg_main_hbox), 10);
renatofilho@754
   172
renatofilho@754
   173
    gtk_container_add(GTK_CONTAINER(epg_event_box), epg_main_hbox);
renatofilho@754
   174
renatofilho@754
   175
    /*
renatofilho@754
   176
     * channels vbox 
renatofilho@754
   177
     */
renatofilho@754
   178
    GtkWidget      *epg_channels_vbox = gtk_vbox_new(FALSE, 3);
renatofilho@754
   179
    private->epg_channels_vbox = epg_channels_vbox;
renatofilho@754
   180
renatofilho@754
   181
    /*
renatofilho@754
   182
     * programs vbox 
renatofilho@754
   183
     */
renatofilho@754
   184
    GtkWidget      *epg_programs_vbox = gtk_vbox_new(FALSE, 3);
renatofilho@20
   185
    private->epg_programs_vbox = epg_programs_vbox;
renatofilho@20
   186
renatofilho@754
   187
    /*
renatofilho@754
   188
     * packing start 
renatofilho@754
   189
     */
renatofilho@754
   190
    gtk_box_pack_start(GTK_BOX(epg_main_hbox),
renatofilho@754
   191
                       epg_channels_vbox, FALSE, FALSE, 0);
renatofilho@754
   192
    gtk_box_pack_start(GTK_BOX(epg_main_hbox),
renatofilho@754
   193
                       epg_programs_vbox, FALSE, FALSE, 0);
renatofilho@754
   194
renatofilho@754
   195
    /*
renatofilho@754
   196
     * table header (first line) 
renatofilho@754
   197
     */
renatofilho@754
   198
    mmyth_epg_grid_widget_mount_header(mmyth_epg_grid_widget);
renatofilho@754
   199
renatofilho@754
   200
    /*
renatofilho@754
   201
     * service programs 
renatofilho@754
   202
     */
renatofilho@754
   203
    /*
renatofilho@754
   204
     * mount service programs with current time 
renatofilho@754
   205
     */
renatofilho@754
   206
    mmyth_epg_grid_widget_mount_services(mmyth_epg_grid_widget,
renatofilho@20
   207
                                         private->current_start_time,
renatofilho@754
   208
                                         private->current_end_time);
renatofilho@20
   209
}
renatofilho@20
   210
renatofilho@754
   211
GtkWidget      *
renatofilho@754
   212
mmyth_epg_grid_widget_new()
renatofilho@20
   213
{
renatofilho@754
   214
    return GTK_WIDGET(gtk_type_new(mmyth_epg_grid_widget_get_type()));
renatofilho@20
   215
}
renatofilho@20
   216
renatofilho@20
   217
static void
renatofilho@754
   218
mmyth_epg_grid_widget_mount_services(MMythEpgGridWidget *
renatofilho@754
   219
                                     mmyth_epg_grid_widget,
renatofilho@754
   220
                                     GTimeVal * start_time,
renatofilho@754
   221
                                     GTimeVal * end_time)
renatofilho@20
   222
{
renatofilho@754
   223
    GList          *proglist;
renatofilho@754
   224
    GList          *channel_list = NULL;
renatofilho@20
   225
    GMythChannelInfo *channel_info;
renatofilho@20
   226
renatofilho@754
   227
    int             chanid;
renatofilho@754
   228
    MMythEpgGridWidgetPrivate *private =
renatofilho@20
   229
        MMYTH_EPG_GRID_WIDGET_GET_PRIVATE(mmyth_epg_grid_widget);
renatofilho@20
   230
renatofilho@754
   231
    // update view_model
renatofilho@754
   232
    /*
renatofilho@754
   233
     * FIXME shallow free or recursive? 
renatofilho@754
   234
     */
renatofilho@754
   235
    if (mmyth_epg_grid_widget->epg_view_model != NULL) {
renatofilho@754
   236
        g_list_free(mmyth_epg_grid_widget->epg_view_model);
renatofilho@754
   237
        mmyth_epg_grid_widget->epg_view_model = NULL;
renatofilho@754
   238
    }
renatofilho@20
   239
renatofilho@754
   240
    if (private->service_model_hash != NULL) {
renatofilho@754
   241
        g_hash_table_destroy(private->service_model_hash);
renatofilho@754
   242
    }
renatofilho@754
   243
renatofilho@754
   244
    private->service_model_hash = g_hash_table_new(NULL, NULL);
renatofilho@754
   245
renatofilho@754
   246
    /*
renatofilho@754
   247
     * fill program infos from db 
renatofilho@754
   248
     */
renatofilho@20
   249
    mmyth_epg_grid_widget_fill_programinfos(private);
renatofilho@754
   250
renatofilho@20
   251
    channel_list = private->channel_list;
renatofilho@754
   252
renatofilho@754
   253
    /*
renatofilho@754
   254
     * for each channel get_programs() 
renatofilho@754
   255
     */
renatofilho@754
   256
    for (chanid = 0; channel_list &&
renatofilho@754
   257
         chanid < private->DISPLAY_CHANS; chanid++) {
renatofilho@754
   258
        proglist = (GList *) private->program_list[chanid];
renatofilho@754
   259
renatofilho@20
   260
        channel_info = (GMythChannelInfo *) channel_list->data;
renatofilho@754
   261
        channel_list = g_list_next(channel_list);
renatofilho@20
   262
renatofilho@754
   263
        /*
renatofilho@754
   264
         * Service Title
renatofilho@754
   265
         */
renatofilho@754
   266
        GString        *name = NULL;
renatofilho@20
   267
        if (channel_info->channel_name)
renatofilho@754
   268
            name = g_string_new(channel_info->channel_name->str);
renatofilho@20
   269
renatofilho@754
   270
        GdkColor        title_bg_color;
renatofilho@754
   271
        title_bg_color.red = 5000;
renatofilho@754
   272
        title_bg_color.green = 9000;
renatofilho@754
   273
        title_bg_color.blue = 40000;
renatofilho@20
   274
renatofilho@754
   275
        GdkColor        title_fg_color;
renatofilho@754
   276
        title_fg_color.red = 60000;
renatofilho@754
   277
        title_fg_color.green = 60000;
renatofilho@754
   278
        title_fg_color.blue = 60000;
renatofilho@20
   279
renatofilho@754
   280
        GtkWidget      *event_box_channel =
renatofilho@754
   281
            create_event_box_lbl(name->str, 90,
renatofilho@754
   282
                                 &title_bg_color,
renatofilho@754
   283
                                 &title_fg_color);
renatofilho@754
   284
renatofilho@754
   285
        gtk_box_pack_start(GTK_BOX(private->epg_channels_vbox),
renatofilho@754
   286
                           event_box_channel, FALSE, FALSE, 0);
renatofilho@754
   287
renatofilho@754
   288
        GtkWidget      *epg_line_hbox = gtk_hbox_new(FALSE, 0);
renatofilho@754
   289
renatofilho@754
   290
        GdkColor        bg_color;
renatofilho@754
   291
        bg_color.red = 5000;
renatofilho@754
   292
        bg_color.green = 30000;
renatofilho@754
   293
        bg_color.blue = 60000;
renatofilho@754
   294
renatofilho@754
   295
        GdkColor        fg_color;
renatofilho@754
   296
        fg_color.red = 60000;
renatofilho@754
   297
        fg_color.green = 60000;
renatofilho@754
   298
        fg_color.blue = 60000;
renatofilho@754
   299
renatofilho@754
   300
        /*
renatofilho@754
   301
         * Content parsing 
renatofilho@754
   302
         */
renatofilho@754
   303
        GList          *epg_grid_list = NULL;
renatofilho@20
   304
renatofilho@20
   305
        GMythProgramInfo *proginfo;
renatofilho@754
   306
        int             pixel_count = 0;
renatofilho@20
   307
        for (; proglist; proglist = proglist->next) {
renatofilho@20
   308
            proginfo = (GMythProgramInfo *) proglist->data;
renatofilho@20
   309
renatofilho@754
   310
            GString        *content_name = proginfo->title;
renatofilho@20
   311
renatofilho@754
   312
            GTimeVal       *initial_time = g_new0(GTimeVal, 1);
renatofilho@754
   313
            GTimeVal       *last_time = g_new0(GTimeVal, 1);
renatofilho@754
   314
            GTimeVal       *duration = g_new0(GTimeVal, 1);
renatofilho@754
   315
renatofilho@754
   316
            GTimeVal       *schedule_start_time = proginfo->startts;
renatofilho@754
   317
            GTimeVal       *schedule_end_time = proginfo->endts;
renatofilho@754
   318
renatofilho@754
   319
            initial_time->tv_sec =
renatofilho@754
   320
                (schedule_start_time->tv_sec <
renatofilho@754
   321
                 start_time->tv_sec) ? start_time->
renatofilho@754
   322
                tv_sec : schedule_start_time->tv_sec;
renatofilho@754
   323
            last_time->tv_sec =
renatofilho@754
   324
                (schedule_end_time->tv_sec >
renatofilho@754
   325
                 end_time->tv_sec) ? end_time->tv_sec : schedule_end_time->
renatofilho@754
   326
                tv_sec;
renatofilho@754
   327
            duration->tv_sec = last_time->tv_sec - initial_time->tv_sec;
renatofilho@754
   328
renatofilho@20
   329
            // Verify program time 
renatofilho@754
   330
#if 0
renatofilho@754
   331
            g_debug("ServiceID: %d, ScheduleID: %d\n", service->id,
renatofilho@754
   332
                    schedule->id);
renatofilho@754
   333
            fprintf(stderr, "program time\nfrom = %d, to = %d\n",
renatofilho@754
   334
                    schedule->validFrom, schedule->validTo);
renatofilho@754
   335
renatofilho@754
   336
            struct tm       loctime;
renatofilho@754
   337
renatofilho@754
   338
            /*
renatofilho@754
   339
             * Convert it to local time representation. 
renatofilho@754
   340
             */
renatofilho@754
   341
            if (localtime_r((time_t *) & schedule->validFrom, &loctime) ==
renatofilho@754
   342
                NULL) {
renatofilho@754
   343
                g_warning("localtime_r error in mmyth_epg_grid_widget!\n");
renatofilho@754
   344
                return NULL;
renatofilho@20
   345
            }
renatofilho@754
   346
            fprintf(stderr, asctime(&loctime));
renatofilho@754
   347
renatofilho@754
   348
            if (localtime_r((time_t *) & schedule->validTo, &loctime) ==
renatofilho@754
   349
                NULL) {
renatofilho@754
   350
                g_warning("localtime_r error in mmyth_epg_grid_widget!\n");
renatofilho@754
   351
                return NULL;
renatofilho@754
   352
            }
renatofilho@754
   353
            fprintf(stderr, asctime(&loctime));
renatofilho@754
   354
#endif
renatofilho@754
   355
renatofilho@754
   356
            /*
renatofilho@754
   357
             * fprintf(stderr, "duration = %d\n", duration); 
renatofilho@754
   358
             */
renatofilho@754
   359
            double          duration_hour =
renatofilho@754
   360
                duration->tv_sec / (double) 3600.0;
renatofilho@754
   361
            /*
renatofilho@754
   362
             * fprintf(stderr, "duration_hour = %lf\n", duration_hour); 
renatofilho@754
   363
             */
renatofilho@754
   364
renatofilho@754
   365
            int             size = PIXELS_HOUR * duration_hour;
renatofilho@754
   366
renatofilho@754
   367
            /*
renatofilho@754
   368
             * complete hour 
renatofilho@754
   369
             */
renatofilho@754
   370
            /*
renatofilho@754
   371
             * FIXME: UGLY WRONG HACK TO ALIGN PROGRAM TIME!!!
renatofilho@754
   372
             */
renatofilho@754
   373
            if (last_time->tv_sec % 3600 != 0) {
renatofilho@754
   374
                size -= PROGRAM_SEPARATION;
renatofilho@754
   375
            }
renatofilho@754
   376
            if (initial_time->tv_sec % 3600 != 0) {
renatofilho@754
   377
                size -= PROGRAM_SEPARATION;
renatofilho@20
   378
            }
renatofilho@20
   379
renatofilho@20
   380
            pixel_count += size + PROGRAM_SEPARATION;
renatofilho@754
   381
            GtkWidget      *event_box =
renatofilho@754
   382
                create_event_box_lbl(content_name->str,
renatofilho@754
   383
                                     size, &bg_color,
renatofilho@754
   384
                                     &fg_color);
renatofilho@754
   385
            gtk_widget_add_events(event_box,
renatofilho@754
   386
                                  GDK_BUTTON_PRESS_MASK |
renatofilho@754
   387
                                  GDK_BUTTON_RELEASE_MASK);
renatofilho@754
   388
renatofilho@754
   389
            /*
renatofilho@754
   390
             * create EpgGridItem 
renatofilho@754
   391
             */
renatofilho@754
   392
            EpgGridItem    *epg_grid_item = g_new0(EpgGridItem, 1);
renatofilho@754
   393
            epg_grid_item->proginfo = proginfo;
renatofilho@20
   394
            epg_grid_item->event_box = event_box;
renatofilho@754
   395
            epg_grid_item->object = mmyth_epg_grid_widget;
renatofilho@20
   396
renatofilho@754
   397
            epg_grid_list =
renatofilho@754
   398
                g_list_prepend(epg_grid_list, (gpointer) epg_grid_item);
renatofilho@754
   399
renatofilho@754
   400
            gtk_box_pack_start(GTK_BOX(epg_line_hbox),
renatofilho@754
   401
                               event_box, FALSE, FALSE,
renatofilho@754
   402
                               PROGRAM_SEPARATION);
renatofilho@754
   403
renatofilho@754
   404
            g_signal_connect(G_OBJECT(event_box), "button-press-event",
renatofilho@754
   405
                             G_CALLBACK(mmyth_epg_grid_widget_clicked),
renatofilho@754
   406
                             (gpointer *) epg_grid_list);
renatofilho@20
   407
        }
renatofilho@20
   408
#if 0
renatofilho@754
   409
        printf("chaind = %d!!!!" chanid);
renatofilho@754
   410
        fflush(stdout);
renatofilho@754
   411
#endif
renatofilho@20
   412
renatofilho@754
   413
        if (!epg_grid_list) {
renatofilho@754
   414
            /*
renatofilho@754
   415
             * No programs for current channel 
renatofilho@754
   416
             */
renatofilho@754
   417
            /*
renatofilho@754
   418
             * FIXME: size HARDCODED 
renatofilho@754
   419
             */
renatofilho@754
   420
            GtkWidget      *event_box =
renatofilho@754
   421
                create_event_box_lbl("No program list available",
renatofilho@754
   422
                                     PIXELS_HOUR * 3, &bg_color,
renatofilho@754
   423
                                     &fg_color);
renatofilho@754
   424
            gtk_widget_add_events(event_box,
renatofilho@754
   425
                                  GDK_BUTTON_PRESS_MASK |
renatofilho@754
   426
                                  GDK_BUTTON_RELEASE_MASK);
renatofilho@20
   427
renatofilho@754
   428
            /*
renatofilho@754
   429
             * create EpgGridItem 
renatofilho@754
   430
             */
renatofilho@754
   431
            EpgGridItem    *epg_grid_item = g_new0(EpgGridItem, 1);
renatofilho@754
   432
            epg_grid_item->proginfo = NULL;
renatofilho@20
   433
            epg_grid_item->event_box = event_box;
renatofilho@754
   434
            epg_grid_item->object = mmyth_epg_grid_widget;
renatofilho@20
   435
renatofilho@754
   436
            epg_grid_list =
renatofilho@754
   437
                g_list_prepend(epg_grid_list, (gpointer) epg_grid_item);
renatofilho@754
   438
renatofilho@754
   439
            gtk_box_pack_start(GTK_BOX(epg_line_hbox),
renatofilho@754
   440
                               event_box, FALSE, FALSE,
renatofilho@754
   441
                               PROGRAM_SEPARATION);
renatofilho@754
   442
renatofilho@754
   443
            g_signal_connect(G_OBJECT(event_box), "button-press-event",
renatofilho@754
   444
                             G_CALLBACK(mmyth_epg_grid_widget_clicked),
renatofilho@754
   445
                             (gpointer *) epg_grid_list);
renatofilho@20
   446
        }
renatofilho@20
   447
renatofilho@20
   448
        epg_grid_list = g_list_reverse(epg_grid_list);
renatofilho@754
   449
        mmyth_epg_grid_widget->epg_view_model =
renatofilho@754
   450
            g_list_append(mmyth_epg_grid_widget->epg_view_model,
renatofilho@754
   451
                          epg_grid_list);
renatofilho@754
   452
renatofilho@754
   453
        gtk_box_pack_start(GTK_BOX(private->epg_programs_vbox),
renatofilho@754
   454
                           epg_line_hbox, FALSE, FALSE, 0);
renatofilho@20
   455
    }
renatofilho@20
   456
}
renatofilho@20
   457
renatofilho@20
   458
static void
renatofilho@754
   459
mmyth_epg_grid_widget_mount_header(MMythEpgGridWidget *
renatofilho@754
   460
                                   mmyth_epg_grid_widget)
renatofilho@754
   461
{
renatofilho@754
   462
    MMythEpgGridWidgetPrivate *private =
renatofilho@20
   463
        MMYTH_EPG_GRID_WIDGET_GET_PRIVATE(mmyth_epg_grid_widget);
renatofilho@20
   464
renatofilho@754
   465
    struct tm       hour_tm;
renatofilho@754
   466
    const gchar     name_title[] = "Today";
renatofilho@754
   467
    GtkWidget      *lbl_title = gtk_label_new(name_title);
renatofilho@20
   468
renatofilho@754
   469
    gtk_misc_set_alignment(GTK_MISC(lbl_title), 0.0, 0.5);
renatofilho@20
   470
renatofilho@754
   471
    gtk_box_pack_start(GTK_BOX(private->epg_channels_vbox),
renatofilho@754
   472
                       lbl_title, FALSE, FALSE, 0);
renatofilho@754
   473
renatofilho@754
   474
    /*
renatofilho@754
   475
     * hours title line 
renatofilho@754
   476
     */
renatofilho@754
   477
    GtkWidget      *epg_programs_hours_hbox = gtk_hbox_new(TRUE, 0);
renatofilho@754
   478
renatofilho@754
   479
    if (localtime_r
renatofilho@754
   480
        ((time_t *) & private->current_start_time->tv_sec,
renatofilho@754
   481
         &hour_tm) == NULL) {
renatofilho@754
   482
        g_warning("localtime_r error in mmyth_epg_grid_widget!\n");
rosfran@244
   483
        return;
renatofilho@754
   484
    }
renatofilho@20
   485
renatofilho@754
   486
    if (hour_tm.tm_min > 30) {
renatofilho@20
   487
        hour_tm.tm_min = 30;
renatofilho@754
   488
    } else if (hour_tm.tm_min > 0) {
renatofilho@20
   489
        hour_tm.tm_min = 0;
renatofilho@20
   490
    }
renatofilho@754
   491
renatofilho@754
   492
    gchar           hour1_str[10];
renatofilho@20
   493
    strftime(hour1_str, 8, "%H:%M", &hour_tm);
renatofilho@754
   494
    GtkWidget      *lbl_hour1 = gtk_label_new(hour1_str);
renatofilho@754
   495
    gtk_misc_set_alignment(GTK_MISC(lbl_hour1), 0.0, 0.5);
renatofilho@20
   496
renatofilho@20
   497
    hour_tm.tm_hour++;
renatofilho@754
   498
    gchar           hour2_str[10];
renatofilho@754
   499
    strftime(hour2_str, 8, "%H:%M", &hour_tm);
renatofilho@754
   500
    GtkWidget      *lbl_hour2 = gtk_label_new(hour2_str);
renatofilho@754
   501
    gtk_misc_set_alignment(GTK_MISC(lbl_hour2), 0.0, 0.5);
renatofilho@754
   502
renatofilho@754
   503
    hour_tm.tm_hour++;
renatofilho@754
   504
    gchar           hour3_str[10];
renatofilho@20
   505
    strftime(hour3_str, 8, "%H:%M", &hour_tm);
renatofilho@754
   506
    GtkWidget      *lbl_hour3 = gtk_label_new(hour3_str);
renatofilho@754
   507
    gtk_misc_set_alignment(GTK_MISC(lbl_hour3), 0.0, 0.5);
renatofilho@754
   508
renatofilho@754
   509
    gtk_box_pack_start(GTK_BOX(epg_programs_hours_hbox),
renatofilho@754
   510
                       lbl_hour1, TRUE, TRUE, 0);
renatofilho@754
   511
    gtk_box_pack_start(GTK_BOX(epg_programs_hours_hbox),
renatofilho@754
   512
                       lbl_hour2, TRUE, TRUE, 0);
renatofilho@754
   513
    gtk_box_pack_start(GTK_BOX(epg_programs_hours_hbox),
renatofilho@754
   514
                       lbl_hour3, TRUE, TRUE, 0);
renatofilho@754
   515
renatofilho@754
   516
    gtk_box_pack_start(GTK_BOX(private->epg_programs_vbox),
renatofilho@754
   517
                       epg_programs_hours_hbox, FALSE, FALSE, 0);
renatofilho@20
   518
}
renatofilho@20
   519
renatofilho@20
   520
/******************************************************************************
renatofilho@20
   521
 *              INTERNAL CALLBACKS FOR STATE CHANGE                           *
renatofilho@20
   522
 *****************************************************************************/
renatofilho@754
   523
static void
renatofilho@754
   524
mmyth_epg_grid_widget_deselect_service(MMythEpgGridWidget *
renatofilho@754
   525
                                       mmyth_epg_grid_widget)
renatofilho@20
   526
{
renatofilho@754
   527
    EpgGridItem    *epg_grid_item;
renatofilho@754
   528
renatofilho@754
   529
    /*
renatofilho@754
   530
     * deselect
renatofilho@754
   531
     */
renatofilho@754
   532
    if (mmyth_epg_grid_widget->selected_grid_item != NULL) {
renatofilho@754
   533
        epg_grid_item =
renatofilho@754
   534
            (EpgGridItem *) mmyth_epg_grid_widget->selected_grid_item->
renatofilho@754
   535
            data;
renatofilho@754
   536
        gtk_widget_set_state(GTK_WIDGET(epg_grid_item->event_box),
renatofilho@754
   537
                             GTK_STATE_NORMAL);
renatofilho@754
   538
    }
renatofilho@20
   539
}
renatofilho@20
   540
renatofilho@754
   541
static void
renatofilho@754
   542
mmyth_epg_grid_widget_clicked(GtkWidget * widget,
renatofilho@754
   543
                              GdkEventExpose * event, gpointer data)
renatofilho@754
   544
{
renatofilho@20
   545
    g_return_if_fail(data != NULL);
renatofilho@20
   546
renatofilho@754
   547
    GList          *epg_grid_item_list = (GList *) data;
renatofilho@754
   548
    EpgGridItem    *epg_grid_item =
renatofilho@754
   549
        (EpgGridItem *) epg_grid_item_list->data;
renatofilho@20
   550
renatofilho@754
   551
    /*
renatofilho@754
   552
     * update the selected service 
renatofilho@754
   553
     */
renatofilho@754
   554
    mmyth_epg_grid_widget_update_service(epg_grid_item->object,
renatofilho@754
   555
                                         (GList *) data);
renatofilho@20
   556
}
renatofilho@20
   557
renatofilho@20
   558
void
renatofilho@20
   559
mmyth_epg_grid_widget_update_service(MMythEpgGridWidget * object,
renatofilho@754
   560
                                     GList * selected_grid_list)
renatofilho@20
   561
{
renatofilho@20
   562
    g_return_if_fail(object != NULL);
renatofilho@20
   563
    g_return_if_fail(selected_grid_list != NULL);
renatofilho@754
   564
renatofilho@754
   565
    EpgGridItem    *epg_grid_item =
renatofilho@754
   566
        (EpgGridItem *) selected_grid_list->data;
renatofilho@20
   567
renatofilho@20
   568
    mmyth_epg_grid_widget_deselect_service(epg_grid_item->object);
renatofilho@20
   569
renatofilho@754
   570
    /*
renatofilho@754
   571
     * updating current selected schedule_item and schedule_list
renatofilho@754
   572
     */
renatofilho@20
   573
    object->selected_grid_item = selected_grid_list;
renatofilho@754
   574
renatofilho@754
   575
    /*
renatofilho@754
   576
     * set state of the event box 
renatofilho@754
   577
     */
renatofilho@754
   578
    gtk_widget_set_state(GTK_WIDGET(epg_grid_item->event_box),
renatofilho@754
   579
                         GTK_STATE_SELECTED);
renatofilho@754
   580
    /*
renatofilho@754
   581
     * emit update signal for listeners 
renatofilho@754
   582
     */
renatofilho@754
   583
    g_signal_emit(object,
renatofilho@20
   584
                  mmyth_epg_grid_widget_signals[SELECTION_UPDATED_SIGNAL],
renatofilho@754
   585
                  0, (gpointer) epg_grid_item);
renatofilho@20
   586
}
renatofilho@20
   587
renatofilho@754
   588
static GtkWidget *
renatofilho@754
   589
create_event_box_lbl(gchar * str, int width, const GdkColor * bg_color,
renatofilho@754
   590
                     const GdkColor * fg_color)
renatofilho@20
   591
{
renatofilho@754
   592
    GtkWidget      *event_box = gtk_event_box_new();
renatofilho@754
   593
    GtkWidget      *lbl = gtk_label_new(str);
renatofilho@20
   594
    gtk_label_set_ellipsize(GTK_LABEL(lbl), PANGO_ELLIPSIZE_END);
renatofilho@20
   595
renatofilho@754
   596
    gtk_widget_modify_bg(event_box, GTK_STATE_NORMAL, bg_color);
renatofilho@754
   597
    gtk_widget_modify_fg(lbl, GTK_STATE_NORMAL, fg_color);
renatofilho@754
   598
renatofilho@754
   599
    /*
renatofilho@754
   600
     * selected colors are const
renatofilho@754
   601
     */
renatofilho@754
   602
    GdkColor        selected_bg_color;
renatofilho@20
   603
    selected_bg_color.red = 100;
renatofilho@20
   604
    selected_bg_color.green = 40000;
renatofilho@754
   605
    selected_bg_color.blue = 100;
renatofilho@20
   606
renatofilho@754
   607
    GdkColor        selected_fg_color;
renatofilho@20
   608
    selected_fg_color.red = 100;
renatofilho@20
   609
    selected_fg_color.green = 100;
renatofilho@754
   610
    selected_fg_color.blue = 100;
renatofilho@754
   611
renatofilho@754
   612
    gtk_widget_modify_bg(event_box, GTK_STATE_SELECTED,
renatofilho@754
   613
                         &selected_bg_color);
renatofilho@754
   614
    gtk_widget_modify_fg(lbl, GTK_STATE_SELECTED, &selected_fg_color);
renatofilho@754
   615
renatofilho@754
   616
    gtk_misc_set_alignment(GTK_MISC(lbl), 0.0, 0.5);
renatofilho@754
   617
    gtk_container_add(GTK_CONTAINER(event_box), lbl);
renatofilho@754
   618
    gtk_widget_set_size_request(event_box, width, -1);
renatofilho@754
   619
renatofilho@20
   620
    return event_box;
renatofilho@20
   621
}
renatofilho@20
   622
renatofilho@20
   623
/******************************************************************************
renatofilho@20
   624
 *                            METHODS                                         *
renatofilho@20
   625
 *****************************************************************************/
renatofilho@20
   626
renatofilho@754
   627
/*
renatofilho@754
   628
 * Callback for hardware keys 
renatofilho@754
   629
 */
renatofilho@20
   630
gboolean
renatofilho@754
   631
mmyth_epg_grid_widget_key_press(MMythEpgGridWidget * object,
renatofilho@754
   632
                                GtkWidget * widget, GdkEventKey * event)
renatofilho@20
   633
{
renatofilho@754
   634
    MMythEpgGridWidgetPrivate *private =
renatofilho@20
   635
        MMYTH_EPG_GRID_WIDGET_GET_PRIVATE(object);
renatofilho@754
   636
renatofilho@754
   637
    EpgGridItem    *epg_grid_item;
renatofilho@754
   638
    GList          *tmp;
renatofilho@754
   639
renatofilho@754
   640
    /*
renatofilho@754
   641
     * List of selected_grid_item 
renatofilho@754
   642
     */
renatofilho@754
   643
    GList          *selected_view_model;
renatofilho@754
   644
renatofilho@754
   645
    gint            channel_index;
renatofilho@754
   646
renatofilho@754
   647
    if (object->selected_grid_item == NULL) {
renatofilho@754
   648
        g_warning("No program selected");
renatofilho@754
   649
        return FALSE;
renatofilho@754
   650
    }
renatofilho@754
   651
renatofilho@754
   652
    epg_grid_item = (EpgGridItem *) object->selected_grid_item->data;
renatofilho@754
   653
renatofilho@20
   654
    channel_index = private->selected_channel_index;
renatofilho@754
   655
renatofilho@20
   656
    switch (event->keyval) {
renatofilho@754
   657
    case GDK_Up:
renatofilho@754
   658
        selected_view_model =
renatofilho@754
   659
            g_list_nth(object->epg_view_model, channel_index - 1);
renatofilho@754
   660
        if (selected_view_model != NULL) {
renatofilho@754
   661
            private->selected_channel_index = channel_index - 1;
renatofilho@754
   662
            tmp = (GList *) selected_view_model->data;
renatofilho@754
   663
            /*
renatofilho@754
   664
             * TODO: select a better centralized item currently is
renatofilho@754
   665
             * picking the 1st or last item 
renatofilho@754
   666
             */
renatofilho@754
   667
            if (g_list_next(object->selected_grid_item) == NULL &&
renatofilho@754
   668
                g_list_previous(object->selected_grid_item) != NULL) {
renatofilho@754
   669
                /*
renatofilho@754
   670
                 * in this case the new selected will be the last 
renatofilho@754
   671
                 */
renatofilho@754
   672
                tmp = g_list_last(tmp);
renatofilho@754
   673
            }
renatofilho@20
   674
renatofilho@754
   675
            /*
renatofilho@754
   676
             * update the selected service 
renatofilho@754
   677
             */
renatofilho@754
   678
            mmyth_epg_grid_widget_update_service(object, tmp);
renatofilho@754
   679
        }
renatofilho@754
   680
        return TRUE;
renatofilho@754
   681
    case GDK_Down:
renatofilho@754
   682
        selected_view_model =
renatofilho@754
   683
            g_list_nth(object->epg_view_model, channel_index + 1);
renatofilho@754
   684
        if (selected_view_model != NULL) {
renatofilho@754
   685
            private->selected_channel_index = channel_index + 1;
renatofilho@754
   686
            tmp = (GList *) selected_view_model->data;
renatofilho@754
   687
            /*
renatofilho@754
   688
             * TODO: select a better centralized item currently is
renatofilho@754
   689
             * picking the 1st or last item 
renatofilho@754
   690
             */
renatofilho@754
   691
            if (g_list_next(object->selected_grid_item) == NULL &&
renatofilho@754
   692
                g_list_previous(object->selected_grid_item) != NULL) {
renatofilho@754
   693
                /*
renatofilho@754
   694
                 * in this case the new selected will be the last 
renatofilho@754
   695
                 */
renatofilho@754
   696
                tmp = g_list_last(tmp);
renatofilho@754
   697
            }
renatofilho@20
   698
renatofilho@754
   699
            /*
renatofilho@754
   700
             * update the selected service 
renatofilho@754
   701
             */
renatofilho@754
   702
            mmyth_epg_grid_widget_update_service(object, tmp);
renatofilho@754
   703
        }
renatofilho@754
   704
        return TRUE;
renatofilho@754
   705
    case GDK_Left:
renatofilho@754
   706
        tmp = g_list_previous(object->selected_grid_item);
renatofilho@754
   707
        if (tmp != NULL) {
renatofilho@754
   708
            /*
renatofilho@754
   709
             * update the selected service 
renatofilho@754
   710
             */
renatofilho@754
   711
            mmyth_epg_grid_widget_update_service(object, tmp);
renatofilho@754
   712
        }
renatofilho@754
   713
        return TRUE;
renatofilho@754
   714
    case GDK_Right:
renatofilho@754
   715
        tmp = g_list_next(object->selected_grid_item);
renatofilho@754
   716
        if (tmp != NULL) {
renatofilho@754
   717
            /*
renatofilho@754
   718
             * update the selected service 
renatofilho@754
   719
             */
renatofilho@754
   720
            mmyth_epg_grid_widget_update_service(object, tmp);
renatofilho@754
   721
        }
renatofilho@754
   722
        return TRUE;
renatofilho@754
   723
    default:
renatofilho@754
   724
        return TRUE;
renatofilho@20
   725
    }
renatofilho@754
   726
renatofilho@20
   727
    return FALSE;
renatofilho@20
   728
}
renatofilho@20
   729
renatofilho@754
   730
static void
renatofilho@754
   731
mmyth_epg_grid_widget_fill_programinfos(MMythEpgGridWidgetPrivate *
renatofilho@754
   732
                                        private)
renatofilho@20
   733
{
renatofilho@754
   734
    GList          *channels_list = NULL;
renatofilho@754
   735
    int             y;
renatofilho@20
   736
renatofilho@20
   737
    if ((private->mmyth_epg != NULL) &&
renatofilho@754
   738
        (gmyth_epg_get_channel_list(private->mmyth_epg, &channels_list) <
renatofilho@754
   739
         0)) {
renatofilho@754
   740
        private->channel_list = NULL;
renatofilho@754
   741
        return;
renatofilho@20
   742
    }
renatofilho@754
   743
renatofilho@20
   744
    private->channel_list = channels_list;
renatofilho@754
   745
renatofilho@20
   746
    for (y = 0; y < private->DISPLAY_CHANS && channels_list; y++) {
renatofilho@754
   747
        GMythChannelInfo *channel_info =
renatofilho@754
   748
            (GMythChannelInfo *) channels_list->data;
renatofilho@20
   749
renatofilho@754
   750
        mmyth_epg_grid_widget_fill_program_row_infos(private,
renatofilho@754
   751
                                                     channel_info->
renatofilho@754
   752
                                                     channel_ID, y);
renatofilho@20
   753
renatofilho@754
   754
        channels_list = g_list_next(channels_list);
renatofilho@20
   755
    }
renatofilho@20
   756
}
renatofilho@20
   757
renatofilho@754
   758
static void
renatofilho@754
   759
mmyth_epg_grid_widget_fill_program_row_infos(MMythEpgGridWidgetPrivate *
renatofilho@754
   760
                                             private, guint chanNum,
renatofilho@754
   761
                                             guint row)
renatofilho@754
   762
{
renatofilho@754
   763
    gint            res = gmyth_epg_get_program_list(private->mmyth_epg,
renatofilho@754
   764
                                                     &(private->
renatofilho@754
   765
                                                       program_list[row]),
renatofilho@754
   766
                                                     chanNum,
renatofilho@754
   767
                                                     private->
renatofilho@754
   768
                                                     current_start_time,
renatofilho@754
   769
                                                     private->
renatofilho@754
   770
                                                     current_end_time);
renatofilho@754
   771
renatofilho@20
   772
    if (res < 0) {
renatofilho@754
   773
        g_warning("[%s] Error while retrieving epg programs",
renatofilho@754
   774
                  __FUNCTION__);
renatofilho@20
   775
    }
renatofilho@20
   776
}