]> git.tdb.fi Git - r2c2.git/commitdiff
Add a dialog to control the clock
authorMikko Rasa <tdb@tdb.fi>
Fri, 30 Jan 2015 09:03:34 +0000 (11:03 +0200)
committerMikko Rasa <tdb@tdb.fi>
Fri, 30 Jan 2015 09:03:34 +0000 (11:03 +0200)
data/clockdialog.ui [new file with mode: 0644]
data/mainwindow.ui
data/r2c2.res
source/engineer/clockdialog.cpp [new file with mode: 0644]
source/engineer/clockdialog.h [new file with mode: 0644]
source/engineer/clockwidget.cpp [new file with mode: 0644]
source/engineer/clockwidget.h [new file with mode: 0644]
source/engineer/mainwindow.cpp
source/engineer/mainwindow.h
source/libr2c2/clock.cpp
source/libr2c2/clock.h

diff --git a/data/clockdialog.ui b/data/clockdialog.ui
new file mode 100644 (file)
index 0000000..321b138
--- /dev/null
@@ -0,0 +1,83 @@
+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";
index 30971f506e02659e09b8ab3c0b4c8d12ae9d54e2..bc97b40cc04ccb081fe3ae6d500cb07c480d2bd5 100644 (file)
@@ -79,8 +79,17 @@ column
                style "digital";
        };
 
-       label "lbl_clock"
+       row
        {
-               style "digital";
+               label "lbl_clock"
+               {
+                       style "digital";
+               };
+               expand true false;
+
+               button "btn_clock"
+               {
+                       text "Clock";
+               };
        };
 };
index c2f72c1a94c1ecf89c02dbc1c6f970baea8e04bd..18cdfc828260824bebd7dce262dfd25e5658f12d 100644 (file)
@@ -729,3 +729,9 @@ style "toggle-lever"
                graphic ACTIVE "lever_up";
        };
 };
+
+style "clock"
+{
+       part "hourhand";
+       part "minutehand";
+};
diff --git a/source/engineer/clockdialog.cpp b/source/engineer/clockdialog.cpp
new file mode 100644 (file)
index 0000000..18d5b93
--- /dev/null
@@ -0,0 +1,77 @@
+#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)
+       {
+       }
+}
diff --git a/source/engineer/clockdialog.h b/source/engineer/clockdialog.h
new file mode 100644 (file)
index 0000000..f4fb54b
--- /dev/null
@@ -0,0 +1,31 @@
+#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
diff --git a/source/engineer/clockwidget.cpp b/source/engineer/clockwidget.cpp
new file mode 100644 (file)
index 0000000..31f5c39
--- /dev/null
@@ -0,0 +1,58 @@
+#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);
+       }
+}
diff --git a/source/engineer/clockwidget.h b/source/engineer/clockwidget.h
new file mode 100644 (file)
index 0000000..10c62bc
--- /dev/null
@@ -0,0 +1,25 @@
+#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
index 22c65d11b2a53d000d1d0f7adb9029bf0a5306b8..7deef738a528a014d3fcc8e35521166c04a4048c 100644 (file)
@@ -2,6 +2,7 @@
 #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"
@@ -26,6 +27,7 @@ MainWindow::MainWindow(Engineer &e):
        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())
@@ -71,6 +73,12 @@ void MainWindow::quit_clicked()
        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);
index ec207958084a5d6c09aa0c438a897bfa781a8ed7..d8f52083240c3fd035b354b46a48aadeb1c719fd 100644 (file)
@@ -28,6 +28,7 @@ private:
        void halt_clicked();
        void trains_clicked();
        void quit_clicked();
+       void clock_clicked();
        void power_event(bool);
        void halt_event(bool);
        void clock_minute();
index 93828cb90e5d87f728b4265a3bbed3f48ca03405..286ce966873af6b6735398ba1e5908f879460eda 100644 (file)
@@ -6,7 +6,8 @@ using namespace Msp;
 namespace R2C2 {
 
 Clock::Clock():
-       rate(1)
+       rate(1),
+       stopped(false)
 { }
 
 void Clock::set_rate(float s)
@@ -19,8 +20,16 @@ void Clock::set_current_time(const Time::TimeDelta &t)
        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)
index 59bffe70f0f3871ff4c469fbc73456bd301db2a5..469d1916e1de77667cb57bb74b84a719c9da0540 100644 (file)
@@ -24,6 +24,7 @@ public:
 private:
        Msp::Time::TimeDelta current_time;
        float rate;
+       bool stopped;
 
 public:
        Clock();
@@ -32,6 +33,8 @@ public:
        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;
 };