From d84f187ca34a6ab2f8c37d85fa13d5c113714344 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Fri, 3 Apr 2015 00:53:08 +0300 Subject: [PATCH] Add a dialog and necessary support code to display departures --- data/departuresdialog.ui | 48 ++++++++ data/r2c2.res | 22 ++++ source/engineer/departuresdialog.cpp | 112 ++++++++++++++++++ source/engineer/departuresdialog.h | 41 +++++++ source/engineer/engineer.cpp | 15 ++- source/libr2c2/departures.cpp | 168 +++++++++++++++++++++++++++ source/libr2c2/departures.h | 52 +++++++++ 7 files changed, 457 insertions(+), 1 deletion(-) create mode 100644 data/departuresdialog.ui create mode 100644 source/engineer/departuresdialog.cpp create mode 100644 source/engineer/departuresdialog.h create mode 100644 source/libr2c2/departures.cpp create mode 100644 source/libr2c2/departures.h diff --git a/data/departuresdialog.ui b/data/departuresdialog.ui new file mode 100644 index 0000000..f124fc7 --- /dev/null +++ b/data/departuresdialog.ui @@ -0,0 +1,48 @@ +layout +{ + margin + { + top 2; + horizontal 8; + bottom 6; + }; +}; + +column +{ + row + { + label "lbl_title" + { + text "Departures"; + }; + + split; + + action_button "btn_close" 0 + { + style "red_cross"; + }; + }; + + dropdown "drp_groups"; + + panel "pnl_departures" + { + style "digital_background"; + layout + { + margin + { + horizontal 4; + vertical 4; + }; + column_spacing 10; + }; + }; +}; + +draghandle ""; +expand true false; +constraint COPY_HEIGHT "lbl_title"; +constraint LEFT_OF "btn_close"; diff --git a/data/r2c2.res b/data/r2c2.res index 18cdfc8..fb67321 100644 --- a/data/r2c2.res +++ b/data/r2c2.res @@ -409,6 +409,28 @@ style "label-digital" }; }; +style "label-digital_borderless" +{ + font "digitalreadout-16.font"; + font_color 0.3 1 0.3; + + part "text" + { + fill 0.0 0.0; + align 0.0 0.5; + }; +}; + +style "panel-digital_background" +{ + part + { + graphic NORMAL "sunken_black_bg"; + }; + + part "children"; +}; + graphic "sunken_white_bg" { texture "gui.png"; diff --git a/source/engineer/departuresdialog.cpp b/source/engineer/departuresdialog.cpp new file mode 100644 index 0000000..bea7f79 --- /dev/null +++ b/source/engineer/departuresdialog.cpp @@ -0,0 +1,112 @@ +#include +#include +#include +#include "libr2c2/layout.h" +#include "libr2c2/train.h" +#include "libr2c2/zone.h" +#include "departuresdialog.h" + +using namespace std; +using namespace Msp; +using namespace R2C2; + +DeparturesDialog::DeparturesDialog(const Layout &l, const string &group): + layout(l), + departures(0) +{ + Loader::WidgetMap widgets; + DataFile::load(*this, "data/departuresdialog.ui", widgets); + + lbl_title = dynamic_cast(get_item(widgets, "lbl_title")); + drp_groups = dynamic_cast(get_item(widgets, "drp_groups")); + drp_groups->set_data(groups); + drp_groups->signal_item_selected.connect(sigc::mem_fun(this, &DeparturesDialog::group_selected)); + pnl_departures = dynamic_cast(get_item(widgets, "pnl_departures")); + + GLtk::Grid grid(*pnl_departures->get_layout(), 2); + rows.resize(8); + for(unsigned i=0; iadd(*(row.lbl_time = new GLtk::Label)); + row.lbl_time->set_style("digital_borderless"); + pnl_departures->add(*(row.lbl_train = new GLtk::Label)); + row.lbl_train->set_style("digital_borderless"); + } + + const set &zones = layout.get_all(); + set group_set; + for(set::const_iterator i=zones.begin(); i!=zones.end(); ++i) + group_set.insert((*i)->get_group()); + + for(set::const_iterator i=group_set.begin(); i!=group_set.end(); ++i) + { + groups.append(*i); + if(*i==group) + drp_groups->set_selected_index(groups.size()-1); + } +} + +void DeparturesDialog::group_selected(unsigned index) +{ + const string &group = groups.get(index); + lbl_title->set_text("Departures from "+group); + + for(vector::iterator i=rows.begin(); i!=rows.end(); ++i) + i->set_departure(0); + + delete departures; + departures = new Departures(layout, group); + departures->signal_departure_added.connect(sigc::mem_fun(this, &DeparturesDialog::departure_added)); + departures->signal_departure_removed.connect(sigc::mem_fun(this, &DeparturesDialog::departure_removed)); + + update_rows(); +} + +void DeparturesDialog::departure_added(const Departures::Departure &) +{ + update_rows(); +} + +void DeparturesDialog::departure_removed(const Departures::Departure &) +{ + update_rows(); +} + +void DeparturesDialog::update_rows() +{ + const list &deps = departures->get_departures(); + list::const_iterator i = deps.begin(); + for(unsigned j=0; jtime/Time::sec; + unsigned hour = secs/3600%24; + unsigned min = secs/60%60; + lbl_time->set_text(format("%2d:%02d", hour, min)); + lbl_train->set_text(departure->train->get_name()); + } + else + { + lbl_time->set_text(string()); + lbl_train->set_text(string()); + } +} diff --git a/source/engineer/departuresdialog.h b/source/engineer/departuresdialog.h new file mode 100644 index 0000000..9dc99b8 --- /dev/null +++ b/source/engineer/departuresdialog.h @@ -0,0 +1,41 @@ +#ifndef DEPARTURESDIALOG_H_ +#define DEPARTURESDIALOG_H_ + +#include +#include +#include +#include "libr2c2/departures.h" + +class DeparturesDialog: public Msp::GLtk::Dialog +{ +private: + struct Row + { + const R2C2::Departures::Departure *departure; + Msp::GLtk::Label *lbl_time; + Msp::GLtk::Label *lbl_train; + + Row(); + + void set_departure(const R2C2::Departures::Departure *); + }; + + const R2C2::Layout &layout; + Msp::GLtk::Dropdown *drp_groups; + Msp::GLtk::Label *lbl_title; + Msp::GLtk::BasicListData groups; + Msp::GLtk::Panel *pnl_departures; + R2C2::Departures *departures; + std::vector rows; + +public: + DeparturesDialog(const R2C2::Layout &, const std::string & = std::string()); + +private: + void group_selected(unsigned); + void departure_added(const R2C2::Departures::Departure &); + void departure_removed(const R2C2::Departures::Departure &); + void update_rows(); +}; + +#endif diff --git a/source/engineer/engineer.cpp b/source/engineer/engineer.cpp index ef5b54d..da95505 100644 --- a/source/engineer/engineer.cpp +++ b/source/engineer/engineer.cpp @@ -20,11 +20,13 @@ #include "libr2c2/driver.h" #include "libr2c2/trackcircuit.h" #include "libr2c2/tracktype.h" +#include "libr2c2/zone.h" #include "3d/allocation.h" #include "3d/path.h" #include "3d/track.h" #include "3d/trackcircuit.h" #include "3d/vehicle.h" +#include "departuresdialog.h" #include "dynamicdialog.h" #include "engineer.h" #include "mainwindow.h" @@ -228,12 +230,23 @@ void Engineer::button_press(unsigned btn) set_status(format("Turnout %d", track->get_turnout_address())); } } - if(unsigned saddr = track->get_sensor_address()) + else if(unsigned saddr = track->get_sensor_address()) { if(options.simulate) layout.get_driver().set_sensor(saddr, !layout.get_driver().get_sensor(saddr)); set_status(format("Sensor %d", saddr)); } + else + { + const set &zones = layout.get_all(); + for(set::const_iterator i=zones.begin(); i!=zones.end(); ++i) + if((*i)->has_track(*track)) + { + DeparturesDialog *dlg = new DeparturesDialog(layout, (*i)->get_group()); + root->add(*dlg); + break; + } + } } else if(Vehicle *veh = dynamic_cast(obj)) { diff --git a/source/libr2c2/departures.cpp b/source/libr2c2/departures.cpp new file mode 100644 index 0000000..d21cc94 --- /dev/null +++ b/source/libr2c2/departures.cpp @@ -0,0 +1,168 @@ +#include "departures.h" +#include "layout.h" +#include "timetable.h" +#include "train.h" +#include "trainrouter.h" +#include "zone.h" + +using namespace std; +using namespace Msp; + +namespace { + +bool departure_time_order(const R2C2::Departures::Departure &d1, const R2C2::Departures::Departure &d2) +{ + return d1.time &trains = layout.get_trains(); + for(map::const_iterator i=trains.begin(); i!=trains.end(); ++i) + { + Timetable *timetable = i->second->get_ai_of_type(); + (void)timetable; + TrainRouter *router = i->second->get_ai_of_type(); + router->signal_route_changed.connect(sigc::bind(sigc::mem_fun(this, &Departures::train_route_changed), sigc::ref(*i->second))); + router->signal_departed.connect(sigc::bind(sigc::mem_fun(this, &Departures::train_departed), sigc::ref(*i->second))); + + update_departures(*i->second); + } +} + +void Departures::train_route_changed(const Route *, Train &train) +{ + update_departures(train); +} + +void Departures::train_departed(Train &train) +{ + update_departures(train); +} + +void Departures::update_departures(Train &train) +{ + const Clock &clock = train.get_layout().get_clock(); + Time::TimeDelta t = clock.get_current_time(); + float rate = clock.get_rate(); + + list collected_departures; + + Timetable *timetable = train.get_ai_of_type(); + unsigned tt_length = timetable->get_length(); + for(unsigned i=0; iget_row(i); + if(row.type==Timetable::DEPART) + if(Zone *zone = get_attached_zone(*row.target)) + { + Time::TimeDelta dt = row.time; + while(dt(); + Time::TimeDelta departure_delay = router->get_departure_delay(); + if(departure_delay) + if(Zone *zone = get_attached_zone(*train.get_block_allocator().last())) + { + Departure dep(*zone, train, t+departure_delay*rate); + + list::iterator i = collected_departures.begin(); + bool duplicate = false; + for(; (i!=collected_departures.end() && !duplicate); ++i) + { + if(i->time>dep.time) + { + duplicate = (i->timetime+Time::min>dep.time); + } + + if(!duplicate) + collected_departures.push_back(dep); + } + + merge_departures(train, collected_departures); +} + +void Departures::merge_departures(Train &train, const std::list &collected_departures) +{ + list::iterator i = departures.begin(); + list::const_iterator j = collected_departures.begin(); + while(i!=departures.end() && j!=collected_departures.end()) + { + if(i->time>j->time) + { + list::iterator k = departures.insert(i, *j); + signal_departure_added.emit(*k); + ++j; + } + else if(i->train==&train) + { + if(i->time==j->time) + { + ++i; + ++j; + } + else + { + signal_departure_removed.emit(*i); + departures.erase(i++); + } + } + else + ++i; + } + + for(; j!=collected_departures.end(); ++j) + { + departures.push_back(*j); + signal_departure_added.emit(departures.back()); + } + + for(; i!=departures.end(); ) + { + if(i->train==&train) + { + signal_departure_removed.emit(*i); + departures.erase(i++); + } + else + ++i; + } +} + +Zone *Departures::get_attached_zone(const TrackChain &chain) const +{ + const TrackChain::TrackSet &tracks = chain.get_tracks(); + for(vector::const_iterator i=zones.begin(); i!=zones.end(); ++i) + { + for(TrackChain::TrackSet::const_iterator j=tracks.begin(); j!=tracks.end(); ++j) + if((*i)->has_track(**j)) + return *i; + } + + return 0; +} + + +Departures::Departure::Departure(Zone &z, Train &t, const Time::TimeDelta &m): + zone(&z), + train(&t), + time(m) +{ } + +} // namespace R2C2 diff --git a/source/libr2c2/departures.h b/source/libr2c2/departures.h new file mode 100644 index 0000000..b513975 --- /dev/null +++ b/source/libr2c2/departures.h @@ -0,0 +1,52 @@ +#ifndef LIBR2C2_DEPARTURES_H_ +#define LIBR2C2_DEPARTURES_H_ + +#include +#include +#include +#include +#include + +namespace R2C2 { + +class Layout; +class Zone; +class Route; +class TrackChain; +class Train; + +class Departures: public sigc::trackable +{ +public: + struct Departure + { + Zone *zone; + Train *train; + Msp::Time::TimeDelta time; + + Departure(Zone &, Train &, const Msp::Time::TimeDelta &); + }; + + sigc::signal signal_departure_added; + sigc::signal signal_departure_removed; + +private: + std::vector zones; + std::list departures; + +public: + Departures(const Layout &, const std::string &); + + const std::list &get_departures() const { return departures; } + +private: + void train_route_changed(const Route *, Train &); + void train_departed(Train &); + void update_departures(Train &); + void merge_departures(Train &, const std::list &); + Zone *get_attached_zone(const TrackChain &) const; +}; + +} // namespace R2C2 + +#endif -- 2.45.2