renatofilho@20: #include renatofilho@20: #include renatofilho@20: #include renatofilho@20: renatofilho@20: #include "mmyth_uicommon.h" renatofilho@20: #include "mmyth_epg_grid_widget.h" renatofilho@20: rosfran@245: #include rosfran@245: #include renatofilho@20: renatofilho@20: #define PIXELS_HOUR 105 renatofilho@20: #define PROGRAM_SEPARATION 2 renatofilho@20: renatofilho@20: enum { renatofilho@20: SELECTION_UPDATED_SIGNAL, renatofilho@20: LAST_SIGNAL renatofilho@20: }; renatofilho@20: renatofilho@20: struct _MMythEpgGridWidgetPrivate { renatofilho@20: /* private widget components */ renatofilho@20: GtkWidget *epg_channels_vbox; renatofilho@20: GtkWidget *epg_programs_vbox; renatofilho@20: renatofilho@20: GHashTable *service_model_hash; renatofilho@20: renatofilho@20: /* guidegrid attributes */ renatofilho@20: gboolean show_favorites; renatofilho@20: gint current_start_channel_id; renatofilho@20: rosfran@244: GTimeVal* current_start_time; rosfran@244: GTimeVal* current_end_time; renatofilho@20: renatofilho@20: guint selected_channel_index; renatofilho@20: renatofilho@20: /* GList of ProgramInfo for each Channel */ renatofilho@20: GList * program_list[MAX_DISPLAY_CHANS]; renatofilho@20: GList * channel_list; renatofilho@20: renatofilho@20: GMythEPG *mmyth_epg; rosfran@208: rosfran@208: GMythBackendInfo *backend_info; renatofilho@20: renatofilho@20: gint DISPLAY_CHANS; renatofilho@20: }; renatofilho@20: renatofilho@20: static void mmyth_epg_grid_widget_class_init (MMythEpgGridWidgetClass *klass); renatofilho@20: static void mmyth_epg_grid_widget_init (MMythEpgGridWidget *object); renatofilho@20: static void mmyth_epg_grid_widget_private_init (MMythEpgGridWidgetPrivate *private); renatofilho@20: static void mmyth_epg_grid_widget_mount_services (MMythEpgGridWidget *object, rosfran@244: GTimeVal* start_time, GTimeVal* end_time); renatofilho@20: static void mmyth_epg_grid_widget_mount_header (MMythEpgGridWidget *object); renatofilho@20: static void mmyth_epg_grid_widget_clicked (GtkWidget* widget, renatofilho@20: GdkEventExpose *event, renatofilho@20: gpointer data); renatofilho@20: static GtkWidget *create_event_box_lbl (gchar *str, int width, renatofilho@20: const GdkColor *bg_color, renatofilho@20: const GdkColor *fg_color); renatofilho@20: renatofilho@20: static void mmyth_epg_grid_widget_fill_programinfos(MMythEpgGridWidgetPrivate *private); renatofilho@20: static void mmyth_epg_grid_widget_fill_program_row_infos( renatofilho@20: MMythEpgGridWidgetPrivate *private, renatofilho@20: unsigned int chanNum, unsigned int row); renatofilho@20: renatofilho@20: static gint mmyth_epg_grid_widget_signals[LAST_SIGNAL] = { 0 }; renatofilho@20: renatofilho@20: G_DEFINE_TYPE(MMythEpgGridWidget, mmyth_epg_grid_widget, GTK_TYPE_EVENT_BOX) renatofilho@20: renatofilho@20: static void renatofilho@20: mmyth_epg_grid_widget_class_init (MMythEpgGridWidgetClass *klass) renatofilho@20: { renatofilho@20: g_type_class_add_private (klass, sizeof (MMythEpgGridWidgetPrivate)); renatofilho@20: renatofilho@20: mmyth_epg_grid_widget_signals[SELECTION_UPDATED_SIGNAL] = g_signal_new ( renatofilho@20: "selection_updated", renatofilho@20: G_TYPE_FROM_CLASS(klass), renatofilho@20: G_SIGNAL_RUN_FIRST, renatofilho@20: 0, renatofilho@20: NULL, renatofilho@20: NULL, renatofilho@20: g_cclosure_marshal_VOID__POINTER, renatofilho@20: G_TYPE_NONE, renatofilho@20: 1, renatofilho@20: G_TYPE_POINTER); renatofilho@20: } renatofilho@20: renatofilho@20: static void renatofilho@20: mmyth_epg_grid_widget_private_init (MMythEpgGridWidgetPrivate *private) renatofilho@20: { renatofilho@20: time_t cur_time; renatofilho@20: renatofilho@20: g_return_if_fail(private != NULL); renatofilho@20: renatofilho@20: private->epg_channels_vbox = NULL; renatofilho@20: private->epg_programs_vbox = NULL; renatofilho@20: private->service_model_hash = NULL; renatofilho@20: renatofilho@20: private->show_favorites = FALSE; renatofilho@20: private->current_start_channel_id = -1; renatofilho@20: renatofilho@20: /* Selected the first diplayable channel initially */ renatofilho@20: private->selected_channel_index = 0; renatofilho@20: renatofilho@20: /* TODO fix the current start/end time */ rosfran@244: private->current_start_time = g_new0( GTimeVal, 1 ); rosfran@244: private->current_start_time->tv_sec = time(&cur_time); rosfran@244: rosfran@244: private->current_end_time = g_new0( GTimeVal, 1 ); rosfran@244: private->current_end_time->tv_sec = time(&cur_time) + 10800; renatofilho@20: renatofilho@20: private->DISPLAY_CHANS = MAX_DISPLAY_CHANS; rosfran@208: rosfran@208: private->backend_info = gmyth_backend_info_new_full ( "192.168.1.109", "mythtv", rosfran@208: "mythtv", "mythconverg", 6543 ); rosfran@208: renatofilho@20: // TODO: Close the epg and unref it in dispose call renatofilho@20: private->mmyth_epg = gmyth_epg_new (); rosfran@208: if (!gmyth_epg_connect (private->mmyth_epg, private->backend_info)) { renatofilho@20: g_warning ("[%s] Could not connect mysql handler to db", __FUNCTION__); renatofilho@20: g_object_unref (private->mmyth_epg); renatofilho@20: private->mmyth_epg = NULL; renatofilho@20: } renatofilho@20: } renatofilho@20: renatofilho@20: static void renatofilho@20: mmyth_epg_grid_widget_init (MMythEpgGridWidget *mmyth_epg_grid_widget) renatofilho@20: { renatofilho@20: MMythEpgGridWidgetPrivate *private = renatofilho@20: MMYTH_EPG_GRID_WIDGET_GET_PRIVATE(mmyth_epg_grid_widget); renatofilho@20: renatofilho@20: /* init private fields */ renatofilho@20: mmyth_epg_grid_widget_private_init(private); renatofilho@20: renatofilho@20: mmyth_epg_grid_widget->epg_view_model = NULL; renatofilho@20: mmyth_epg_grid_widget->selected_grid_item = NULL; renatofilho@20: renatofilho@20: GtkWidget *epg_event_box = GTK_WIDGET(mmyth_epg_grid_widget); renatofilho@20: gtk_widget_modify_bg(epg_event_box, GTK_STATE_NORMAL, &main_bg_color); renatofilho@20: gtk_widget_set_size_request (epg_event_box, 0, 125); renatofilho@20: renatofilho@20: GtkWidget *epg_main_hbox = gtk_hbox_new (FALSE, 10); renatofilho@20: gtk_container_set_border_width(GTK_CONTAINER (epg_main_hbox), 10); renatofilho@20: renatofilho@20: gtk_container_add (GTK_CONTAINER (epg_event_box), renatofilho@20: epg_main_hbox); renatofilho@20: renatofilho@20: /* channels vbox */ renatofilho@20: GtkWidget *epg_channels_vbox = gtk_vbox_new (FALSE, 3); renatofilho@20: private->epg_channels_vbox = epg_channels_vbox; renatofilho@20: renatofilho@20: /* programs vbox */ renatofilho@20: GtkWidget *epg_programs_vbox = gtk_vbox_new (FALSE, 3); renatofilho@20: private->epg_programs_vbox = epg_programs_vbox; renatofilho@20: renatofilho@20: /* packing start */ renatofilho@20: gtk_box_pack_start (GTK_BOX (epg_main_hbox), renatofilho@20: epg_channels_vbox, FALSE, FALSE, 0); renatofilho@20: gtk_box_pack_start (GTK_BOX (epg_main_hbox), renatofilho@20: epg_programs_vbox, FALSE, FALSE, 0); renatofilho@20: renatofilho@20: /* table header (first line) */ renatofilho@20: mmyth_epg_grid_widget_mount_header(mmyth_epg_grid_widget); renatofilho@20: renatofilho@20: /* service programs */ renatofilho@20: /* mount service programs with current time */ renatofilho@20: mmyth_epg_grid_widget_mount_services(mmyth_epg_grid_widget, renatofilho@20: private->current_start_time, renatofilho@20: private->current_end_time); renatofilho@20: } renatofilho@20: renatofilho@20: GtkWidget* renatofilho@20: mmyth_epg_grid_widget_new () renatofilho@20: { renatofilho@20: return GTK_WIDGET ( gtk_type_new (mmyth_epg_grid_widget_get_type ())); renatofilho@20: } renatofilho@20: renatofilho@20: static void rosfran@244: mmyth_epg_grid_widget_mount_services( MMythEpgGridWidget *mmyth_epg_grid_widget, rosfran@244: GTimeVal* start_time, GTimeVal* end_time ) renatofilho@20: { renatofilho@20: GList *proglist; renatofilho@20: GList *channel_list = NULL; renatofilho@20: GMythChannelInfo *channel_info; renatofilho@20: renatofilho@20: int chanid; renatofilho@20: MMythEpgGridWidgetPrivate *private = renatofilho@20: MMYTH_EPG_GRID_WIDGET_GET_PRIVATE(mmyth_epg_grid_widget); renatofilho@20: renatofilho@20: // update view_model renatofilho@20: /* FIXME shallow free or recursive? */ renatofilho@20: if(mmyth_epg_grid_widget->epg_view_model != NULL) { renatofilho@20: g_list_free(mmyth_epg_grid_widget->epg_view_model); renatofilho@20: mmyth_epg_grid_widget->epg_view_model = NULL; renatofilho@20: } renatofilho@20: renatofilho@20: if(private->service_model_hash != NULL) { renatofilho@20: g_hash_table_destroy(private->service_model_hash); renatofilho@20: } renatofilho@20: renatofilho@20: private->service_model_hash = g_hash_table_new(NULL, NULL); renatofilho@20: renatofilho@20: /* fill program infos from db */ renatofilho@20: mmyth_epg_grid_widget_fill_programinfos(private); renatofilho@20: renatofilho@20: channel_list = private->channel_list; renatofilho@20: renatofilho@20: /* for each channel get_programs() */ renatofilho@20: for (chanid=0; channel_list && renatofilho@20: chanid < private->DISPLAY_CHANS; chanid++) { renatofilho@20: proglist = (GList *) private->program_list[chanid]; renatofilho@20: renatofilho@20: channel_info = (GMythChannelInfo *) channel_list->data; renatofilho@20: channel_list = g_list_next(channel_list); renatofilho@20: renatofilho@20: /* Service Title*/ renatofilho@20: GString *name = NULL; renatofilho@20: if (channel_info->channel_name) renatofilho@20: name = g_string_new (channel_info->channel_name->str); renatofilho@20: renatofilho@20: GdkColor title_bg_color; renatofilho@20: title_bg_color.red = 5000; renatofilho@20: title_bg_color.green = 9000; renatofilho@20: title_bg_color.blue = 40000; renatofilho@20: renatofilho@20: GdkColor title_fg_color; renatofilho@20: title_fg_color.red = 60000; renatofilho@20: title_fg_color.green = 60000; renatofilho@20: title_fg_color.blue = 60000; renatofilho@20: renatofilho@20: GtkWidget *event_box_channel = create_event_box_lbl( renatofilho@20: name->str, 90, renatofilho@20: &title_bg_color, renatofilho@20: &title_fg_color); renatofilho@20: renatofilho@20: gtk_box_pack_start (GTK_BOX (private->epg_channels_vbox), renatofilho@20: event_box_channel, FALSE, FALSE, 0); renatofilho@20: renatofilho@20: GtkWidget *epg_line_hbox = gtk_hbox_new (FALSE, 0); renatofilho@20: renatofilho@20: GdkColor bg_color; renatofilho@20: bg_color.red = 5000; renatofilho@20: bg_color.green = 30000; renatofilho@20: bg_color.blue = 60000; renatofilho@20: renatofilho@20: GdkColor fg_color; renatofilho@20: fg_color.red = 60000; renatofilho@20: fg_color.green = 60000; renatofilho@20: fg_color.blue = 60000; renatofilho@20: renatofilho@20: /* Content parsing */ renatofilho@20: GList *epg_grid_list = NULL; renatofilho@20: renatofilho@20: GMythProgramInfo *proginfo; renatofilho@20: int pixel_count = 0; renatofilho@20: for (; proglist; proglist = proglist->next) { renatofilho@20: proginfo = (GMythProgramInfo *) proglist->data; renatofilho@20: renatofilho@20: GString *content_name = proginfo->title; renatofilho@20: rosfran@244: GTimeVal* initial_time = g_new0( GTimeVal, 1 ); rosfran@244: GTimeVal* last_time = g_new0( GTimeVal, 1 ); rosfran@244: GTimeVal* duration = g_new0( GTimeVal, 1 ); renatofilho@20: rosfran@244: GTimeVal* schedule_start_time = proginfo->startts; rosfran@244: GTimeVal* schedule_end_time = proginfo->endts; renatofilho@20: rosfran@244: initial_time->tv_sec = rosfran@244: (schedule_start_time->tv_sec < start_time->tv_sec) ? start_time->tv_sec : schedule_start_time->tv_sec; rosfran@244: last_time->tv_sec = (schedule_end_time->tv_sec > end_time->tv_sec) ? end_time->tv_sec : schedule_end_time->tv_sec; rosfran@244: duration->tv_sec = last_time->tv_sec - initial_time->tv_sec; renatofilho@20: renatofilho@20: // Verify program time renatofilho@20: #if 0 renatofilho@20: g_debug ("ServiceID: %d, ScheduleID: %d\n", service->id, schedule->id); renatofilho@20: fprintf (stderr, "program time\nfrom = %d, to = %d\n", renatofilho@20: schedule->validFrom, schedule->validTo); renatofilho@20: renatofilho@20: struct tm loctime; renatofilho@20: renatofilho@20: /* Convert it to local time representation. */ renatofilho@20: if (localtime_r((time_t *)&schedule->validFrom, &loctime) == NULL) { renatofilho@20: g_warning ("localtime_r error in mmyth_epg_grid_widget!\n"); renatofilho@20: return NULL; renatofilho@20: } renatofilho@20: fprintf (stderr, asctime (&loctime)); renatofilho@20: renatofilho@20: if (localtime_r((time_t *)&schedule->validTo, &loctime) == NULL) { renatofilho@20: g_warning ("localtime_r error in mmyth_epg_grid_widget!\n"); renatofilho@20: return NULL; renatofilho@20: } renatofilho@20: fprintf (stderr, asctime (&loctime)); renatofilho@20: #endif renatofilho@20: renatofilho@20: /* fprintf(stderr, "duration = %d\n", duration); */ rosfran@244: double duration_hour = duration->tv_sec / (double) 3600.0; renatofilho@20: /* fprintf(stderr, "duration_hour = %lf\n", duration_hour); */ renatofilho@20: renatofilho@20: int size = PIXELS_HOUR * duration_hour; renatofilho@20: renatofilho@20: /* complete hour */ renatofilho@20: /* FIXME: UGLY WRONG HACK TO ALIGN PROGRAM TIME!!!*/ rosfran@244: if( last_time->tv_sec % 3600 != 0 ) { renatofilho@20: size -= PROGRAM_SEPARATION; renatofilho@20: } rosfran@244: if ( initial_time->tv_sec % 3600 != 0 ) { renatofilho@20: size -= PROGRAM_SEPARATION; renatofilho@20: } renatofilho@20: renatofilho@20: pixel_count += size + PROGRAM_SEPARATION; renatofilho@20: GtkWidget *event_box = create_event_box_lbl(content_name->str, renatofilho@20: size, &bg_color, renatofilho@20: &fg_color); renatofilho@20: gtk_widget_add_events(event_box, renatofilho@20: GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); renatofilho@20: renatofilho@20: /* create EpgGridItem */ rosfran@244: EpgGridItem *epg_grid_item = g_new0(EpgGridItem, 1); renatofilho@20: epg_grid_item->proginfo = proginfo; renatofilho@20: epg_grid_item->event_box = event_box; renatofilho@20: epg_grid_item->object = mmyth_epg_grid_widget; renatofilho@20: renatofilho@20: epg_grid_list = g_list_prepend(epg_grid_list, (gpointer) epg_grid_item); renatofilho@20: renatofilho@20: gtk_box_pack_start (GTK_BOX (epg_line_hbox), renatofilho@20: event_box, FALSE, FALSE, PROGRAM_SEPARATION); renatofilho@20: renatofilho@20: g_signal_connect (G_OBJECT (event_box), "button-press-event", renatofilho@20: G_CALLBACK (mmyth_epg_grid_widget_clicked), renatofilho@20: (gpointer*) epg_grid_list); renatofilho@20: } renatofilho@20: #if 0 renatofilho@20: printf("chaind = %d!!!!" chanid);fflush(stdout); renatofilho@20: #endif renatofilho@20: renatofilho@20: if(!epg_grid_list) { renatofilho@20: /* No programs for current channel */ renatofilho@20: /* FIXME: size HARDCODED */ renatofilho@20: GtkWidget *event_box = create_event_box_lbl("No program list available", renatofilho@20: PIXELS_HOUR * 3, &bg_color, renatofilho@20: &fg_color); renatofilho@20: gtk_widget_add_events(event_box, renatofilho@20: GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); renatofilho@20: renatofilho@20: /* create EpgGridItem */ rosfran@244: EpgGridItem *epg_grid_item = g_new0(EpgGridItem, 1); renatofilho@20: epg_grid_item->proginfo = NULL; renatofilho@20: epg_grid_item->event_box = event_box; renatofilho@20: epg_grid_item->object = mmyth_epg_grid_widget; renatofilho@20: renatofilho@20: epg_grid_list = g_list_prepend(epg_grid_list, (gpointer) epg_grid_item); renatofilho@20: renatofilho@20: gtk_box_pack_start (GTK_BOX (epg_line_hbox), renatofilho@20: event_box, FALSE, FALSE, PROGRAM_SEPARATION); renatofilho@20: renatofilho@20: g_signal_connect (G_OBJECT (event_box), "button-press-event", renatofilho@20: G_CALLBACK (mmyth_epg_grid_widget_clicked), renatofilho@20: (gpointer*) epg_grid_list); renatofilho@20: } renatofilho@20: renatofilho@20: epg_grid_list = g_list_reverse(epg_grid_list); renatofilho@20: mmyth_epg_grid_widget->epg_view_model = renatofilho@20: g_list_append(mmyth_epg_grid_widget->epg_view_model, epg_grid_list); renatofilho@20: renatofilho@20: gtk_box_pack_start (GTK_BOX (private->epg_programs_vbox), renatofilho@20: epg_line_hbox, FALSE, FALSE, 0); renatofilho@20: } renatofilho@20: } renatofilho@20: renatofilho@20: static void renatofilho@20: mmyth_epg_grid_widget_mount_header(MMythEpgGridWidget *mmyth_epg_grid_widget) renatofilho@20: { renatofilho@20: MMythEpgGridWidgetPrivate *private = renatofilho@20: MMYTH_EPG_GRID_WIDGET_GET_PRIVATE(mmyth_epg_grid_widget); renatofilho@20: renatofilho@20: struct tm hour_tm; renatofilho@20: const gchar name_title[] = "Today"; renatofilho@20: GtkWidget * lbl_title = gtk_label_new(name_title); renatofilho@20: renatofilho@20: gtk_misc_set_alignment (GTK_MISC(lbl_title), 0.0, 0.5); renatofilho@20: renatofilho@20: gtk_box_pack_start (GTK_BOX (private->epg_channels_vbox), renatofilho@20: lbl_title, FALSE, FALSE, 0); renatofilho@20: renatofilho@20: /* hours title line */ renatofilho@20: GtkWidget *epg_programs_hours_hbox = gtk_hbox_new (TRUE, 0); renatofilho@20: rosfran@244: if (localtime_r((time_t *)&private->current_start_time->tv_sec, &hour_tm) == NULL) { renatofilho@20: g_warning ("localtime_r error in mmyth_epg_grid_widget!\n"); rosfran@244: return; renatofilho@20: } renatofilho@20: renatofilho@20: if (hour_tm.tm_min>30) { renatofilho@20: hour_tm.tm_min = 30; renatofilho@20: } else if (hour_tm.tm_min>0) { renatofilho@20: hour_tm.tm_min = 0; renatofilho@20: } renatofilho@20: renatofilho@20: gchar hour1_str[10]; renatofilho@20: strftime(hour1_str, 8, "%H:%M", &hour_tm); renatofilho@20: GtkWidget * lbl_hour1 = gtk_label_new(hour1_str); renatofilho@20: gtk_misc_set_alignment (GTK_MISC(lbl_hour1), 0.0, 0.5); renatofilho@20: renatofilho@20: hour_tm.tm_hour++; renatofilho@20: gchar hour2_str[10]; renatofilho@20: strftime(hour2_str, 8, "%H:%M", &hour_tm); renatofilho@20: GtkWidget * lbl_hour2 = gtk_label_new(hour2_str); renatofilho@20: gtk_misc_set_alignment (GTK_MISC(lbl_hour2), 0.0, 0.5); renatofilho@20: renatofilho@20: hour_tm.tm_hour++; renatofilho@20: gchar hour3_str[10]; renatofilho@20: strftime(hour3_str, 8, "%H:%M", &hour_tm); renatofilho@20: GtkWidget * lbl_hour3 = gtk_label_new(hour3_str); renatofilho@20: gtk_misc_set_alignment (GTK_MISC(lbl_hour3), 0.0, 0.5); renatofilho@20: renatofilho@20: gtk_box_pack_start (GTK_BOX (epg_programs_hours_hbox), renatofilho@20: lbl_hour1, TRUE, TRUE, 0); renatofilho@20: gtk_box_pack_start (GTK_BOX (epg_programs_hours_hbox), renatofilho@20: lbl_hour2, TRUE, TRUE, 0); renatofilho@20: gtk_box_pack_start (GTK_BOX (epg_programs_hours_hbox), renatofilho@20: lbl_hour3, TRUE, TRUE, 0); renatofilho@20: renatofilho@20: gtk_box_pack_start (GTK_BOX (private->epg_programs_vbox), renatofilho@20: epg_programs_hours_hbox, FALSE, FALSE, 0); renatofilho@20: } renatofilho@20: renatofilho@20: /****************************************************************************** renatofilho@20: * INTERNAL CALLBACKS FOR STATE CHANGE * renatofilho@20: *****************************************************************************/ renatofilho@20: static void renatofilho@20: mmyth_epg_grid_widget_deselect_service(MMythEpgGridWidget *mmyth_epg_grid_widget) renatofilho@20: { renatofilho@20: EpgGridItem *epg_grid_item; renatofilho@20: renatofilho@20: /* deselect*/ renatofilho@20: if(mmyth_epg_grid_widget->selected_grid_item != NULL) { renatofilho@20: epg_grid_item = renatofilho@20: (EpgGridItem*) mmyth_epg_grid_widget->selected_grid_item->data; renatofilho@20: gtk_widget_set_state(GTK_WIDGET(epg_grid_item->event_box), GTK_STATE_NORMAL); renatofilho@20: } renatofilho@20: } renatofilho@20: renatofilho@20: static void renatofilho@20: mmyth_epg_grid_widget_clicked (GtkWidget* widget, renatofilho@20: GdkEventExpose *event, gpointer data) renatofilho@20: { renatofilho@20: g_return_if_fail(data != NULL); renatofilho@20: renatofilho@20: GList *epg_grid_item_list = (GList *) data; renatofilho@20: EpgGridItem *epg_grid_item = (EpgGridItem *) epg_grid_item_list->data; renatofilho@20: renatofilho@20: /* update the selected service */ renatofilho@20: mmyth_epg_grid_widget_update_service( epg_grid_item->object, (GList*) data ); renatofilho@20: } renatofilho@20: renatofilho@20: void renatofilho@20: mmyth_epg_grid_widget_update_service(MMythEpgGridWidget * object, renatofilho@20: GList *selected_grid_list) renatofilho@20: { renatofilho@20: g_return_if_fail(object != NULL); renatofilho@20: g_return_if_fail(selected_grid_list != NULL); renatofilho@20: renatofilho@20: EpgGridItem *epg_grid_item = (EpgGridItem *) selected_grid_list->data; renatofilho@20: renatofilho@20: mmyth_epg_grid_widget_deselect_service(epg_grid_item->object); renatofilho@20: renatofilho@20: /* updating current selected schedule_item and schedule_list*/ renatofilho@20: object->selected_grid_item = selected_grid_list; renatofilho@20: renatofilho@20: /* set state of the event box */ renatofilho@20: gtk_widget_set_state(GTK_WIDGET(epg_grid_item->event_box), GTK_STATE_SELECTED); renatofilho@20: /* emit update signal for listeners */ renatofilho@20: g_signal_emit(object, renatofilho@20: mmyth_epg_grid_widget_signals[SELECTION_UPDATED_SIGNAL], renatofilho@20: 0, renatofilho@20: (gpointer) epg_grid_item); renatofilho@20: } renatofilho@20: renatofilho@20: static GtkWidget * renatofilho@20: create_event_box_lbl(gchar *str, int width, const GdkColor *bg_color, renatofilho@20: const GdkColor *fg_color) renatofilho@20: { renatofilho@20: GtkWidget *event_box = gtk_event_box_new(); renatofilho@20: GtkWidget *lbl = gtk_label_new(str); renatofilho@20: gtk_label_set_ellipsize(GTK_LABEL(lbl), PANGO_ELLIPSIZE_END); renatofilho@20: renatofilho@20: gtk_widget_modify_bg(event_box, GTK_STATE_NORMAL, bg_color); renatofilho@20: gtk_widget_modify_fg(lbl, GTK_STATE_NORMAL, fg_color); renatofilho@20: renatofilho@20: /* selected colors are const*/ renatofilho@20: GdkColor selected_bg_color; renatofilho@20: selected_bg_color.red = 100; renatofilho@20: selected_bg_color.green = 40000; renatofilho@20: selected_bg_color.blue = 100; renatofilho@20: renatofilho@20: GdkColor selected_fg_color; renatofilho@20: selected_fg_color.red = 100; renatofilho@20: selected_fg_color.green = 100; renatofilho@20: selected_fg_color.blue = 100; renatofilho@20: renatofilho@20: gtk_widget_modify_bg(event_box, GTK_STATE_SELECTED, &selected_bg_color); renatofilho@20: gtk_widget_modify_fg(lbl, GTK_STATE_SELECTED, &selected_fg_color); renatofilho@20: renatofilho@20: gtk_misc_set_alignment (GTK_MISC(lbl), 0.0, 0.5); renatofilho@20: gtk_container_add (GTK_CONTAINER (event_box), renatofilho@20: lbl); renatofilho@20: gtk_widget_set_size_request(event_box, width, -1); renatofilho@20: renatofilho@20: return event_box; renatofilho@20: } renatofilho@20: renatofilho@20: /****************************************************************************** renatofilho@20: * METHODS * renatofilho@20: *****************************************************************************/ renatofilho@20: renatofilho@20: /* Callback for hardware keys */ renatofilho@20: gboolean renatofilho@20: mmyth_epg_grid_widget_key_press (MMythEpgGridWidget * object, renatofilho@20: GtkWidget * widget, GdkEventKey * event) renatofilho@20: { renatofilho@20: MMythEpgGridWidgetPrivate *private = renatofilho@20: MMYTH_EPG_GRID_WIDGET_GET_PRIVATE(object); renatofilho@20: renatofilho@20: EpgGridItem *epg_grid_item; renatofilho@20: GList *tmp; renatofilho@20: renatofilho@20: /* List of selected_grid_item */ renatofilho@20: GList *selected_view_model; renatofilho@20: renatofilho@20: gint channel_index; renatofilho@20: renatofilho@20: if(object->selected_grid_item == NULL) { renatofilho@20: g_warning ("No program selected"); renatofilho@20: return FALSE; renatofilho@20: } renatofilho@20: renatofilho@20: epg_grid_item = (EpgGridItem*) object->selected_grid_item->data; renatofilho@20: renatofilho@20: channel_index = private->selected_channel_index; renatofilho@20: renatofilho@20: switch (event->keyval) { renatofilho@20: case GDK_Up: renatofilho@20: selected_view_model = g_list_nth( object->epg_view_model, channel_index - 1 ); renatofilho@20: if(selected_view_model != NULL) { renatofilho@20: private->selected_channel_index = channel_index - 1; renatofilho@20: tmp = (GList *) selected_view_model->data; renatofilho@20: /* TODO: select a better centralized item renatofilho@20: currently is picking the 1st or last item */ renatofilho@20: if(g_list_next(object->selected_grid_item) == NULL && renatofilho@20: g_list_previous(object->selected_grid_item) != NULL) { renatofilho@20: /* in this case the new selected will be the last */ renatofilho@20: tmp = g_list_last(tmp); renatofilho@20: } renatofilho@20: renatofilho@20: /* update the selected service */ renatofilho@20: mmyth_epg_grid_widget_update_service( object, tmp ); renatofilho@20: } renatofilho@20: return TRUE; renatofilho@20: case GDK_Down: renatofilho@20: selected_view_model = g_list_nth( object->epg_view_model, channel_index + 1 ); renatofilho@20: if(selected_view_model != NULL) { renatofilho@20: private->selected_channel_index = channel_index + 1; renatofilho@20: tmp = (GList *) selected_view_model->data; renatofilho@20: /* TODO: select a better centralized item renatofilho@20: currently is picking the 1st or last item */ renatofilho@20: if(g_list_next(object->selected_grid_item) == NULL && renatofilho@20: g_list_previous(object->selected_grid_item) != NULL) { renatofilho@20: /* in this case the new selected will be the last */ renatofilho@20: tmp = g_list_last(tmp); renatofilho@20: } renatofilho@20: renatofilho@20: /* update the selected service */ renatofilho@20: mmyth_epg_grid_widget_update_service( object, tmp ); renatofilho@20: } renatofilho@20: return TRUE; renatofilho@20: case GDK_Left: renatofilho@20: tmp = g_list_previous( object->selected_grid_item ); renatofilho@20: if(tmp != NULL) { renatofilho@20: /* update the selected service */ renatofilho@20: mmyth_epg_grid_widget_update_service( object, tmp ); renatofilho@20: } renatofilho@20: return TRUE; renatofilho@20: case GDK_Right: renatofilho@20: tmp = g_list_next( object->selected_grid_item ); renatofilho@20: if(tmp != NULL) { renatofilho@20: /* update the selected service */ renatofilho@20: mmyth_epg_grid_widget_update_service( object, tmp ); renatofilho@20: } renatofilho@20: return TRUE; renatofilho@20: default: renatofilho@20: return TRUE; renatofilho@20: } renatofilho@20: renatofilho@20: return FALSE; renatofilho@20: } renatofilho@20: renatofilho@20: static void renatofilho@20: mmyth_epg_grid_widget_fill_programinfos (MMythEpgGridWidgetPrivate *private) renatofilho@20: { renatofilho@20: GList *channels_list = NULL; renatofilho@20: int y; renatofilho@20: renatofilho@20: if ((private->mmyth_epg != NULL) && renatofilho@20: (gmyth_epg_get_channel_list (private->mmyth_epg, &channels_list) < 0 )) { renatofilho@20: private->channel_list = NULL; renatofilho@20: return; renatofilho@20: } renatofilho@20: renatofilho@20: private->channel_list = channels_list; renatofilho@20: renatofilho@20: for (y = 0; y < private->DISPLAY_CHANS && channels_list; y++) { renatofilho@20: GMythChannelInfo *channel_info = (GMythChannelInfo *) channels_list->data; renatofilho@20: renatofilho@20: mmyth_epg_grid_widget_fill_program_row_infos( renatofilho@20: private, channel_info->channel_ID, y); renatofilho@20: renatofilho@20: channels_list = g_list_next (channels_list); renatofilho@20: } renatofilho@20: } renatofilho@20: renatofilho@20: static void renatofilho@20: mmyth_epg_grid_widget_fill_program_row_infos(MMythEpgGridWidgetPrivate *private, renatofilho@20: guint chanNum, guint row) renatofilho@20: { renatofilho@20: gint res = gmyth_epg_get_program_list (private->mmyth_epg, renatofilho@20: &(private->program_list[row]), renatofilho@20: chanNum, private->current_start_time, renatofilho@20: private->current_end_time); renatofilho@20: renatofilho@20: if (res < 0) { renatofilho@20: g_warning ("[%s] Error while retrieving epg programs", __FUNCTION__); renatofilho@20: } renatofilho@20: } renatofilho@20: