]> git.tdb.fi Git - r2c2.git/blob - source/engineer/timetablepanel.cpp
Also use TrackChains as target locations in 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/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                 if(row->target)
114                         lbl_target->set_text(row->target->get_name());
115                 ent_time->set_text(format_time(row->time));
116         }
117 }
118
119 void TimetablePanel::pick_clicked()
120 {
121         target_pick = true;
122         picked_target = 0;
123         shift = false;
124         signal_grab_pointer.emit();
125 }
126
127 void TimetablePanel::insert_clicked()
128 {
129         int index = lst_timetable->get_selected_index();
130         if(index<0)
131                 index = timetable->get_length();
132         timetable->insert_row(index, create_row());
133 }
134
135 void TimetablePanel::delete_clicked()
136 {
137         int index = lst_timetable->get_selected_index();
138         if(index>=0)
139                 timetable->remove_row(index);
140 }
141
142 void TimetablePanel::apply_clicked()
143 {
144         int index = lst_timetable->get_selected_index();
145         if(index>=0)
146                 timetable->modify_row(index, create_row());
147 }
148
149 void TimetablePanel::key_press(unsigned key, unsigned mod)
150 {
151         Panel::key_press(key, mod);
152
153         if(key==Input::KEY_SHIFT_R || key==Input::KEY_SHIFT_L)
154                 shift = true;
155 }
156
157 void TimetablePanel::key_release(unsigned key, unsigned mod)
158 {
159         Panel::key_release(key, mod);
160
161         if(key==Input::KEY_SHIFT_R || key==Input::KEY_SHIFT_L)
162                 shift = false;
163 }
164
165 void TimetablePanel::button_press(int x, int y, unsigned btn)
166 {
167         Panel::button_press(x, y, btn);
168
169         if(target_pick)
170         {
171                 signal_ungrab_pointer.emit();
172                 target_pick = false;
173
174                 delete pick_highlight;
175                 pick_highlight = 0;
176
177                 if(picked_target && btn==1)
178                 {
179                         target = picked_target;
180                         lbl_target->set_text(target->get_name());
181                 }
182         }
183 }
184
185 void TimetablePanel::pointer_motion(int x, int y)
186 {
187         Panel::pointer_motion(x, y);
188
189         if(target_pick)
190         {
191                 int rx = x;
192                 int ry = y;
193                 map_coords_to_ancestor(rx, ry, *find_ancestor<GLtk::Root>());
194                 Ray ray = engineer.get_main_view().create_ray(rx, ry);
195                 Track *track = engineer.get_layout().pick<Track>(ray);
196                 if(track)
197                 {
198                         TrackChain *t = 0;
199                         if(!shift)
200                         {
201                                 const set<Zone *> &zones = engineer.get_layout().get_all<Zone>();
202                                 for(set<Zone *>::const_iterator i=zones.begin(); (!t && i!=zones.end()); ++i)
203                                         if((*i)->has_track(*track))
204                                                 t = *i;
205                         }
206
207                         if(!t)
208                                 t = &track->get_block();
209
210                         if(t!=picked_target)
211                         {
212                                 picked_target = t;
213                                 delete pick_highlight;
214                                 pick_highlight = new TrackChain3D(engineer.get_layout_3d(), *picked_target);
215                         }
216                 }
217         }
218 }
219
220
221 TimetableRowItem::TimetableRowItem(ValueType row)
222 {
223         if(row)
224         {
225                 add(*new GLtk::Label(format_time(row->time)));
226                 if(row->target)
227                 {
228                         string type;
229                         switch(row->type)
230                         {
231                         case Timetable::ARRIVE: type = "Arrive at "; break;
232                         case Timetable::DEPART: type = "Depart from "; break;
233                         }
234                         add(*new GLtk::Label(type+row->target->get_name()));
235                 }
236                 else
237                         add(*new GLtk::Label);
238         }
239         else
240         {
241                 add(*new GLtk::Label("--:--:--"));
242                 add(*new GLtk::Label("End of timetable"));
243         }
244 }