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