/* clist.c - Created by Giampiero Caprino $Id: clist.c,v 1.2 2004/03/11 05:31:15 claude Exp $ This file is part of Train Director Train Director is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. Train Director is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Train Director; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include "html.h" #include "gtkopen.h" #include "trsim.h" void wcreate_list(void); Track **get_station_list(void); extern Train *schedule; struct asgn_s { GtkWidget *window; GtkCList *clist; int assigned_row; } asgn_struct; static gboolean train_dialogue_close(GtkWidget *widget); static gchar *en_titles[] = { "Arrival", "From", "To", "Arrival", "Train", "Speed", "Min.Del.", "Min.Late", "Status", NULL }; static gchar *titles[sizeof(en_titles)/sizeof(char *)]; extern gchar *station_titles[]; extern char *station_schedule_cur; int schedule_widths[] = { 50, 50, 50, 50, 50, 50, 60, 60, 200, 0 }; struct clist schedule_info; GtkCList *schedule_list; int selected_row; int assigned_row; Train *oldtrain; GtkCList *station_schedule_list; gchar *paths_titles[] = { "From", "To", "Entry/exit", "Times", NULL }; GtkWidget *hbox_new(GtkWidget *parent) { GtkWidget *hbox = gtk_hbox_new(FALSE, 5); gtk_container_set_border_width(GTK_CONTAINER(hbox), 5); gtk_box_pack_start(GTK_BOX(parent), hbox, FALSE, FALSE, 0); gtk_widget_show(hbox); return hbox; } void label_combo(GtkWidget *hbox, char *txt, GtkWidget *list) { GtkWidget *lbl; lbl = gtk_label_new(txt); gtk_box_pack_start(GTK_BOX(hbox), lbl, FALSE, FALSE, 0); gtk_widget_show(lbl); gtk_box_pack_start(GTK_BOX(hbox), list, FALSE, FALSE, 0); } void append_button(GtkWidget *hbox, char *txt, void (*cb)(), void *window) { GtkWidget *lbl; lbl = gtk_button_new_with_label(L(txt)); gtk_box_pack_start(GTK_BOX(hbox), lbl, FALSE, FALSE, 0); if(cb) gtk_signal_connect_object(GTK_OBJECT(lbl), "clicked", GTK_SIGNAL_FUNC(cb), window); gtk_widget_show(lbl); } static gboolean cmw_destroy_cb(GtkWidget *widget) { /* This is needed to get out of gtk_main */ gtk_main_quit(); return FALSE; } static void button_save_clicked(gpointer data) { save_schedule_status(); } static void station_list_destroy(GtkWidget *w) { gtk_widget_destroy(w); station_schedule_list = 0; } static void fill_station_schedule(GtkCList *clist, char *station) { /* Here we do the actual adding of the text. It's done once for * each row. */ int i; Track *t; struct station_sched *sc; char buffs[5][60]; char *cols[5]; gtk_clist_clear(clist); gtk_clist_freeze(clist); station_schedule_cur = station; build_station_schedule(station); cols[0] = buffs[0]; cols[1] = buffs[1]; cols[2] = buffs[2]; cols[3] = buffs[3]; cols[4] = buffs[4]; i = 0; for(sc = stat_sched; sc; sc = sc->next) { /* when reassigning train stock, we consider only trains that are scheduled to depart at the same station where the assignee has arrived. */ strcpy(cols[0], sc->tr->name); if(sc->arrival != -1) { strcpy(cols[1], format_time(sc->arrival)); strcpy(cols[2], sc->tr->entrance); } else *cols[1] = *cols[2] = 0; if(sc->departure != -1) { strcpy(cols[3], format_time(sc->departure)); strcpy(cols[4], sc->tr->exit); } else *cols[3] = *cols[4] = 0; gtk_clist_append(clist, cols); } gtk_clist_thaw(clist); } static gboolean station_select_cb(GtkWidget *widget, void *data) { GtkCList *clist; clist = station_schedule_list; if(!clist) return 0; fill_station_schedule(clist, data); return 0; } static GtkWidget *build_station_menu(Track **stlist, void (*cb)()) { GtkWidget *omenu; GtkWidget *menu; GtkWidget *menu_item; GSList *group; gint i; char buff[256]; char *p; omenu = gtk_option_menu_new(); menu = gtk_menu_new(); group = NULL; for(i = 0; stlist[i]; i++) { strcpy(buff, stlist[i]->station); if((p = strchr(buff, '@'))) *p = 0; menu_item = gtk_radio_menu_item_new_with_label(group, buff); if(cb) gtk_signal_connect(GTK_OBJECT(menu_item), "activate", (GtkSignalFunc)cb, stlist[i]->station); group = gtk_radio_menu_item_group(GTK_RADIO_MENU_ITEM(menu_item)); gtk_menu_append(GTK_MENU(menu), menu_item); gtk_widget_show(menu_item); } gtk_option_menu_set_menu(GTK_OPTION_MENU(omenu), menu); gtk_option_menu_set_history(GTK_OPTION_MENU(omenu), 0); return omenu; } void station_list_print(GtkWidget *w) { do_station_list_print(); } /* * * PERFORMANCE WINDOW * * */ void performance_window(void) { GtkWidget *window, *scrolled_window; GtkWidget *text; GdkFont *font; Train *tr; GtkWidget *box1, *box2, *hbox; GtkWidget *saveb; char buff[512]; window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_widget_set_name(window, "text window"); gtk_widget_set_usize(window, 700, 300); gtk_window_set_policy(GTK_WINDOW(window), TRUE, TRUE, FALSE); gtk_window_set_title(GTK_WINDOW(window), L("Performance Statistics")); gtk_container_set_border_width(GTK_CONTAINER(window), 0); box1 = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(window), box1); gtk_widget_show(box1); box2 = gtk_vbox_new(FALSE, 10); gtk_container_set_border_width(GTK_CONTAINER(box2), 10); gtk_box_pack_start(GTK_BOX(box1), box2, TRUE, TRUE, 0); gtk_widget_show(box2); scrolled_window = gtk_scrolled_window_new(NULL, NULL); gtk_box_pack_start(GTK_BOX(box2), scrolled_window, TRUE, TRUE, 0); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); gtk_widget_show(scrolled_window); text = gtk_text_new(NULL, NULL); gtk_text_set_editable(GTK_TEXT(text), FALSE); gtk_text_set_word_wrap(GTK_TEXT(text), FALSE); gtk_container_add(GTK_CONTAINER(scrolled_window), text); gtk_widget_show(text); gtk_text_freeze(GTK_TEXT(text)); font = gdk_font_load("-adobe-courier-medium-r-normal--*-120-*-*-*-*-*-*"); for(tr = schedule; tr; tr = tr->next) { format_schedule(tr, buff); gtk_text_insert(GTK_TEXT(text), font, NULL, NULL, buff, -1); } gdk_font_unref(font); gtk_text_thaw(GTK_TEXT(text)); hbox = gtk_hbutton_box_new(); gtk_box_pack_start(GTK_BOX(box2), hbox, FALSE, FALSE, 0); gtk_widget_show(hbox); saveb = gtk_button_new_with_label(L("Save")); gtk_signal_connect(GTK_OBJECT(saveb), "clicked", GTK_SIGNAL_FUNC(button_save_clicked), NULL); gtk_box_pack_start(GTK_BOX(hbox), saveb, TRUE, TRUE, 0); gtk_widget_show(saveb); gtk_widget_show(window); } static GtkStyle *get_style(GtkCList *lst, int r, int g, int b, int bg) { GtkStyle *style; GdkColor col1; GdkColor col2; col1.red = r; col1.green = g; col1.blue = b; col2.red = 56000 - r; col2.green = 56000 - g; col2.blue = 56000 - b; style = gtk_style_copy(GTK_WIDGET(lst)->style); if(bg) { style->base[GTK_STATE_NORMAL] = col1; style->base[GTK_STATE_SELECTED] = col2; } else { style->fg[GTK_STATE_NORMAL] = col1; style->fg[GTK_STATE_SELECTED] = col2; } return style; } void set_schedule_style(GtkCList *list, int row, Train *t) { static GtkStyle *ready = NULL; static GtkStyle *running = NULL; static GtkStyle *arrived = NULL; GtkStyle *style; if(!ready) { ready = get_style(list, 0, 0, 56000, 0); running = get_style(list, 0, 0, 0, 0); arrived = get_style(list, 0, 56000, 0, 0); #if 0 gdk_font_unref(arrived->font); arrived->font = gdk_font_load("-*-courier-medium-*-*-*-*-120-*-*-*-*-*-*"); #endif } switch(t->status) { case train_READY: style = ready; if(t->days && run_day && !(t->days & run_day)) style = arrived; break; case train_ARRIVED: case train_DERAILED: style = arrived; break; default: style = running; } gtk_clist_set_row_style(list, row, style); /* was: gtk_clist_set_cell_style(list, row, 8, style); */ } void gr_update_schedule(Train *t, int i) { GtkCList *clist; /*clist = asgn_struct.clist; if(!clist)*/ clist = schedule_list; if(!clist) return; gtk_clist_set_text(clist, i, 5, current_speed); gtk_clist_set_text(clist, i, 6, current_delay); gtk_clist_set_text(clist, i, 7, current_late); gtk_clist_set_text(clist, i, 8, current_status); set_schedule_style(clist, i, t); } char *schedule_value(int row, int col, void *ptr) { Train *t; for(t = schedule; t && row > 0; --row, t = t->next); if(!t) return(""); /* when reassigning train stock, we consider only trains that are scheduled to depart at the same station where the assignee has arrived. */ /* if(assign && (t->status != train_READY || strcmp(oldtrain->position->station, t->entrance))) return("");*/ if(!t->entrance) return(""); print_train_info(t); return(disp_columns[col]); } void fill_schedule(Train *t, int assign) { /* Here we do the actual adding of the text. It's done once for * each row. */ int i; GtkCList *clist; if(assign) clist = asgn_struct.clist; else clist = schedule_list; if(!clist) return; gtk_clist_clear(clist); gtk_clist_freeze(clist); i = 0; for(; t; t = t->next) { /* when reassigning train stock, we consider only trains that are scheduled to depart at the same station where the assignee has arrived. */ if(assign && (t->status != train_READY || !sameStation(oldtrain->position->station, t->entrance))) continue; if(!t->entrance) continue; print_train_info(t); gtk_clist_append(clist, disp_columns); set_schedule_style(clist, i, t); ++i; } gtk_clist_thaw(clist); } /* The user clicked the "Hide/Show titles" button. */ void button_hide_show_clicked( gpointer data ) { /* Just a flag to remember the status. 0 = currently visible */ static short int flag = 0; if(flag == 0) { /* Hide the titles and set the flag to 1 */ gtk_clist_column_titles_hide((GtkCList *) data); flag++; } else { /* Show the titles and reset flag to 0 */ gtk_clist_column_titles_show((GtkCList *) data); flag--; } } /* The user clicked the "Hide/Show titles" button. */ void button_prop_clicked( gpointer data ) { gchar *p; Train *t; if(selected_row == -1) return; gtk_clist_get_text(GTK_CLIST(data), selected_row, 4, &p); if(!p || !(t = findTrainNamed(p))) return; train_info_dialog(t); } /* The user clicked the "Hide/Show titles" button. */ void button_close_clicked( gpointer data ) { gtk_widget_destroy((GtkWidget *)data); schedule_list = 0; } /* The user clicked the "Hide/Show titles" button. */ void button_assign_clicked( gpointer data ) { gchar *p; Train *t; struct asgn_s *sp = (struct asgn_s *)data; if(selected_row == -1) return; gtk_clist_get_text(GTK_CLIST(sp->clist), selected_row, 4, &p); if(!p || !(t = findTrainNamed(p))) return; sp->assigned_row = selected_row; assign_train(t, oldtrain); gtk_widget_destroy((GtkWidget *)sp->window); } /* The user clicked the "Hide/Show titles" button. */ void button_shunt_clicked( gpointer data ) { struct asgn_s *sp = (struct asgn_s *)data; char buff[40]; sprintf(buff, "shunt %s", oldtrain->name); trainsim_cmd(buff); gtk_widget_destroy((GtkWidget *)sp->window); } /* If we come here, then the user has selected a row in the list. */ void selection_made(GtkWidget *clist, gint row, gint column, GdkEventButton *event, gpointer data) { selected_row = row; } int create_schedule(int assign) { #if 01 GtkWidget *window; GtkWidget *vbox, *hbox; GtkWidget *scrolled_window, *clist; GtkWidget *button_add, *button_prop, *button_hide_show; GtkWidget *button_save; GtkWidget *button_print = 0; GtkWidget *button_shunt = 0; int i; if(assign) memset(&asgn_struct, 0, sizeof(asgn_struct)); else if(schedule_list) /* no reentrancy */ return 0; window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_widget_set_usize(GTK_WIDGET(window), 832, 200); if(assign) gtk_window_set_modal(GTK_WINDOW(window),TRUE); gtk_window_set_title(GTK_WINDOW(window), assign ? L("Departing trains") : L("Train Schedule")); gtk_signal_connect(GTK_OBJECT(window), "destroy", GTK_SIGNAL_FUNC(button_close_clicked), NULL); hbox = gtk_hbox_new(FALSE, 5); gtk_container_set_border_width(GTK_CONTAINER(hbox), 5); gtk_container_add(GTK_CONTAINER(window), hbox); gtk_widget_show(hbox); /* Create a scrolled window to pack the CList widget into */ scrolled_window = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); gtk_box_pack_start(GTK_BOX(hbox), scrolled_window, TRUE, TRUE, 0); gtk_widget_show(scrolled_window); for(i = 0; en_titles[i]; ++i) titles[i] = L(en_titles[i]); titles[i] = 0; clist = gtk_clist_new_with_titles(9, titles); if(!assign) schedule_list = (GtkCList *)clist; /* When a selection is made, we want to know about it. The callback * used is selection_made, and its code can be found further down */ gtk_signal_connect(GTK_OBJECT(clist), "select_row", GTK_SIGNAL_FUNC(selection_made), NULL); /* It isn't necessary to shadow the border, but it looks nice :) */ gtk_clist_set_shadow_type(GTK_CLIST(clist), GTK_SHADOW_OUT); /* What however is important, is that we set the column widths as * they will never be right otherwise. Note that the columns are * numbered from 0 and up (to 1 in this case). */ gtk_clist_set_column_width(GTK_CLIST(clist), 0, 50); gtk_clist_set_column_width(GTK_CLIST(clist), 1, 50); gtk_clist_set_column_width(GTK_CLIST(clist), 2, 50); gtk_clist_set_column_width(GTK_CLIST(clist), 3, 50); gtk_clist_set_column_width(GTK_CLIST(clist), 4, 50); gtk_clist_set_column_width(GTK_CLIST(clist), 5, 50); gtk_clist_set_column_width(GTK_CLIST(clist), 6, 60); gtk_clist_set_column_width(GTK_CLIST(clist), 7, 60); gtk_clist_set_column_width(GTK_CLIST(clist), 8, 200); /* Add the CList widget to the vertical box and show it. */ gtk_container_add(GTK_CONTAINER(scrolled_window), clist); gtk_widget_show(clist); /* Create the buttons and add them to the window. See the button * tutorial for more examples and comments on this. */ vbox = gtk_vbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, TRUE, 0); gtk_widget_show(vbox); if(!assign) { button_add = gtk_button_new_with_label(L("Close")); button_save = gtk_button_new_with_label(L("Stats")); button_print = gtk_button_new_with_label(L("Print...")); } else { button_add = gtk_button_new_with_label(L("Assign")); button_shunt = gtk_button_new_with_label(L("Shunt")); button_save = gtk_button_new_with_label(L("Cancel")); } button_prop = gtk_button_new_with_label(L("Properties")); button_hide_show = gtk_button_new_with_label(L("Hide/Show titles")); gtk_box_pack_start(GTK_BOX(vbox), button_add, TRUE, FALSE, 0); if(button_shunt) gtk_box_pack_start(GTK_BOX(vbox), button_shunt, TRUE, FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), button_save, TRUE, FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), button_prop, TRUE, FALSE, 0); if(button_print) gtk_box_pack_start(GTK_BOX(vbox), button_print, TRUE, FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), button_hide_show, TRUE, FALSE, 0); /* Connect our callbacks to the three buttons */ if(!assign) { gtk_signal_connect_object(GTK_OBJECT(button_add), "clicked", GTK_SIGNAL_FUNC(button_close_clicked), (gpointer) window); gtk_signal_connect_object(GTK_OBJECT(button_save), "clicked", GTK_SIGNAL_FUNC(performance_window), (gpointer) window); gtk_signal_connect(GTK_OBJECT(button_print), "clicked", GTK_SIGNAL_FUNC(button_save_clicked), (gpointer) window); } else { asgn_struct.window = window; asgn_struct.clist = (GtkCList *)clist; asgn_struct.assigned_row = -1; gtk_signal_connect_object(GTK_OBJECT(button_add), "clicked", GTK_SIGNAL_FUNC(button_assign_clicked), (gpointer) &asgn_struct); gtk_signal_connect_object(GTK_OBJECT(button_shunt), "clicked", GTK_SIGNAL_FUNC(button_shunt_clicked), (gpointer) &asgn_struct); gtk_signal_connect_object(GTK_OBJECT(button_save), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), (gpointer) window); gtk_signal_connect(GTK_OBJECT(window), "destroy", GTK_SIGNAL_FUNC(cmw_destroy_cb),NULL); } gtk_signal_connect_object(GTK_OBJECT(button_prop), "clicked", GTK_SIGNAL_FUNC(button_prop_clicked), (gpointer) clist); gtk_signal_connect_object(GTK_OBJECT(button_hide_show), "clicked", GTK_SIGNAL_FUNC(button_hide_show_clicked), (gpointer) clist); gtk_widget_show(button_add); gtk_widget_show(button_save); gtk_widget_show(button_prop); gtk_widget_show(button_hide_show); if(button_shunt) gtk_widget_show(button_shunt); if(button_print) gtk_widget_show(button_print); /* The interface is completely set up so we show the window and * enter the gtk_main loop. */ fill_schedule(schedule, assign); selected_row = -1; gtk_widget_show_all(window); #else schedule_info.title = L("Train Schedule"); schedule_info.headers = titles; schedule_info.col_string = schedule_value; schedule_info.col_width = schedule_widths; wcreate_list(&schedule_info); #endif return(0); } /* * * STATION SCHEDULE DIALOG * * */ int gtk_station_sched_dialog(char *station) { GtkWidget *window; GtkWidget *lbl; GtkWidget *vbox, *hbox; GtkWidget *scrolled_window, *clist; GtkWidget *button_add, *button_prop, *button_hide_show; GtkWidget *button_save; GtkWidget *button_shunt = 0; Track **stlist; int i; if(station_schedule_list) /* no reentrancy */ return 0; stlist = get_station_list(); if(!stlist) { do_alert(L("No stations in this layout!")); return 0; } window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_widget_set_usize(GTK_WIDGET(window), 480, 260); gtk_window_set_title(GTK_WINDOW(window), L("Station Schedule")); gtk_signal_connect(GTK_OBJECT(window), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroy), NULL); vbox = gtk_vbox_new(FALSE, 5); gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); gtk_container_add(GTK_CONTAINER(window), vbox); gtk_widget_show(vbox); hbox = hbox_new(vbox); label_combo(hbox, L("Station :"), build_station_menu(stlist, (void *)station_select_cb)); /*lbl = gtk_button_new_with_label("Print"); gtk_box_pack_start(GTK_BOX(hbox), lbl, FALSE, FALSE, 0); gtk_widget_show(lbl);*/ append_button(hbox, L("Print..."), station_list_print, window); append_button(hbox, L("Close"), station_list_destroy, window); lbl = gtk_hseparator_new(); gtk_box_pack_start(GTK_BOX(vbox), lbl, FALSE, FALSE, 0); gtk_widget_show(lbl); hbox = gtk_hbox_new(FALSE, 5); gtk_container_set_border_width(GTK_CONTAINER(hbox), 5); gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0); gtk_widget_show(hbox); /* Create a scrolled window to pack the CList widget into */ scrolled_window = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); gtk_box_pack_start(GTK_BOX(hbox), scrolled_window, TRUE, TRUE, 0); gtk_widget_show(scrolled_window); clist = gtk_clist_new_with_titles(5, station_titles); /* It isn't necessary to shadow the border, but it looks nice :) */ gtk_clist_set_shadow_type(GTK_CLIST(clist), GTK_SHADOW_OUT); /* What however is important, is that we set the column widths as * they will never be right otherwise. Note that the columns are * numbered from 0 and up (to 1 in this case). */ gtk_clist_set_column_width(GTK_CLIST(clist), 0, 80); gtk_clist_set_column_width(GTK_CLIST(clist), 1, 80); gtk_clist_set_column_width(GTK_CLIST(clist), 2, 80); gtk_clist_set_column_width(GTK_CLIST(clist), 3, 80); gtk_clist_set_column_width(GTK_CLIST(clist), 4, 80); /* Add the CList widget to the vertical box and show it. */ gtk_container_add(GTK_CONTAINER(scrolled_window), clist); station_schedule_list = GTK_CLIST(clist); if(!station) station_select_cb(clist, stlist[0]->station); else for(i = 0; stlist[i]; ++i) if(sameStation(stlist[i]->station, station)) { station_select_cb(clist, stlist[i]->station); break; } gtk_widget_show(clist); gtk_widget_show_all(window); free(stlist); return(0); } /* * * PATHS DIALOG * * */ struct w_path { char **stlist; Track **entrylist; GtkWidget *from; GtkWidget *to; GtkWidget *point; GtkWidget *times; } wpath; void format_ptimes(char *dst, Path *path) { sprintf(dst, "%d/%d/%d/%d", path->times[0]/60, path->times[1]/60, path->times[2]/60, path->times[3]/60); } void path_selected(GtkWidget *clist, gint row, gint column, GdkEventButton *event, gpointer data) { Path *path; int i; char buff[64]; selected_row = row; path = paths; while(path && row-- > 0) path = path->next; if(!path) return; format_ptimes(buff, path); gtk_entry_set_text(GTK_ENTRY(wpath.times), buff); for(i = 0; wpath.entrylist[i]; ++i) { if(!strcmp(path->enter, wpath.entrylist[i]->station)) { gtk_option_menu_set_history(GTK_OPTION_MENU(wpath.point), i); break; } } for(i = 0; wpath.stlist[i]; ++i) { if(!strcmp(path->from, wpath.stlist[i])) { gtk_option_menu_set_history(GTK_OPTION_MENU(wpath.from), i); break; } } for(i = 0; wpath.stlist[i]; ++i) { if(!strcmp(path->to, wpath.stlist[i])) { gtk_option_menu_set_history(GTK_OPTION_MENU(wpath.to), i); break; } } } static GtkWidget *build_names_menu(char **stlist) { GtkWidget *omenu; GtkWidget *menu; GtkWidget *menu_item; GSList *group; gint i; omenu = gtk_option_menu_new(); menu = gtk_menu_new(); group = NULL; for(i = 0; stlist[i]; i++) { menu_item = gtk_radio_menu_item_new_with_label(group, stlist[i]); group = gtk_radio_menu_item_group(GTK_RADIO_MENU_ITEM(menu_item)); gtk_menu_append(GTK_MENU(menu), menu_item); gtk_widget_show(menu_item); } gtk_option_menu_set_menu(GTK_OPTION_MENU(omenu), menu); gtk_option_menu_set_history(GTK_OPTION_MENU(omenu), 0); return omenu; } int create_path_window(void) { #if 01 GtkWidget *window; GtkWidget *lbl; GtkWidget *vbox, *hbox; GtkWidget *scrolled_window, *clist; GtkWidget *button_add, *button_prop, *button_hide_show; GtkWidget *button_save; GtkWidget *button_shunt = 0; Track **stlist; Path *pt; int i; char *cols[4]; char buff[64]; if(station_schedule_list) /* no reentrancy */ return 0; stlist = get_station_list(); if(!stlist) { do_alert("No stations in this layout!"); return 0; } window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_widget_set_usize(GTK_WIDGET(window), 480, 260); gtk_window_set_title(GTK_WINDOW(window), "Path Editor"); gtk_signal_connect(GTK_OBJECT(window), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroy), NULL); vbox = gtk_vbox_new(FALSE, 5); gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); gtk_container_add(GTK_CONTAINER(window), vbox); gtk_widget_show(vbox); hbox = hbox_new(vbox); wpath.stlist = get_all_station_list(); wpath.entrylist = get_entry_list(); wpath.from = build_names_menu(wpath.stlist); wpath.to = build_names_menu(wpath.stlist); wpath.point = build_station_menu(wpath.entrylist, NULL); label_combo(hbox, " From : ", wpath.from); label_combo(hbox, " To : ", wpath.to); hbox = hbox_new(vbox); label_combo(hbox, "Entry/exit : ", wpath.point); lbl = gtk_label_new("Times : "); gtk_box_pack_start(GTK_BOX(hbox), lbl, FALSE, FALSE, 0); gtk_widget_show(lbl); wpath.times = gtk_entry_new(); gtk_box_pack_start(GTK_BOX(hbox), wpath.times, FALSE, FALSE, 0); gtk_widget_show(lbl); hbox = hbox_new(vbox); append_button(hbox, "Apply", NULL, window); append_button(hbox, "Save", NULL, window); append_button(hbox, "Cancel", NULL, window); append_button(hbox, "Close", station_list_destroy, window); lbl = gtk_hseparator_new(); gtk_box_pack_start(GTK_BOX(vbox), lbl, FALSE, FALSE, 0); gtk_widget_show(lbl); hbox = gtk_hbox_new(FALSE, 5); gtk_container_set_border_width(GTK_CONTAINER(hbox), 5); gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0); gtk_widget_show(hbox); /* Create a scrolled window to pack the CList widget into */ scrolled_window = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); gtk_box_pack_start(GTK_BOX(hbox), scrolled_window, TRUE, TRUE, 0); gtk_widget_show(scrolled_window); clist = gtk_clist_new_with_titles(4, paths_titles); gtk_signal_connect(GTK_OBJECT(clist), "select_row", GTK_SIGNAL_FUNC(path_selected), NULL); /* It isn't necessary to shadow the border, but it looks nice :) */ gtk_clist_set_shadow_type(GTK_CLIST(clist), GTK_SHADOW_OUT); /* What however is important, is that we set the column widths as * they will never be right otherwise. Note that the columns are * numbered from 0 and up (to 1 in this case). */ gtk_clist_set_column_width(GTK_CLIST(clist), 0, 80); gtk_clist_set_column_width(GTK_CLIST(clist), 1, 80); gtk_clist_set_column_width(GTK_CLIST(clist), 2, 80); gtk_clist_set_column_width(GTK_CLIST(clist), 3, 80); /* Add the CList widget to the vertical box and show it. */ gtk_container_add(GTK_CONTAINER(scrolled_window), clist); /*station_schedule_list = clist; station_select_cb(clist, stlist[0]->station);*/ for(i = 0, pt = paths; pt; ++i, pt = pt->next) { format_ptimes(buff, pt); cols[0] = pt->from; cols[1] = pt->to; cols[2] = pt->enter; cols[3] = buff; gtk_clist_append(GTK_CLIST(clist), cols); } gtk_widget_show(clist); gtk_widget_show_all(window); free(stlist); #else schedule_info.title = "Train schedule"; schedule_info.headers = titles; schedule_info.col_string = schedule_value; schedule_info.col_width = schedule_widths; wcreate_list(&schedule_info); #endif return(0); } /* * * TRAIN PROPERTIES DIALOG * * */ #define MAXSTAT 13 static struct trn_vars { Train *trn; GtkWidget *name; GtkWidget *type; GtkWidget *entrance; GtkWidget *timein; GtkWidget *exit; GtkWidget *timeout; GtkWidget *waitfor; GtkWidget *stock; GtkWidget *station_name[MAXSTAT]; GtkWidget *arrival[MAXSTAT]; GtkWidget *departure[MAXSTAT]; GtkWidget *minstop[MAXSTAT]; } tvars; static int closed_ok; static gboolean train_dialogue_close(GtkWidget *widget) { char *p; Train *t; TrainStop *ts; int i; t = tvars.trn; if(t->name) free(t->name); p = gtk_entry_get_text(GTK_ENTRY(tvars.name)); if(!p) return FALSE; t->name = strdup(p); p = gtk_entry_get_text(GTK_ENTRY(tvars.type)); if(atoi(p) - 1 < 4) t->type = atoi(p) - 1; p = gtk_entry_get_text(GTK_ENTRY(tvars.entrance)); t->entrance = strdup(p); p = gtk_entry_get_text(GTK_ENTRY(tvars.timein)); t->timein = parse_time(&p); p = gtk_entry_get_text(GTK_ENTRY(tvars.exit)); t->exit = strdup(p); p = gtk_entry_get_text(GTK_ENTRY(tvars.timeout)); t->timeout = parse_time(&p); p = gtk_entry_get_text(GTK_ENTRY(tvars.waitfor)); if(p) while(*p == ' ') ++p; if(t->waitfor) free(t->waitfor); t->waitfor = (p && *p) ? strdup(p) : 0; p = gtk_entry_get_text(GTK_ENTRY(tvars.stock)); if(p) while(*p == ' ') ++p; if(t->stock) free(t->stock); t->stock = (p && *p) ? strdup(p) : 0; while((ts = t->stops)) { if(ts->station) free(ts->station); t->stops = ts->next; free(ts); } t->laststop = 0; for(i = 0; i < MAXSTAT; ++i) { p = gtk_entry_get_text(GTK_ENTRY(tvars.station_name[i])); if(!p || !*p) continue; ts = (TrainStop *)malloc(sizeof(TrainStop)); memset(ts, 0, sizeof(TrainStop)); if(!t->stops) t->stops = ts; else t->laststop->next = ts; t->laststop = ts; ts->station = strdup(p); p = gtk_entry_get_text(GTK_ENTRY(tvars.arrival[i])); ts->arrival = parse_time(&p); p = gtk_entry_get_text(GTK_ENTRY(tvars.departure[i])); ts->departure = parse_time(&p); p = gtk_entry_get_text(GTK_ENTRY(tvars.minstop[i])); ts->minstop = atol(p); } /* This is needed to get out of gtk_main */ gtk_widget_destroy(widget); closed_ok = 1; return FALSE; } static gboolean train_dialogue_print(GtkWidget *widget) { train_print(tvars.trn); return FALSE; } void gtk_train_info_dialog(Train *t) { GtkWidget *window = NULL; GtkWidget *box1,*box2; GtkWidget *frame1; GtkWidget *btnColor,*btnFile,*btnClose; GtkWidget *child; TrainStop *ts, *ts1; int i; char *p; char buff[256]; closed_ok = 0; tvars.trn = t; /* Create modal window (Here you can use any window descendent )*/ window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), L("Train Properties")); /* Set window as modal */ /* gtk_window_set_modal(GTK_WINDOW(window),TRUE); */ /* Create widgets */ box1 = gtk_vbox_new(FALSE, 5); gtk_container_add(GTK_CONTAINER(window), box1); box2 = gtk_table_new(5, 3, FALSE); gtk_table_set_row_spacings(GTK_TABLE(box2), 20); gtk_box_pack_start(GTK_BOX(box1), box2, FALSE, FALSE, 0); child = gtk_label_new(L("Train name")); gtk_misc_set_alignment(GTK_MISC (child), 0.0, 0.5); gtk_table_attach_defaults(GTK_TABLE(box2), child, 0, 1, 0, 2); child = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(child), t->name ? t->name : ""); gtk_table_attach_defaults(GTK_TABLE(box2), child, 1, 2, 0, 2); tvars.name = child; child = gtk_label_new(L("Train type")); gtk_misc_set_alignment(GTK_MISC (child), 0.0, 0.5); gtk_table_attach_defaults(GTK_TABLE(box2), child, 2, 3, 0, 2); child = gtk_entry_new(); sprintf(buff, "%d", t->type + 1); gtk_entry_set_text(GTK_ENTRY(child), buff); gtk_table_attach_defaults(GTK_TABLE(box2), child, 3, 4, 0, 2); tvars.type = child; child = gtk_label_new(L("Entry point")); gtk_misc_set_alignment(GTK_MISC (child), 0.0, 0.5); gtk_table_attach_defaults(GTK_TABLE(box2), child, 0, 1, 1, 3); child = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(child), t->entrance ? t->entrance : ""); gtk_table_attach_defaults(GTK_TABLE(box2), child, 1, 2, 1, 3); tvars.entrance = child; child = gtk_label_new(L("Entry time (hh:mm)")); gtk_misc_set_alignment(GTK_MISC (child), 0.0, 0.5); gtk_table_attach_defaults(GTK_TABLE(box2), child, 2, 3, 1, 3); child = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(child), format_time(t->timein)); gtk_table_attach_defaults(GTK_TABLE(box2), child, 3, 4, 1, 3); tvars.timein = child; child = gtk_label_new(L("Exit point")); gtk_misc_set_alignment(GTK_MISC (child), 0.0, 0.5); gtk_table_attach_defaults(GTK_TABLE(box2), child, 0, 1, 2, 4); child = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(child), t->exit ? t->exit : ""); gtk_table_attach_defaults(GTK_TABLE(box2), child, 1, 2, 2, 4); tvars.exit = child; child = gtk_label_new(L("Exit time (hh:mm)")); gtk_misc_set_alignment(GTK_MISC (child), 0.0, 0.5); gtk_table_attach_defaults(GTK_TABLE(box2), child, 2, 3, 2, 4); child = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(child), format_time(t->timeout)); gtk_table_attach_defaults(GTK_TABLE(box2), child, 3, 4, 2, 4); tvars.timeout = child; child = gtk_label_new(L("Wait arrival of train")); gtk_misc_set_alignment(GTK_MISC (child), 0.0, 0.5); gtk_table_attach_defaults(GTK_TABLE(box2), child, 0, 1, 3, 5); child = gtk_entry_new(); if(t->waitfor) gtk_entry_set_text(GTK_ENTRY(child), t->waitfor); gtk_table_attach_defaults(GTK_TABLE(box2), child, 1, 2, 3, 5); tvars.waitfor = child; child = gtk_label_new(L("Stock for train")); gtk_misc_set_alignment(GTK_MISC (child), 0.0, 0.5); gtk_table_attach_defaults(GTK_TABLE(box2), child, 2, 3, 3, 5); child = gtk_entry_new(); if(t->stock) gtk_entry_set_text(GTK_ENTRY(child), t->stock); gtk_table_attach_defaults(GTK_TABLE(box2), child, 3, 4, 3, 5); tvars.stock = child; gtk_box_pack_start(GTK_BOX(box1), gtk_hseparator_new(), FALSE, FALSE, 4); box2 = gtk_table_new(12, 4, TRUE); gtk_table_set_row_spacings(GTK_TABLE(box2), 1); gtk_box_pack_start(GTK_BOX(box1), box2, TRUE, TRUE, 4); child = gtk_label_new(L("Station")); gtk_table_attach_defaults(GTK_TABLE(box2), child, 0, 1, 0, 2); gtk_widget_show(child); child = gtk_label_new(L("Arrival")); gtk_table_attach_defaults(GTK_TABLE(box2), child, 1, 2, 0, 2); gtk_widget_show(child); child = gtk_label_new(L("Departure")); gtk_table_attach_defaults(GTK_TABLE(box2), child, 2, 3, 0, 2); gtk_widget_show(child); child = gtk_label_new(L("Minimum stop (sec)")); gtk_table_attach_defaults(GTK_TABLE(box2), child, 3, 4, 0, 2); gtk_widget_show(child); #if 0 child = gtk_label_new(L(" Stopped ")); gtk_table_attach_defaults(GTK_TABLE(box2), child, 4, 5, 0, 2); gtk_widget_show(child); child = gtk_label_new(L(" Late mins. ")); gtk_table_attach_defaults(GTK_TABLE(box2), child, 5, 6, 0, 2); gtk_widget_show(child); #endif child = gtk_label_new(" "); gtk_table_attach_defaults(GTK_TABLE(box2), child, 0, 2, 1, 3); ts = t->stops; for(i = 0; i < MAXSTAT; ) { child = gtk_entry_new(); if(ts) { strcpy(buff, ts->station); if((p = strchr(buff, '@'))) *p = 0; if(!findStationNamed(buff)) { ts = ts->next; continue; } } gtk_entry_set_text(GTK_ENTRY(child), ts ? ts->station : ""); gtk_table_attach_defaults(GTK_TABLE(box2), child, 0, 1, i + 2, i + 4); tvars.station_name[i] = child; child = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(child), ts ? format_time(ts->arrival) : ""); gtk_table_attach_defaults(GTK_TABLE(box2), child, 1, 2, i + 2, i + 4); tvars.arrival[i] = child; child = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(child), ts ? format_time(ts->departure) : ""); gtk_table_attach_defaults(GTK_TABLE(box2), child, 2, 3, i + 2, i + 4); tvars.departure[i] = child; buff[0] = 0; if(ts) sprintf(buff, "%d", ts->minstop); child = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(child), buff); gtk_table_attach_defaults(GTK_TABLE(box2), child, 3, 4, i + 2, i + 4); tvars.minstop[i] = child; #if 0 child = gtk_label_new(ts ? (ts->stopped ? "Y" : "N") : ""); gtk_table_attach_defaults(GTK_TABLE(box2), child, 4, 5, i + 2, i + 4); strcpy(buff, " "); if(ts) sprintf(buff, "%2d", ts->delay); child = gtk_label_new(buff); gtk_table_attach_defaults(GTK_TABLE(box2), child, 5, 6, i + 2, i + 4); #endif if(ts) ts = ts->next; ++i; } gtk_box_pack_start(GTK_BOX(box1), gtk_hseparator_new(), FALSE, FALSE, 4); box2 = gtk_hbox_new(FALSE, 5); gtk_box_pack_start(GTK_BOX(box1), box2, TRUE, FALSE, 4); btnClose = gtk_button_new_with_label("Ok"); gtk_box_pack_start(GTK_BOX(box2), btnClose, FALSE, FALSE, 4); gtk_signal_connect_object(GTK_OBJECT(btnClose), "clicked", GTK_SIGNAL_FUNC(train_dialogue_close), GTK_OBJECT(window)); btnClose = gtk_button_new_with_label(L("Print...")); gtk_box_pack_start(GTK_BOX(box2), btnClose, FALSE, FALSE, 4); gtk_signal_connect_object(GTK_OBJECT(btnClose), "clicked", GTK_SIGNAL_FUNC(train_dialogue_print), GTK_OBJECT(window)); btnClose = gtk_button_new_with_label(L("Close")); gtk_box_pack_start(GTK_BOX(box2), btnClose, FALSE, FALSE, 4); gtk_signal_connect_object(GTK_OBJECT(btnClose), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(window)); gtk_signal_connect(GTK_OBJECT(window), "destroy", GTK_SIGNAL_FUNC(cmw_destroy_cb),NULL); gtk_widget_show_all(window); gtk_main(); } void create_train(void) { Train *t; t = (Train *)calloc(sizeof(Train), 1); train_info_dialog(t); if(closed_ok) { t->next = schedule; schedule = sort_schedule(t); fill_schedule(schedule, 0); } } int gtk_assign_dialog(Train *t) { oldtrain = t; create_schedule(1); gtk_main(); asgn_struct.clist = 0; asgn_struct.window = 0; if(asgn_struct.assigned_row == -1) return 0; return 1; } /* * * LAYOUT ERROR WINDOW * * */ GtkWidget *layout_error_w; /* outside window */ GtkWidget *layout_error_t; /* text widget */ GdkFont *layout_error_f; /* font */ int layout_error_ended; /* need to clear old text */ void destroy_error_w(GtkWidget window) { gdk_font_unref(layout_error_f); layout_error_w = 0; layout_error_t = 0; layout_error_f = 0; } void create_error_window(void) { GtkWidget *window, *scrolled_window; GtkWidget *text; GdkFont *font; Train *tr; GtkWidget *box1, *box2, *hbox; GtkWidget *saveb; char buff[512]; window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_widget_set_name(window, "text window"); gtk_widget_set_usize(window, 700, 300); gtk_window_set_policy(GTK_WINDOW(window), TRUE, TRUE, FALSE); gtk_window_set_title(GTK_WINDOW(window), L("Layout Errors")); gtk_container_set_border_width(GTK_CONTAINER(window), 0); box1 = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(window), box1); gtk_widget_show(box1); box2 = gtk_vbox_new(FALSE, 10); gtk_container_set_border_width(GTK_CONTAINER(box2), 10); gtk_box_pack_start(GTK_BOX(box1), box2, TRUE, TRUE, 0); gtk_widget_show(box2); scrolled_window = gtk_scrolled_window_new(NULL, NULL); gtk_box_pack_start(GTK_BOX(box2), scrolled_window, TRUE, TRUE, 0); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); gtk_widget_show(scrolled_window); text = gtk_text_new(NULL, NULL); gtk_text_set_editable(GTK_TEXT(text), FALSE); gtk_text_set_word_wrap(GTK_TEXT(text), FALSE); gtk_container_add(GTK_CONTAINER(scrolled_window), text); gtk_widget_show(text); gtk_signal_connect(GTK_OBJECT(window), "destroy", GTK_SIGNAL_FUNC(destroy_error_w), NULL); font = gdk_font_load("-adobe-courier-medium-r-normal--*-120-*-*-*-*-*-*"); gtk_text_freeze(GTK_TEXT(text)); gtk_widget_show(window); layout_error_w = window; layout_error_t = text; layout_error_f = font; } void layout_error(char *msg) { char *cols[2]; int len; if(!layout_error_w) create_error_window(); else if(layout_error_ended) { gtk_text_set_point(GTK_TEXT(layout_error_t), 0); len = gtk_text_get_length(GTK_TEXT(layout_error_t)); gtk_text_forward_delete(GTK_TEXT(layout_error_t), len); } layout_error_ended = 0; cols[0] = msg; cols[1] = 0; gtk_text_insert(GTK_TEXT(layout_error_t), layout_error_f, NULL, NULL, msg, -1); } void end_layout_error(void) { if(layout_error_t) gtk_text_thaw(GTK_TEXT(layout_error_t)); layout_error_ended = 1; }