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