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