]> git.tdb.fi Git - r2c2.git/blob - source/engineer/timetablepanel.cpp
New timetable system, which works like an actual timetable
[r2c2.git] / source / engineer / timetablepanel.cpp
1 #include <msp/core/maputils.h>
2 #include <msp/gltk/button.h>
3 #include <msp/gltk/root.h>
4 #include <msp/strings/format.h>
5 #include <msp/strings/regex.h>
6 #include "libr2c2/zone.h"
7 #include "engineer.h"
8 #include "timetablepanel.h"
9
10 using namespace std;
11 using namespace Msp;
12 using namespace R2C2;
13
14 class TimetableRowItem: public GLtk::List::MultiColumnItem
15 {
16 public:
17         typedef const Timetable::Row *ValueType;
18
19         TimetableRowItem(ValueType);
20 };
21
22
23 string format_time(const Time::TimeDelta &time)
24 {
25         unsigned second = time/Time::sec;
26         unsigned hour = second/3600;
27         unsigned minute = second/60%60;
28         second %= 60;
29         return format("%02d:%02d:%02d", hour, minute, second);
30 }
31
32
33 TimetablePanel::TimetablePanel(Engineer &e, R2C2::Train &t):
34         engineer(e),
35         train(t),
36         zone(0),
37         zone_pick(false),
38         picked_zone(0),
39         pick_highlight(0)
40 {
41         Loader::WidgetMap widgets;
42         DataFile::load(*this, "data/timetablepanel.ui", widgets);
43
44         lst_timetable = dynamic_cast<GLtk::List *>(get_item(widgets, "lst_timetable"));
45         lst_timetable->set_data(rows);
46         lst_timetable->set_item_type<TimetableRowItem>();
47         lst_timetable->signal_item_selected.connect(sigc::mem_fun(this, &TimetablePanel::row_selected));
48
49         drp_type = dynamic_cast<GLtk::Dropdown *>(get_item(widgets, "drp_type"));
50         lbl_zone = dynamic_cast<GLtk::Label *>(get_item(widgets, "lbl_zone"));
51         ent_time = dynamic_cast<GLtk::Entry *>(get_item(widgets, "ent_time"));
52
53         dynamic_cast<GLtk::Button *>(get_item(widgets, "btn_pick"))->signal_clicked.connect(sigc::mem_fun(this, &TimetablePanel::pick_clicked));
54         dynamic_cast<GLtk::Button *>(get_item(widgets, "btn_insert"))->signal_clicked.connect(sigc::mem_fun(this, &TimetablePanel::insert_clicked));
55         dynamic_cast<GLtk::Button *>(get_item(widgets, "btn_delete"))->signal_clicked.connect(sigc::mem_fun(this, &TimetablePanel::delete_clicked));
56         dynamic_cast<GLtk::Button *>(get_item(widgets, "btn_apply"))->signal_clicked.connect(sigc::mem_fun(this, &TimetablePanel::apply_clicked));
57
58         timetable = train.get_ai_of_type<Timetable>();
59         if(!timetable)
60                 timetable = new Timetable(train);
61
62         unsigned length = timetable->get_length();
63         for(unsigned i=0; i<length; ++i)
64                 rows.append(&timetable->get_row(i));
65         rows.append(0);
66         timetable->signal_row_added.connect(sigc::mem_fun(this, &TimetablePanel::row_added));
67         timetable->signal_row_modified.connect(sigc::mem_fun(this, &TimetablePanel::row_modified));
68         timetable->signal_row_removed.connect(sigc::mem_fun(this, &TimetablePanel::row_removed));
69 }
70
71 void TimetablePanel::row_added(unsigned i, const Timetable::Row &row)
72 {
73         rows.insert(i, &row);
74 }
75
76 void TimetablePanel::row_modified(unsigned i, const Timetable::Row &)
77 {
78         rows.refresh(i);
79 }
80
81 void TimetablePanel::row_removed(unsigned i)
82 {
83         rows.remove(i);
84 }
85
86 Timetable::Row TimetablePanel::create_row()
87 {
88         Timetable::Row row;
89
90         row.type = static_cast<Timetable::RowType>(drp_type->get_selected_index()+1);
91         row.zone = zone;
92
93         Regex r_time("([01]?[0-9]|2[0-3]):([0-5][0-9])(:([0-5][0-9]))?");
94         RegMatch m = r_time.match(ent_time->get_text());
95         if(m)
96         {
97                 row.time = lexical_cast<unsigned>(m[1].str)*Time::hour;
98                 row.time += lexical_cast<unsigned>(m[2].str)*Time::min;
99                 if(m[3])
100                         row.time += lexical_cast<unsigned>(m[4].str)*Time::sec;
101         }
102
103         return row;
104 }
105
106 void TimetablePanel::row_selected(unsigned i)
107 {
108         const Timetable::Row *row = rows.get(i);
109         if(row)
110         {
111                 drp_type->set_selected_index(row->type-1);
112                 if(row->zone)
113                         lbl_zone->set_text(row->zone->get_name());
114                 ent_time->set_text(format_time(row->time));
115         }
116 }
117
118 void TimetablePanel::pick_clicked()
119 {
120         zone_pick = true;
121         picked_zone = 0;
122         signal_grab_pointer.emit();
123 }
124
125 void TimetablePanel::insert_clicked()
126 {
127         int index = lst_timetable->get_selected_index();
128         if(index<0)
129                 index = timetable->get_length();
130         timetable->insert_row(index, create_row());
131 }
132
133 void TimetablePanel::delete_clicked()
134 {
135         int index = lst_timetable->get_selected_index();
136         if(index>=0)
137                 timetable->remove_row(index);
138 }
139
140 void TimetablePanel::apply_clicked()
141 {
142         int index = lst_timetable->get_selected_index();
143         if(index>=0)
144                 timetable->modify_row(index, create_row());
145 }
146
147 void TimetablePanel::button_press(int x, int y, unsigned btn)
148 {
149         Panel::button_press(x, y, btn);
150
151         if(zone_pick)
152         {
153                 signal_ungrab_pointer.emit();
154                 zone_pick = false;
155
156                 delete pick_highlight;
157                 pick_highlight = 0;
158
159                 if(picked_zone && btn==1)
160                 {
161                         zone = picked_zone;
162                         lbl_zone->set_text(zone->get_name());
163                 }
164         }
165 }
166
167 void TimetablePanel::pointer_motion(int x, int y)
168 {
169         Panel::pointer_motion(x, y);
170
171         if(zone_pick)
172         {
173                 int rx = x;
174                 int ry = y;
175                 map_coords_to_ancestor(rx, ry, *find_ancestor<GLtk::Root>());
176                 Ray ray = engineer.get_main_view().create_ray(rx, ry);
177                 Track *track = engineer.get_layout().pick<Track>(ray);
178                 if(track)
179                 {
180                         const set<Zone *> &zones = engineer.get_layout().get_all<Zone>();
181                         Zone *track_zone = 0;
182                         for(set<Zone *>::const_iterator i=zones.begin(); (!track_zone && i!=zones.end()); ++i)
183                                 if((*i)->has_track(*track))
184                                         track_zone = *i;
185                         if(track_zone!=picked_zone)
186                         {
187                                 picked_zone = track_zone;
188                                 delete pick_highlight;
189                                 if(picked_zone)
190                                         pick_highlight = new TrackChain3D(engineer.get_layout_3d(), *track_zone);
191                                 else
192                                         pick_highlight = 0;
193                         }
194                 }
195         }
196 }
197
198
199 TimetableRowItem::TimetableRowItem(ValueType row)
200 {
201         if(row)
202         {
203                 add(*new GLtk::Label(format_time(row->time)));
204                 if(row->zone)
205                 {
206                         string type;
207                         switch(row->type)
208                         {
209                         case Timetable::ARRIVE: type = "Arrive at "; break;
210                         case Timetable::DEPART: type = "Depart from "; break;
211                         }
212                         add(*new GLtk::Label(type+row->zone->get_name()));
213                 }
214                 else
215                         add(*new GLtk::Label);
216         }
217         else
218         {
219                 add(*new GLtk::Label("--:--:--"));
220                 add(*new GLtk::Label("End of timetable"));
221         }
222 }