From: Ira W. Snyder Date: Sun, 7 Oct 2007 03:46:42 +0000 (-0700) Subject: Implement the GUI X-Git-Url: https://irasnyder.com/gitweb/?a=commitdiff_plain;ds=inline;h=c08c30e78fdbbde7e5823b26303b0dded3a4c1cf;p=cs356-p1-elevator.git Implement the GUI This implements the GUI in it's entirety. Signed-off-by: Ira W. Snyder --- diff --git a/Makefile b/Makefile index 116c3ce..acc9a11 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,14 @@ -test: position.o stop.o elevator.o elevatorcontroller.o test.o - g++ -o $@ $^ +CC=g++ +CFLAGS=`pkg-config gtkmm-2.4 --cflags` +LIBS=`pkg-config gtkmm-2.4 --libs` + +SRCS=position.cpp stop.cpp elevator.cpp elevatorcontroller.cpp elevatordoor.cpp callbutton.cpp positionlabel.cpp requestbutton.cpp elevatorgui.cpp test.cpp + +test: $(SRCS:.cpp=.o) + $(CC) -o $@ $^ $(LIBS) + +.cpp.o: + $(CC) $(CFLAGS) -c -o $@ $< run: test ./test diff --git a/callbutton.cpp b/callbutton.cpp new file mode 100644 index 0000000..5139130 --- /dev/null +++ b/callbutton.cpp @@ -0,0 +1,21 @@ +#include "callbutton.hpp" + +CallButton::CallButton (int floor, Direction direction) + : Gtk::ToggleButton() + , floor_(floor) + , direction_(direction) +{ + // Intentionally Left Empty +} + +int CallButton::getFloorNumber () const +{ + return floor_; +} + +Direction CallButton::getDirection () const +{ + return direction_; +} + +/* vim: set ts=4 sts=4 sw=4 noet tw=112: */ diff --git a/callbutton.hpp b/callbutton.hpp new file mode 100644 index 0000000..262c5ff --- /dev/null +++ b/callbutton.hpp @@ -0,0 +1,22 @@ +#ifndef CALLBUTTON_HPP +#define CALLBUTTON_HPP + +#include "direction.hpp" +#include + +class CallButton : public Gtk::ToggleButton +{ + public: + CallButton (int floor, Direction direction); + + int getFloorNumber () const; + Direction getDirection () const; + + private: + int floor_; + Direction direction_; +}; + +#endif /* CALLBUTTON_HPP */ + +/* vim: set ts=4 sts=4 sw=4 noet tw=112: */ diff --git a/eclose.png b/eclose.png new file mode 100644 index 0000000..95047b7 Binary files /dev/null and b/eclose.png differ diff --git a/elevatordoor.cpp b/elevatordoor.cpp new file mode 100644 index 0000000..5edbd4f --- /dev/null +++ b/elevatordoor.cpp @@ -0,0 +1,31 @@ +#include "elevatordoor.hpp" + +ElevatorDoor::ElevatorDoor (int elevator, int floor) + : Gtk::Image (CLOSED_IMAGE) + , elevator_(elevator) + , floor_(floor) +{ + // Intentionally Left Empty +} + +int ElevatorDoor::getElevatorNumber () const +{ + return elevator_; +} + +int ElevatorDoor::getFloorNumber () const +{ + return floor_; +} + +void ElevatorDoor::open () +{ + Gtk::Image::set (OPENED_IMAGE); +} + +void ElevatorDoor::close () +{ + Gtk::Image::set (CLOSED_IMAGE); +} + +/* vim: set ts=4 sts=4 sw=4 noet tw=112: */ diff --git a/elevatordoor.hpp b/elevatordoor.hpp new file mode 100644 index 0000000..49c9a11 --- /dev/null +++ b/elevatordoor.hpp @@ -0,0 +1,30 @@ +#ifndef ELEVATORDOOR_HPP +#define ELEVATORDOOR_HPP + +#include +#include + + +const std::string OPENED_IMAGE = "eopen2.png"; +const std::string CLOSED_IMAGE = "eclose.png"; + + +class ElevatorDoor : public Gtk::Image +{ + public: + ElevatorDoor (int elevator, int floor); + + int getElevatorNumber() const; + int getFloorNumber() const; + + void open (); + void close (); + + private: + int elevator_; + int floor_; +}; + +#endif /* ELEVATORDOOR_HPP */ + +/* vim: set ts=4 sts=4 sw=4 noet tw=112: */ diff --git a/elevatorgui.cpp b/elevatorgui.cpp new file mode 100644 index 0000000..f9d03a1 --- /dev/null +++ b/elevatorgui.cpp @@ -0,0 +1,295 @@ +#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 ( + 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 ( + sigc::mem_fun (*this, &ElevatorGUI::on_call_button_toggled), + callbutton + ) + ); + + call_buttons_.push_back (callbutton); + box->pack_end (*callbutton); + } + + for (e=0; eset_label (str.str()); + + // Connect the on_request_button_toggled() signal + button->signal_toggled().connect ( + sigc::bind ( + 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; epack_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: */ diff --git a/elevatorgui.hpp b/elevatorgui.hpp new file mode 100644 index 0000000..77f4d58 --- /dev/null +++ b/elevatorgui.hpp @@ -0,0 +1,77 @@ +#ifndef ELEVATORGUI_HPP +#define ELEVATORGUI_HPP + +#include +#include +#include +#include +#include + +#include "elevatorcontroller.hpp" + +#include "elevatordoor.hpp" +#include "callbutton.hpp" +#include "positionlabel.hpp" +#include "requestbutton.hpp" + + +typedef std::vector CallButtonVector; +typedef std::vector PositionLabelVector; +typedef std::vector RequestButtonVector; +typedef std::vector 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: */ diff --git a/eopen2.png b/eopen2.png new file mode 100644 index 0000000..4521d83 Binary files /dev/null and b/eopen2.png differ diff --git a/positionlabel.cpp b/positionlabel.cpp new file mode 100644 index 0000000..bdbe24d --- /dev/null +++ b/positionlabel.cpp @@ -0,0 +1,15 @@ +#include "positionlabel.hpp" + +PositionLabel::PositionLabel (int elevator, const std::string text) + : Gtk::Label (text) + , elevator_(elevator) +{ + // Intentionally Left Empty +} + +int PositionLabel::getElevatorNumber () const +{ + return elevator_; +} + +/* vim: set ts=4 sts=4 sw=4 noet tw=112: */ diff --git a/positionlabel.hpp b/positionlabel.hpp new file mode 100644 index 0000000..bd90449 --- /dev/null +++ b/positionlabel.hpp @@ -0,0 +1,20 @@ +#ifndef POSITIONLABEL_HPP +#define POSITIONLABEL_HPP + +#include +#include + +class PositionLabel : public Gtk::Label +{ + public: + PositionLabel (int elevator, const std::string text="0.0"); + + int getElevatorNumber() const; + + private: + int elevator_; +}; + +#endif /* POSITIONLABEL_HPP */ + +/* vim: set ts=4 sts=4 sw=4 noet tw=112: */ diff --git a/requestbutton.cpp b/requestbutton.cpp new file mode 100644 index 0000000..95fae24 --- /dev/null +++ b/requestbutton.cpp @@ -0,0 +1,21 @@ +#include "requestbutton.hpp" + +RequestButton::RequestButton (int elevator, int floor, const std::string text) + : Gtk::ToggleButton (text) + , elevator_(elevator) + , floor_(floor) +{ + // Intentionally Left Empty +} + +int RequestButton::getElevatorNumber () const +{ + return elevator_; +} + +int RequestButton::getFloorNumber () const +{ + return floor_; +} + +/* vim: set ts=4 sts=4 sw=4 noet tw=112: */ diff --git a/requestbutton.hpp b/requestbutton.hpp new file mode 100644 index 0000000..8c14c31 --- /dev/null +++ b/requestbutton.hpp @@ -0,0 +1,22 @@ +#ifndef REQUESTBUTTON_HPP +#define REQUESTBUTTON_HPP + +#include +#include + +class RequestButton : public Gtk::ToggleButton +{ + public: + RequestButton (int elevator, int floor, const std::string text="0"); + + int getElevatorNumber () const; + int getFloorNumber() const; + + private: + int elevator_; + int floor_; +}; + +#endif /* REQUESTBUTTON_HPP */ + +/* vim: set ts=4 sts=4 sw=4 noet tw=112: */ diff --git a/test.cpp b/test.cpp index 6f85ea1..bcfe3b3 100644 --- a/test.cpp +++ b/test.cpp @@ -7,10 +7,27 @@ using namespace std; #include "position.hpp" #include "elevator.hpp" #include "elevatorcontroller.hpp" +#include "elevatorgui.hpp" + +#include int main (int argc, char *argv[]) { + const int floors = 7; + const int elevators = 3; + + // Start GTK + Gtk::Main app(argc, argv); + + ElevatorGUI eg(floors, elevators); + eg.show (); + + Gtk::Main::run (eg); + + + +#if TEST_ELEVATORCONTROLLER const int floors = 10; const int elevators = 2; @@ -30,6 +47,7 @@ int main (int argc, char *argv[]) for (int i=0; i<35; i++) ec.move_elevators (); +#endif #if TEST_ELEVATOR