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