+#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: */