Make PositionLabels have direction status indicators
[cs356-p1-elevator.git] / elevatorgui.cpp
1 #include "elevatorgui.hpp"
2
3 ElevatorGUI::ElevatorGUI (int floors, int elevators)
4         : Gtk::Window()
5         , number_of_floors_(floors)
6         , number_of_elevators_(elevators)
7         , simulation_status_(STOPPED)
8
9         /* The ElevatorController */
10         , ec_(floors, elevators)
11
12         /* The Timer */
13         , timer_()
14
15         /* GUI Elements */
16         , table_(floors+1, elevators+3)
17         , button_playpause_(Gtk::Stock::MEDIA_PLAY)
18         , button_stop_(Gtk::Stock::STOP)
19         , button_quit_(Gtk::Stock::QUIT)
20
21         /* Storage for GUI elements for later lookup */
22         , call_buttons_()
23         , position_labels_()
24         , request_buttons_()
25         , elevator_doors_()
26 {
27         int i, j, e, f, e_num, f_num, f_attach;
28         std::ostringstream str;
29
30         /* Fill in all of the ElevatorDoors and CallButtons */
31         for (f_attach=0, f=floors-1; f>=0; --f, ++f_attach)
32         {
33                 /* Create and attach the VBox */
34                 Gtk::VBox *box = new Gtk::VBox ();
35                 table_.attach (*box, 0, 1, f_attach, f_attach+1);
36
37                 /* Only create UP CallButton if we are not on the top floor */
38                 if (f != floors-1)
39                 {
40                         CallButton *callbutton = new CallButton (f, UP);
41                         callbutton->set_label ("Up");
42
43                         // Connect to the on_call_button_toggled() signal
44                         callbutton->signal_toggled().connect (
45                                         sigc::bind <CallButton*> (
46                                                 sigc::mem_fun (*this, &ElevatorGUI::on_call_button_toggled),
47                                                 callbutton
48                                         )
49                         );
50
51                         call_buttons_.push_back (callbutton);
52                         box->pack_start (*callbutton);
53                 }
54
55                 /* Only create the DOWN CallButton if we are not on the bottom floor */
56                 if (f != 0)
57                 {
58                         CallButton *callbutton = new CallButton (f, DOWN);
59                         callbutton->set_label ("Down");
60
61                         // Connect to the on_call_button_toggled() signal
62                         callbutton->signal_toggled().connect (
63                                         sigc::bind <CallButton*> (
64                                                 sigc::mem_fun (*this, &ElevatorGUI::on_call_button_toggled),
65                                                 callbutton
66                                         )
67                         );
68
69                         call_buttons_.push_back (callbutton);
70                         box->pack_end (*callbutton);
71                 }
72
73                 for (e=0; e<elevators; ++e) // run left-to-right
74                 {
75                         ElevatorDoor *door = new ElevatorDoor (e, f);
76                         elevator_doors_.push_back (door);
77                         table_.attach (*door, e+1, e+2, f_attach, f_attach+1);
78                 }
79         }
80
81
82
83         /* Fill in all of the Elevator Request Panels */
84         for (e=0; e<elevators; ++e)
85         {
86                 // Create a 2-column table with enough slots for each Floor
87                 Gtk::Table *panel = new Gtk::Table ((floors+1)/2, 2);
88
89                 for (f=0; f<floors; ++f)
90                 {
91                         f_attach = f / 2;
92                         // Create the label
93                         str.str ("");
94                         str << f;
95
96                         // Create the button
97                         RequestButton *button = new RequestButton (e, f);
98                         button->set_label (str.str());
99
100                         // Connect the on_request_button_toggled() signal
101                         button->signal_toggled().connect (
102                                         sigc::bind <RequestButton*> (
103                                                 sigc::mem_fun (*this, &ElevatorGUI::on_request_button_toggled),
104                                                 button
105                                         )
106                         );
107
108                         // save the button
109                         request_buttons_.push_back (button);
110
111                         // If floor is odd, attach in the left col
112                         // Otherwise, attach in the right col
113                         if (f % 2 == 0)
114                                 panel->attach (*button, 0, 1, f_attach, f_attach+1);
115                         else
116                                 panel->attach (*button, 1, 2, f_attach, f_attach+1);
117                 }
118
119                 // Attach the Panel
120                 table_.attach (*panel, e+1, e+2, floors, floors+1);
121         }
122
123
124
125         /* Fill in all of the PositionLabels */
126         for (e=0; e<elevators; ++e)
127         {
128                 PositionLabel *label = new PositionLabel (e);
129                 position_labels_.push_back (label);
130                 table_.attach (*label, e+1, e+2, floors+1, floors+2);
131         }
132
133
134         /* Fill in the control buttons */
135         Gtk::HBox *box = new Gtk::HBox ();
136
137         button_quit_.signal_clicked().connect (
138                         sigc::mem_fun (*this, &ElevatorGUI::on_quit_button_clicked));
139         button_stop_.signal_clicked().connect (
140                         sigc::mem_fun (*this, &ElevatorGUI::on_stop_button_clicked));
141         button_playpause_.signal_clicked().connect (
142                         sigc::mem_fun (*this, &ElevatorGUI::on_playpause_button_clicked));
143
144         box->pack_start (button_playpause_);
145         box->pack_start (button_stop_);
146         box->pack_start (button_quit_);
147
148         /* Attach the box to the bottom of the GUI */
149         table_.attach (*box, 0, elevators+1, floors+2, floors+3);
150
151         /* Add the table to the window */
152         add (table_);
153
154         /* Show everything, we're up and running! */
155         show_all_children ();
156         show ();
157 }
158
159 void ElevatorGUI::on_quit_button_clicked ()
160 {
161         Gtk::Main::quit ();
162 }
163
164 void ElevatorGUI::on_playpause_button_clicked ()
165 {
166         std::string names[] = { "STOPPED", "RUNNING", "PAUSED" };
167         std::cout << "Play/Pause pressed with status=" << names[simulation_status_] << std::endl;
168
169         switch (simulation_status_)
170         {
171                 case STOPPED:
172                         simulation_status_ = RUNNING;
173
174                         // add and start timer
175                         timer_ = Glib::signal_timeout().connect (
176                                                 sigc::mem_fun (*this, &ElevatorGUI::on_timer_tick),
177                                                 timer_tick_ms_);
178
179                         break;
180                 case RUNNING:
181                         simulation_status_= PAUSED;
182
183                         // stop and remove timer
184                         timer_.disconnect ();
185
186                         break;
187                 case PAUSED:
188                         simulation_status_ = RUNNING;
189
190                         // add and start timer
191                         timer_ = Glib::signal_timeout().connect (
192                                                 sigc::mem_fun (*this, &ElevatorGUI::on_timer_tick),
193                                                 timer_tick_ms_);
194
195                         break;
196                 default:
197                         std::cout << "Bad Simulation Status in Play/Pause" << std::endl;
198                         break;
199         }
200 }
201
202 void ElevatorGUI::on_stop_button_clicked ()
203 {
204         // FIXME: implement this
205         std::cout << "STOP Button Clicked" << std::endl;
206
207         simulation_status_ = STOPPED;
208 }
209
210 void ElevatorGUI::on_request_button_toggled (RequestButton *button)
211 {
212         // Only send an elevator if we are toggled to on
213         if (button->get_active())
214         {
215                 std::cout << "Request elevator=" << button->getElevatorNumber()
216                                   << " to floor=" << button->getFloorNumber() << std::endl;
217                 ec_.elevator_request (button->getElevatorNumber(), button->getFloorNumber());
218         }
219 }
220
221 void ElevatorGUI::on_call_button_toggled (CallButton *button)
222 {
223         // Only send an elevator if we are toggled to on
224         if (button->get_active())
225         {
226                 std::cout << "Elevator Called on floor=" << button->getFloorNumber()
227                                   << " in direction=" << button->getDirection() << std::endl;
228                 ec_.call_elevator_to (button->getFloorNumber(), button->getDirection());
229         }
230 }
231
232 void ElevatorGUI::gui_update_position_label (int elevator, float new_position, Direction direction)
233 {
234         // Find the correct label and set it
235         PositionLabelVector::iterator it;
236
237         for (it=position_labels_.begin(); it!=position_labels_.end(); it++)
238                 if ((*it)->getElevatorNumber() == elevator)
239                         (*it)->update_position (new_position, direction);
240 }
241
242 void ElevatorGUI::gui_unpress_call_button (int floor, Direction direction)
243 {
244         CallButtonVector::iterator it;
245
246         for (it=call_buttons_.begin(); it!=call_buttons_.end(); it++)
247                 if ((*it)->getFloorNumber() == floor && (*it)->getDirection() == direction)
248                         (*it)->set_active (false);
249 }
250
251 void ElevatorGUI::gui_unpress_request_button (int elevator, int floor)
252 {
253         RequestButtonVector::iterator it;
254
255         for (it=request_buttons_.begin(); it!=request_buttons_.end(); it++)
256                 if ((*it)->getElevatorNumber() == elevator && (*it)->getFloorNumber() == floor)
257                         (*it)->set_active (false);
258 }
259
260 void ElevatorGUI::gui_open_door (int elevator, int floor)
261 {
262         ElevatorDoorVector::iterator it;
263
264         for (it=elevator_doors_.begin(); it!=elevator_doors_.end(); it++)
265                 if ((*it)->getElevatorNumber() == elevator && (*it)->getFloorNumber() == floor)
266                         (*it)->open();
267 }
268
269 void ElevatorGUI::gui_close_door (int elevator, int floor)
270 {
271         ElevatorDoorVector::iterator it;
272
273         for (it=elevator_doors_.begin(); it!=elevator_doors_.end(); it++)
274                 if ((*it)->getElevatorNumber() == elevator && (*it)->getFloorNumber() == floor)
275                         (*it)->close ();
276 }
277
278 bool ElevatorGUI::on_timer_tick ()
279 {
280         ec_.move_elevators ();
281
282         // Keep going (do NOT disconnect yet)
283         return true;
284 }
285
286 /* vim: set ts=4 sts=4 sw=4 noet tw=112: */