]> git.tdb.fi Git - r2c2.git/blob - source/engineer/traindialog.cpp
Persist most dialogs across runs
[r2c2.git] / source / engineer / traindialog.cpp
1 #include <msp/core/maputils.h>
2 #include <msp/core/raii.h>
3 #include <msp/gltk/part.h>
4 #include <msp/gltk/root.h>
5 #include <msp/gltk/stack.h>
6 #include <msp/strings/format.h>
7 #include "libr2c2/aicontrol.h"
8 #include "libr2c2/catalogue.h"
9 #include "libr2c2/layout.h"
10 #include "libr2c2/trainstatus.h"
11 #include "controlpanel.h"
12 #include "engineer.h"
13 #include "routerpanel.h"
14 #include "timetablepanel.h"
15 #include "traindialog.h"
16 #include "vehiclespanel.h"
17
18 using namespace std;
19 using namespace Msp;
20 using namespace R2C2;
21
22 TrainDialog::TrainDialog(Engineer &e, R2C2::Train &t):
23         DynamicDialog(e.get_user_interface()),
24         engineer(e),
25         train(t),
26         updating(false)
27 {
28         Loader::WidgetMap widgets;
29         DataFile::load(*this, "data/traindialog.ui", widgets);
30
31         lbl_title = dynamic_cast<GLtk::Label *>(get_item(widgets, "lbl_title"));
32         lbl_title->set_text(t.get_name());
33
34         btn_expand = dynamic_cast<GLtk::Button *>(get_item(widgets, "btn_expand"));
35         btn_expand->signal_clicked.connect(sigc::mem_fun(this, &TrainDialog::expand_clicked));
36         lbl_speed = dynamic_cast<GLtk::Label *>(get_item(widgets, "lbl_speed"));
37         sld_speed = dynamic_cast<GLtk::Slider *>(get_item(widgets, "sld_speed"));
38         float max_speed = train.get_maximum_speed();
39         if(max_speed>0)
40                 sld_speed->set_range(0, max_speed*3.6/train.get_layout().get_catalogue().get_scale());
41         sld_speed->signal_value_changed.connect(sigc::mem_fun(this, &TrainDialog::ui_speed_changed));
42         tgl_forward = dynamic_cast<GLtk::Toggle *>(get_item(widgets, "tgl_forward"));
43         tgl_forward->signal_toggled.connect(sigc::mem_fun(this, &TrainDialog::ui_forward_toggled));
44         lbl_status = dynamic_cast<GLtk::Label *>(get_item(widgets, "lbl_status"));
45         pnl_expander = dynamic_cast<GLtk::Panel *>(get_item(widgets, "pnl_expander"));
46
47         Panel *pnl;
48
49         GLtk::Stack stack(*pnl_expander->get_layout());
50         stack.arrange(*get_item(widgets, "lbl_detail_placeholder"));
51
52         pnl_expander->add(*(pnl = new VehiclesPanel(train)));
53         panels.push_back(pnl);
54         dynamic_cast<GLtk::Toggle *>(get_item(widgets, "tgl_vehicles"))->signal_toggled.connect(sigc::bind(sigc::mem_fun(this, &TrainDialog::toggle_panel), pnl));
55
56         pnl_expander->add(*(pnl = new ControlPanel(engineer, train)));
57         pnl->set_visible(false);
58         panels.push_back(pnl);
59         dynamic_cast<GLtk::Toggle *>(get_item(widgets, "tgl_control"))->signal_toggled.connect(sigc::bind(sigc::mem_fun(this, &TrainDialog::toggle_panel), pnl));
60
61         pnl_expander->add(*(pnl = new RouterPanel(engineer, train)));
62         pnl->set_visible(false);
63         panels.push_back(pnl);
64         dynamic_cast<GLtk::Toggle *>(get_item(widgets, "tgl_router"))->signal_toggled.connect(sigc::bind(sigc::mem_fun(this, &TrainDialog::toggle_panel), pnl));
65
66         pnl_expander->add(*(pnl = new TimetablePanel(engineer, train)));
67         pnl->set_visible(false);
68         panels.push_back(pnl);
69         dynamic_cast<GLtk::Toggle *>(get_item(widgets, "tgl_timetable"))->signal_toggled.connect(sigc::bind(sigc::mem_fun(this, &TrainDialog::toggle_panel), pnl));
70
71         AIControl *control = train.get_ai_of_type<AIControl>();
72         if(!control)
73                 control = new AIControl(train);
74         update_forward(!control->get_reverse());
75         update_speed_display(control->get_target_speed());
76
77         TrainStatus *status = train.get_ai_of_type<TrainStatus>();
78         if(!status)
79                 status = new TrainStatus(train);
80         lbl_status->set_text(status->get_status());
81
82         train.signal_ai_event.connect(sigc::mem_fun(this, &TrainDialog::ai_event));
83 }
84
85 void TrainDialog::autosize_special(const GLtk::Part &part, GLtk::Geometry &ageom) const
86 {
87         GLtk::Dialog::autosize_special(part, ageom);
88
89         if(part.get_name()=="children")
90         {
91                 GLtk::Geometry egeom;
92                 pnl_expander->autosize(egeom);
93                 const GLtk::Sides &margin = layout->get_margin();
94                 ageom.w = max(ageom.w, margin.left+margin.right+egeom.w);
95         }
96 }
97
98 void TrainDialog::ai_event(TrainAI &, const TrainAI::Message &msg)
99 {
100         if(msg.type=="status-changed")
101                 lbl_status->set_text(msg.value.value<string>());
102         else if(msg.type=="target-speed-changed")
103                 update_speed_display(msg.value.value<float>());
104         else if(msg.type=="reverse-changed")
105                 update_forward(!msg.value.value<bool>());
106 }
107
108 void TrainDialog::update_speed_display(float speed)
109 {
110         SetFlag setf(updating);
111         float scale_speed = speed*3.6/train.get_layout().get_catalogue().get_scale();
112         lbl_speed->set_text(format("%3.0f", scale_speed));
113         sld_speed->set_value(scale_speed);
114 }
115
116 void TrainDialog::ui_speed_changed(double value)
117 {
118         if(!updating)
119         {
120                 float real_speed = value/3.6*train.get_layout().get_catalogue().get_scale();
121                 train.ai_message(TrainAI::Message("set-target-speed", real_speed));
122         }
123 }
124
125 void TrainDialog::update_forward(bool value)
126 {
127         SetFlag setf(updating);
128         tgl_forward->set_value(value);
129 }
130
131 void TrainDialog::ui_forward_toggled(bool value)
132 {
133         if(!updating)
134                 train.ai_message(TrainAI::Message("set-reverse", !value));
135 }
136
137 void TrainDialog::expand_clicked()
138 {
139         set_expanded(!pnl_expander->is_visible());
140 }
141
142 void TrainDialog::set_expanded(bool e)
143 {
144         pnl_expander->set_visible(e);
145         btn_expand->set_style(e ? "arrow_up" : "arrow_down");
146         signal_autosize_changed.emit();
147         find_ancestor<GLtk::Root>()->get_layout()->update();
148 }
149
150 void TrainDialog::toggle_panel(bool show, GLtk::Panel *panel)
151 {
152         panel->set_visible(show);
153 }
154
155 bool TrainDialog::save_state(DataFile::Statement &st) const
156 {
157         st.keyword = "traindialog";
158         st.append(train.get_address());
159         st.sub.push_back((DataFile::Statement("expanded"), pnl_expander->is_visible()));
160         save_position(st.sub);
161
162         return true;
163 }
164
165
166 TrainDialog::StateLoader::StateLoader(TrainDialog &td):
167         DataFile::DerivedObjectLoader<TrainDialog, DynamicDialog::StateLoader>(td)
168 {
169         add("expanded", &StateLoader::expanded);
170 }
171
172 void TrainDialog::StateLoader::expanded(bool e)
173 {
174         obj.set_expanded(e);
175 }