--- /dev/null
+layout
+{
+ margin
+ {
+ top 2;
+ horizontal 8;
+ bottom 6;
+ };
+};
+
+column
+{
+ row
+ {
+ label "lbl_title"
+ {
+ text "Clock";
+ };
+
+ split;
+
+ action_button "btn_close" 0
+ {
+ style "red_cross";
+ };
+ };
+
+ label "placeholder";
+
+ row
+ {
+ label ""
+ {
+ text "Rate";
+ };
+
+ entry "ent_rate";
+
+ button "btn_rate"
+ {
+ text "Set";
+ };
+
+ split;
+
+ button "btn_stop"
+ {
+ text "Stop";
+ };
+ };
+
+ row
+ {
+ label ""
+ {
+ text "Time";
+ };
+
+ entry "ent_hour";
+
+ label ""
+ {
+ text ":";
+ };
+
+ entry "ent_minute";
+
+ button "btn_time"
+ {
+ text "Set";
+ };
+ };
+};
+
+indicator "ind_stopped";
+constraint ALIGN_LEFT "btn_stop";
+constraint ALIGN_RIGHT "btn_stop";
+constraint ABOVE "btn_stop";
+
+draghandle "";
+expand true false;
+constraint COPY_HEIGHT "lbl_title";
+constraint LEFT_OF "btn_close";
style "digital";
};
- label "lbl_clock"
+ row
{
- style "digital";
+ label "lbl_clock"
+ {
+ style "digital";
+ };
+ expand true false;
+
+ button "btn_clock"
+ {
+ text "Clock";
+ };
};
};
graphic ACTIVE "lever_up";
};
};
+
+style "clock"
+{
+ part "hourhand";
+ part "minutehand";
+};
--- /dev/null
+#include <msp/gltk/button.h>
+#include <msp/gltk/stack.h>
+#include "libr2c2/layout.h"
+#include "clockdialog.h"
+#include "clockwidget.h"
+#include "engineer.h"
+
+using namespace std;
+using namespace Msp;
+using namespace R2C2;
+
+ClockDialog::ClockDialog(Engineer &engineer):
+ clock(engineer.get_layout().get_clock())
+{
+ Loader::WidgetMap widgets;
+ DataFile::load(*this, "data/clockdialog.ui", widgets);
+
+ GLtk::Button *button = dynamic_cast<GLtk::Button *>(get_item(widgets, "btn_rate"));
+ button->signal_clicked.connect(sigc::mem_fun(this, &ClockDialog::set_rate));
+ ent_rate = dynamic_cast<GLtk::Entry *>(get_item(widgets, "ent_rate"));
+
+ button = dynamic_cast<GLtk::Button *>(get_item(widgets, "btn_stop"));
+ button->signal_clicked.connect(sigc::mem_fun(this, &ClockDialog::stop_clicked));
+ ind_stopped = dynamic_cast<GLtk::Indicator *>(get_item(widgets, "ind_stopped"));
+ ind_stopped->set_active(clock.is_stopped());
+
+ button = dynamic_cast<GLtk::Button *>(get_item(widgets, "btn_time"));
+ button->signal_clicked.connect(sigc::mem_fun(this, &ClockDialog::set_time));
+ ent_hour = dynamic_cast<GLtk::Entry *>(get_item(widgets, "ent_hour"));
+ ent_minute = dynamic_cast<GLtk::Entry *>(get_item(widgets, "ent_minute"));
+
+ GLtk::Stack stack(*layout);
+ stack.arrange(*get_item(widgets, "placeholder"));
+ add(*(new ClockWidget(clock)));
+
+ clock.signal_minute.connect(sigc::mem_fun(this, &ClockDialog::minute_changed));
+}
+
+void ClockDialog::minute_changed()
+{
+ Time::TimeDelta time = clock.get_current_time();
+ unsigned hour = time/Time::hour;
+ unsigned minute = static_cast<unsigned>(time/Time::min)%60;
+ ent_hour->set_text(lexical_cast<string>(hour));
+ ent_minute->set_text(lexical_cast<string>(minute));
+}
+
+void ClockDialog::set_rate()
+{
+ try
+ {
+ float rate = lexical_cast<float>(ent_rate->get_text());
+ clock.set_rate(rate);
+ }
+ catch(const lexical_error &e)
+ {
+ }
+}
+
+void ClockDialog::stop_clicked()
+{
+ clock.stop(!clock.is_stopped());
+ ind_stopped->set_active(clock.is_stopped());
+}
+
+void ClockDialog::set_time()
+{
+ try
+ {
+ unsigned hour = lexical_cast<unsigned>(ent_hour->get_text());
+ unsigned minute = lexical_cast<unsigned>(ent_minute->get_text());
+ clock.set_current_time(hour*Time::hour+minute*Time::min);
+ }
+ catch(const lexical_error &e)
+ {
+ }
+}
--- /dev/null
+#ifndef CLOCKDIALOG_H_
+#define CLOCKDIALOG_H_
+
+#include <msp/gltk/dialog.h>
+#include <msp/gltk/entry.h>
+#include <msp/gltk/indicator.h>
+#include "libr2c2/clock.h"
+
+class ClockWidget;
+class Engineer;
+
+class ClockDialog: public Msp::GLtk::Dialog, public sigc::trackable
+{
+private:
+ R2C2::Clock &clock;
+ Msp::GLtk::Entry *ent_rate;
+ Msp::GLtk::Indicator *ind_stopped;
+ Msp::GLtk::Entry *ent_hour;
+ Msp::GLtk::Entry *ent_minute;
+
+public:
+ ClockDialog(Engineer &);
+
+private:
+ void minute_changed();
+ void set_rate();
+ void stop_clicked();
+ void set_time();
+};
+
+#endif
--- /dev/null
+#include <msp/gl/meshbuilder.h>
+#include <msp/gl/renderer.h>
+#include <msp/gltk/part.h>
+#include "clockwidget.h"
+
+using namespace std;
+using namespace Msp;
+
+ClockWidget::ClockWidget(R2C2::Clock &c):
+ clock(c),
+ hour_hand((GL::VERTEX2, GL::COLOR4_UBYTE)),
+ minute_hand((GL::VERTEX2, GL::COLOR4_UBYTE))
+{ }
+
+void ClockWidget::autosize_special(const GLtk::Part &, GLtk::Geometry &ageom) const
+{
+ ageom.w = max(ageom.w, 200U);
+ ageom.h = max(ageom.h, 200U);
+}
+
+void ClockWidget::rebuild_special(const GLtk::Part &part)
+{
+ if(part.get_name()=="hourhand" || part.get_name()=="minutehand")
+ {
+ bool minute = (part.get_name()=="minutehand");
+ GL::Mesh &mesh = (minute ? minute_hand : hour_hand);
+ float length = min(geom.w, geom.h)*(minute ? 0.5f : 0.35f);
+ float width = length*(minute ? 0.05f : 0.1f);
+ mesh.clear();
+ GL::MeshBuilder bld(mesh);
+ bld.color(0.0f, 0.0f, 0.0f);
+ bld.begin(GL::TRIANGLES);
+ bld.vertex(width, -width);
+ bld.vertex(0.0f, length);
+ bld.vertex(-width, -width);
+ bld.end();
+
+ part_cache.insert_special(part);
+ }
+}
+
+void ClockWidget::render_special(const GLtk::Part &part, GL::Renderer &renderer) const
+{
+ if(part.get_name()=="hourhand" || part.get_name()=="minutehand")
+ {
+ bool minute = (part.get_name()=="minutehand");
+ const GL::Mesh &mesh = (minute ? minute_hand : hour_hand);
+
+ float orientation = clock.get_current_time()/((minute ? 1 : 12)*Time::hour);
+ Geometry::Angle<float> angle = Geometry::Angle<float>::from_turns(orientation);
+
+ GL::Renderer::Push push(renderer);
+ renderer.set_texture(0);
+ renderer.matrix_stack() *= GL::Matrix::translation(GL::Vector3(geom.w*0.5f, geom.h*0.5f, 0.0f));
+ renderer.matrix_stack() *= GL::Matrix::rotation(angle, GL::Vector3(0, 0, -1));
+ mesh.draw(renderer);
+ }
+}
--- /dev/null
+#ifndef CLOCKWIDGET_H_
+#define CLOCKWIDGET_H_
+
+#include <msp/gltk/widget.h>
+#include "libr2c2/clock.h"
+
+class ClockWidget: public Msp::GLtk::Widget
+{
+private:
+ R2C2::Clock &clock;
+ Msp::GL::Mesh hour_hand;
+ Msp::GL::Mesh minute_hand;
+
+public:
+ ClockWidget(R2C2::Clock &);
+
+ virtual const char *get_class() const { return "clock"; }
+
+private:
+ virtual void autosize_special(const Msp::GLtk::Part &, Msp::GLtk::Geometry &) const;
+ virtual void rebuild_special(const Msp::GLtk::Part &);
+ virtual void render_special(const Msp::GLtk::Part &, Msp::GL::Renderer &) const;
+};
+
+#endif
#include <msp/strings/format.h>
#include "libr2c2/clock.h"
#include "libr2c2/driver.h"
+#include "clockdialog.h"
#include "engineer.h"
#include "mainwindow.h"
#include "trainlistdialog.h"
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));
+ dynamic_cast<GLtk::Button *>(get_item(widgets, "btn_clock"))->signal_clicked.connect(sigc::mem_fun(this, &MainWindow::clock_clicked));
R2C2::Driver &driver = engineer.get_layout().get_driver();
if(driver.get_power())
engineer.quit();
}
+void MainWindow::clock_clicked()
+{
+ ClockDialog *dlg = new ClockDialog(engineer);
+ find_ancestor<GLtk::Root>()->add(*dlg);
+}
+
void MainWindow::power_event(bool p)
{
ind_on->set_active(p);
void halt_clicked();
void trains_clicked();
void quit_clicked();
+ void clock_clicked();
void power_event(bool);
void halt_event(bool);
void clock_minute();
namespace R2C2 {
Clock::Clock():
- rate(1)
+ rate(1),
+ stopped(false)
{ }
void Clock::set_rate(float s)
current_time = t;
}
+void Clock::stop(bool s)
+{
+ stopped = s;
+}
+
void Clock::tick(const Time::TimeDelta &dt)
{
+ if(stopped)
+ return;
+
unsigned prev_minute = current_time/Time::min;
current_time += dt*rate;
if(current_time>=Time::day)
private:
Msp::Time::TimeDelta current_time;
float rate;
+ bool stopped;
public:
Clock();
float get_rate() const { return rate; }
void set_current_time(const Msp::Time::TimeDelta &);
const Msp::Time::TimeDelta &get_current_time() const { return current_time; }
+ void stop(bool);
+ bool is_stopped() const { return stopped; }
void tick(const Msp::Time::TimeDelta &);
void save(std::list<Msp::DataFile::Statement> &) const;
};