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