]> git.tdb.fi Git - r2c2.git/blobdiff - source/engineer/timetablepanel.cpp
New timetable system, which works like an actual timetable
[r2c2.git] / source / engineer / timetablepanel.cpp
diff --git a/source/engineer/timetablepanel.cpp b/source/engineer/timetablepanel.cpp
new file mode 100644 (file)
index 0000000..6104873
--- /dev/null
@@ -0,0 +1,222 @@
+#include <msp/core/maputils.h>
+#include <msp/gltk/button.h>
+#include <msp/gltk/root.h>
+#include <msp/strings/format.h>
+#include <msp/strings/regex.h>
+#include "libr2c2/zone.h"
+#include "engineer.h"
+#include "timetablepanel.h"
+
+using namespace std;
+using namespace Msp;
+using namespace R2C2;
+
+class TimetableRowItem: public GLtk::List::MultiColumnItem
+{
+public:
+       typedef const Timetable::Row *ValueType;
+
+       TimetableRowItem(ValueType);
+};
+
+
+string format_time(const Time::TimeDelta &time)
+{
+       unsigned second = time/Time::sec;
+       unsigned hour = second/3600;
+       unsigned minute = second/60%60;
+       second %= 60;
+       return format("%02d:%02d:%02d", hour, minute, second);
+}
+
+
+TimetablePanel::TimetablePanel(Engineer &e, R2C2::Train &t):
+       engineer(e),
+       train(t),
+       zone(0),
+       zone_pick(false),
+       picked_zone(0),
+       pick_highlight(0)
+{
+       Loader::WidgetMap widgets;
+       DataFile::load(*this, "data/timetablepanel.ui", widgets);
+
+       lst_timetable = dynamic_cast<GLtk::List *>(get_item(widgets, "lst_timetable"));
+       lst_timetable->set_data(rows);
+       lst_timetable->set_item_type<TimetableRowItem>();
+       lst_timetable->signal_item_selected.connect(sigc::mem_fun(this, &TimetablePanel::row_selected));
+
+       drp_type = dynamic_cast<GLtk::Dropdown *>(get_item(widgets, "drp_type"));
+       lbl_zone = dynamic_cast<GLtk::Label *>(get_item(widgets, "lbl_zone"));
+       ent_time = dynamic_cast<GLtk::Entry *>(get_item(widgets, "ent_time"));
+
+       dynamic_cast<GLtk::Button *>(get_item(widgets, "btn_pick"))->signal_clicked.connect(sigc::mem_fun(this, &TimetablePanel::pick_clicked));
+       dynamic_cast<GLtk::Button *>(get_item(widgets, "btn_insert"))->signal_clicked.connect(sigc::mem_fun(this, &TimetablePanel::insert_clicked));
+       dynamic_cast<GLtk::Button *>(get_item(widgets, "btn_delete"))->signal_clicked.connect(sigc::mem_fun(this, &TimetablePanel::delete_clicked));
+       dynamic_cast<GLtk::Button *>(get_item(widgets, "btn_apply"))->signal_clicked.connect(sigc::mem_fun(this, &TimetablePanel::apply_clicked));
+
+       timetable = train.get_ai_of_type<Timetable>();
+       if(!timetable)
+               timetable = new Timetable(train);
+
+       unsigned length = timetable->get_length();
+       for(unsigned i=0; i<length; ++i)
+               rows.append(&timetable->get_row(i));
+       rows.append(0);
+       timetable->signal_row_added.connect(sigc::mem_fun(this, &TimetablePanel::row_added));
+       timetable->signal_row_modified.connect(sigc::mem_fun(this, &TimetablePanel::row_modified));
+       timetable->signal_row_removed.connect(sigc::mem_fun(this, &TimetablePanel::row_removed));
+}
+
+void TimetablePanel::row_added(unsigned i, const Timetable::Row &row)
+{
+       rows.insert(i, &row);
+}
+
+void TimetablePanel::row_modified(unsigned i, const Timetable::Row &)
+{
+       rows.refresh(i);
+}
+
+void TimetablePanel::row_removed(unsigned i)
+{
+       rows.remove(i);
+}
+
+Timetable::Row TimetablePanel::create_row()
+{
+       Timetable::Row row;
+
+       row.type = static_cast<Timetable::RowType>(drp_type->get_selected_index()+1);
+       row.zone = zone;
+
+       Regex r_time("([01]?[0-9]|2[0-3]):([0-5][0-9])(:([0-5][0-9]))?");
+       RegMatch m = r_time.match(ent_time->get_text());
+       if(m)
+       {
+               row.time = lexical_cast<unsigned>(m[1].str)*Time::hour;
+               row.time += lexical_cast<unsigned>(m[2].str)*Time::min;
+               if(m[3])
+                       row.time += lexical_cast<unsigned>(m[4].str)*Time::sec;
+       }
+
+       return row;
+}
+
+void TimetablePanel::row_selected(unsigned i)
+{
+       const Timetable::Row *row = rows.get(i);
+       if(row)
+       {
+               drp_type->set_selected_index(row->type-1);
+               if(row->zone)
+                       lbl_zone->set_text(row->zone->get_name());
+               ent_time->set_text(format_time(row->time));
+       }
+}
+
+void TimetablePanel::pick_clicked()
+{
+       zone_pick = true;
+       picked_zone = 0;
+       signal_grab_pointer.emit();
+}
+
+void TimetablePanel::insert_clicked()
+{
+       int index = lst_timetable->get_selected_index();
+       if(index<0)
+               index = timetable->get_length();
+       timetable->insert_row(index, create_row());
+}
+
+void TimetablePanel::delete_clicked()
+{
+       int index = lst_timetable->get_selected_index();
+       if(index>=0)
+               timetable->remove_row(index);
+}
+
+void TimetablePanel::apply_clicked()
+{
+       int index = lst_timetable->get_selected_index();
+       if(index>=0)
+               timetable->modify_row(index, create_row());
+}
+
+void TimetablePanel::button_press(int x, int y, unsigned btn)
+{
+       Panel::button_press(x, y, btn);
+
+       if(zone_pick)
+       {
+               signal_ungrab_pointer.emit();
+               zone_pick = false;
+
+               delete pick_highlight;
+               pick_highlight = 0;
+
+               if(picked_zone && btn==1)
+               {
+                       zone = picked_zone;
+                       lbl_zone->set_text(zone->get_name());
+               }
+       }
+}
+
+void TimetablePanel::pointer_motion(int x, int y)
+{
+       Panel::pointer_motion(x, y);
+
+       if(zone_pick)
+       {
+               int rx = x;
+               int ry = y;
+               map_coords_to_ancestor(rx, ry, *find_ancestor<GLtk::Root>());
+               Ray ray = engineer.get_main_view().create_ray(rx, ry);
+               Track *track = engineer.get_layout().pick<Track>(ray);
+               if(track)
+               {
+                       const set<Zone *> &zones = engineer.get_layout().get_all<Zone>();
+                       Zone *track_zone = 0;
+                       for(set<Zone *>::const_iterator i=zones.begin(); (!track_zone && i!=zones.end()); ++i)
+                               if((*i)->has_track(*track))
+                                       track_zone = *i;
+                       if(track_zone!=picked_zone)
+                       {
+                               picked_zone = track_zone;
+                               delete pick_highlight;
+                               if(picked_zone)
+                                       pick_highlight = new TrackChain3D(engineer.get_layout_3d(), *track_zone);
+                               else
+                                       pick_highlight = 0;
+                       }
+               }
+       }
+}
+
+
+TimetableRowItem::TimetableRowItem(ValueType row)
+{
+       if(row)
+       {
+               add(*new GLtk::Label(format_time(row->time)));
+               if(row->zone)
+               {
+                       string type;
+                       switch(row->type)
+                       {
+                       case Timetable::ARRIVE: type = "Arrive at "; break;
+                       case Timetable::DEPART: type = "Depart from "; break;
+                       }
+                       add(*new GLtk::Label(type+row->zone->get_name()));
+               }
+               else
+                       add(*new GLtk::Label);
+       }
+       else
+       {
+               add(*new GLtk::Label("--:--:--"));
+               add(*new GLtk::Label("End of timetable"));
+       }
+}