]> git.tdb.fi Git - r2c2.git/commitdiff
Persist most dialogs across runs
authorMikko Rasa <tdb@tdb.fi>
Fri, 3 Apr 2015 22:42:35 +0000 (01:42 +0300)
committerMikko Rasa <tdb@tdb.fi>
Fri, 3 Apr 2015 22:42:35 +0000 (01:42 +0300)
17 files changed:
source/engineer/clockdialog.cpp
source/engineer/clockdialog.h
source/engineer/departuresdialog.cpp
source/engineer/departuresdialog.h
source/engineer/dynamicdialog.cpp
source/engineer/dynamicdialog.h
source/engineer/engineer.cpp
source/engineer/options.cpp
source/engineer/options.h
source/engineer/telemetrydialog.cpp
source/engineer/telemetrydialog.h
source/engineer/traindialog.cpp
source/engineer/traindialog.h
source/engineer/trainlistdialog.cpp
source/engineer/trainlistdialog.h
source/engineer/userinterface.cpp
source/engineer/userinterface.h

index ba73a5ec0fbc4ea8441134fae83080e4318c2a0e..c348de2d7ccf6cbeea013bb2637c302500bd813f 100644 (file)
@@ -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;
+}
index a1a1f724fd6e03ffcf0d519d1ad3f49ec9c99956..48dfc70c21f5d335aa25d848a588fba785e660f9 100644 (file)
@@ -1,15 +1,15 @@
 #ifndef CLOCKDIALOG_H_
 #define CLOCKDIALOG_H_
 
-#include <msp/gltk/dialog.h>
 #include <msp/gltk/entry.h>
 #include <msp/gltk/indicator.h>
 #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
index a1a31121447a7e825dc75a628fa51f1d59850934..c5f1b8b07821a9935ed8e4bab5b3c4d4aa3d115e 100644 (file)
@@ -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<DeparturesDialog, DynamicDialog::StateLoader>(dd)
+{
+       add("group", &StateLoader::group);
+}
+
+void DeparturesDialog::StateLoader::group(const string &g)
+{
+       obj.set_group(g);
+}
index 3b7b2ce11fb6da9144f376da68e06dfac3976b8e..bbc8246bdfe46b79d612913af12336bd832f3c07 100644 (file)
@@ -1,13 +1,25 @@
 #ifndef DEPARTURESDIALOG_H_
 #define DEPARTURESDIALOG_H_
 
-#include <msp/gltk/dialog.h>
 #include <msp/gltk/dropdown.h>
 #include <msp/gltk/label.h>
 #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<DeparturesDialog, DynamicDialog::StateLoader>
+       {
+       public:
+               StateLoader(DeparturesDialog &);
+
+       private:
+               void group(const std::string &);
+       };
+
 private:
        struct Row
        {
@@ -29,13 +41,16 @@ private:
        std::vector<Row> 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
index 6d9afb4861432c208a305ce673a16d6f0a0b68b8..4e3312fbe8ad5a6813b7b6cfd39a1583771f518f 100644 (file)
@@ -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<DataFile::Statement> &st) const
+{
+       GLtk::Root *root = find_ancestor<GLtk::Root>();
+       if(root)
+       {
+               const GLtk::Geometry &rgeom = root->get_geometry();
+               float x = static_cast<float>(geom.x)/(rgeom.w-geom.w);
+               float y = static_cast<float>(geom.y)/(rgeom.h-geom.h);
+               st.push_back((DataFile::Statement("position"), x, y));
+       }
+}
+
+
+DynamicDialog::StateLoader::StateLoader(DynamicDialog &dd):
+       DataFile::ObjectLoader<DynamicDialog>(dd)
+{
+       add("position", &StateLoader::position);
+}
+
+void DynamicDialog::StateLoader::position(float x, float y)
+{
+       GLtk::Root *root = obj.find_ancestor<GLtk::Root>();
+       if(root)
+       {
+               const GLtk::Geometry &rgeom = root->get_geometry();
+               obj.set_position(x*(rgeom.w-obj.geom.w), y*(rgeom.h-obj.geom.h));
+       }
+}
index 0bf1996b2aae8e757679efbe9a71522e36f0f98c..3c174428083714b0cf12e25b3c916b33b451235f 100644 (file)
@@ -7,6 +7,16 @@ class UserInterface;
 
 class DynamicDialog: public Msp::GLtk::Dialog
 {
+public:
+       class StateLoader: public Msp::DataFile::ObjectLoader<DynamicDialog>
+       {
+       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<Msp::DataFile::Statement> &) const;
 };
 
 #endif
index 7327d6bf901ade03795f5ba45bcb7acc5bcf6fa4..18258090c7755213f8cec76226418fd32e33ce27 100644 (file)
@@ -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();
 
index 7eabb8e2d288d2554c8fc254511ac775bba34a91..0108ba5925e44d376d3244cc2418133e3e20578b 100644 (file)
@@ -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";
 }
index f64cc78fe006e7772e3c1cf6912a9569a17ef998..652e1fcaa6a459f310ccef83fea1415c02845380 100644 (file)
@@ -15,6 +15,7 @@ struct Options
        float sim_speed;
        std::string layout_fn;
        std::string state_fn;
+       std::string uistate_fn;
 
        Options(int, char **);
 };
index 09bddbc9857c7a4b43f53e165185d5eca524221e..a1652b4bebd1dd572494f916f56e65a6f5ab7f44 100644 (file)
@@ -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;
+}
index 876ed1b481daf6a7c70d571f922a7793a11c1de3..b9bd1c8a050f406bfabceb6121fe288ec33113bd 100644 (file)
@@ -21,7 +21,8 @@ private:
 public:
        TelemetryDialog(Engineer &);
 
-       void update();
+       virtual void update();
+       virtual bool save_state(Msp::DataFile::Statement &) const;
 };
 
 #endif
index 6aa469a37bc7edc85403c694c2b321f9c2e51186..985d4c94ea09eca8bb358e516c19b5641b58619e 100644 (file)
@@ -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<TrainDialog, DynamicDialog::StateLoader>(td)
+{
+       add("expanded", &StateLoader::expanded);
+}
+
+void TrainDialog::StateLoader::expanded(bool e)
+{
+       obj.set_expanded(e);
+}
index 3d6d1438895544ba6bb8780823c8fc8fa3b81c08..64ddb96a05851b308bbc5a5784a329dbae1d981b 100644 (file)
@@ -2,16 +2,26 @@
 #define TRAINDIALOG_H_
 
 #include <msp/gltk/button.h>
-#include <msp/gltk/dialog.h>
 #include <msp/gltk/hslider.h>
 #include <msp/gltk/label.h>
 #include <msp/gltk/toggle.h>
 #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<TrainDialog, DynamicDialog::StateLoader>
+       {
+       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
index a29bc304c34cb822076bcdd175ea2cd755c2b482..5e3c50b6873e827c0d3ba8b77ce14104e99e6ede 100644 (file)
@@ -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)
 {
index 9403d2f3fe50ac2cb2ba1c9062eb2e3a55e5c8bd..e73a6bbdaeb02478df214bf55a4217fb300de27c 100644 (file)
@@ -2,14 +2,14 @@
 #define TRAINLISTDIALOG_H_
 
 #include <sigc++/trackable.h>
-#include <msp/gltk/dialog.h>
 #include <msp/gltk/list.h>
 #include <msp/gltk/listdata.h>
 #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
index aec54ad041331ef79ab44f0ba8090c74b9fa2db3..8eadecc8ed72d67fd4be71f97444211ed82670ef 100644 (file)
@@ -1,9 +1,13 @@
+#include <msp/datafile/writer.h>
 #include <msp/gltk/floatingarrangement.h>
 #include <msp/time/utils.h>
+#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<DynamicDialog *>::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<UserInterface>(ui)
+{
+       add("clockdialog", &Loader::basic_dialog<ClockDialog>);
+       add("departuresdialog", &Loader::basic_dialog<DeparturesDialog>);
+       add("telemetrydialog", &Loader::basic_dialog<TelemetryDialog>);
+       add("traindialog", &Loader::traindialog);
+       add("trainlistdialog", &Loader::basic_dialog<TrainListDialog>);
+}
+
+template<typename T>
+void UserInterface::Loader::dialog(T &dlg)
+{
+       obj.root.add(dlg);
+       typename T::StateLoader ldr(dlg);
+       load_sub_with(ldr);
+}
+
+template<typename T>
+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)));
+}
index 1df53887622842230bd719e44038633f3d1e3399..6c9673809e81f4c1b9f77a7d8ad5efa630da56c7 100644 (file)
@@ -12,6 +12,22 @@ class DynamicDialog;
 
 class UserInterface
 {
+public:
+       class Loader: public Msp::DataFile::ObjectLoader<UserInterface>
+       {
+       public:
+               Loader(UserInterface &);
+
+       private:
+               template<typename T>
+               void dialog(T &);
+
+               template<typename T>
+               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