--- /dev/null
+#include "elevatorgui.hpp"
+
+ElevatorGUI::ElevatorGUI (int floors, int elevators)
+ : Gtk::Window()
+ , number_of_floors_(floors)
+ , number_of_elevators_(elevators)
+ , simulation_status_(STOPPED)
+
+ /* The ElevatorController */
+ , ec_(floors, elevators)
+
+ /* The Timer */
+ , timer_()
+
+ /* GUI Elements */
+ , table_(floors+1, elevators+3)
+ , button_playpause_(Gtk::Stock::MEDIA_PLAY)
+ , button_stop_(Gtk::Stock::STOP)
+ , button_quit_(Gtk::Stock::QUIT)
+
+ /* Storage for GUI elements for later lookup */
+ , call_buttons_()
+ , position_labels_()
+ , request_buttons_()
+ , elevator_doors_()
+{
+ int i, j, e, f, e_num, f_num, f_attach;
+ std::ostringstream str;
+
+ /* Fill in all of the ElevatorDoors and CallButtons */
+ for (f_attach=0, f=floors-1; f>=0; --f, ++f_attach)
+ {
+ std::cout << "at floor: " << f << std::endl;
+
+ /* Create and attach the VBox */
+ Gtk::VBox *box = new Gtk::VBox ();
+ table_.attach (*box, 0, 1, f_attach, f_attach+1);
+
+ /* Only create UP CallButton if we are not on the top floor */
+ if (f != floors-1)
+ {
+ CallButton *callbutton = new CallButton (f, UP);
+ callbutton->set_label ("Up");
+
+ // Connect to the on_call_button_toggled() signal
+ callbutton->signal_toggled().connect (
+ sigc::bind <CallButton*> (
+ sigc::mem_fun (*this, &ElevatorGUI::on_call_button_toggled),
+ callbutton
+ )
+ );
+
+ call_buttons_.push_back (callbutton);
+ box->pack_start (*callbutton);
+ }
+
+ /* Only create the DOWN CallButton if we are not on the bottom floor */
+ if (f != 0)
+ {
+ CallButton *callbutton = new CallButton (f, DOWN);
+ callbutton->set_label ("Down");
+
+ // Connect to the on_call_button_toggled() signal
+ callbutton->signal_toggled().connect (
+ sigc::bind <CallButton*> (
+ sigc::mem_fun (*this, &ElevatorGUI::on_call_button_toggled),
+ callbutton
+ )
+ );
+
+ call_buttons_.push_back (callbutton);
+ box->pack_end (*callbutton);
+ }
+
+ for (e=0; e<elevators; ++e) // run left-to-right
+ {
+ std::cout << "Attaching ElevatorDoor (e=" << e << ", f=" << f << ")" << std::endl;
+ ElevatorDoor *door = new ElevatorDoor (e, f);
+ elevator_doors_.push_back (door);
+ table_.attach (*door, e+1, e+2, f_attach, f_attach+1);
+ }
+ }
+
+
+
+ /* Fill in all of the Elevator Request Panels */
+ for (e=0; e<elevators; ++e)
+ {
+ // Create a 2-column table with enough slots for each Floor
+ Gtk::Table *panel = new Gtk::Table ((floors+1)/2, 2);
+
+ for (f=0; f<floors; ++f)
+ {
+ f_attach = f / 2;
+ // Create the label
+ str.str ("");
+ str << f;
+
+ // Create the button
+ RequestButton *button = new RequestButton (e, f);
+ button->set_label (str.str());
+
+ // Connect the on_request_button_toggled() signal
+ button->signal_toggled().connect (
+ sigc::bind <RequestButton*> (
+ sigc::mem_fun (*this, &ElevatorGUI::on_request_button_toggled),
+ button
+ )
+ );
+
+ // save the button
+ request_buttons_.push_back (button);
+
+ // If floor is odd, attach in the left col
+ // Otherwise, attach in the right col
+ if (f % 2 == 0)
+ panel->attach (*button, 0, 1, f_attach, f_attach+1);
+ else
+ panel->attach (*button, 1, 2, f_attach, f_attach+1);
+ }
+
+ // Attach the Panel
+ table_.attach (*panel, e+1, e+2, floors, floors+1);
+ }
+
+
+
+ /* Fill in all of the PositionLabels */
+ for (e=0; e<elevators; ++e)
+ {
+ PositionLabel *label = new PositionLabel (e);
+ position_labels_.push_back (label);
+ table_.attach (*label, e+1, e+2, floors+1, floors+2);
+ }
+
+
+ /* Fill in the control buttons */
+ Gtk::HBox *box = new Gtk::HBox ();
+
+ button_quit_.signal_clicked().connect (
+ sigc::mem_fun (*this, &ElevatorGUI::on_quit_button_clicked));
+ button_stop_.signal_clicked().connect (
+ sigc::mem_fun (*this, &ElevatorGUI::on_stop_button_clicked));
+ button_playpause_.signal_clicked().connect (
+ sigc::mem_fun (*this, &ElevatorGUI::on_playpause_button_clicked));
+
+ box->pack_start (button_playpause_);
+ box->pack_start (button_stop_);
+ box->pack_start (button_quit_);
+
+ /* Attach the box to the bottom of the GUI */
+ table_.attach (*box, 0, elevators+1, floors+2, floors+3);
+
+ /* Add the table to the window */
+ add (table_);
+
+ /* Show everything, we're up and running! */
+ show_all_children ();
+ show ();
+}
+
+void ElevatorGUI::on_quit_button_clicked ()
+{
+ Gtk::Main::quit ();
+}
+
+void ElevatorGUI::on_playpause_button_clicked ()
+{
+ std::string names[] = { "STOPPED", "RUNNING", "PAUSED" };
+ std::cout << "Play/Pause pressed with status=" << names[simulation_status_] << std::endl;
+
+ switch (simulation_status_)
+ {
+ case STOPPED:
+ simulation_status_ = RUNNING;
+
+ // add and start timer
+ timer_ = Glib::signal_timeout().connect (
+ sigc::mem_fun (*this, &ElevatorGUI::on_timer_tick),
+ timer_tick_ms_);
+
+ break;
+ case RUNNING:
+ simulation_status_= PAUSED;
+
+ // stop and remove timer
+ timer_.disconnect ();
+
+ break;
+ case PAUSED:
+ simulation_status_ = RUNNING;
+
+ // add and start timer
+ timer_ = Glib::signal_timeout().connect (
+ sigc::mem_fun (*this, &ElevatorGUI::on_timer_tick),
+ timer_tick_ms_);
+
+ break;
+ default:
+ std::cout << "Bad Simulation Status in Play/Pause" << std::endl;
+ break;
+ }
+}
+
+void ElevatorGUI::on_stop_button_clicked ()
+{
+ // FIXME: implement this
+ std::cout << "STOP Button Clicked" << std::endl;
+
+ simulation_status_ = STOPPED;
+}
+
+void ElevatorGUI::on_request_button_toggled (RequestButton *button)
+{
+ // Only send an elevator if we are toggled to on
+ if (button->get_active())
+ {
+ std::cout << "Request elevator=" << button->getElevatorNumber()
+ << " to floor=" << button->getFloorNumber() << std::endl;
+ ec_.elevator_request (button->getElevatorNumber(), button->getFloorNumber());
+ }
+}
+
+void ElevatorGUI::on_call_button_toggled (CallButton *button)
+{
+ // Only send an elevator if we are toggled to on
+ if (button->get_active())
+ {
+ std::cout << "Elevator Called on floor=" << button->getFloorNumber()
+ << " in direction=" << button->getDirection() << std::endl;
+ ec_.call_elevator_to (button->getFloorNumber(), button->getDirection());
+ }
+}
+
+void ElevatorGUI::gui_update_position_label (int elevator, float new_position)
+{
+ std::ostringstream str;
+
+ // Generate the text
+ str << std::setiosflags (std::ios_base::showpoint | std::ios_base::fixed)
+ << std::setprecision(1) << new_position;
+
+ // Find the correct label and set it
+ PositionLabelVector::iterator it;
+
+ for (it=position_labels_.begin(); it!=position_labels_.end(); it++)
+ if ((*it)->getElevatorNumber() == elevator)
+ (*it)->set_text (str.str());
+}
+
+void ElevatorGUI::gui_unpress_call_button (int floor, Direction direction)
+{
+ CallButtonVector::iterator it;
+
+ for (it=call_buttons_.begin(); it!=call_buttons_.end(); it++)
+ if ((*it)->getFloorNumber() == floor && (*it)->getDirection() == direction)
+ (*it)->set_active (false);
+}
+
+void ElevatorGUI::gui_unpress_request_button (int elevator, int floor)
+{
+ RequestButtonVector::iterator it;
+
+ for (it=request_buttons_.begin(); it!=request_buttons_.end(); it++)
+ if ((*it)->getElevatorNumber() == elevator && (*it)->getFloorNumber() == floor)
+ (*it)->set_active (false);
+}
+
+void ElevatorGUI::gui_open_door (int elevator, int floor)
+{
+ ElevatorDoorVector::iterator it;
+
+ for (it=elevator_doors_.begin(); it!=elevator_doors_.end(); it++)
+ if ((*it)->getElevatorNumber() == elevator && (*it)->getFloorNumber() == floor)
+ (*it)->open();
+}
+
+void ElevatorGUI::gui_close_door (int elevator, int floor)
+{
+ ElevatorDoorVector::iterator it;
+
+ for (it=elevator_doors_.begin(); it!=elevator_doors_.end(); it++)
+ if ((*it)->getElevatorNumber() == elevator && (*it)->getFloorNumber() == floor)
+ (*it)->close ();
+}
+
+bool ElevatorGUI::on_timer_tick ()
+{
+ ec_.move_elevators ();
+
+ // Keep going (do NOT disconnect yet)
+ return true;
+}
+
+/* vim: set ts=4 sts=4 sw=4 noet tw=112: */
--- /dev/null
+#ifndef ELEVATORGUI_HPP
+#define ELEVATORGUI_HPP
+
+#include <gtkmm.h>
+#include <iostream>
+#include <iomanip>
+#include <vector>
+#include <sstream>
+
+#include "elevatorcontroller.hpp"
+
+#include "elevatordoor.hpp"
+#include "callbutton.hpp"
+#include "positionlabel.hpp"
+#include "requestbutton.hpp"
+
+
+typedef std::vector<CallButton*> CallButtonVector;
+typedef std::vector<PositionLabel*> PositionLabelVector;
+typedef std::vector<RequestButton*> RequestButtonVector;
+typedef std::vector<ElevatorDoor*> ElevatorDoorVector;
+
+
+class ElevatorGUI : public Gtk::Window
+{
+ public:
+ ElevatorGUI (int floors, int elevators);
+
+ /* Functions to be called from Elevator to change GUI status */
+ void gui_update_position_label (int elevator, float new_position);
+ void gui_unpress_call_button (int floor, Direction direction);
+ void gui_unpress_request_button (int elevator, int floor);
+ void gui_open_door (int elevator, int floor);
+ void gui_close_door (int elevator, int floor);
+
+ private:
+ /* Callbacks from button presses */
+ void on_call_button_toggled (CallButton *button);
+ void on_request_button_toggled (RequestButton *button);
+ void on_playpause_button_clicked ();
+ void on_stop_button_clicked ();
+ void on_quit_button_clicked ();
+
+ /* Timer Function */
+ bool on_timer_tick ();
+ sigc::connection timer_;
+ static const int timer_tick_ms_ = 500;
+
+ int number_of_floors_;
+ int number_of_elevators_;
+
+ enum { STOPPED, RUNNING, PAUSED } simulation_status_;
+
+ ElevatorController ec_;
+
+ // holds custom CallButton which knows it's direction and floor#
+ CallButtonVector call_buttons_;
+
+ // holds custom position label which knows it's elevator#
+ PositionLabelVector position_labels_;
+
+ // holds custom RequestButton which knows it's elevator# and floor#
+ RequestButtonVector request_buttons_;
+
+ // holds custom ElevatorDoor which knows it's elevator# and floor#
+ ElevatorDoorVector elevator_doors_;
+
+ // Holds the Play / Pause button, Stop button, and Quit button
+ Gtk::Button button_playpause_, button_stop_, button_quit_;
+
+ // Holds the Table which holds everything
+ Gtk::Table table_;
+};
+
+#endif /* ELEVATORGUI_HPP */
+
+/* vim: set ts=4 sts=4 sw=4 noet tw=112: */