From cf52013784607dc4d307bd1244c5346ee88336a4 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sat, 24 Apr 2010 21:01:15 +0000 Subject: [PATCH] Add a UI for editing train timetables Add an enabled flag to Timetable Display turnout and sensor ids when clicked --- source/engineer/engineer.cpp | 6 ++- source/engineer/timetabledialog.cpp | 79 +++++++++++++++++++++++++++ source/engineer/timetabledialog.h | 32 +++++++++++ source/engineer/trainpanel.cpp | 28 ++++++++-- source/engineer/trainpanel.h | 1 + source/libmarklin/timetable.cpp | 83 +++++++++++++++++++++++++++++ source/libmarklin/timetable.h | 14 +++++ source/libmarklin/train.cpp | 6 +++ source/libmarklin/train.h | 3 ++ 9 files changed, 246 insertions(+), 6 deletions(-) create mode 100644 source/engineer/timetabledialog.cpp create mode 100644 source/engineer/timetabledialog.h diff --git a/source/engineer/engineer.cpp b/source/engineer/engineer.cpp index c809287..ff13b6e 100644 --- a/source/engineer/engineer.cpp +++ b/source/engineer/engineer.cpp @@ -270,12 +270,14 @@ void Engineer::button_press(int x, int y, unsigned btn, unsigned) ++i; } track.set_active_path(i); + set_status(format("Turnout %d", track.get_turnout_id())); } } - else if(options.simulate) + if(unsigned sid = track.get_sensor_id()) { - if(unsigned sid=track.get_sensor_id()) + if(options.simulate) layout.get_driver().set_sensor(sid, !layout.get_driver().get_sensor(sid)); + set_status(format("Sensor %d", sid)); } } } diff --git a/source/engineer/timetabledialog.cpp b/source/engineer/timetabledialog.cpp new file mode 100644 index 0000000..978b14b --- /dev/null +++ b/source/engineer/timetabledialog.cpp @@ -0,0 +1,79 @@ +/* $Id$ + +This file is part of the MSP Märklin suite +Copyright © 2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#include +#include +#include +#include "timetabledialog.h" + +using namespace std; +using namespace Msp; +using namespace Marklin; + +TimetableDialog::TimetableDialog(const GLtk::Resources &r, Timetable &tt): + GLtk::Widget(r), + GLtk::Dialog(r), + timetable(tt) +{ + set_size(200, 200); + + GLtk::Button *btn; + + add_button(*(btn = new GLtk::Button(res, "Cncl")), 0); + btn->set_geometry(GLtk::Geometry(geom.w-80, 10, 30, 25)); + btn->set_style("red"); + + add_button(*(btn = new GLtk::Button(res, "OK")), 1); + btn->set_geometry(GLtk::Geometry(geom.w-40, 10, 30, 25)); + btn->set_style("green"); + + add(*(tgl_enabled = new GLtk::Toggle(res, "On"))); + tgl_enabled->set_geometry(GLtk::Geometry(10, 10, 40, 27)); + tgl_enabled->set_value(timetable.is_enabled()); + tgl_enabled->signal_toggled.connect(sigc::mem_fun(this, &TimetableDialog::enabled_toggled)); + + add(*(ent_timetable = new GLtk::Entry(res))); + ent_timetable->set_geometry(GLtk::Geometry(10, 45, geom.w-20, geom.h-55)); + ent_timetable->set_multiline(true); + + string text; + for(unsigned i=0; iset_text(text); +} + +void TimetableDialog::enabled_toggled(bool value) +{ + timetable.set_enabled(value); +} + +void TimetableDialog::on_response(int code) +{ + if(code) + { + timetable.clear(); + vector lines = split(ent_timetable->get_text(), '\n'); + vector rows; + rows.reserve(lines.size()); + try + { + for(vector::const_iterator i=lines.begin(); i!=lines.end(); ++i) + rows.push_back(Timetable::Row::parse(*i)); + for(vector::const_iterator i=rows.begin(); i!=rows.end(); ++i) + timetable.append(*i); + } + catch(const Exception &e) + { + // XXX Need a better way to report errors. Also, should not let the dialog close. + IO::print("%s\n", e.what()); + } + } +} diff --git a/source/engineer/timetabledialog.h b/source/engineer/timetabledialog.h new file mode 100644 index 0000000..a75a091 --- /dev/null +++ b/source/engineer/timetabledialog.h @@ -0,0 +1,32 @@ +/* $Id$ + +This file is part of the MSP Märklin suite +Copyright © 2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL +*/ + +#ifndef TIMETABLEDIALOG_H_ +#define TIMETABLEDIALOG_H_ + +#include +#include +#include +#include "libmarklin/timetable.h" + +class TimetableDialog: public Msp::GLtk::Dialog +{ +private: + Marklin::Timetable &timetable; + Msp::GLtk::Entry *ent_timetable; + Msp::GLtk::Toggle *tgl_enabled; + +public: + TimetableDialog(const Msp::GLtk::Resources &, Marklin::Timetable &); + +private: + void enabled_toggled(bool); + + virtual void on_response(int); +}; + +#endif diff --git a/source/engineer/trainpanel.cpp b/source/engineer/trainpanel.cpp index 6685727..590f1cd 100644 --- a/source/engineer/trainpanel.cpp +++ b/source/engineer/trainpanel.cpp @@ -9,8 +9,10 @@ Distributed under the GPL #include #include #include "libmarklin/locotype.h" +#include "libmarklin/timetable.h" #include "engineer.h" #include "routeselect.h" +#include "timetabledialog.h" #include "trainpanel.h" #include "trainproperties.h" @@ -84,20 +86,24 @@ TrainPanel::TrainPanel(Engineer &e, const GLtk::Resources &r, Train &t): GLtk::Button *btn; add(*(btn=new GLtk::Button(res, "Edit"))); - btn->set_geometry(GLtk::Geometry(geom.w-50, 10, 40, 24)); + btn->set_geometry(GLtk::Geometry(geom.w-46, 10, 36, 24)); btn->signal_clicked.connect(sigc::mem_fun(this, &TrainPanel::edit_clicked)); add(*(btn=new GLtk::Button(res, "Place"))); - btn->set_geometry(GLtk::Geometry(geom.w-90, 10, 40, 24)); + btn->set_geometry(GLtk::Geometry(geom.w-82, 10, 36, 24)); btn->signal_clicked.connect(sigc::mem_fun(this, &TrainPanel::place_clicked)); add(*(btn=new GLtk::Button(res, "GoTo"))); - btn->set_geometry(GLtk::Geometry(geom.w-130, 10, 40, 24)); + btn->set_geometry(GLtk::Geometry(geom.w-118, 10, 36, 24)); btn->signal_clicked.connect(sigc::mem_fun(this, &TrainPanel::goto_clicked)); add(*(btn=new GLtk::Button(res, "Route"))); - btn->set_geometry(GLtk::Geometry(geom.w-170, 10, 40, 24)); + btn->set_geometry(GLtk::Geometry(geom.w-154, 10, 36, 24)); btn->signal_clicked.connect(sigc::mem_fun(this, &TrainPanel::route_clicked)); + + add(*(btn=new GLtk::Button(res, "TTbl"))); + btn->set_geometry(GLtk::Geometry(geom.w-190, 10, 36, 24)); + btn->signal_clicked.connect(sigc::mem_fun(this, &TrainPanel::timetable_clicked)); } void TrainPanel::speed_slider_changed(double value) @@ -168,6 +174,20 @@ void TrainPanel::goto_clicked() pick_conn = engineer.signal_pick_done.connect(sigc::mem_fun(this, &TrainPanel::go_to)); } +void TrainPanel::timetable_clicked() +{ + Timetable *timetable = train.get_timetable(); + if(!timetable) + { + timetable = new Timetable(train); + train.set_timetable(timetable); + } + + TimetableDialog *dialog = new TimetableDialog(res, *timetable); + engineer.get_root().add(*dialog); + dialog->set_position(geom.x+geom.w, geom.y+geom.h-dialog->get_geometry().h); +} + void TrainPanel::forward_toggled(bool /*value*/) { train.set_control("speed", 0); diff --git a/source/engineer/trainpanel.h b/source/engineer/trainpanel.h index 12aa8fc..2f1453f 100644 --- a/source/engineer/trainpanel.h +++ b/source/engineer/trainpanel.h @@ -45,6 +45,7 @@ private: void edit_clicked(); void route_clicked(); void goto_clicked(); + void timetable_clicked(); void forward_toggled(bool); void func_toggled(bool, unsigned); void place(Marklin::Track *, unsigned); diff --git a/source/libmarklin/timetable.cpp b/source/libmarklin/timetable.cpp index bd9d4b3..cfe2ef6 100644 --- a/source/libmarklin/timetable.cpp +++ b/source/libmarklin/timetable.cpp @@ -5,6 +5,7 @@ Copyright © 2010 Mikkosoft Productions, Mikko Rasa Distributed under the GPL */ +#include #include #include "block.h" #include "catalogue.h" @@ -20,6 +21,7 @@ namespace Marklin { Timetable::Timetable(Train &t): train(t), + enabled(false), current_row(0), executing(true), pending_block(0) @@ -28,8 +30,44 @@ Timetable::Timetable(Train &t): train.get_layout().get_driver().signal_sensor.connect(sigc::mem_fun(this, &Timetable::sensor_event)); } +void Timetable::set_enabled(bool e) +{ + enabled = e; +} + +void Timetable::clear() +{ + rows.clear(); + current_row = 0; +} + +void Timetable::append(const Row &row) +{ + rows.push_back(row); +} + +void Timetable::insert(unsigned i, const Row &row) +{ + if(i>rows.size()) + throw InvalidParameterValue("Insert position out of range"); + + rows.insert(rows.begin()+i, row); + if(i<=current_row) + ++current_row; +} + +const Timetable::Row &Timetable::get_row(unsigned i) const +{ + if(i>=rows.size()) + throw InvalidParameterValue("Row index out of range"); + return rows[i]; +} + void Timetable::tick(const Time::TimeStamp &t) { + if(rows.empty() || !enabled) + return; + if(wait_timeout && t>=wait_timeout) { wait_timeout = Time::TimeStamp(); @@ -131,6 +169,51 @@ Timetable::Row::Row(RowType t, const string &p): strparam(p) { } +string Timetable::Row::str() const +{ + switch(type) + { + case GOTO: + return "go to "+strparam; + case TRAVEL: + return "travel to "+strparam; + case WAIT: + return format("wait for %d seconds", intparam); + case SPEED: + return format("set speed %d km/h", intparam); + case ROUTE: + return "set route "+strparam; + default: + return "invalid row"; + } +} + +Timetable::Row Timetable::Row::parse(const string &s) +{ + if(!s.compare(0, 6, "go to ")) + return Row(GOTO, s.substr(6)); + else if(!s.compare(0, 10, "travel to ")) + return Row(TRAVEL, s.substr(10)); + else if(!s.compare(0, 9, "wait for ") && isdigit(s[9])) + { + unsigned nondigit = 10; + while(nondigit(s.substr(9, nondigit-9))); + } + else if(!s.compare(0, 10, "set speed ")) + { + unsigned nondigit = 11; + while(nondigit(s.substr(10, nondigit-10))); + } + else if(!s.compare(0, 10, "set route ")) + return Row(ROUTE, s.substr(10)); + + throw InvalidParameterValue("Invalid row"); +} + Timetable::Loader::Loader(Timetable &tt): DataFile::ObjectLoader(tt) diff --git a/source/libmarklin/timetable.h b/source/libmarklin/timetable.h index 3c76055..6631f38 100644 --- a/source/libmarklin/timetable.h +++ b/source/libmarklin/timetable.h @@ -51,10 +51,15 @@ public: Row(RowType, int); Row(RowType, const std::string &); + + std::string str() const; + + static Row parse(const std::string &); }; private: Train &train; + bool enabled; std::vector rows; unsigned current_row; bool executing; @@ -64,6 +69,15 @@ private: public: Timetable(Train &); + void set_enabled(bool); + bool is_enabled() const { return enabled; } + + void clear(); + void append(const Row &); + void insert(unsigned, const Row &); + unsigned get_n_rows() const { return rows.size(); } + const Row &get_row(unsigned) const; + void tick(const Msp::Time::TimeStamp &); void save(std::list &) const; private: diff --git a/source/libmarklin/train.cpp b/source/libmarklin/train.cpp index efe1a14..a6fd46d 100644 --- a/source/libmarklin/train.cpp +++ b/source/libmarklin/train.cpp @@ -141,6 +141,12 @@ bool Train::get_function(unsigned func) const return (functions>>func)&1; } +void Train::set_timetable(Timetable *tt) +{ + delete timetable; + timetable = tt; +} + void Train::set_route(const Route *r) { if(!rsv_blocks.empty()) diff --git a/source/libmarklin/train.h b/source/libmarklin/train.h index 8087745..ccfcbec 100644 --- a/source/libmarklin/train.h +++ b/source/libmarklin/train.h @@ -120,6 +120,9 @@ public: bool get_function(unsigned) const; unsigned get_functions() const { return functions; } + void set_timetable(Timetable *); + Timetable *get_timetable() { return timetable; } + void set_route(const Route *); void go_to(const Track &); const Route *get_route() const { return route; } -- 2.43.0