]> git.tdb.fi Git - r2c2.git/blob - source/engineer/userinterface.cpp
Persist most dialogs across runs
[r2c2.git] / source / engineer / userinterface.cpp
1 #include <msp/datafile/writer.h>
2 #include <msp/gltk/floatingarrangement.h>
3 #include <msp/time/utils.h>
4 #include "clockdialog.h"
5 #include "departuresdialog.h"
6 #include "engineer.h"
7 #include "newtraindialog.h"
8 #include "telemetrydialog.h"
9 #include "traindialog.h"
10 #include "trainlistdialog.h"
11 #include "userinterface.h"
12
13 using namespace std;
14 using namespace Msp;
15 using namespace R2C2;
16
17 UserInterface::UserInterface(Engineer &e, Graphics::Window &window, Input::Keyboard &keyboard, Input::Mouse &mouse):
18         engineer(e),
19         resources("data/r2c2.res"),
20         root(resources, &window, &keyboard, &mouse),
21         main_wnd(engineer),
22         import_active(false)
23 {
24         GLtk::Layout *root_layout = new GLtk::Layout;
25         root.set_layout(root_layout);
26         root_layout->set_margin(GLtk::Sides());
27         root_arrangement = new GLtk::FloatingArrangement(*root_layout);
28         root.set_visible(true);
29
30         root.add(main_wnd);
31         main_wnd.autosize();
32         main_wnd.set_position(0, window.get_height()-main_wnd.get_geometry().h);
33
34         Layout &layout = engineer.get_layout();
35         if(layout.has_driver())
36         {
37                 Driver &driver = layout.get_driver();
38                 driver.signal_locomotive_detected.connect(sigc::mem_fun(this, &UserInterface::locomotive_detected));
39         }
40
41         engineer.get_layout().signal_emergency.connect(sigc::hide<0>(sigc::mem_fun(this, &UserInterface::set_status)));
42 }
43
44 UserInterface::~UserInterface()
45 {
46         while(!dyn_dialogs.empty())
47                 delete *dyn_dialogs.begin();
48         delete root_arrangement;
49 }
50
51 void UserInterface::set_status(const string &text)
52 {
53         main_wnd.set_status_text(text);
54         status_timeout = Time::now()+10*Time::sec;
55 }
56
57 void UserInterface::add_dynamic_dialog(DynamicDialog &dd)
58 {
59         dyn_dialogs.insert(&dd);
60 }
61
62 void UserInterface::remove_dynamic_dialog(DynamicDialog &dd)
63 {
64         dyn_dialogs.erase(&dd);
65 }
66
67 void UserInterface::show_train(Train &train)
68 {
69         TrainDialog *dlg = new TrainDialog(engineer, train);
70         root.add(*dlg);
71 }
72
73 void UserInterface::show_zone(Zone &zone)
74 {
75         DeparturesDialog *dlg = new DeparturesDialog(engineer, zone.get_group());
76         root.add(*dlg);
77 }
78
79 void UserInterface::locomotive_detected(const Driver::DetectedLocomotive &loco)
80 {
81         if(!import_active)
82         {
83                 NewTrainDialog *dlg = new NewTrainDialog(engineer);
84                 dlg->prefill(loco);
85                 dlg->signal_response.connect(sigc::mem_fun(this, &UserInterface::import_finished));
86                 root.add(*dlg);
87                 import_active = true;
88         }
89 }
90
91 void UserInterface::import_finished(int)
92 {
93         import_active = false;
94 }
95
96 void UserInterface::tick()
97 {
98         Time::TimeStamp t = Time::now();
99         if(status_timeout && t>status_timeout)
100         {
101                 main_wnd.set_status_text(string());
102                 status_timeout = Time::TimeStamp();
103         }
104
105         for(set<DynamicDialog *>::iterator i=dyn_dialogs.begin(); i!=dyn_dialogs.end(); ++i)
106                 (*i)->update();
107 }
108
109 void UserInterface::render() const
110 {
111         root.render();
112 }
113
114 void UserInterface::save_state(const string &fn) const
115 {
116         IO::BufferedFile out(fn, IO::M_WRITE);
117         DataFile::Writer writer(out);
118
119         for(set<DynamicDialog *>::const_iterator i=dyn_dialogs.begin(); i!=dyn_dialogs.end(); ++i)
120         {
121                 DataFile::Statement st;
122                 if((*i)->save_state(st))
123                         writer.write(st);
124         }
125 }
126
127
128 UserInterface::Loader::Loader(UserInterface &ui):
129         DataFile::ObjectLoader<UserInterface>(ui)
130 {
131         add("clockdialog", &Loader::basic_dialog<ClockDialog>);
132         add("departuresdialog", &Loader::basic_dialog<DeparturesDialog>);
133         add("telemetrydialog", &Loader::basic_dialog<TelemetryDialog>);
134         add("traindialog", &Loader::traindialog);
135         add("trainlistdialog", &Loader::basic_dialog<TrainListDialog>);
136 }
137
138 template<typename T>
139 void UserInterface::Loader::dialog(T &dlg)
140 {
141         obj.root.add(dlg);
142         typename T::StateLoader ldr(dlg);
143         load_sub_with(ldr);
144 }
145
146 template<typename T>
147 void UserInterface::Loader::basic_dialog()
148 {
149         dialog(*(new T(obj.engineer)));
150 }
151
152 void UserInterface::Loader::traindialog(unsigned a)
153 {
154         Train &train = obj.engineer.get_layout().get_train(a);
155         dialog(*(new TrainDialog(obj.engineer, train)));
156 }