tgl_forward->set_geometry(GLtk::Geometry(geom.w-30, geom.h-59, 20, 27));
tgl_forward->set_value(!train.get_locomotive().get_reverse());
tgl_forward->signal_toggled.connect(sigc::mem_fun(this, &TrainPanel::forward_toggled));
+ train.get_locomotive().signal_reverse_changed.connect(sigc::mem_fun(this, &TrainPanel::train_reverse_changed));
add(*(lbl_route=new GLtk::Label(res, "Free run")));
lbl_route->set_style("digital");
sld_speed->set_value(speed);
}
+void TrainPanel::train_reverse_changed(bool reverse)
+{
+ tgl_forward->set_value(!reverse);
+}
+
void TrainPanel::loco_function_changed(unsigned func, bool value)
{
map<unsigned, GLtk::Toggle *>::iterator i = tgl_funcs.find(func);
private:
void speed_slider_changed(double);
void train_speed_changed(unsigned);
+ void train_reverse_changed(bool);
void loco_function_changed(unsigned, bool);
void train_route_changed(const Marklin::Route *);
void train_status_changed(const std::string &);
signal_route_added.emit(r);
}
+Route &Layout::get_route(const string &name) const
+{
+ for(set<Route *>::const_iterator i=routes.begin(); i!=routes.end(); ++i)
+ if((*i)->get_name()==name)
+ return **i;
+ throw KeyError("Unknown route", name);
+}
+
void Layout::remove_route(Route &r)
{
if(routes.erase(&r))
void remove_track(Track &);
void add_route(Route &);
const std::set<Route *> &get_routes() const { return routes; }
+ Route &get_route(const std::string &) const;
void remove_route(Route &);
void save(const std::string &);
private:
~TrafficManager();
Control &get_control() const { return control; }
+ Layout &get_layout() const { return layout; }
const std::list<Block *> &get_blocks() const { return blocks; }
Block &get_block_by_track(const Track &) const;
const std::list<Train *> &get_trains() const { return trains; }
get_train(pkt.address).process_packet(pkt);
}
+void Client::receive(const RouteInfoPacket &pkt)
+{
+ routes.push_back(pkt.name);
+}
+
+void Client::receive(const TrainRoutePacket &pkt)
+{
+ get_train(pkt.address).process_packet(pkt);
+}
+
} // namespace Marklin
class Client: public Msp::Net::PacketReceiver<TrainInfoPacket>,
Msp::Net::PacketReceiver<TrainSpeedPacket>,
Msp::Net::PacketReceiver<TrainFunctionPacket>,
- Msp::Net::PacketReceiver<TrainStatusPacket>
+ Msp::Net::PacketReceiver<TrainStatusPacket>,
+ Msp::Net::PacketReceiver<RouteInfoPacket>,
+ Msp::Net::PacketReceiver<TrainRoutePacket>
{
public:
sigc::signal<void, NetTrain &> signal_train_added;
Msp::Net::StreamSocket *socket;
Msp::Net::Communicator *comm;
Msp::IO::EventDispatcher *event_disp;
+ std::list<std::string> routes;
std::map<unsigned, NetTrain *> trains;
public:
{ if(comm) comm->send(pkt); }
const Catalogue &get_catalogue() const { return catalogue; }
+ const std::list<std::string> &get_routes() const { return routes; }
NetTrain &get_train(unsigned);
private:
virtual void receive(const TrainSpeedPacket &);
virtual void receive(const TrainFunctionPacket &);
virtual void receive(const TrainStatusPacket &);
+ virtual void receive(const RouteInfoPacket &);
+ virtual void receive(const TrainRoutePacket &);
};
} // namespace Marklin
std::string status;
};
+struct RouteInfoPacket
+{
+ std::string name;
+};
+
+struct TrainRoutePacket
+{
+ unsigned address;
+ std::string route;
+};
+
+struct ErrorPacket
+{
+ std::string message;
+};
+
} // namespace Marklin
#endif
(&TrainFunctionPacket::functions);
add<TrainStatusPacket>() (&TrainStatusPacket::address)
(&TrainStatusPacket::status);
+ add<RouteInfoPacket>() (&RouteInfoPacket::name);
+ add<TrainRoutePacket>() (&TrainRoutePacket::address)
+ (&TrainRoutePacket::route);
+ add<ErrorPacket>() (&ErrorPacket::message);
}
} // namespace Marklin
#include <msp/net/inet.h>
#include "libmarklin/control.h"
+#include "libmarklin/layout.h"
#include "libmarklin/locomotive.h"
#include "libmarklin/locotype.h"
+#include "libmarklin/route.h"
#include "server.h"
using namespace std;
{
const list<Train *> &trains = trfc_mgr.get_trains();
for(list<Train *>::const_iterator i=trains.begin(); i!=trains.end(); ++i)
- {
- Locomotive &loco = (*i)->get_locomotive();
- (*i)->signal_target_speed_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_speed_changed), sigc::ref(**i)));
- loco.signal_function_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_function_changed), sigc::ref(**i)));
- (*i)->signal_status_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_status_changed), sigc::ref(**i)));
- }
+ train_added(**i);
listen_sock.listen(Net::InetAddr(0, 8315), 4);
listen_sock.signal_data_available.connect(sigc::mem_fun(this, &Server::incoming_connection));
{
Locomotive &loco = train.get_locomotive();
train.signal_target_speed_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_speed_changed), sigc::ref(train)));
+ loco.signal_reverse_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_reverse_changed), sigc::ref(train)));
loco.signal_function_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_function_changed), sigc::ref(train)));
+ train.signal_route_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_route_changed), sigc::ref(train)));
train.signal_status_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_status_changed), sigc::ref(train)));
TrainInfoPacket pkt;
send(pkt);
}
+void Server::train_reverse_changed(const Train &train, bool reverse)
+{
+ TrainSpeedPacket pkt;
+ pkt.address = train.get_locomotive().get_address();
+ pkt.speed = train.get_target_speed();
+ pkt.reverse = reverse;
+ send(pkt);
+}
+
void Server::train_function_changed(const Train &train, unsigned, bool)
{
TrainFunctionPacket pkt;
send(pkt);
}
+void Server::train_route_changed(const Train &train, const Route *route)
+{
+ TrainRoutePacket pkt;
+ pkt.address = train.get_locomotive().get_address();
+ if(route)
+ pkt.route = route->get_name();
+ send(pkt);
+}
+
void Server::train_status_changed(const Train &train, const string &status)
{
TrainStatusPacket pkt;
void Server::Connection::handshake_done()
{
+ const set<Route *> &routes = server.trfc_mgr.get_layout().get_routes();
+ for(set<Route *>::const_iterator i=routes.begin(); i!=routes.end(); ++i)
+ {
+ RouteInfoPacket pkt;
+ pkt.name = (*i)->get_name();
+ comm.send(pkt);
+ }
+
const list<Train *> &trains = server.trfc_mgr.get_trains();
for(list<Train *>::const_iterator i=trains.begin(); i!=trains.end(); ++i)
{
pkt.status = (*i)->get_status();
comm.send(pkt);
}
+ if((*i)->get_route())
+ {
+ TrainRoutePacket pkt;
+ pkt.address = loco.get_address();
+ pkt.route = (*i)->get_route()->get_name();
+ comm.send(pkt);
+ }
}
}
void Server::Connection::receive(const TrainSpeedPacket &pkt)
{
- Locomotive &loco = server.trfc_mgr.get_control().get_locomotive(pkt.address);
- Train &train = server.trfc_mgr.get_train_by_locomotive(loco);
- if(pkt.reverse!=loco.get_reverse())
- train.set_reverse(pkt.reverse);
- else
- train.set_speed(pkt.speed);
+ try
+ {
+ Locomotive &loco = server.trfc_mgr.get_control().get_locomotive(pkt.address);
+ Train &train = server.trfc_mgr.get_train_by_locomotive(loco);
+ if(pkt.reverse!=loco.get_reverse())
+ train.set_reverse(pkt.reverse);
+ else
+ train.set_speed(pkt.speed);
+ }
+ catch(const Exception &e)
+ {
+ error(e.what());
+ }
}
void Server::Connection::receive(const TrainFunctionPacket &pkt)
{
- Locomotive &loco = server.trfc_mgr.get_control().get_locomotive(pkt.address);
- for(unsigned i=0; i<9; ++i)
- if(((pkt.functions^loco.get_functions())>>i)&1)
- loco.set_function(i, (pkt.functions>>i)&1);
+ try
+ {
+ Locomotive &loco = server.trfc_mgr.get_control().get_locomotive(pkt.address);
+ for(unsigned i=0; i<9; ++i)
+ if(((pkt.functions^loco.get_functions())>>i)&1)
+ loco.set_function(i, (pkt.functions>>i)&1);
+ }
+ catch(const Exception &e)
+ {
+ error(e.what());
+ }
+}
+
+void Server::Connection::receive(const TrainRoutePacket &pkt)
+{
+ try
+ {
+ Locomotive &loco = server.trfc_mgr.get_control().get_locomotive(pkt.address);
+ Train &train = server.trfc_mgr.get_train_by_locomotive(loco);
+ if(pkt.route.empty())
+ train.set_route(0);
+ else
+ {
+ Route &route = server.trfc_mgr.get_layout().get_route(pkt.route);
+ train.set_route(&route);
+ }
+ }
+ catch(const Exception &e)
+ {
+ error(e.what());
+ }
+}
+
+void Server::Connection::error(const string &msg)
+{
+ ErrorPacket pkt;
+ pkt.message = msg;
+ comm.send(pkt);
}
} // namespace Marklin
{
private:
struct Connection: private Msp::Net::PacketReceiver<TrainSpeedPacket>,
- private Msp::Net::PacketReceiver<TrainFunctionPacket>
+ private Msp::Net::PacketReceiver<TrainFunctionPacket>,
+ private Msp::Net::PacketReceiver<TrainRoutePacket>
{
Server &server;
Msp::Net::StreamSocket *socket;
void end_of_file();
virtual void receive(const TrainSpeedPacket &);
virtual void receive(const TrainFunctionPacket &);
+ virtual void receive(const TrainRoutePacket &);
+ void error(const std::string &);
};
Protocol proto;
void train_added(Train &);
void train_speed_changed(const Train &, unsigned);
+ void train_reverse_changed(const Train &, bool);
void train_function_changed(const Train &, unsigned, bool);
+ void train_route_changed(const Train &, const Route *);
void train_status_changed(const Train &, const std::string &);
template<typename P>
client.send(pkt);
}
+void NetTrain::set_route(const string &r)
+{
+ if(r==route)
+ return;
+
+ TrainRoutePacket pkt;
+ pkt.address = address;
+ pkt.route = r;
+ client.send(pkt);
+}
+
void NetTrain::process_packet(const TrainSpeedPacket &pkt)
{
if(pkt.speed!=speed)
signal_status_changed.emit(status);
}
+void NetTrain::process_packet(const TrainRoutePacket &pkt)
+{
+ route = pkt.route;
+ signal_route_changed.emit(route);
+}
+
} // namespace Marklin
sigc::signal<void, unsigned> signal_speed_changed;
sigc::signal<void, bool> signal_reverse_changed;
sigc::signal<void, unsigned, bool> signal_function_changed;
+ sigc::signal<void, const std::string &> signal_route_changed;
sigc::signal<void, const std::string &> signal_status_changed;
private:
unsigned speed;
bool reverse;
unsigned functions;
+ std::string route;
std::string status;
public:
bool get_reverse() const { return reverse; }
void set_function(unsigned, bool);
bool get_function(unsigned i) const { return (functions>>i)&1; }
+ void set_route(const std::string &);
+ const std::string &get_route() const { return route; }
void process_packet(const TrainSpeedPacket &);
void process_packet(const TrainFunctionPacket &);
+ void process_packet(const TrainRoutePacket &);
void process_packet(const TrainStatusPacket &);
};
Distributed under the GPL
*/
+#include <gtkmm/separator.h>
#include <msp/net/resolve.h>
#include <msp/time/units.h>
#include "remote.h"
delete addr;
window.signal_hide().connect(sigc::bind(sigc::mem_fun(this, &Remote::exit), 0));
+ window.set_default_size(300, 200);
window.set_border_width(5);
+
train_box = new Gtk::VBox(false, 5);
window.add(*manage(train_box));
+
window.show_all();
}
void Remote::train_added(Marklin::NetTrain &t)
{
- TrainPanel *panel = new TrainPanel(t);
- train_box->add(*manage(panel));
+ TrainPanel *panel = new TrainPanel(client, t);
+ if(!train_panels.empty())
+ {
+ Gtk::HSeparator *sep = new Gtk::HSeparator;
+ train_box->pack_start(*manage(sep), false, true);
+ sep->show();
+ }
+ train_box->pack_start(*manage(panel), false, true);
+ train_panels.push_back(panel);
}
#include <msp/core/application.h>
#include "network/client.h"
+class TrainPanel;
+
class Remote: public Msp::Application
{
private:
Gtk::Main gtk;
Gtk::Window window;
Gtk::Box *train_box;
+ std::vector<TrainPanel *> train_panels;
static Msp::Application::RegApp<Remote> reg;
*/
#include <gtkmm/box.h>
+#include <gtkmm/liststore.h>
#include "libmarklin/locotype.h"
#include "trainpanel.h"
using namespace std;
-TrainPanel::TrainPanel(Marklin::NetTrain &t):
+TrainPanel::TrainPanel(Marklin::Client &c, Marklin::NetTrain &t):
+ client(c),
train(t)
{
train.signal_name_changed.connect(sigc::mem_fun(this, &TrainPanel::name_changed));
train.signal_speed_changed.connect(sigc::mem_fun(this, &TrainPanel::speed_changed));
+ train.signal_reverse_changed.connect(sigc::mem_fun(this, &TrainPanel::reverse_changed));
train.signal_function_changed.connect(sigc::mem_fun(this, &TrainPanel::function_changed));
+ train.signal_route_changed.connect(sigc::mem_fun(this, &TrainPanel::route_changed));
train.signal_status_changed.connect(sigc::mem_fun(this, &TrainPanel::status_changed));
set_label(train.get_name());
add(*manage(vbox));
vbox->set_border_width(5);
- vbox->add(*manage(scl_speed = new Gtk::HScale));
+ Gtk::HBox *hbox = new Gtk::HBox(false, 5);
+ vbox->add(*manage(hbox));
+
+ hbox->add(*manage(scl_speed = new Gtk::HScale));
scl_speed->set_digits(0);
scl_speed->set_range(0, 14);
scl_speed->set_increments(1, 1);
- scl_speed->set_size_request(280, -1);
+ scl_speed->set_size_request(210, -1);
scl_speed->signal_value_changed().connect(sigc::mem_fun(this, &TrainPanel::ui_speed_changed));
+ hbox->add(*manage(chk_reverse = new Gtk::CheckButton("Rev")));
+ chk_reverse->signal_toggled().connect(sigc::mem_fun(this, &TrainPanel::ui_reverse_changed));
+
Gtk::HBox *func_box = new Gtk::HBox(false, 5);
vbox->add(*manage(func_box));
const std::map<unsigned, string> &funcs = train.get_loco_type().get_functions();
chk->signal_toggled().connect(sigc::bind(sigc::mem_fun(this, &TrainPanel::ui_function_changed), i->first));
}
+ Glib::RefPtr<Gtk::ListStore> route_store = Gtk::ListStore::create(route_columns);
+ vbox->add(*manage(cmb_route = new Gtk::ComboBox(route_store)));
+ cmb_route->pack_start(route_columns.name);
+ route_store->append();
+ const list<string> &routes = client.get_routes();
+ for(list<string>::const_iterator i=routes.begin(); i!=routes.end(); ++i)
+ {
+ Gtk::TreeIter iter = route_store->append();
+ (*iter)[route_columns.name] = *i;
+ }
+ cmb_route->signal_changed().connect(sigc::mem_fun(this, &TrainPanel::ui_route_changed));
+
vbox->add(*manage(lbl_status = new Gtk::Label));
show_all();
scl_speed->set_value(speed);
}
+void TrainPanel::reverse_changed(bool rev)
+{
+ chk_reverse->set_active(rev);
+}
+
void TrainPanel::function_changed(unsigned func, bool set)
{
std::map<unsigned, Gtk::CheckButton *>::iterator i = chk_funcs.find(func);
i->second->set_active(set);
}
+void TrainPanel::route_changed(const string &route)
+{
+ Gtk::TreeNodeChildren children = cmb_route->get_model()->children();
+ for(Gtk::TreeIter i=children.begin(); i!=children.end(); ++i)
+ if((*i)[route_columns.name]==route)
+ {
+ cmb_route->set_active(i);
+ break;
+ }
+}
+
void TrainPanel::ui_speed_changed()
{
train.set_speed(static_cast<unsigned>(scl_speed->get_value()));
}
+void TrainPanel::ui_reverse_changed()
+{
+ train.set_reverse(chk_reverse->get_active());
+}
+
void TrainPanel::ui_function_changed(unsigned func)
{
std::map<unsigned, Gtk::CheckButton *>::iterator i = chk_funcs.find(func);
if(i!=chk_funcs.end())
train.set_function(func, i->second->get_active());
}
+
+void TrainPanel::ui_route_changed()
+{
+ Gtk::TreeIter iter = cmb_route->get_active();
+ train.set_route(Glib::ustring((*iter)[route_columns.name]));
+}
+
+
+TrainPanel::RouteRecord::RouteRecord()
+{
+ add(name);
+}
#define TRAINPANEL_H_
#include <gtkmm/checkbutton.h>
-#include <gtkmm/frame.h>
+#include <gtkmm/combobox.h>
+#include <gtkmm/expander.h>
#include <gtkmm/label.h>
#include <gtkmm/scale.h>
+#include "network/client.h"
#include "network/train.h"
-class TrainPanel: public Gtk::Frame
+class TrainPanel: public Gtk::Expander
{
private:
+ struct RouteRecord: public Gtk::TreeModelColumnRecord
+ {
+ Gtk::TreeModelColumn<Glib::ustring> name;
+
+ RouteRecord();
+ };
+
+ Marklin::Client &client;
Marklin::NetTrain &train;
Gtk::Scale *scl_speed;
Gtk::Label *lbl_status;
+ Gtk::CheckButton *chk_reverse;
+ RouteRecord route_columns;
+ Gtk::ComboBox *cmb_route;
std::map<unsigned, Gtk::CheckButton *> chk_funcs;
public:
- TrainPanel(Marklin::NetTrain &);
+ TrainPanel(Marklin::Client &, Marklin::NetTrain &);
private:
void name_changed(const std::string &);
void status_changed(const std::string &);
void speed_changed(unsigned);
+ void reverse_changed(bool);
void function_changed(unsigned, bool);
+ void route_changed(const std::string &);
void ui_speed_changed();
+ void ui_reverse_changed();
void ui_function_changed(unsigned);
+ void ui_route_changed();
};
#endif