From: Mikko Rasa Date: Fri, 30 Jan 2015 09:03:34 +0000 (+0200) Subject: Add a dialog to control the clock X-Git-Url: http://git.tdb.fi/?p=r2c2.git;a=commitdiff_plain;h=f139a89c01dfc6580ecd1a5399e146ce45f865a4 Add a dialog to control the clock --- diff --git a/data/clockdialog.ui b/data/clockdialog.ui new file mode 100644 index 0000000..321b138 --- /dev/null +++ b/data/clockdialog.ui @@ -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"; diff --git a/data/mainwindow.ui b/data/mainwindow.ui index 30971f5..bc97b40 100644 --- a/data/mainwindow.ui +++ b/data/mainwindow.ui @@ -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"; + }; }; }; diff --git a/data/r2c2.res b/data/r2c2.res index c2f72c1..18cdfc8 100644 --- a/data/r2c2.res +++ b/data/r2c2.res @@ -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 index 0000000..18d5b93 --- /dev/null +++ b/source/engineer/clockdialog.cpp @@ -0,0 +1,77 @@ +#include +#include +#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(get_item(widgets, "btn_rate")); + button->signal_clicked.connect(sigc::mem_fun(this, &ClockDialog::set_rate)); + ent_rate = dynamic_cast(get_item(widgets, "ent_rate")); + + button = dynamic_cast(get_item(widgets, "btn_stop")); + button->signal_clicked.connect(sigc::mem_fun(this, &ClockDialog::stop_clicked)); + ind_stopped = dynamic_cast(get_item(widgets, "ind_stopped")); + ind_stopped->set_active(clock.is_stopped()); + + button = dynamic_cast(get_item(widgets, "btn_time")); + button->signal_clicked.connect(sigc::mem_fun(this, &ClockDialog::set_time)); + ent_hour = dynamic_cast(get_item(widgets, "ent_hour")); + ent_minute = dynamic_cast(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(time/Time::min)%60; + ent_hour->set_text(lexical_cast(hour)); + ent_minute->set_text(lexical_cast(minute)); +} + +void ClockDialog::set_rate() +{ + try + { + float rate = lexical_cast(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(ent_hour->get_text()); + unsigned minute = lexical_cast(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 index 0000000..f4fb54b --- /dev/null +++ b/source/engineer/clockdialog.h @@ -0,0 +1,31 @@ +#ifndef CLOCKDIALOG_H_ +#define CLOCKDIALOG_H_ + +#include +#include +#include +#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 index 0000000..31f5c39 --- /dev/null +++ b/source/engineer/clockwidget.cpp @@ -0,0 +1,58 @@ +#include +#include +#include +#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 angle = Geometry::Angle::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 index 0000000..10c62bc --- /dev/null +++ b/source/engineer/clockwidget.h @@ -0,0 +1,25 @@ +#ifndef CLOCKWIDGET_H_ +#define CLOCKWIDGET_H_ + +#include +#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 diff --git a/source/engineer/mainwindow.cpp b/source/engineer/mainwindow.cpp index 22c65d1..7deef73 100644 --- a/source/engineer/mainwindow.cpp +++ b/source/engineer/mainwindow.cpp @@ -2,6 +2,7 @@ #include #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(get_item(widgets, "btn_halt"))->signal_clicked.connect(sigc::mem_fun(this, &MainWindow::halt_clicked)); dynamic_cast(get_item(widgets, "btn_trains"))->signal_clicked.connect(sigc::mem_fun(this, &MainWindow::trains_clicked)); dynamic_cast(get_item(widgets, "btn_quit"))->signal_clicked.connect(sigc::mem_fun(this, &MainWindow::quit_clicked)); + dynamic_cast(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()->add(*dlg); +} + void MainWindow::power_event(bool p) { ind_on->set_active(p); diff --git a/source/engineer/mainwindow.h b/source/engineer/mainwindow.h index ec20795..d8f5208 100644 --- a/source/engineer/mainwindow.h +++ b/source/engineer/mainwindow.h @@ -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(); diff --git a/source/libr2c2/clock.cpp b/source/libr2c2/clock.cpp index 93828cb..286ce96 100644 --- a/source/libr2c2/clock.cpp +++ b/source/libr2c2/clock.cpp @@ -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) diff --git a/source/libr2c2/clock.h b/source/libr2c2/clock.h index 59bffe7..469d191 100644 --- a/source/libr2c2/clock.h +++ b/source/libr2c2/clock.h @@ -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 &) const; };