From abed4a255060d5a233ec0ac2dd60af9132e29201 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sat, 4 Apr 2015 01:42:35 +0300 Subject: [PATCH] Persist most dialogs across runs --- source/engineer/clockdialog.cpp | 9 +++++ source/engineer/clockdialog.h | 7 ++-- source/engineer/departuresdialog.cpp | 29 ++++++++++++++-- source/engineer/departuresdialog.h | 21 ++++++++++-- source/engineer/dynamicdialog.cpp | 32 ++++++++++++++++++ source/engineer/dynamicdialog.h | 15 ++++++++- source/engineer/engineer.cpp | 5 +++ source/engineer/options.cpp | 4 +++ source/engineer/options.h | 1 + source/engineer/telemetrydialog.cpp | 8 +++++ source/engineer/telemetrydialog.h | 3 +- source/engineer/traindialog.cpp | 24 +++++++++++++ source/engineer/traindialog.h | 17 ++++++++-- source/engineer/trainlistdialog.cpp | 9 +++++ source/engineer/trainlistdialog.h | 7 ++-- source/engineer/userinterface.cpp | 50 +++++++++++++++++++++++++++- source/engineer/userinterface.h | 18 ++++++++++ 17 files changed, 245 insertions(+), 14 deletions(-) diff --git a/source/engineer/clockdialog.cpp b/source/engineer/clockdialog.cpp index ba73a5e..c348de2 100644 --- a/source/engineer/clockdialog.cpp +++ b/source/engineer/clockdialog.cpp @@ -10,6 +10,7 @@ using namespace Msp; using namespace R2C2; ClockDialog::ClockDialog(Engineer &engineer): + DynamicDialog(engineer.get_user_interface()), clock(engineer.get_layout().get_clock()) { Loader::WidgetMap widgets; @@ -78,3 +79,11 @@ void ClockDialog::set_time() { } } + +bool ClockDialog::save_state(DataFile::Statement &st) const +{ + st.keyword = "clockdialog"; + save_position(st.sub); + + return true; +} diff --git a/source/engineer/clockdialog.h b/source/engineer/clockdialog.h index a1a1f72..48dfc70 100644 --- a/source/engineer/clockdialog.h +++ b/source/engineer/clockdialog.h @@ -1,15 +1,15 @@ #ifndef CLOCKDIALOG_H_ #define CLOCKDIALOG_H_ -#include #include #include #include "libr2c2/clock.h" +#include "dynamicdialog.h" class ClockWidget; class Engineer; -class ClockDialog: public Msp::GLtk::Dialog, public sigc::trackable +class ClockDialog: public DynamicDialog, public sigc::trackable { private: R2C2::Clock &clock; @@ -26,6 +26,9 @@ private: void set_rate(); void stop_clicked(); void set_time(); + +public: + virtual bool save_state(Msp::DataFile::Statement &) const; }; #endif diff --git a/source/engineer/departuresdialog.cpp b/source/engineer/departuresdialog.cpp index a1a3112..c5f1b8b 100644 --- a/source/engineer/departuresdialog.cpp +++ b/source/engineer/departuresdialog.cpp @@ -5,13 +5,15 @@ #include "libr2c2/train.h" #include "libr2c2/zone.h" #include "departuresdialog.h" +#include "engineer.h" using namespace std; using namespace Msp; using namespace R2C2; -DeparturesDialog::DeparturesDialog(const Layout &l, const string &group): - layout(l), +DeparturesDialog::DeparturesDialog(Engineer &engineer, const string &group): + DynamicDialog(engineer.get_user_interface()), + layout(engineer.get_layout()), departures(0) { Loader::WidgetMap widgets; @@ -85,6 +87,17 @@ void DeparturesDialog::update_rows() } } +bool DeparturesDialog::save_state(DataFile::Statement &st) const +{ + st.keyword = "departuresdialog"; + int sel = drp_groups->get_selected_index(); + if(sel>=0) + st.sub.push_back((DataFile::Statement("group"), groups.get(sel))); + save_position(st.sub); + + return true; +} + DeparturesDialog::Row::Row(): departure(0), @@ -109,3 +122,15 @@ void DeparturesDialog::Row::set_departure(const Departures::Departure *d) lbl_train->set_text(string()); } } + + +DeparturesDialog::StateLoader::StateLoader(DeparturesDialog &dd): + DataFile::DerivedObjectLoader(dd) +{ + add("group", &StateLoader::group); +} + +void DeparturesDialog::StateLoader::group(const string &g) +{ + obj.set_group(g); +} diff --git a/source/engineer/departuresdialog.h b/source/engineer/departuresdialog.h index 3b7b2ce..bbc8246 100644 --- a/source/engineer/departuresdialog.h +++ b/source/engineer/departuresdialog.h @@ -1,13 +1,25 @@ #ifndef DEPARTURESDIALOG_H_ #define DEPARTURESDIALOG_H_ -#include #include #include #include "libr2c2/departures.h" +#include "dynamicdialog.h" -class DeparturesDialog: public Msp::GLtk::Dialog +class Engineer; + +class DeparturesDialog: public DynamicDialog { +public: + class StateLoader: public Msp::DataFile::DerivedObjectLoader + { + public: + StateLoader(DeparturesDialog &); + + private: + void group(const std::string &); + }; + private: struct Row { @@ -29,13 +41,16 @@ private: std::vector rows; public: - DeparturesDialog(const R2C2::Layout &, const std::string & = std::string()); + DeparturesDialog(Engineer &, const std::string & = std::string()); void set_group(const std::string &); private: void group_selected(unsigned); void update_rows(); + +public: + virtual bool save_state(Msp::DataFile::Statement &) const; }; #endif diff --git a/source/engineer/dynamicdialog.cpp b/source/engineer/dynamicdialog.cpp index 6d9afb4..4e3312f 100644 --- a/source/engineer/dynamicdialog.cpp +++ b/source/engineer/dynamicdialog.cpp @@ -1,6 +1,9 @@ #include "dynamicdialog.h" #include "userinterface.h" +using namespace std; +using namespace Msp; + DynamicDialog::DynamicDialog(UserInterface &u): ui(u) { @@ -11,3 +14,32 @@ DynamicDialog::~DynamicDialog() { ui.remove_dynamic_dialog(*this); } + +void DynamicDialog::save_position(list &st) const +{ + GLtk::Root *root = find_ancestor(); + if(root) + { + const GLtk::Geometry &rgeom = root->get_geometry(); + float x = static_cast(geom.x)/(rgeom.w-geom.w); + float y = static_cast(geom.y)/(rgeom.h-geom.h); + st.push_back((DataFile::Statement("position"), x, y)); + } +} + + +DynamicDialog::StateLoader::StateLoader(DynamicDialog &dd): + DataFile::ObjectLoader(dd) +{ + add("position", &StateLoader::position); +} + +void DynamicDialog::StateLoader::position(float x, float y) +{ + GLtk::Root *root = obj.find_ancestor(); + if(root) + { + const GLtk::Geometry &rgeom = root->get_geometry(); + obj.set_position(x*(rgeom.w-obj.geom.w), y*(rgeom.h-obj.geom.h)); + } +} diff --git a/source/engineer/dynamicdialog.h b/source/engineer/dynamicdialog.h index 0bf1996..3c17442 100644 --- a/source/engineer/dynamicdialog.h +++ b/source/engineer/dynamicdialog.h @@ -7,6 +7,16 @@ class UserInterface; class DynamicDialog: public Msp::GLtk::Dialog { +public: + class StateLoader: public Msp::DataFile::ObjectLoader + { + public: + StateLoader(DynamicDialog &); + + private: + void position(float, float); + }; + protected: UserInterface &ui; @@ -14,7 +24,10 @@ protected: public: virtual ~DynamicDialog(); - virtual void update() = 0; + virtual void update() { }; + virtual bool save_state(Msp::DataFile::Statement &) const { return false; } +protected: + void save_position(std::list &) const; }; #endif diff --git a/source/engineer/engineer.cpp b/source/engineer/engineer.cpp index 7327d6b..1825809 100644 --- a/source/engineer/engineer.cpp +++ b/source/engineer/engineer.cpp @@ -75,6 +75,9 @@ Engineer::Engineer(int argc, char **argv): if(FS::exists(options.state_fn)) DataFile::load(layout, options.state_fn); + if(FS::exists(options.uistate_fn)) + DataFile::load(ui, options.uistate_fn); + if(options.network) { server = new Server(layout); @@ -111,6 +114,8 @@ Engineer::~Engineer() FS::rename(options.state_fn+".tmp", options.state_fn); } + ui.save_state(options.uistate_fn); + layout.get_driver().halt(true); layout.get_driver().flush(); diff --git a/source/engineer/options.cpp b/source/engineer/options.cpp index 7eabb8e..0108ba5 100644 --- a/source/engineer/options.cpp +++ b/source/engineer/options.cpp @@ -27,6 +27,7 @@ Options::Options(int argc, char **argv): getopt.add_option( "sim-speed", sim_speed, GetOpt::REQUIRED_ARG); getopt.add_option('n', "network", network, GetOpt::NO_ARG); getopt.add_option( "state", state_fn, GetOpt::REQUIRED_ARG); + getopt.add_option( "uistate", uistate_fn, GetOpt::REQUIRED_ARG); getopt.add_argument("layout", layout_fn, GetOpt::REQUIRED_ARG); getopt(argc, argv); @@ -43,4 +44,7 @@ Options::Options(int argc, char **argv): if(state_fn.empty()) state_fn = FS::basepart(layout_fn)+".state"; + + if(uistate_fn.empty()) + uistate_fn = FS::basepart(layout_fn)+".uistate"; } diff --git a/source/engineer/options.h b/source/engineer/options.h index f64cc78..652e1fc 100644 --- a/source/engineer/options.h +++ b/source/engineer/options.h @@ -15,6 +15,7 @@ struct Options float sim_speed; std::string layout_fn; std::string state_fn; + std::string uistate_fn; Options(int, char **); }; diff --git a/source/engineer/telemetrydialog.cpp b/source/engineer/telemetrydialog.cpp index 09bddbc..a1652b4 100644 --- a/source/engineer/telemetrydialog.cpp +++ b/source/engineer/telemetrydialog.cpp @@ -51,3 +51,11 @@ void TelemetryDialog::update() i->label->set_text(text); } } + +bool TelemetryDialog::save_state(DataFile::Statement &st) const +{ + st.keyword = "telemetrydialog"; + save_position(st.sub); + + return true; +} diff --git a/source/engineer/telemetrydialog.h b/source/engineer/telemetrydialog.h index 876ed1b..b9bd1c8 100644 --- a/source/engineer/telemetrydialog.h +++ b/source/engineer/telemetrydialog.h @@ -21,7 +21,8 @@ private: public: TelemetryDialog(Engineer &); - void update(); + virtual void update(); + virtual bool save_state(Msp::DataFile::Statement &) const; }; #endif diff --git a/source/engineer/traindialog.cpp b/source/engineer/traindialog.cpp index 6aa469a..985d4c9 100644 --- a/source/engineer/traindialog.cpp +++ b/source/engineer/traindialog.cpp @@ -9,6 +9,7 @@ #include "libr2c2/layout.h" #include "libr2c2/trainstatus.h" #include "controlpanel.h" +#include "engineer.h" #include "routerpanel.h" #include "timetablepanel.h" #include "traindialog.h" @@ -19,6 +20,7 @@ using namespace Msp; using namespace R2C2; TrainDialog::TrainDialog(Engineer &e, R2C2::Train &t): + DynamicDialog(e.get_user_interface()), engineer(e), train(t), updating(false) @@ -149,3 +151,25 @@ void TrainDialog::toggle_panel(bool show, GLtk::Panel *panel) { panel->set_visible(show); } + +bool TrainDialog::save_state(DataFile::Statement &st) const +{ + st.keyword = "traindialog"; + st.append(train.get_address()); + st.sub.push_back((DataFile::Statement("expanded"), pnl_expander->is_visible())); + save_position(st.sub); + + return true; +} + + +TrainDialog::StateLoader::StateLoader(TrainDialog &td): + DataFile::DerivedObjectLoader(td) +{ + add("expanded", &StateLoader::expanded); +} + +void TrainDialog::StateLoader::expanded(bool e) +{ + obj.set_expanded(e); +} diff --git a/source/engineer/traindialog.h b/source/engineer/traindialog.h index 3d6d143..64ddb96 100644 --- a/source/engineer/traindialog.h +++ b/source/engineer/traindialog.h @@ -2,16 +2,26 @@ #define TRAINDIALOG_H_ #include -#include #include #include #include #include "libr2c2/train.h" +#include "dynamicdialog.h" class Engineer; -class TrainDialog: public Msp::GLtk::Dialog, public sigc::trackable +class TrainDialog: public DynamicDialog, public sigc::trackable { +public: + class StateLoader: public Msp::DataFile::DerivedObjectLoader + { + public: + StateLoader(TrainDialog &); + + private: + void expanded(bool); + }; + private: Engineer &engineer; R2C2::Train &train; @@ -39,6 +49,9 @@ private: void expand_clicked(); void set_expanded(bool); void toggle_panel(bool, Msp::GLtk::Panel *); + +public: + virtual bool save_state(Msp::DataFile::Statement &) const; }; #endif diff --git a/source/engineer/trainlistdialog.cpp b/source/engineer/trainlistdialog.cpp index a29bc30..5e3c50b 100644 --- a/source/engineer/trainlistdialog.cpp +++ b/source/engineer/trainlistdialog.cpp @@ -30,6 +30,7 @@ public: TrainListDialog::TrainListDialog(Engineer &e): + DynamicDialog(e.get_user_interface()), engineer(e), layout(engineer.get_layout()) { @@ -135,6 +136,14 @@ void TrainListDialog::train_name_changed(Train &train) trains.refresh(&train); } +bool TrainListDialog::save_state(DataFile::Statement &st) const +{ + st.keyword = "trainlistdialog"; + save_position(st.sub); + + return true; +} + TrainItem::TrainItem(ValueType train) { diff --git a/source/engineer/trainlistdialog.h b/source/engineer/trainlistdialog.h index 9403d2f..e73a6bb 100644 --- a/source/engineer/trainlistdialog.h +++ b/source/engineer/trainlistdialog.h @@ -2,14 +2,14 @@ #define TRAINLISTDIALOG_H_ #include -#include #include #include #include "libr2c2/layout.h" +#include "dynamicdialog.h" class Engineer; -class TrainListDialog: public Msp::GLtk::Dialog, public sigc::trackable +class TrainListDialog: public DynamicDialog, public sigc::trackable { private: Engineer &engineer; @@ -31,6 +31,9 @@ private: void train_added(R2C2::Train &); void train_removed(R2C2::Train &); void train_name_changed(R2C2::Train &); + +public: + virtual bool save_state(Msp::DataFile::Statement &) const; }; #endif diff --git a/source/engineer/userinterface.cpp b/source/engineer/userinterface.cpp index aec54ad..8eadecc 100644 --- a/source/engineer/userinterface.cpp +++ b/source/engineer/userinterface.cpp @@ -1,9 +1,13 @@ +#include #include #include +#include "clockdialog.h" #include "departuresdialog.h" #include "engineer.h" #include "newtraindialog.h" +#include "telemetrydialog.h" #include "traindialog.h" +#include "trainlistdialog.h" #include "userinterface.h" using namespace std; @@ -68,7 +72,7 @@ void UserInterface::show_train(Train &train) void UserInterface::show_zone(Zone &zone) { - DeparturesDialog *dlg = new DeparturesDialog(engineer.get_layout(), zone.get_group()); + DeparturesDialog *dlg = new DeparturesDialog(engineer, zone.get_group()); root.add(*dlg); } @@ -106,3 +110,47 @@ void UserInterface::render() const { root.render(); } + +void UserInterface::save_state(const string &fn) const +{ + IO::BufferedFile out(fn, IO::M_WRITE); + DataFile::Writer writer(out); + + for(set::const_iterator i=dyn_dialogs.begin(); i!=dyn_dialogs.end(); ++i) + { + DataFile::Statement st; + if((*i)->save_state(st)) + writer.write(st); + } +} + + +UserInterface::Loader::Loader(UserInterface &ui): + DataFile::ObjectLoader(ui) +{ + add("clockdialog", &Loader::basic_dialog); + add("departuresdialog", &Loader::basic_dialog); + add("telemetrydialog", &Loader::basic_dialog); + add("traindialog", &Loader::traindialog); + add("trainlistdialog", &Loader::basic_dialog); +} + +template +void UserInterface::Loader::dialog(T &dlg) +{ + obj.root.add(dlg); + typename T::StateLoader ldr(dlg); + load_sub_with(ldr); +} + +template +void UserInterface::Loader::basic_dialog() +{ + dialog(*(new T(obj.engineer))); +} + +void UserInterface::Loader::traindialog(unsigned a) +{ + Train &train = obj.engineer.get_layout().get_train(a); + dialog(*(new TrainDialog(obj.engineer, train))); +} diff --git a/source/engineer/userinterface.h b/source/engineer/userinterface.h index 1df5388..6c96738 100644 --- a/source/engineer/userinterface.h +++ b/source/engineer/userinterface.h @@ -12,6 +12,22 @@ class DynamicDialog; class UserInterface { +public: + class Loader: public Msp::DataFile::ObjectLoader + { + public: + Loader(UserInterface &); + + private: + template + void dialog(T &); + + template + void basic_dialog(); + + void traindialog(unsigned); + }; + private: Engineer &engineer; Msp::GLtk::Resources resources; @@ -43,6 +59,8 @@ private: public: void tick(); void render() const; + + void save_state(const std::string &) const; }; #endif -- 2.43.0