--- /dev/null
+style "group";
+layout
+{
+ margin
+ {
+ horizontal 0;
+ vertical 0;
+ };
+};
+
+column
+{
+ row
+ {
+ label "lbl1"
+ {
+ text "Protocol:";
+ };
+
+ label "lbl_protocol";
+ };
+
+ row
+ {
+ label "lbl2"
+ {
+ text "Address:";
+ };
+ constraint COPY_WIDTH "lbl1";
+
+ label "lbl_address";
+ };
+
+ panel "pnl_functions"
+ {
+ style "group";
+ layout
+ {
+ margin
+ {
+ horizontal 0;
+ vertical 0;
+ };
+ };
+ };
+
+ row
+ {
+ button "btn_place"
+ {
+ text "Place";
+ };
+
+ button "btn_take"
+ {
+ text "Take";
+ };
+
+ button "btn_view"
+ {
+ text "View";
+ };
+ };
+};
--- /dev/null
+layout
+{
+ margin
+ {
+ top 2;
+ horizontal 8;
+ bottom 6;
+ };
+};
+
+column
+{
+ stack
+ {
+ label "lbl_title"
+ {
+ text "Railroad Computer Control";
+ };
+
+ draghandle "";
+ };
+
+ row
+ {
+ indicator "ind_off"
+ {
+ style "red";
+ };
+
+ indicator "ind_on"
+ {
+ style "green";
+ };
+
+ indicator "ind_halt";
+ };
+
+ row
+ {
+ button "btn_off"
+ {
+ style "red";
+ text "Off";
+ };
+ constraint ALIGN_LEFT "ind_off";
+ constraint COPY_WIDTH "ind_off";
+
+ button "btn_on"
+ {
+ style "green";
+ text "On";
+ };
+ constraint ALIGN_LEFT "ind_on";
+ constraint COPY_WIDTH "ind_on";
+
+ button "btn_halt"
+ {
+ text "Halt";
+ };
+ constraint ALIGN_LEFT "ind_halt";
+ constraint COPY_WIDTH "ind_halt";
+
+ button "btn_trains"
+ {
+ text "Trains";
+ };
+
+ split;
+
+ button "btn_quit"
+ {
+ style "red";
+ text "Quit";
+ };
+ };
+
+ label "lbl_status"
+ {
+ style "digital";
+ };
+};
--- /dev/null
+layout
+{
+ margin
+ {
+ top 2;
+ horizontal 8;
+ bottom 6;
+ };
+};
+
+column
+{
+ row
+ {
+ label "lbl_title"
+ {
+ text "New train";
+ };
+
+ split;
+
+ action_button "btn_close" 0
+ {
+ style "red_cross";
+ };
+ };
+
+ row
+ {
+ label "lbl_protocol"
+ {
+ text "Protocol";
+ };
+
+ dropdown "drp_protocol";
+ };
+
+ row
+ {
+ label "lbl_address"
+ {
+ text "Address:";
+ };
+ constraint COPY_WIDTH "lbl_protocol";
+
+ entry "ent_address"
+ {
+ edit_size 8 1;
+ };
+ };
+
+ row
+ {
+ label "lbl_name"
+ {
+ text "Name:";
+ };
+ constraint COPY_WIDTH "lbl_address";
+
+ entry "ent_name"
+ {
+ edit_size 30 1;
+ };
+ };
+
+ row
+ {
+ label "lbl_loco_type"
+ {
+ text "Locomotive:";
+ };
+ constraint COPY_WIDTH "lbl_name";
+
+ dropdown "drp_loco_type"
+ {
+ };
+ };
+
+ row
+ {
+ split;
+
+ action_button "btn_ok" 1
+ {
+ style "green";
+ text "Ok";
+ };
+ };
+};
+
+draghandle "";
+expand true false;
+constraint COPY_HEIGHT "lbl_title";
+constraint LEFT_OF "btn_close";
--- /dev/null
+layout
+{
+ margin
+ {
+ top 2;
+ horizontal 8;
+ bottom 6;
+ };
+};
+
+column
+{
+ row
+ {
+ label "lbl_title"
+ {
+ text "Add vehicle";
+ };
+
+ split;
+
+ action_button "btn_close" 0
+ {
+ style "red_cross";
+ };
+ };
+
+ label "lbl_target";
+
+ row
+ {
+ panel ""
+ {
+ style "group";
+
+ layout
+ {
+ margin
+ {
+ horizontal 0;
+ vertical 0;
+ };
+
+ row_spacing 0;
+ };
+
+ column
+ {
+ toggle "tgl_loco_types"
+ {
+ style "pointer_left";
+ text "Loco";
+ exclusive true;
+ value true;
+ };
+
+ toggle "tgl_wagon_types"
+ {
+ style "pointer_left";
+ text "Wagn";
+ exclusive true;
+ };
+ };
+ };
+
+ stack
+ {
+ list "lst_loco_types"
+ {
+ view_size 10;
+ };
+
+ list "lst_wagon_types"
+ {
+ visible false;
+ };
+ };
+ };
+
+ row
+ {
+ button "btn_add"
+ {
+ text "Add";
+ };
+ };
+};
+
+draghandle "";
+constraint COPY_HEIGHT "lbl_title";
+constraint LEFT_OF "btn_close";
+expand true false;
--- /dev/null
+style "group";
+layout
+{
+ margin
+ {
+ horizontal 0;
+ vertical 0;
+ };
+};
+
+column
+{
+ label "lbl_route"
+ {
+ style "digital";
+ };
+ expand true false;
+
+ dropdown "drp_routes";
+
+ row
+ {
+ button "btn_goto"
+ {
+ text "GoTo";
+ };
+ };
+};
--- /dev/null
+layout
+{
+ margin
+ {
+ top 2;
+ horizontal 8;
+ bottom 6;
+ };
+};
+
+column
+{
+ row
+ {
+ label "lbl_title";
+
+ split;
+
+ button "btn_expand"
+ {
+ style "arrow_down";
+ };
+
+ action_button "btn_close" 0
+ {
+ style "red_cross";
+ };
+ };
+
+ row
+ {
+ label "lbl_speed"
+ {
+ style "digital";
+ text " 0";
+ };
+
+ hslider "sld_speed"
+ {
+ range 0 200;
+ step 5;
+ };
+ expand;
+
+ toggle "tgl_forward"
+ {
+ style "lever";
+ text "Fwd";
+ value true;
+ };
+ };
+
+ panel "pnl_expander"
+ {
+ layout
+ {
+ margin
+ {
+ horizontal 0;
+ vertical 0;
+ };
+ row_spacing 0;
+ };
+
+ style "group";
+ visible false;
+ row
+ {
+ column
+ {
+ toggle "tgl_vehicles"
+ {
+ text "Vehs";
+ style "pointer_left";
+ exclusive true;
+ value true;
+ };
+
+ toggle "tgl_control"
+ {
+ text "Ctrl";
+ style "pointer_left";
+ exclusive true;
+ };
+
+ toggle "tgl_router"
+ {
+ text "Rte";
+ style "pointer_left";
+ exclusive true;
+ };
+ };
+
+ label "lbl_detail_placeholder"
+ {
+ visible false;
+ };
+ expand;
+ };
+ };
+
+ label "lbl_status"
+ {
+ style "digital";
+ };
+ constraint FAR_BELOW "lbl_speed";
+};
+
+draghandle "";
+expand true false;
+constraint COPY_HEIGHT "lbl_title";
+constraint LEFT_OF "btn_expand";
--- /dev/null
+layout
+{
+ margin
+ {
+ top 2;
+ horizontal 8;
+ bottom 6;
+ };
+};
+
+column
+{
+ row
+ {
+ label "lbl_title"
+ {
+ text "Trains";
+ };
+
+ split;
+
+ action_button "btn_close" 0
+ {
+ style "red_cross";
+ };
+ };
+
+ list "lst_trains"
+ {
+ view_size 10;
+ };
+
+ row
+ {
+ button "btn_new"
+ {
+ text "New";
+ };
+
+ button "btn_show"
+ {
+ text "Show";
+ };
+ };
+};
+
+draghandle "";
+expand true false;
+constraint COPY_HEIGHT "lbl_title";
+constraint LEFT_OF "btn_close";
--- /dev/null
+layout
+{
+ margin
+ {
+ top 2;
+ horizontal 8;
+ bottom 6;
+ };
+};
+
+column
+{
+ row
+ {
+ label "lbl_title";
+
+ split;
+
+ action_button "btn_close" 0
+ {
+ style "red_cross";
+ };
+ };
+
+ row
+ {
+ column
+ {
+ toggle "tgl_forward"
+ {
+ text "Fwd";
+ value true;
+ };
+
+ panel "pnl_mode"
+ {
+ style "group";
+ layout
+ {
+ margin
+ {
+ horizontal 0;
+ vertical 0;
+ };
+ row_spacing 0;
+ };
+
+ column
+ {
+ toggle "tgl_roof"
+ {
+ style "pointer_left";
+ text "Roof";
+ exclusive true;
+ };
+
+ toggle "tgl_side"
+ {
+ style "pointer_left";
+ text "Side";
+ exclusive true;
+ value true;
+ };
+
+ toggle "tgl_head"
+ {
+ style "pointer_left";
+ text "Head";
+ exclusive true;
+ };
+ };
+ };
+ };
+
+ image "img_view";
+ };
+};
+
+draghandle "";
+expand true false;
+constraint COPY_HEIGHT "lbl_title";
+constraint LEFT_OF "btn_close";
--- /dev/null
+style "group";
+layout
+{
+ margin
+ {
+ horizontal 0;
+ vertical 0;
+ };
+};
+
+column
+{
+ list "lst_vehicles";
+ expand true true;
+
+ row
+ {
+ button "btn_add"
+ {
+ text "Add";
+ };
+
+ button "btn_remove"
+ {
+ text "Rem";
+ };
+ };
+};
shadow { right 1; bottom 1; };
};
+graphic "red_cross_button"
+{
+ texture "gui.png";
+ slice 74 2 13 14;
+ shadow { right 1; bottom 2; };
+};
+
+graphic "red_cross_button_pressed"
+{
+ texture "gui.png";
+ slice 89 3 13 13;
+ shadow { right 1; bottom 1; };
+};
+
style "button"
{
font_color 0 0 0;
};
};
+style "button-red_cross"
+{
+ part
+ {
+ graphic NORMAL "red_cross_button";
+ graphic ACTIVE "red_cross_button_pressed";
+ align 0.5 0.5;
+ fill 0.0 0.0;
+ };
+};
+
graphic "yellow_lamp"
{
texture "gui.png";
{
fill 0.0 0.0;
align 0.5 0.5;
- margin { top 1; };
+ margin { horizontal 4; top 2; bottom 1; };
};
};
{
align 0.5 1.0;
fill 0.0 0.0;
+ margin { bottom 10; };
};
part
part "slider"
{
graphic NORMAL "horizontal_knob";
+ align 0.0 0.5;
fill 0.0 0.0;
};
};
align 0.0 1.0;
};
};
+
+style "draghandle";
+
+graphic "pointer_down"
+{
+ texture "gui.png";
+ slice 98 36 13 14;
+ shadow { right 1; bottom 2; };
+};
+
+graphic "pointer_up"
+{
+ texture "gui.png";
+ slice 83 36 13 14;
+ shadow { right 1; bottom 2; };
+};
+
+graphic "pointer_left"
+{
+ texture "gui.png";
+ slice 83 21 13 14;
+ shadow { right 1; bottom 2; };
+};
+
+graphic "pointer_right"
+{
+ texture "gui.png";
+ slice 98 21 13 14;
+ shadow { right 1; bottom 2; };
+};
+
+style "toggle-pointer_left"
+{
+ font_color 0.0 0.0 0.0;
+
+ part "text"
+ {
+ align 0.0 0.5;
+ fill 0.0 0.0;
+ margin { vertical 2; right 4; left 2; };
+ };
+
+ part
+ {
+ graphic NORMAL "vertical_slot";
+ align 1.0 0.0;
+ fill 0.0 1.0;
+ };
+
+ part
+ {
+ graphic ACTIVE "pointer_left";
+ align 1.0 0.5;
+ fill 0.0 0.0;
+ };
+};
+
+graphic "lever_down"
+{
+ texture "gui.png";
+ slice 103 52 20 22;
+ shadow { right 3; bottom 4; };
+};
+
+graphic "lever_up"
+{
+ texture "gui.png";
+ slice 103 76 20 22;
+ shadow { right 3; bottom 4; };
+};
+
+style "toggle-lever"
+{
+ font_color 0.0 0.0 0.0;
+
+ part
+ {
+ align 0.5 0.5;
+ fill 0.0 0.0;
+ graphic NORMAL "lever_down";
+ graphic ACTIVE "lever_up";
+ };
+};
--- /dev/null
+#include <msp/core/maputils.h>
+#include <msp/core/raii.h>
+#include <msp/gltk/button.h>
+#include <msp/gltk/label.h>
+#include <msp/gltk/row.h>
+#include "libr2c2/vehicle.h"
+#include "controlpanel.h"
+#include "engineer.h"
+#include "trainview.h"
+
+using namespace std;
+using namespace Msp;
+using namespace R2C2;
+
+ControlPanel::ControlPanel(Engineer &e, Train &t):
+ engineer(e),
+ train(t),
+ updating(false)
+{
+ Loader::WidgetMap widgets;
+ DataFile::load(*this, "data/controlpanel.ui", widgets);
+
+ dynamic_cast<GLtk::Label *>(get_item(widgets, "lbl_protocol"))->set_text(train.get_protocol());
+ dynamic_cast<GLtk::Label *>(get_item(widgets, "lbl_address"))->set_text(lexical_cast<string>(train.get_address()));
+
+ dynamic_cast<GLtk::Button *>(get_item(widgets, "btn_place"))->signal_clicked.connect(sigc::mem_fun(this, &ControlPanel::place_clicked));
+ dynamic_cast<GLtk::Button *>(get_item(widgets, "btn_take"))->signal_clicked.connect(sigc::mem_fun(this, &ControlPanel::take_clicked));
+ dynamic_cast<GLtk::Button *>(get_item(widgets, "btn_view"))->signal_clicked.connect(sigc::mem_fun(this, &ControlPanel::view_clicked));
+
+ GLtk::Panel *pnl_functions = dynamic_cast<GLtk::Panel *>(get_item(widgets, "pnl_functions"));
+
+ const VehicleType::FunctionMap &funcs = train.get_vehicle(0).get_type().get_functions();
+ GLtk::Row row(*pnl_functions->get_layout());
+ for(VehicleType::FunctionMap::const_iterator i=funcs.begin(); i!=funcs.end(); ++i)
+ {
+ GLtk::Toggle *tgl = new GLtk::Toggle(i->second);
+ tgl->signal_toggled.connect(sigc::bind(sigc::mem_fun(this, &ControlPanel::ui_function_toggled), i->first));
+ pnl_functions->add(*tgl);
+ tgl_funcs[i->first] = tgl;
+ }
+
+ train.signal_function_changed.connect(sigc::mem_fun(this, &ControlPanel::train_function_changed));
+}
+
+void ControlPanel::ui_function_toggled(bool value, unsigned func)
+{
+ if(!updating)
+ train.set_function(func, value);
+}
+
+void ControlPanel::train_function_changed(unsigned func, bool value)
+{
+ SetFlag setf(updating);
+ map<unsigned, GLtk::Toggle *>::iterator i = tgl_funcs.find(func);
+ if(i!=tgl_funcs.end())
+ i->second->set_value(value);
+}
+
+void ControlPanel::place_clicked()
+{
+ pick_conn = engineer.signal_pick_done.connect(sigc::mem_fun(this, &ControlPanel::place_pick_done));
+ engineer.pick(true);
+}
+
+void ControlPanel::place_pick_done(Track *track, unsigned ep)
+{
+ pick_conn.disconnect();
+ train.place(TrackIter(track, ep).block_iter());
+}
+
+void ControlPanel::take_clicked()
+{
+ train.unplace();
+}
+
+void ControlPanel::view_clicked()
+{
+ GLtk::Container *root = parent;
+ while(root->get_parent())
+ root = root->get_parent();
+
+ TrainView *dlg = new TrainView(engineer, train);
+ root->add(*dlg);
+ dlg->autosize();
+}
--- /dev/null
+#ifndef CONTROLPANEL_H_
+#define CONTROLPANEL_H_
+
+#include <map>
+#include <msp/gltk/panel.h>
+#include <msp/gltk/toggle.h>
+#include "libr2c2/train.h"
+
+class Engineer;
+
+class ControlPanel: public Msp::GLtk::Panel
+{
+private:
+ Engineer &engineer;
+ R2C2::Train &train;
+ bool updating;
+ std::map<unsigned, Msp::GLtk::Toggle *> tgl_funcs;
+ sigc::connection pick_conn;
+
+public:
+ ControlPanel(Engineer &, R2C2::Train &);
+
+private:
+ void ui_function_toggled(bool, unsigned);
+ void train_function_changed(unsigned, bool);
+ void place_clicked();
+ void place_pick_done(R2C2::Track *, unsigned);
+ void take_clicked();
+ void view_clicked();
+};
+
+#endif
+++ /dev/null
-#include "dialog.h"
-
-using namespace Msp;
-
-Dialog::Dialog():
- stale(false)
-{
- add(*(btn_ok=new GLtk::Button("OK")));
- btn_ok->set_style("green");
- btn_ok->set_geometry(GLtk::Geometry(geom.w-40, 10, 30, 25));
- btn_ok->signal_clicked.connect(sigc::mem_fun(this, &Dialog::on_ok_clicked));
- btn_ok->signal_clicked.connect(signal_ok);
- btn_ok->signal_clicked.connect(sigc::mem_fun(this, &Dialog::dismiss));
-
- add(*(btn_cancel=new GLtk::Button("Cncl")));
- btn_cancel->set_style("red");
- btn_cancel->set_geometry(GLtk::Geometry(geom.w-80, 10, 30, 25));
- btn_cancel->signal_clicked.connect(signal_cancel);
- btn_cancel->signal_clicked.connect(sigc::mem_fun(this, &Dialog::dismiss));
-}
-
-void Dialog::button_release(int x, int y, unsigned btn)
-{
- Panel::button_release(x, y, btn);
- if(stale)
- delete this;
-}
-
-void Dialog::on_geometry_change()
-{
- btn_ok->set_geometry(GLtk::Geometry(geom.w-40, 10, 30, 25));
- btn_cancel->set_geometry(GLtk::Geometry(geom.w-80, 10, 30, 25));
-}
-
-void Dialog::dismiss()
-{
- stale = true;
-}
+++ /dev/null
-#ifndef DIALOG_H_
-#define DIALOG_H_
-
-#include <msp/gltk/button.h>
-#include <msp/gltk/panel.h>
-
-class Dialog: public Msp::GLtk::Panel
-{
-public:
- sigc::signal<void> signal_ok;
- sigc::signal<void> signal_cancel;
-
-protected:
- Msp::GLtk::Button *btn_ok;
- Msp::GLtk::Button *btn_cancel;
- bool stale;
-
- Dialog();
-
- virtual void button_release(int, int, unsigned);
- virtual void on_geometry_change();
-
- virtual void on_ok_clicked() { }
- void dismiss();
-};
-
-#endif
#include "3d/track.h"
#include "3d/vehicle.h"
#include "engineer.h"
-#include "mainpanel.h"
-#include "trainpanel.h"
-#include "trainproperties.h"
+#include "mainwindow.h"
+#include "traindialog.h"
#include "trainview.h"
using namespace std;
window.set_title("Railroad Engineer");
window.signal_close.connect(sigc::bind(sigc::mem_fun(this, &Engineer::exit), 0));
- root = new GLtk::Root(ui_res, window);
+ root = new GLtk::Root(ui_res, &window, &keyboard, &mouse);
mouse.signal_button_press.connect(sigc::bind_return(sigc::mem_fun(this, &Engineer::button_press), false));
mouse.signal_axis_motion.connect(sigc::bind_return(sigc::mem_fun(this, &Engineer::axis_motion), false));
root->set_visible(true);
- main_panel = new MainPanel(*this);
- root->add(*main_panel);
- main_panel->set_position(0, window.get_height()-main_panel->get_geometry().h);
- main_panel->set_visible(true);
+ main_wnd = new MainWindow(*this);
+ root->add(*main_wnd);
+ main_wnd->autosize();
+ main_wnd->set_position(0, window.get_height()-main_wnd->get_geometry().h);
overlay = new Overlay3D(ui_res.get_default_font());
void Engineer::set_status(const string &text)
{
- main_panel->set_status_text(text);
+ main_wnd->set_status_text(text);
status_timeout = Time::now()+10*Time::sec;
}
-void Engineer::rearrange_panels()
-{
- int y = main_panel->get_geometry().y;
- for(list<TrainPanel *>::iterator i=train_panels.begin(); i!=train_panels.end(); ++i)
- {
- y -= (*i)->get_geometry().h;
- (*i)->set_position(0, y);
- }
-}
-
void Engineer::add_train_view(TrainView &tv)
{
train_views.push_back(&tv);
if(status_timeout && Time::now()>status_timeout)
{
- main_panel->set_status_text(string());
+ main_wnd->set_status_text(string());
status_timeout = Time::TimeStamp();
}
if(picking)
{
- Track *track = pick_track(pointer);
+ Track *track = dynamic_cast<Track *>(pick_object(pointer));
if(track && track!=picking_track)
{
picking_track = track;
}
else
{
- Track *track = pick_track(pointer);
- if(track)
+ Object *obj = pick_object(pointer);
+ if(Track *track = dynamic_cast<Track *>(obj))
{
if(track->get_turnout_id())
{
set_status(format("Sensor %d", sid));
}
}
+ else if(Vehicle *veh = dynamic_cast<Vehicle *>(obj))
+ {
+ TrainDialog *dlg = new TrainDialog(*this, *veh->get_train());
+ root->add(*dlg);
+ dlg->autosize();
+ }
}
}
{
const Layout3D::TrackMap &tracks = layout_3d.get_tracks();
- float view_aspect = float(window.get_width()-200)/window.get_height();
+ float view_aspect = float(window.get_width())/window.get_height();
float view_height = tan(camera.get_field_of_view()/2.0f)*2.0f;
float best_score = 0;
GL::Vector3 pos;
float size = max(width/view_aspect, height);
float c = cos(angle);
float s = sin(angle);
- float x = (minp.x+maxp.x)/2-size*105/window.get_height();
+ float x = (minp.x+maxp.x)/2;
float y = (minp.y+maxp.y)/2;
float z = max(size*1.05/view_height, 0.15);
set_block_color(block, GL::Color(1));
}
-Track *Engineer::pick_track(const Vector &p)
+Object *Engineer::pick_object(const Vector &p)
{
const GL::Vector3 &start = camera.get_position();
GL::Vector4 ray = camera.unproject(GL::Vector4(p.x, p.y, 0, 0));
+ // XXX Do this better; make this function a template?
+ if(Vehicle *veh = layout.pick<Vehicle>(Ray(start, Vector(ray))))
+ return veh;
return layout.pick<Track>(Ray(start, Vector(ray)));
}
void Engineer::process_new_train(Train &train)
{
- TrainPanel *tpanel = new TrainPanel(*this, train);
- root->add(*tpanel);
- train_panels.push_back(tpanel);
- rearrange_panels();
-
Vehicle3D &loco3d = layout_3d.get_vehicle(train.get_vehicle(0));
overlay->set_label(loco3d, train.get_name());
train.signal_name_changed.connect(sigc::bind<0>(sigc::mem_fun(overlay, &Overlay3D::set_label), sigc::ref(loco3d)));
#include "network/server.h"
#include "options.h"
-class MainPanel;
-class TrainPanel;
+class MainWindow;
class TrainView;
class Engineer: public Msp::RegisteredApplication<Engineer>
Msp::GL::Pipeline pipeline;
Msp::GL::Mesh arrow_mesh;
- MainPanel *main_panel;
+ MainWindow *main_wnd;
std::list<R2C2::Train *> new_trains;
- std::list<TrainPanel *> train_panels;
std::list<TrainView *> train_views;
Msp::Time::TimeStamp status_timeout;
bool picking;
R2C2::Layout3D &get_layout_3d() { return layout_3d; }
const Msp::GL::Lighting &get_lighting() const { return lighting; }
void set_status(const std::string &);
- void rearrange_panels();
void add_train_view(TrainView &);
void remove_train_view(TrainView &);
void pick(bool);
void reset_block_color(const R2C2::Block &);
void sensor_event(unsigned, bool);
void block_reserved(const R2C2::Block &, const R2C2::Train *);
- R2C2::Track *pick_track(const R2C2::Vector &);
+ R2C2::Object *pick_object(const R2C2::Vector &);
void train_added(R2C2::Train &);
void process_new_train(R2C2::Train &);
virtual void sighandler(int);
+++ /dev/null
-#include <msp/gltk/button.h>
-#include "libr2c2/driver.h"
-#include "engineer.h"
-#include "mainpanel.h"
-#include "trainproperties.h"
-
-using namespace std;
-using namespace Msp;
-
-MainPanel::MainPanel(Engineer &e):
- engineer(e)
-{
- set_size(200, 117);
-
- GLtk::Button *btn;
-
- add(*(btn=new GLtk::Button("Off")));
- btn->set_geometry(GLtk::Geometry(10, 70, 40, 25));
- btn->set_style("red");
- btn->signal_clicked.connect(sigc::mem_fun(this, &MainPanel::power_off));
-
- add(*(ind_off=new GLtk::Indicator));
- ind_off->set_geometry(GLtk::Geometry(10, 95, 40, 12));
- ind_off->set_style("red");
-
- add(*(btn=new GLtk::Button("On")));
- btn->set_geometry(GLtk::Geometry(50, 70, 40, 25));
- btn->set_style("green");
- btn->signal_clicked.connect(sigc::mem_fun(this, &MainPanel::power_on));
-
- add(*(ind_on=new GLtk::Indicator));
- ind_on->set_geometry(GLtk::Geometry(50, 95, 40, 12));
- ind_on->set_style("green");
-
- add(*(btn=new GLtk::Button("Halt")));
- btn->set_geometry(GLtk::Geometry(90, 70, 40, 25));
- btn->signal_clicked.connect(sigc::mem_fun(this, &MainPanel::toggle_halt));
-
- add(*(ind_halt=new GLtk::Indicator));
- ind_halt->set_geometry(GLtk::Geometry(90, 95, 40, 12));
-
- add(*(btn=new GLtk::Button("Quit")));
- btn->set_geometry(GLtk::Geometry(150, 70, 40, 25));
- btn->set_style("red");
- btn->signal_clicked.connect(sigc::mem_fun(this, &MainPanel::quit));
-
- add(*(btn=new GLtk::Button("+Loc")));
- btn->set_geometry(GLtk::Geometry(10, 40, 40, 25));
- btn->signal_clicked.connect(sigc::mem_fun(this, &MainPanel::new_loc));
-
- add(*(lbl_status=new GLtk::Label));
- lbl_status->set_geometry(GLtk::Geometry(10, 10, 180, 20));
- lbl_status->set_style("digital");
-
- R2C2::Driver &driver = engineer.get_layout().get_driver();
- if(driver.get_power())
- ind_on->set_active(true);
- else
- ind_off->set_active(true);
-
- driver.signal_power.connect(sigc::mem_fun(this, &MainPanel::power_event));
- driver.signal_halt.connect(sigc::mem_fun(this, &MainPanel::halt_event));
-}
-
-void MainPanel::set_status_text(const string &txt)
-{
- lbl_status->set_text(txt);
-}
-
-void MainPanel::power_on()
-{
- engineer.get_layout().get_driver().set_power(true);
-}
-
-void MainPanel::power_off()
-{
- engineer.get_layout().get_driver().set_power(false);
-}
-
-void MainPanel::toggle_halt()
-{
- R2C2::Driver &driver = engineer.get_layout().get_driver();
- driver.halt(!driver.is_halted());
-}
-
-void MainPanel::new_loc()
-{
- TrainProperties *dialog = new TrainProperties(engineer, 0);
- engineer.get_root().add(*dialog);
- dialog->set_position(geom.x+geom.w, geom.y+geom.h-dialog->get_geometry().h);
- dialog->set_visible(true);
-}
-
-void MainPanel::quit()
-{
- engineer.quit();
-}
-
-void MainPanel::power_event(bool p)
-{
- ind_on->set_active(p);
- ind_off->set_active(!p);
-}
-
-void MainPanel::halt_event(bool h)
-{
- ind_halt->set_active(h);
-}
+++ /dev/null
-#ifndef MAINPANEL_H_
-#define MAINPANEL_H_
-
-#include <sigc++/trackable.h>
-#include <msp/gltk/indicator.h>
-#include <msp/gltk/label.h>
-#include <msp/gltk/panel.h>
-
-class Engineer;
-
-class MainPanel: public Msp::GLtk::Panel, public sigc::trackable
-{
-private:
- Engineer &engineer;
- Msp::GLtk::Indicator *ind_on;
- Msp::GLtk::Indicator *ind_off;
- Msp::GLtk::Label *lbl_status;
- Msp::GLtk::Indicator *ind_halt;
-
-public:
- MainPanel(Engineer &);
-
- void set_status_text(const std::string &);
-private:
- void power_on();
- void power_off();
- void toggle_halt();
- void new_loc();
- void quit();
- void power_event(bool);
- void halt_event(bool);
-};
-
-#endif
--- /dev/null
+#include <msp/gltk/button.h>
+#include "libr2c2/driver.h"
+#include "engineer.h"
+#include "mainwindow.h"
+#include "trainlistdialog.h"
+
+using namespace std;
+using namespace Msp;
+
+MainWindow::MainWindow(Engineer &e):
+ engineer(e)
+{
+ Loader::WidgetMap widgets;
+ DataFile::load(*this, "data/mainwindow.ui", widgets);
+
+ ind_on = dynamic_cast<GLtk::Indicator *>(get_item(widgets, "ind_on"));
+ ind_off = dynamic_cast<GLtk::Indicator *>(get_item(widgets, "ind_off"));
+ ind_halt = dynamic_cast<GLtk::Indicator *>(get_item(widgets, "ind_halt"));
+ lbl_status = dynamic_cast<GLtk::Label *>(get_item(widgets, "lbl_status"));
+
+ dynamic_cast<GLtk::Button *>(get_item(widgets, "btn_on"))->signal_clicked.connect(sigc::mem_fun(this, &MainWindow::on_clicked));
+ dynamic_cast<GLtk::Button *>(get_item(widgets, "btn_off"))->signal_clicked.connect(sigc::mem_fun(this, &MainWindow::off_clicked));
+ dynamic_cast<GLtk::Button *>(get_item(widgets, "btn_halt"))->signal_clicked.connect(sigc::mem_fun(this, &MainWindow::halt_clicked));
+ dynamic_cast<GLtk::Button *>(get_item(widgets, "btn_trains"))->signal_clicked.connect(sigc::mem_fun(this, &MainWindow::trains_clicked));
+ dynamic_cast<GLtk::Button *>(get_item(widgets, "btn_quit"))->signal_clicked.connect(sigc::mem_fun(this, &MainWindow::quit_clicked));
+
+ R2C2::Driver &driver = engineer.get_layout().get_driver();
+ if(driver.get_power())
+ ind_on->set_active(true);
+ else
+ ind_off->set_active(true);
+
+ driver.signal_power.connect(sigc::mem_fun(this, &MainWindow::power_event));
+ driver.signal_halt.connect(sigc::mem_fun(this, &MainWindow::halt_event));
+}
+
+void MainWindow::set_status_text(const string &txt)
+{
+ lbl_status->set_text(txt);
+}
+
+void MainWindow::on_clicked()
+{
+ engineer.get_layout().get_driver().set_power(true);
+}
+
+void MainWindow::off_clicked()
+{
+ engineer.get_layout().get_driver().set_power(false);
+}
+
+void MainWindow::halt_clicked()
+{
+ R2C2::Driver &driver = engineer.get_layout().get_driver();
+ driver.halt(!driver.is_halted());
+}
+
+void MainWindow::trains_clicked()
+{
+ GLtk::Container *root = parent;
+ while(root->get_parent())
+ root = root->get_parent();
+
+ TrainListDialog *dlg = new TrainListDialog(engineer);
+ root->add(*dlg);
+ dlg->autosize();
+}
+
+void MainWindow::quit_clicked()
+{
+ engineer.quit();
+}
+
+void MainWindow::power_event(bool p)
+{
+ ind_on->set_active(p);
+ ind_off->set_active(!p);
+}
+
+void MainWindow::halt_event(bool h)
+{
+ ind_halt->set_active(h);
+}
--- /dev/null
+#ifndef MAINWINDOW_H_
+#define MAINWINDOW_H_
+
+#include <sigc++/trackable.h>
+#include <msp/gltk/indicator.h>
+#include <msp/gltk/label.h>
+#include <msp/gltk/panel.h>
+
+class Engineer;
+
+class MainWindow: public Msp::GLtk::Panel, public sigc::trackable
+{
+private:
+ Engineer &engineer;
+ Msp::GLtk::Indicator *ind_on;
+ Msp::GLtk::Indicator *ind_off;
+ Msp::GLtk::Indicator *ind_halt;
+ Msp::GLtk::Label *lbl_status;
+
+public:
+ MainWindow(Engineer &);
+
+ void set_status_text(const std::string &);
+private:
+ void on_clicked();
+ void off_clicked();
+ void halt_clicked();
+ void trains_clicked();
+ void quit_clicked();
+ void power_event(bool);
+ void halt_event(bool);
+};
+
+#endif
--- /dev/null
+#include <msp/core/maputils.h>
+#include <msp/strings/format.h>
+#include "libr2c2/catalogue.h"
+#include "libr2c2/driver.h"
+#include "libr2c2/layout.h"
+#include "libr2c2/vehicletype.h"
+#include "engineer.h"
+#include "newtraindialog.h"
+#include "traindialog.h"
+
+using namespace std;
+using namespace Msp;
+using namespace R2C2;
+
+static string vehicle_type_name(const VehicleType *const &vehtype)
+{
+ return format("%s %s", vehtype->get_article_number(), vehtype->get_name());
+}
+
+NewTrainDialog::NewTrainDialog(Engineer &e):
+ engineer(e),
+ loco_types(vehicle_type_name)
+{
+ Loader::WidgetMap widgets;
+ DataFile::load(*this, "data/newtraindialog.ui", widgets);
+
+ drp_protocol = dynamic_cast<GLtk::Dropdown *>(get_item(widgets, "drp_protocol"));
+ drp_protocol->set_data(protocols);
+ ent_address = dynamic_cast<GLtk::Entry *>(get_item(widgets, "ent_address"));
+ ent_name = dynamic_cast<GLtk::Entry *>(get_item(widgets, "ent_name"));
+ drp_loco_type = dynamic_cast<GLtk::Dropdown *>(get_item(widgets, "drp_loco_type"));
+ drp_loco_type->set_data(loco_types);
+
+ const Driver &driver = engineer.get_layout().get_driver();
+ for(unsigned i=0;; ++i)
+ {
+ if(const char *proto = driver.enumerate_protocols(i))
+ protocols.append(proto);
+ else
+ break;
+ }
+
+ drp_protocol->set_selected_index(0);
+
+ const Catalogue::VehicleMap &cat_vtypes = engineer.get_layout().get_catalogue().get_vehicles();
+ for(Catalogue::VehicleMap::const_iterator i=cat_vtypes.begin(); i!=cat_vtypes.end(); ++i)
+ if(i->second->is_locomotive())
+ loco_types.append(i->second);
+}
+
+void NewTrainDialog::on_response(int code)
+{
+ if(code)
+ {
+ int index = drp_protocol->get_selected_index();
+ if(index<0)
+ return;
+ string protocol = protocols.get(index);
+
+ unsigned address = lexical_cast<unsigned>(ent_address->get_text());
+
+ index = drp_loco_type->get_selected_index();
+ if(index<0)
+ return;
+ const VehicleType &type = *loco_types.get(index);
+
+ Train *train = new Train(engineer.get_layout(), type, address, protocol);
+ train->set_name(ent_name->get_text());
+
+ GLtk::Container *root = parent;
+ while(root->get_parent())
+ root = root->get_parent();
+
+ TrainDialog *dlg = new TrainDialog(engineer, *train);
+ root->add(*dlg);
+ dlg->autosize();
+ }
+}
--- /dev/null
+#ifndef NEWTRAINDIALOG_H_
+#define NEWTRAINDIALOG_H_
+
+#include <msp/gltk/dialog.h>
+#include <msp/gltk/dropdown.h>
+#include <msp/gltk/entry.h>
+#include <msp/gltk/listdata.h>
+#include "libr2c2/catalogue.h"
+
+class Engineer;
+
+class NewTrainDialog: public Msp::GLtk::Dialog
+{
+private:
+ Engineer &engineer;
+ Msp::GLtk::BasicListData<std::string> protocols;
+ Msp::GLtk::Dropdown *drp_protocol;
+ Msp::GLtk::Entry *ent_address;
+ Msp::GLtk::Entry *ent_name;
+ Msp::GLtk::FunctionListData<const R2C2::VehicleType *> loco_types;
+ Msp::GLtk::Dropdown *drp_loco_type;
+
+public:
+ NewTrainDialog(Engineer &);
+
+private:
+ virtual void on_response(int);
+};
+
+#endif
--- /dev/null
+#include <msp/core/maputils.h>
+#include <msp/gltk/button.h>
+#include <msp/gltk/toggle.h>
+#include <msp/strings/format.h>
+#include "libr2c2/catalogue.h"
+#include "libr2c2/layout.h"
+#include "newvehicledialog.h"
+
+using namespace std;
+using namespace Msp;
+using namespace R2C2;
+
+static string vehicle_type_name(const VehicleType *const &vehtype)
+{
+ return format("%s %s", vehtype->get_article_number(), vehtype->get_name());
+}
+
+NewVehicleDialog::NewVehicleDialog(Train &t):
+ train(t),
+ loco_types(&vehicle_type_name),
+ wagon_types(&vehicle_type_name)
+{
+ Loader::WidgetMap widgets;
+ DataFile::load(*this, "data/newvehicledialog.ui", widgets);
+
+ dynamic_cast<GLtk::Label *>(get_item(widgets, "lbl_title"))->set_text(format("Add vehicle to %s", train.get_name()));
+
+ GLtk::List *lst_loco_types = dynamic_cast<GLtk::List *>(get_item(widgets, "lst_loco_types"));
+ lst_loco_types->set_data(loco_types);
+ active_list = lst_loco_types;
+
+ GLtk::List *lst_wagon_types = dynamic_cast<GLtk::List *>(get_item(widgets, "lst_wagon_types"));
+ lst_wagon_types->set_data(wagon_types);
+
+ dynamic_cast<GLtk::Toggle *>(get_item(widgets, "tgl_loco_types"))->signal_toggled.connect(sigc::bind(sigc::mem_fun(this, &NewVehicleDialog::toggle_list), lst_loco_types));
+ dynamic_cast<GLtk::Toggle *>(get_item(widgets, "tgl_wagon_types"))->signal_toggled.connect(sigc::bind(sigc::mem_fun(this, &NewVehicleDialog::toggle_list), lst_wagon_types));
+
+ dynamic_cast<GLtk::Button *>(get_item(widgets, "btn_add"))->signal_clicked.connect(sigc::mem_fun(this, &NewVehicleDialog::add_clicked));
+
+ const Catalogue::VehicleMap &cat_vtypes = train.get_layout().get_catalogue().get_vehicles();
+ for(Catalogue::VehicleMap::const_iterator i=cat_vtypes.begin(); i!=cat_vtypes.end(); ++i)
+ {
+ if(i->second->is_locomotive())
+ loco_types.append(i->second);
+ else
+ wagon_types.append(i->second);
+ }
+}
+
+void NewVehicleDialog::toggle_list(bool show, GLtk::List *lst)
+{
+ lst->set_visible(show);
+ if(show)
+ active_list = lst;
+}
+
+void NewVehicleDialog::add_clicked()
+{
+ int index = active_list->get_selected_index();
+ if(index>=0)
+ {
+ const VehicleType *vtype = static_cast<GLtk::ListDataStore<const R2C2::VehicleType *> &>(active_list->get_data()).get(index);
+ train.add_vehicle(*vtype);
+ }
+}
--- /dev/null
+#ifndef NEWVEHICLEDIALOG_H_
+#define NEWVEHICLEDIALOG_H_
+
+#include <msp/gltk/dialog.h>
+#include <msp/gltk/list.h>
+#include <msp/gltk/listdata.h>
+#include "libr2c2/train.h"
+#include "libr2c2/vehicletype.h"
+
+class NewVehicleDialog: public Msp::GLtk::Dialog
+{
+private:
+ R2C2::Train &train;
+ Msp::GLtk::FunctionListData<const R2C2::VehicleType *> loco_types;
+ Msp::GLtk::FunctionListData<const R2C2::VehicleType *> wagon_types;
+ Msp::GLtk::List *active_list;
+
+public:
+ NewVehicleDialog(R2C2::Train &);
+
+private:
+ void toggle_list(bool, Msp::GLtk::List *);
+ void add_clicked();
+};
+
+#endif
--- /dev/null
+#include <msp/core/maputils.h>
+#include <msp/core/raii.h>
+#include <msp/gltk/button.h>
+#include <msp/gltk/column.h>
+#include "libr2c2/layout.h"
+#include "libr2c2/route.h"
+#include "libr2c2/trainrouter.h"
+#include "engineer.h"
+#include "routerpanel.h"
+
+using namespace std;
+using namespace Msp;
+using namespace R2C2;
+
+string route_name(const Route *const &route)
+{
+ return route->get_name();
+}
+
+RouterPanel::RouterPanel(Engineer &e, Train &t):
+ engineer(e),
+ train(t),
+ routes(&route_name),
+ updating(false)
+{
+ Loader::WidgetMap widgets;
+ DataFile::load(*this, "data/routerpanel.ui", widgets);
+
+ lbl_route = dynamic_cast<GLtk::Label *>(get_item(widgets, "lbl_route"));
+ drp_routes = dynamic_cast<GLtk::Dropdown *>(get_item(widgets, "drp_routes"));
+ drp_routes->set_data(routes);
+ drp_routes->signal_item_selected.connect(sigc::mem_fun(this, &RouterPanel::route_selected));
+
+ dynamic_cast<GLtk::Button *>(get_item(widgets, "btn_goto"))->signal_clicked.connect(sigc::mem_fun(this, &RouterPanel::goto_clicked));
+
+ const set<Route *> &lroutes = train.get_layout().get_all<Route>();
+ for(set<Route *>::const_iterator i=lroutes.begin(); i!=lroutes.end(); ++i)
+ routes.append(*i);
+
+ TrainRouter *router = train.get_ai_of_type<TrainRouter>();
+ if(!router)
+ router = new TrainRouter(train);
+ update_route(router->get_route());
+
+ train.signal_ai_event.connect(sigc::mem_fun(this, &RouterPanel::ai_event));
+}
+
+void RouterPanel::ai_event(TrainAI &, const TrainAI::Message &msg)
+{
+ if(msg.type=="route-changed")
+ update_route(msg.value.value<const Route *>());
+}
+
+void RouterPanel::update_route(const Route *route)
+{
+ SetFlag setf(updating);
+ if(route)
+ lbl_route->set_text(route->get_name());
+ else
+ lbl_route->set_text("Free run");
+ drp_routes->set_selected_index(routes.find(route));
+}
+
+void RouterPanel::route_selected(unsigned index)
+{
+ if(!updating)
+ {
+ const Route *route = routes.get(index);
+ train.ai_message(TrainAI::Message("set-route", route));
+ }
+}
+
+void RouterPanel::goto_clicked()
+{
+ engineer.pick(false);
+ pick_conn = engineer.signal_pick_done.connect(sigc::mem_fun(this, &RouterPanel::goto_pick_done));
+}
+
+void RouterPanel::goto_pick_done(Track *track, unsigned)
+{
+ pick_conn.disconnect();
+ train.ai_message(TrainAI::Message("set-destination-block", &track->get_block()));
+}
--- /dev/null
+#ifndef ROUTERPANEL_H_
+#define ROUTERPANEL_H_
+
+#include <msp/gltk/dropdown.h>
+#include <msp/gltk/label.h>
+#include <msp/gltk/panel.h>
+#include "libr2c2/train.h"
+
+class Engineer;
+
+class RouterPanel: public Msp::GLtk::Panel, public sigc::trackable
+{
+private:
+ Engineer &engineer;
+ R2C2::Train &train;
+ Msp::GLtk::Label *lbl_route;
+ Msp::GLtk::FunctionListData<const R2C2::Route *> routes;
+ Msp::GLtk::Dropdown *drp_routes;
+ sigc::connection pick_conn;
+ bool updating;
+
+public:
+ RouterPanel(Engineer &, R2C2::Train &);
+
+private:
+ void ai_event(R2C2::TrainAI &, const R2C2::TrainAI::Message &);
+ void update_route(const R2C2::Route *);
+ void route_selected(unsigned);
+ void goto_clicked();
+ void goto_pick_done(R2C2::Track *, unsigned);
+};
+
+#endif
+++ /dev/null
-#include <msp/gltk/label.h>
-#include "engineer.h"
-#include "libr2c2/route.h"
-#include "libr2c2/trainrouter.h"
-#include "routeselect.h"
-
-using namespace std;
-using namespace Msp;
-using namespace R2C2;
-
-RouteSelect::RouteSelect(Engineer &e, Train &t):
- engineer(e),
- train(t)
-{
- set_size(200, 95);
-
- GLtk::Label *label;
- add(*(label = new GLtk::Label("Select route")));
- label->set_geometry(GLtk::Geometry(10, geom.h-25, geom.w-20, 20));
-
- add(*(drp_route = new GLtk::Dropdown));
- drp_route->set_geometry(GLtk::Geometry(10, geom.h-50, geom.w-20, 20));
- drp_route->append("(none)");
- drp_route->set_selected_index(0);
-
- const Route *current_route = 0;
- if(TrainRouter *router = train.get_ai_of_type<TrainRouter>())
- current_route = router->get_route();
-
- const set<Route *> &routes = engineer.get_layout().get_all<Route>();
- unsigned n = 1;
- for(set<Route *>::const_iterator i=routes.begin(); i!=routes.end(); ++i)
- if(!(*i)->is_temporary())
- {
- drp_route->append((*i)->get_name());
- if(*i==current_route)
- drp_route->set_selected_index(n);
- ++n;
- }
-}
-
-void RouteSelect::on_ok_clicked()
-{
- if(drp_route->get_selected_index()>0)
- {
- const set<Route *> &routes = engineer.get_layout().get_all<Route>();
- set<Route *>::const_iterator i = routes.begin();
- unsigned n = drp_route->get_selected_index()-1;
- while(i!=routes.end())
- {
- if(!(*i)->is_temporary())
- {
- if(!n)
- break;
- --n;
- }
- ++i;
- }
-
- train.ai_message(TrainAI::Message("set-route", *i));
- }
- else
- train.ai_message(TrainAI::Message("clear-route"));
-}
+++ /dev/null
-#ifndef ROUTESELECT_H_
-#define ROUTESELECT_H_
-
-#include <msp/gltk/dropdown.h>
-#include "libr2c2/train.h"
-#include "dialog.h"
-
-class Engineer;
-
-class RouteSelect: public Dialog
-{
-private:
- Engineer &engineer;
- R2C2::Train &train;
- Msp::GLtk::Dropdown *drp_route;
-
-public:
- RouteSelect(Engineer &, R2C2::Train &);
-private:
- virtual void on_ok_clicked();
-};
-
-#endif
--- /dev/null
+#include <msp/core/maputils.h>
+#include <msp/core/raii.h>
+#include <msp/gltk/stack.h>
+#include <msp/strings/format.h>
+#include "libr2c2/aicontrol.h"
+#include "libr2c2/catalogue.h"
+#include "libr2c2/layout.h"
+#include "libr2c2/trainstatus.h"
+#include "controlpanel.h"
+#include "routerpanel.h"
+#include "traindialog.h"
+#include "vehiclespanel.h"
+
+using namespace std;
+using namespace Msp;
+using namespace R2C2;
+
+TrainDialog::TrainDialog(Engineer &e, R2C2::Train &t):
+ engineer(e),
+ train(t),
+ updating(false)
+{
+ Loader::WidgetMap widgets;
+ DataFile::load(*this, "data/traindialog.ui", widgets);
+
+ lbl_title = dynamic_cast<GLtk::Label *>(get_item(widgets, "lbl_title"));
+ lbl_title->set_text(t.get_name());
+
+ btn_expand = dynamic_cast<GLtk::Button *>(get_item(widgets, "btn_expand"));
+ btn_expand->signal_clicked.connect(sigc::mem_fun(this, &TrainDialog::expand_clicked));
+ lbl_speed = dynamic_cast<GLtk::Label *>(get_item(widgets, "lbl_speed"));
+ sld_speed = dynamic_cast<GLtk::Slider *>(get_item(widgets, "sld_speed"));
+ sld_speed->signal_value_changed.connect(sigc::mem_fun(this, &TrainDialog::ui_speed_changed));
+ tgl_forward = dynamic_cast<GLtk::Toggle *>(get_item(widgets, "tgl_forward"));
+ tgl_forward->signal_toggled.connect(sigc::mem_fun(this, &TrainDialog::ui_forward_toggled));
+ lbl_status = dynamic_cast<GLtk::Label *>(get_item(widgets, "lbl_status"));
+ pnl_expander = dynamic_cast<GLtk::Panel *>(get_item(widgets, "pnl_expander"));
+
+ Panel *pnl;
+
+ GLtk::Stack stack(*pnl_expander->get_layout());
+ stack.arrange(*get_item(widgets, "lbl_detail_placeholder"));
+
+ pnl_expander->add(*(pnl = new VehiclesPanel(train)));
+ panels.push_back(pnl);
+ dynamic_cast<GLtk::Toggle *>(get_item(widgets, "tgl_vehicles"))->signal_toggled.connect(sigc::bind(sigc::mem_fun(this, &TrainDialog::toggle_panel), pnl));
+
+ pnl_expander->add(*(pnl = new ControlPanel(engineer, train)));
+ pnl->set_visible(false);
+ panels.push_back(pnl);
+ dynamic_cast<GLtk::Toggle *>(get_item(widgets, "tgl_control"))->signal_toggled.connect(sigc::bind(sigc::mem_fun(this, &TrainDialog::toggle_panel), pnl));
+
+ pnl_expander->add(*(pnl = new RouterPanel(engineer, train)));
+ pnl->set_visible(false);
+ panels.push_back(pnl);
+ dynamic_cast<GLtk::Toggle *>(get_item(widgets, "tgl_router"))->signal_toggled.connect(sigc::bind(sigc::mem_fun(this, &TrainDialog::toggle_panel), pnl));
+
+ AIControl *control = train.get_ai_of_type<AIControl>();
+ if(!control)
+ control = new AIControl(train);
+ update_forward(!control->get_reverse());
+ update_speed_display(control->get_target_speed());
+
+ TrainStatus *status = train.get_ai_of_type<TrainStatus>();
+ if(!status)
+ status = new TrainStatus(train);
+ lbl_status->set_text(status->get_status());
+
+ train.signal_ai_event.connect(sigc::mem_fun(this, &TrainDialog::ai_event));
+}
+
+void TrainDialog::ai_event(TrainAI &, const TrainAI::Message &msg)
+{
+ if(msg.type=="status-changed")
+ lbl_status->set_text(msg.value.value<string>());
+ else if(msg.type=="target-speed-changed")
+ update_speed_display(msg.value.value<float>());
+ else if(msg.type=="reverse-changed")
+ update_forward(!msg.value.value<bool>());
+}
+
+void TrainDialog::update_speed_display(float speed)
+{
+ SetFlag setf(updating);
+ float scale_speed = speed*3.6/train.get_layout().get_catalogue().get_scale();
+ lbl_speed->set_text(format("%3.0f", scale_speed));
+ sld_speed->set_value(scale_speed);
+}
+
+void TrainDialog::ui_speed_changed(double value)
+{
+ if(!updating)
+ {
+ float real_speed = value/3.6*train.get_layout().get_catalogue().get_scale();
+ train.ai_message(TrainAI::Message("set-target-speed", real_speed));
+ }
+}
+
+void TrainDialog::update_forward(bool value)
+{
+ SetFlag setf(updating);
+ tgl_forward->set_value(value);
+}
+
+void TrainDialog::ui_forward_toggled(bool value)
+{
+ if(!updating)
+ train.ai_message(TrainAI::Message("set-reverse", !value));
+}
+
+void TrainDialog::expand_clicked()
+{
+ pnl_expander->set_visible(!pnl_expander->is_visible());
+ btn_expand->set_style(pnl_expander->is_visible() ? "arrow_up" : "arrow_down");
+ GLtk::Geometry ageom = geom;
+ ageom.h = 0;
+ layout->autosize(ageom);
+ ageom.y = geom.y+geom.h-ageom.h;
+ set_geometry(ageom);
+}
+
+void TrainDialog::toggle_panel(bool show, GLtk::Panel *panel)
+{
+ panel->set_visible(show);
+}
--- /dev/null
+#ifndef TRAINDIALOG_H_
+#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"
+
+class Engineer;
+
+class TrainDialog: public Msp::GLtk::Dialog, public sigc::trackable
+{
+private:
+ Engineer &engineer;
+ R2C2::Train &train;
+ Msp::GLtk::Label *lbl_title;
+ Msp::GLtk::Button *btn_expand;
+ Msp::GLtk::Label *lbl_speed;
+ Msp::GLtk::Slider *sld_speed;
+ Msp::GLtk::Toggle *tgl_forward;
+ Msp::GLtk::Label *lbl_status;
+ Msp::GLtk::Panel *pnl_expander;
+ std::list<Msp::GLtk::Panel *> panels;
+ bool updating;
+
+public:
+ TrainDialog(Engineer &, R2C2::Train &);
+
+private:
+ void ai_event(R2C2::TrainAI &, const R2C2::TrainAI::Message &);
+ void update_speed_display(float);
+ void ui_speed_changed(double);
+ void update_forward(bool);
+ void ui_forward_toggled(bool);
+ void expand_clicked();
+ void toggle_panel(bool, Msp::GLtk::Panel *);
+};
+
+#endif
--- /dev/null
+#include <msp/core/maputils.h>
+#include <msp/gltk/button.h>
+#include <msp/gltk/style.h>
+#include "engineer.h"
+#include "libr2c2/train.h"
+#include "newtraindialog.h"
+#include "traindialog.h"
+#include "trainlistdialog.h"
+
+using namespace std;
+using namespace Msp;
+using namespace R2C2;
+
+class TrainItem: public GLtk::List::Item
+{
+private:
+ GLtk::Label address;
+ GLtk::Label name;
+
+public:
+ typedef R2C2::Train *ValueType;
+
+ TrainItem(ValueType);
+
+private:
+ virtual void on_style_change();
+};
+
+
+TrainListDialog::TrainListDialog(Engineer &e):
+ engineer(e),
+ layout(engineer.get_layout())
+{
+ Loader::WidgetMap widgets;
+ DataFile::load(*this, "data/trainlistdialog.ui", widgets);
+
+ lst_trains = dynamic_cast<GLtk::List *>(get_item(widgets, "lst_trains"));
+ lst_trains->set_data(trains);
+ lst_trains->set_item_type<TrainItem>();
+
+ dynamic_cast<GLtk::Button *>(get_item(widgets, "btn_new"))->signal_clicked.connect(sigc::mem_fun(this, &TrainListDialog::new_clicked));
+ dynamic_cast<GLtk::Button *>(get_item(widgets, "btn_show"))->signal_clicked.connect(sigc::mem_fun(this, &TrainListDialog::show_clicked));
+
+ const map<unsigned, Train *> <rains = layout.get_trains();
+ for(map<unsigned, Train *>::const_iterator i=ltrains.begin(); i!=ltrains.end(); ++i)
+ trains.append(i->second);
+}
+
+void TrainListDialog::new_clicked()
+{
+ GLtk::Container *root = parent;
+ while(root->get_parent())
+ root = root->get_parent();
+
+ NewTrainDialog *dlg = new NewTrainDialog(engineer);
+ root->add(*dlg);
+ dlg->autosize();
+}
+
+void TrainListDialog::show_clicked()
+{
+ int index = lst_trains->get_selected_index();
+ if(index>=0)
+ {
+ GLtk::Container *root = parent;
+ while(root->get_parent())
+ root = root->get_parent();
+
+ TrainDialog *dlg = new TrainDialog(engineer, *trains.get(index));
+ root->add(*dlg);
+ dlg->autosize();
+ }
+}
+
+
+TrainItem::TrainItem(ValueType train):
+ address(lexical_cast<string>(train->get_address())),
+ name(train->get_name())
+{
+ add(address);
+ add(name);
+}
+
+void TrainItem::on_style_change()
+{
+ if(!style)
+ return;
+
+ address.autosize();
+ name.autosize();
+
+ if(const GLtk::Part *part = style->get_part("children"))
+ {
+ const GLtk::Sides &margin = part->get_margin();
+ address.set_position(margin.left, margin.bottom);
+ name.set_position(margin.left+30, margin.bottom);
+ }
+}
--- /dev/null
+#ifndef TRAINLISTDIALOG_H_
+#define TRAINLISTDIALOG_H_
+
+#include <msp/gltk/dialog.h>
+#include <msp/gltk/list.h>
+#include <msp/gltk/listdata.h>
+#include "libr2c2/layout.h"
+
+class Engineer;
+
+class TrainListDialog: public Msp::GLtk::Dialog
+{
+private:
+ Engineer &engineer;
+ R2C2::Layout &layout;
+ Msp::GLtk::BasicListData<R2C2::Train *> trains;
+ Msp::GLtk::List *lst_trains;
+
+public:
+ TrainListDialog(Engineer &);
+
+private:
+ void new_clicked();
+ void show_clicked();
+};
+
+#endif
+++ /dev/null
-#include <cmath>
-#include <msp/strings/format.h>
-#include "libr2c2/aicontrol.h"
-#include "libr2c2/trackiter.h"
-#include "libr2c2/trainrouter.h"
-#include "libr2c2/vehicletype.h"
-#include "engineer.h"
-#include "routeselect.h"
-#include "trainpanel.h"
-#include "trainproperties.h"
-#include "trainview.h"
-
-using namespace std;
-using namespace Msp;
-using namespace R2C2;
-
-TrainPanel::TrainPanel(Engineer &e, Train &t):
- engineer(e),
- train(t),
- status(train),
- expanded(false)
-{
- set_size(200, 65);
-
- AIControl *ai = new AIControl(train);
- ai->signal_event.connect(sigc::mem_fun(this, &TrainPanel::ai_event));
-
- add(*(pnl_basic = new GLtk::Panel));
- pnl_basic->set_style("group");
- pnl_basic->set_geometry(GLtk::Geometry(0, geom.h-58, geom.w, 45));
-
- pnl_basic->add(*(lbl_addr = new GLtk::Label(format("%2d", train.get_address()))));
- lbl_addr->set_style("digital");
- lbl_addr->set_geometry(GLtk::Geometry(10, 28, 35, 20));
-
- pnl_basic->add(*(lbl_name = new GLtk::Label(train.get_name())));
- lbl_name->set_style("digital");
- lbl_name->set_geometry(GLtk::Geometry(50, 28, geom.w-77, 20));
- train.signal_name_changed.connect(sigc::mem_fun(lbl_name, &GLtk::Label::set_text));
-
- pnl_basic->add(*(lbl_speed = new GLtk::Label(" 0")));
- lbl_speed->set_style("digital");
- lbl_speed->set_geometry(GLtk::Geometry(10, 3, 35, 20));
-
- pnl_basic->add(*(sld_speed = new GLtk::HSlider));
- sld_speed->set_geometry(GLtk::Geometry(50, 8, geom.w-80, 10));
- sld_speed->set_range(0, 200);
- sld_speed->set_step(5);
- sld_speed->signal_value_changed.connect(sigc::mem_fun(this, &TrainPanel::speed_slider_changed));
-
- pnl_basic->add(*(tgl_forward = new GLtk::Toggle));
- tgl_forward->set_text("Fwd");
- tgl_forward->set_geometry(GLtk::Geometry(geom.w-30, 0, 20, 27));
- tgl_forward->set_value(true);
- tgl_forward->signal_toggled.connect(sigc::mem_fun(this, &TrainPanel::forward_toggled));
-
- pnl_basic->add(*(btn_expand = new GLtk::Button));
- btn_expand->set_style("arrow_down");
- btn_expand->set_geometry(GLtk::Geometry(geom.w-22, 28, 12, 20));
- btn_expand->signal_clicked.connect(sigc::mem_fun(this, &TrainPanel::expand_clicked));
-
- add(*(pnl_extra = new GLtk::Panel));
- pnl_extra->set_style("group");
- pnl_extra->set_geometry(GLtk::Geometry(0, 10, geom.w, 135));
- pnl_extra->set_visible(false);
-
- TrainRouter *router = train.get_ai_of_type<TrainRouter>();
- if(!router)
- router = new TrainRouter(train);
-
- const Route *route = router->get_route();
- pnl_extra->add(*(lbl_route = new GLtk::Label((route ? route->get_name() : "Free run"))));
- lbl_route->set_style("digital");
- lbl_route->set_geometry(GLtk::Geometry(10, 85, geom.w-20, 20));
- router->signal_route_changed.connect(sigc::mem_fun(this, &TrainPanel::train_route_changed));
-
- pnl_extra->add(*(lbl_status = new GLtk::Label(status.get_status())));
- lbl_status->set_style("digital");
- lbl_status->set_geometry(GLtk::Geometry(10, 60, geom.w-20, 20));
- status.signal_changed.connect(sigc::mem_fun(this, &TrainPanel::train_status_changed));
-
- const VehicleType::FunctionMap &funcs = train.get_locomotive_type().get_functions();
- unsigned x = 10;
- for(VehicleType::FunctionMap::const_iterator i=funcs.begin(); i!=funcs.end(); ++i, x+=36)
- {
- string fname = i->second;
- fname[0] = toupper(fname[0]);
- GLtk::Toggle *tgl;
- pnl_extra->add(*(tgl = new GLtk::Toggle));
- tgl->set_text(fname);
- tgl->set_geometry(GLtk::Geometry(x, 108, 36, 27));
- tgl->set_value(train.get_function(i->first));
- tgl->signal_toggled.connect(sigc::bind(sigc::mem_fun(this, &TrainPanel::func_toggled), i->first));
-
- tgl_funcs[i->first] = tgl;
- }
- train.signal_function_changed.connect(sigc::mem_fun(this, &TrainPanel::train_function_changed));
-
- GLtk::Button *btn;
-
- pnl_extra->add(*(btn = new GLtk::Button("Edit")));
- btn->set_geometry(GLtk::Geometry(10, 30, 36, 25));
- btn->signal_clicked.connect(sigc::mem_fun(this, &TrainPanel::edit_clicked));
-
- pnl_extra->add(*(btn = new GLtk::Button("Place")));
- btn->set_geometry(GLtk::Geometry(10, 0, 36, 25));
- btn->signal_clicked.connect(sigc::mem_fun(this, &TrainPanel::place_clicked));
-
- pnl_extra->add(*(btn = new GLtk::Button("Take")));
- btn->set_geometry(GLtk::Geometry(46, 0, 36, 25));
- btn->signal_clicked.connect(sigc::mem_fun(this, &TrainPanel::take_clicked));
-
- pnl_extra->add(*(btn = new GLtk::Button("GoTo")));
- btn->set_geometry(GLtk::Geometry(100, 0, 36, 25));
- btn->signal_clicked.connect(sigc::mem_fun(this, &TrainPanel::goto_clicked));
-
- pnl_extra->add(*(btn = new GLtk::Button("Route")));
- btn->set_geometry(GLtk::Geometry(100, 30, 36, 25));
- btn->signal_clicked.connect(sigc::mem_fun(this, &TrainPanel::route_clicked));
-
- pnl_extra->add(*(btn = new GLtk::Button("View")));
- btn->set_geometry(GLtk::Geometry(geom.w-46, 30, 36, 25));
- btn->signal_clicked.connect(sigc::mem_fun(this, &TrainPanel::view_clicked));
-}
-
-void TrainPanel::expand(bool e)
-{
- expanded = e;
- pnl_extra->set_visible(expanded);
- if(expanded)
- {
- set_size(geom.w, 205);
- btn_expand->set_style("arrow_up");
- }
- else
- {
- set_size(geom.w, 65);
- btn_expand->set_style("arrow_down");
- }
- pnl_basic->set_geometry(GLtk::Geometry(0, geom.h-58, geom.w, 45));
- engineer.rearrange_panels();
-}
-
-void TrainPanel::ai_event(const TrainAI::Message &msg)
-{
- if(msg.type=="target-speed-changed")
- {
- float speed = msg.value.value<float>()/engineer.get_layout().get_catalogue().get_scale()*3.6;
- sld_speed->set_value(speed);
- lbl_speed->set_text(format("%3.0f", speed));
- }
- else if(msg.type=="reverse-changed")
- tgl_forward->set_value(!msg.value.value<bool>());
-}
-
-void TrainPanel::train_function_changed(unsigned func, bool value)
-{
- map<unsigned, GLtk::Toggle *>::iterator i = tgl_funcs.find(func);
- if(i!=tgl_funcs.end())
- i->second->set_value(value);
-}
-
-void TrainPanel::train_route_changed(const Route *r)
-{
- if(r)
- lbl_route->set_text(r->get_name());
- else
- lbl_route->set_text("Free run");
-}
-
-void TrainPanel::train_status_changed(const string &s)
-{
- lbl_status->set_text(s);
-}
-
-void TrainPanel::place_clicked()
-{
- engineer.pick(true);
- pick_conn = engineer.signal_pick_done.connect(sigc::mem_fun(this, &TrainPanel::place));
-}
-
-void TrainPanel::take_clicked()
-{
- train.unplace();
-}
-
-void TrainPanel::edit_clicked()
-{
- TrainProperties *dialog = new TrainProperties(engineer, &train);
- engineer.get_root().add(*dialog);
- dialog->set_position(geom.x+geom.w, geom.y+geom.h-dialog->get_geometry().h);
-}
-
-void TrainPanel::route_clicked()
-{
- RouteSelect *dialog = new RouteSelect(engineer, train);
- engineer.get_root().add(*dialog);
- dialog->set_position(geom.x+geom.w, geom.y+geom.h-dialog->get_geometry().h);
-}
-
-void TrainPanel::goto_clicked()
-{
- engineer.pick(false);
- pick_conn = engineer.signal_pick_done.connect(sigc::mem_fun(this, &TrainPanel::go_to));
-}
-
-void TrainPanel::view_clicked()
-{
- TrainView *dialog = new TrainView(engineer, train);
- engineer.get_root().add(*dialog);
- dialog->set_position(geom.x+geom.w, geom.y+geom.h-dialog->get_geometry().h);
-}
-
-void TrainPanel::expand_clicked()
-{
- expand(!expanded);
-}
-
-void TrainPanel::speed_slider_changed(double value)
-{
- float speed = value/3.6*engineer.get_layout().get_catalogue().get_scale();
- train.ai_message(TrainAI::Message("set-target-speed", speed));
-}
-
-void TrainPanel::forward_toggled(bool value)
-{
- train.ai_message(TrainAI::Message("set-reverse", !value));
-}
-
-void TrainPanel::func_toggled(bool value, unsigned func)
-{
- train.set_function(func, value);
-}
-
-void TrainPanel::place(Track *track, unsigned ep)
-{
- pick_conn.disconnect();
-
- BlockIter block = TrackIter(track, ep).block_iter();
- if(block)
- train.place(block);
-}
-
-void TrainPanel::go_to(Track *track, unsigned)
-{
- pick_conn.disconnect();
-
- TrainRouter *router = train.get_ai_of_type<TrainRouter>();
- if(router)
- router->set_destination(track->get_block());
-}
+++ /dev/null
-#ifndef TRAINPANEL_H_
-#define TRAINPANEL_H_
-
-#include <sigc++/trackable.h>
-#include <msp/gltk/button.h>
-#include <msp/gltk/hslider.h>
-#include <msp/gltk/label.h>
-#include <msp/gltk/panel.h>
-#include <msp/gltk/toggle.h>
-#include "libr2c2/route.h"
-#include "libr2c2/train.h"
-#include "libr2c2/trainstatus.h"
-
-class Engineer;
-
-class TrainPanel: public Msp::GLtk::Panel, public sigc::trackable
-{
-private:
- Engineer &engineer;
- R2C2::Train &train;
- R2C2::TrainStatus status;
- Msp::GLtk::Panel *pnl_basic;
- Msp::GLtk::Panel *pnl_extra;
- Msp::GLtk::Button *btn_expand;
- Msp::GLtk::Label *lbl_addr;
- Msp::GLtk::Label *lbl_name;
- Msp::GLtk::HSlider *sld_speed;
- Msp::GLtk::Label *lbl_speed;
- Msp::GLtk::Label *lbl_route;
- Msp::GLtk::Label *lbl_status;
- Msp::GLtk::Toggle *tgl_forward;
- std::map<unsigned, Msp::GLtk::Toggle *> tgl_funcs;
- sigc::connection pick_conn;
- bool expanded;
-
-public:
- TrainPanel(Engineer &, R2C2::Train &);
- void expand(bool = true);
-
-private:
- void ai_event(const R2C2::TrainAI::Message &);
- void train_function_changed(unsigned, bool);
- void train_route_changed(const R2C2::Route *);
- void train_status_changed(const std::string &);
- void place_clicked();
- void take_clicked();
- void edit_clicked();
- void route_clicked();
- void goto_clicked();
- void view_clicked();
- void expand_clicked();
- void speed_slider_changed(double);
- void forward_toggled(bool);
- void func_toggled(bool, unsigned);
- void place(R2C2::Track *, unsigned);
- void go_to(R2C2::Track *, unsigned);
-};
-
-#endif
+++ /dev/null
-#include <msp/gltk/label.h>
-#include <msp/strings/format.h>
-#include <msp/strings/lexicalcast.h>
-#include "libr2c2/driver.h"
-#include "libr2c2/trainrouter.h"
-#include "libr2c2/vehicle.h"
-#include "libr2c2/vehicletype.h"
-#include "engineer.h"
-#include "trainproperties.h"
-
-using namespace std;
-using namespace Msp;
-using namespace R2C2;
-
-TrainProperties::TrainProperties(Engineer &e, Train *t):
- engineer(e),
- train(t)
-{
- set_size(250, 305);
-
- GLtk::Label *label;
- add(*(label = new GLtk::Label("Train properties")));
- label->set_geometry(GLtk::Geometry(10, geom.h-25, geom.w-20, 20));
-
- add(*(ent_addr = new GLtk::Entry));
- ent_addr->set_geometry(GLtk::Geometry(10, geom.h-50, 40, 20));
-
- add(*(drp_protocol = new GLtk::Dropdown));
- drp_protocol->set_geometry(GLtk::Geometry(60, geom.h-50, 60, 20));
- for(unsigned i=0;; ++i)
- {
- if(const char *proto = engineer.get_layout().get_driver().enumerate_protocols(i))
- drp_protocol->append(proto);
- else
- break;
- }
- drp_protocol->set_selected_index(0);
-
- add(*(drp_type = new GLtk::Dropdown));
- drp_type->set_geometry(GLtk::Geometry(130, geom.h-50, geom.w-140, 20));
-
- const Catalogue::VehicleMap &vehs = engineer.get_catalogue().get_vehicles();
- unsigned n = 0;
- for(Catalogue::VehicleMap::const_iterator i=vehs.begin(); i!=vehs.end(); ++i)
- {
- if(!i->second->is_locomotive())
- continue;
-
- drp_type->append(format("%d %s", i->second->get_article_number(), i->second->get_name()));
- if(train && i->second==&train->get_locomotive_type())
- drp_type->set_selected_index(n);
-
- ++n;
- }
-
- add(*(ent_name = new GLtk::Entry));
- ent_name->set_geometry(GLtk::Geometry(10, geom.h-75, geom.w-20, 20));
-
- add(*(drp_priority = new GLtk::Dropdown));
- drp_priority->set_geometry(GLtk::Geometry(10, geom.h-100, geom.w-20, 20));
- drp_priority->append("Standard freight");
- drp_priority->append("Express freight");
- drp_priority->append("Unspecified");
- drp_priority->append("Standard passenger");
- drp_priority->append("Express passenger");
-
- add(*(lst_vehicles = new GLtk::List));
- lst_vehicles->set_geometry(GLtk::Geometry(10, 100, geom.w-20, geom.h-205));
-
- GLtk::Button *btn;
-
- add(*(btn = new GLtk::Button("Rem")));
- btn->set_geometry(GLtk::Geometry(10, 70, 40, 25));
- btn->signal_clicked.connect(sigc::mem_fun(this, &TrainProperties::remove_vehicle_clicked));
-
- add(*(drp_new_vehicle = new GLtk::Dropdown));
- drp_new_vehicle->set_geometry(GLtk::Geometry(10, 45, geom.w-20, 20));
- drp_new_vehicle->append("(new vehicle)");
- drp_new_vehicle->set_selected_index(0);
- for(Catalogue::VehicleMap::const_iterator i=vehs.begin(); i!=vehs.end(); ++i)
- {
- if(i->second->is_locomotive())
- continue;
-
- drp_new_vehicle->append(format("%d %s", i->second->get_article_number(), i->second->get_name()));
- }
- drp_new_vehicle->signal_item_selected.connect(sigc::mem_fun(this, &TrainProperties::new_vehicle_selected));
-
- if(train)
- {
- ent_addr->set_text(lexical_cast<string>(train->get_address()));
- ent_name->set_text(train->get_name());
- if(TrainRouter *router = train->get_ai_of_type<TrainRouter>())
- drp_priority->set_selected_index(router->get_priority()+2);
-
- unsigned n_vehicles = train->get_n_vehicles();
- for(unsigned i=1; i<n_vehicles; ++i)
- {
- const VehicleType &type = train->get_vehicle(i).get_type();
- lst_vehicles->append(format("%d %s", type.get_article_number(), type.get_name()));
- }
- }
- else
- {
- ent_name->set_text(format("Train %d", engineer.get_layout().get_trains().size()+1));
- drp_priority->set_selected_index(2);
- }
-}
-
-void TrainProperties::on_ok_clicked()
-{
- if(!train)
- {
- const VehicleType &type = get_vehicle_type(drp_type->get_selected_index(), true);
- unsigned addr = lexical_cast<unsigned>(ent_addr->get_text());
- train = new Train(engineer.get_layout(), type, addr, drp_protocol->get_selected());
- }
-
- train->set_name(ent_name->get_text());
- if(TrainRouter *router = train->get_ai_of_type<TrainRouter>())
- router->set_priority(drp_priority->get_selected_index()-2);
-
- // The locomotive is vehicle 0 so we need to add 1
- for(set<unsigned>::const_iterator i=rem_vehicles.end(); i!=rem_vehicles.begin();)
- train->remove_vehicle(*--i+1);
- for(vector<const VehicleType *>::const_iterator i=add_vehicles.begin(); i!=add_vehicles.end(); ++i)
- train->add_vehicle(**i);
-}
-
-void TrainProperties::new_vehicle_selected(unsigned n, const string &)
-{
- if(n==0)
- return;
-
- const VehicleType &type = get_vehicle_type(n-1, false);
- add_vehicles.push_back(&type);
- lst_vehicles->append(format("%d %s", type.get_article_number(), type.get_name()));
-
- drp_new_vehicle->set_selected_index(0);
-}
-
-void TrainProperties::remove_vehicle_clicked()
-{
- int selected = lst_vehicles->get_selected_index();
- if(selected<0)
- return;
-
- lst_vehicles->remove(selected);
-
- unsigned n_vehicles = (train ? train->get_n_vehicles()-rem_vehicles.size() : 0);
- if(static_cast<unsigned>(selected)>=n_vehicles)
- add_vehicles.erase(add_vehicles.begin()+(selected-n_vehicles));
- else
- {
- for(set<unsigned>::const_iterator i=rem_vehicles.begin(); i!=rem_vehicles.end(); ++i)
- if(*i<=static_cast<unsigned>(selected))
- ++selected;
- rem_vehicles.insert(selected);
- }
-}
-
-const VehicleType &TrainProperties::get_vehicle_type(unsigned n, bool loco)
-{
- const Catalogue::VehicleMap &vehs = engineer.get_catalogue().get_vehicles();
- Catalogue::VehicleMap::const_iterator i = vehs.begin();
- while(i!=vehs.end())
- {
- if(i->second->is_locomotive()==loco)
- {
- if(!n)
- return *i->second;
- --n;
- }
- ++i;
- }
-
- throw out_of_range("TrainProperties::get_vehicle_type");
-}
+++ /dev/null
-#ifndef TRAINPROPERTIES_H_
-#define TRAINPROPERTIES_H_
-
-#include <msp/gltk/dropdown.h>
-#include <msp/gltk/entry.h>
-#include <libr2c2/train.h>
-#include "dialog.h"
-
-class Engineer;
-
-class TrainProperties: public Dialog
-{
-private:
- Engineer &engineer;
- R2C2::Train *train;
- Msp::GLtk::Entry *ent_addr;
- Msp::GLtk::Dropdown *drp_protocol;
- Msp::GLtk::Dropdown *drp_type;
- Msp::GLtk::Entry *ent_name;
- Msp::GLtk::Dropdown *drp_priority;
- Msp::GLtk::List *lst_vehicles;
- Msp::GLtk::Dropdown *drp_new_vehicle;
- std::vector<const R2C2::VehicleType *> add_vehicles;
- std::set<unsigned> rem_vehicles;
-
-public:
- TrainProperties(Engineer &, R2C2::Train *);
-private:
- virtual void on_ok_clicked();
- void new_vehicle_selected(unsigned, const std::string &);
- void remove_vehicle_clicked();
- const R2C2::VehicleType &get_vehicle_type(unsigned, bool);
-};
-
-#endif
+#include <msp/core/maputils.h>
#include <msp/gl/tests.h>
#include <msp/gltk/button.h>
#include <msp/gltk/image.h>
+#include <msp/gltk/label.h>
+#include <msp/strings/format.h>
#include "libr2c2/vehicle.h"
#include "libr2c2/vehicletype.h"
#include "engineer.h"
train(t),
mode(SIDE),
forward(true),
- pipeline(280, 280, false),
- stale(false)
+ pipeline(400, 300, false)
{
- set_size(300, 330);
+ Loader::WidgetMap widgets;
+ DataFile::load(*this, "data/trainview.ui", widgets);
+
+ dynamic_cast<GLtk::Label *>(get_item(widgets, "lbl_title"))->set_text(format("View of %s", train.get_name()));
+ dynamic_cast<GLtk::Toggle *>(get_item(widgets, "tgl_forward"))->signal_toggled.connect(sigc::mem_fun(this, &TrainView::set_forward));
+ dynamic_cast<GLtk::Toggle *>(get_item(widgets, "tgl_roof"))->signal_toggled.connect(sigc::bind(sigc::mem_fun(this, &TrainView::ui_mode_toggled), ROOF));
+ dynamic_cast<GLtk::Toggle *>(get_item(widgets, "tgl_side"))->signal_toggled.connect(sigc::bind(sigc::mem_fun(this, &TrainView::ui_mode_toggled), SIDE));
+ dynamic_cast<GLtk::Toggle *>(get_item(widgets, "tgl_head"))->signal_toggled.connect(sigc::bind(sigc::mem_fun(this, &TrainView::ui_mode_toggled), HEAD));
tex.set_min_filter(GL::LINEAR);
- tex.storage(GL::RGB, 280, 280);
+ tex.storage(GL::RGB, 400, 300);
tex.image(0, GL::RGB, GL::UNSIGNED_BYTE, 0);
fbo.attach(GL::COLOR_ATTACHMENT0, tex, 0);
- depth.storage(GL::DEPTH_COMPONENT, 280, 280);
+ depth.storage(GL::DEPTH_COMPONENT, 400, 300);
fbo.attach(GL::DEPTH_ATTACHMENT, depth);
camera.set_up_direction(GL::Vector3(0, 0, 1));
pass->set_depth_test(&GL::DepthTest::lequal());
pass->set_lighting(&engineer.get_lighting());
- GLtk::Image *image;
- add(*(image = new GLtk::Image(&tex)));
- image->set_geometry(GLtk::Geometry(10, 40, geom.w-20, geom.h-50));
-
- GLtk::Button *btn;
-
- add(*(btn = new GLtk::Button("Roof")));
- btn->set_geometry(GLtk::Geometry(10, 10, 36, 25));
- btn->signal_clicked.connect(sigc::bind(sigc::mem_fun(this, &TrainView::set_mode), ROOF));
-
- add(*(btn = new GLtk::Button("Side")));
- btn->set_geometry(GLtk::Geometry(46, 10, 36, 25));
- btn->signal_clicked.connect(sigc::bind(sigc::mem_fun(this, &TrainView::set_mode), SIDE));
-
- add(*(btn = new GLtk::Button("Head")));
- btn->set_geometry(GLtk::Geometry(82, 10, 36, 25));
- btn->signal_clicked.connect(sigc::bind(sigc::mem_fun(this, &TrainView::set_mode), HEAD));
-
- add(*(tgl_forward = new GLtk::Toggle("Fwd")));
- tgl_forward->set_geometry(GLtk::Geometry(118, 8, 36, 27));
- tgl_forward->set_value(true);
- tgl_forward->signal_toggled.connect(sigc::mem_fun(this, &TrainView::set_forward));
-
- add(*(btn = new GLtk::Button("Close")));
- btn->set_geometry(GLtk::Geometry(geom.w-46, 10, 36, 25));
- btn->signal_clicked.connect(sigc::mem_fun(this, &TrainView::close_clicked));
+ dynamic_cast<GLtk::Image *>(get_item(widgets, "img_view"))->set_image(&tex);
engineer.add_train_view(*this);
}
mode = m;
}
+void TrainView::ui_mode_toggled(bool v, Mode m)
+{
+ if(v)
+ set_mode(m);
+}
+
void TrainView::set_forward(bool f)
{
forward = f;
fbo.clear(GL::COLOR_BUFFER_BIT|GL::DEPTH_BUFFER_BIT);
pipeline.render();
}
-
-void TrainView::button_release(int x, int y, unsigned btn)
-{
- GLtk::Panel::button_release(x, y, btn);
- if(stale)
- delete this;
-}
-
-void TrainView::close_clicked()
-{
- stale = true;
-}
#include <msp/gl/renderbuffer.h>
#include <msp/gl/framebuffer.h>
#include <msp/gl/texture2d.h>
-#include <msp/gltk/panel.h>
+#include <msp/gltk/dialog.h>
#include <msp/gltk/toggle.h>
#include "libr2c2/train.h"
class Engineer;
-class TrainView: public Msp::GLtk::Panel
+class TrainView: public Msp::GLtk::Dialog
{
public:
enum Mode
Msp::GL::Renderbuffer depth;
Msp::GL::Camera camera;
Msp::GL::Pipeline pipeline;
- bool stale;
public:
TrainView(Engineer &, const R2C2::Train &);
~TrainView();
void set_mode(Mode);
+private:
+ void ui_mode_toggled(bool, Mode);
+public:
void set_forward(bool);
void prepare();
-private:
- virtual void button_release(int, int, unsigned);
- void close_clicked();
};
#endif
--- /dev/null
+#include <msp/core/maputils.h>
+#include <msp/gltk/button.h>
+#include <msp/strings/format.h>
+#include "libr2c2/layout.h"
+#include "libr2c2/vehicle.h"
+#include "newvehicledialog.h"
+#include "vehiclespanel.h"
+
+using namespace std;
+using namespace Msp;
+using namespace R2C2;
+
+static string vehicle_name(Vehicle *const &veh)
+{
+ return format("%s %s", veh->get_type().get_article_number(), veh->get_type().get_name());
+}
+
+VehiclesPanel::VehiclesPanel(Train &t):
+ train(t),
+ vehicles(&vehicle_name)
+{
+ Loader::WidgetMap widgets;
+ DataFile::load(*this, "data/vehiclespanel.ui", widgets);
+
+ lst_vehicles = dynamic_cast<GLtk::List *>(get_item(widgets, "lst_vehicles"));
+ //lst_vehicles->set_data(vehicles);
+
+ dynamic_cast<GLtk::Button *>(get_item(widgets, "btn_add"))->signal_clicked.connect(sigc::mem_fun(this, &VehiclesPanel::add_clicked));
+ dynamic_cast<GLtk::Button *>(get_item(widgets, "btn_remove"))->signal_clicked.connect(sigc::mem_fun(this, &VehiclesPanel::remove_clicked));
+
+ unsigned n_veh = train.get_n_vehicles();
+ for(unsigned i=0; i<n_veh; ++i)
+ vehicles.append(&train.get_vehicle(i));
+
+ train.signal_vehicle_added.connect(sigc::mem_fun(this, &VehiclesPanel::vehicle_added));
+ train.signal_vehicle_removed.connect(sigc::mem_fun(this, &VehiclesPanel::vehicle_removed));
+
+ lst_vehicles->set_data(vehicles);
+}
+
+void VehiclesPanel::add_clicked()
+{
+ GLtk::Container *root = parent;
+ while(root->get_parent())
+ root = root->get_parent();
+
+ NewVehicleDialog *dlg = new NewVehicleDialog(train);
+ root->add(*dlg);
+ dlg->autosize();
+}
+
+void VehiclesPanel::remove_clicked()
+{
+ int index = lst_vehicles->get_selected_index();
+ if(index>0)
+ {
+ train.remove_vehicle(index);
+ lst_vehicles->set_selected_index(static_cast<unsigned>(index)<vehicles.size() ? index : index-1);
+ }
+}
+
+void VehiclesPanel::vehicle_added(unsigned i, Vehicle &veh)
+{
+ vehicles.insert(i, &veh);
+}
+
+void VehiclesPanel::vehicle_removed(unsigned i, Vehicle &)
+{
+ vehicles.remove(i);
+}
--- /dev/null
+#ifndef VEHICLESPANEL_H_
+#define VEHICLESPANEL_H_
+
+#include <msp/gltk/list.h>
+#include <msp/gltk/listdata.h>
+#include <msp/gltk/panel.h>
+#include "libr2c2/train.h"
+
+class VehiclesPanel: public Msp::GLtk::Panel
+{
+private:
+ R2C2::Train &train;
+ Msp::GLtk::FunctionListData<R2C2::Vehicle *> vehicles;
+ Msp::GLtk::List *lst_vehicles;
+
+public:
+ VehiclesPanel(R2C2::Train &);
+
+private:
+ void add_clicked();
+ void remove_clicked();
+ void vehicle_added(unsigned, R2C2::Vehicle &);
+ void vehicle_removed(unsigned, R2C2::Vehicle &);
+};
+
+#endif