]> Shamusworld >> Repos - apple2/blob - apple2/src/gui/gui.cpp
Creating trunk (should've done this from the start)...
[apple2] / apple2 / src / gui / gui.cpp
1 //
2 // GUI.CPP
3 //
4 // Graphical User Interface support
5 // by James L. Hammons
6 //
7 // JLH = James L. Hammons <jlhamm@acm.org>
8 //
9 // WHO  WHEN        WHAT
10 // ---  ----------  ------------------------------------------------------------
11 // JLH  02/03/2006  Created this file
12 // JLH  03/13/2006  Added functions to allow shutting down GUI externally
13 //
14
15 // STILL TO FIX:
16 //
17 // - Memory leak on quitting with a window active
18 // - Multiple window handling
19 //
20
21 #include "gui.h"
22 #include "menu.h"                                                               // Element class methods are pulled in here...
23 #include "window.h"
24 #include "video.h"
25
26 // Debug support
27
28 //#define DEBUG_MAIN_LOOP
29
30 #ifdef DEBUG_MAIN_LOOP
31 #include "log.h"
32 #endif
33
34
35 GUI::GUI(SDL_Surface * mainSurface): mainMenu(new Menu()), menuItem(new MenuItems())
36 {
37         Element::SetScreen(mainSurface);
38 }
39
40 GUI::~GUI()
41 {
42         if (mainMenu)
43                 delete mainMenu;
44
45         if (menuItem)
46                 delete menuItem;
47 }
48
49 void GUI::AddMenuTitle(const char * title)
50 {
51         menuItem->title = title;
52         menuItem->item.clear();
53 }
54
55 void GUI::AddMenuItem(const char * item, Element * (* a)(void)/*= NULL*/, SDLKey k/*= SDLK_UNKNOWN*/)
56 {
57         menuItem->item.push_back(NameAction(item, a, k));
58 }
59
60 void GUI::CommitItemsToMenu(void)
61 {
62         mainMenu->Add(*menuItem);
63 }
64
65
66 void GUI::Run(void)
67 {
68         exitGUI = false;
69
70         bool showMouse = true;
71         int mouseX = 0, mouseY = 0;
72         int oldMouseX = 0, oldMouseY = 0;
73         Element * mainWindow = NULL;
74         SDL_Event event;
75
76         SDL_EnableKeyRepeat(150, 75);
77         // Initial update...
78 //Shouldn't we save the state of the GUI instead of doing things this way?
79 //We have a memory leak whenever a mainWindow is active and we quit... !!! FIX !!!
80         mainMenu->Draw();
81         RenderScreenBuffer();
82
83         // Main loop
84         while (!exitGUI)
85         {
86                 if (SDL_PollEvent(&event))
87                 {
88 #ifdef DEBUG_MAIN_LOOP
89 WriteLog("An event was found!");
90 #endif
91                         if (event.type == SDL_USEREVENT)
92                         {
93 #ifdef DEBUG_MAIN_LOOP
94 WriteLog(" -- SDL_USEREVENT\n");
95 #endif
96 //Mebbe add another user event for screen refresh? Why not!
97                                 if (event.user.code == WINDOW_CLOSE)
98                                 {
99                                         delete mainWindow;
100                                         mainWindow = NULL;
101                                 }
102                                 else if (event.user.code == MENU_ITEM_CHOSEN)
103                                 {
104                                         // Confused? Let me enlighten... What we're doing here is casting
105                                         // data1 as a pointer to a function which returns a Window pointer and
106                                         // which takes no parameters (the "(Window *(*)(void))" part), then
107                                         // derefencing it (the "*" in front of that) in order to call the
108                                         // function that it points to. Clear as mud? Yeah, I hate function
109                                         // pointers too, but what else are you gonna do?
110                                         mainWindow = (*(Element *(*)(void))event.user.data1)();
111
112                                         while (SDL_PollEvent(&event));  // Flush the event queue...
113                                         event.type = SDL_MOUSEMOTION;
114                                         int mx, my;
115                                         SDL_GetMouseState(&mx, &my);
116                                         event.motion.x = mx, event.motion.y = my;
117                                     SDL_PushEvent(&event);                      // & update mouse position...!
118
119                                         oldMouseX = mouseX, oldMouseY = mouseY;
120                                         mouseX = mx, mouseY = my;               // This prevents "mouse flash"...
121                                 }
122 //There's a *small* problem with this approach--if a window and a bunch of child
123 //widgets send this message, we'll get a bunch of unnecessary refresh events...
124 //This could be controlled by having the main window refresh itself intelligently...
125
126 //What we could do instead is set a variable in Element and check it after the fact
127 //to see whether or not a refresh is needed.
128
129 //Dirty rectangle is also possible...
130                                 else if (event.user.code == SCREEN_REFRESH_NEEDED)
131                                         RenderScreenBuffer();
132                         }
133                         else if (event.type == SDL_ACTIVEEVENT)
134                         {
135                                 if (event.active.state == SDL_APPMOUSEFOCUS)
136                                         showMouse = (event.active.gain ? true : false);
137                         }
138                         else if (event.type == SDL_KEYDOWN)
139                         {
140 #ifdef DEBUG_MAIN_LOOP
141 WriteLog(" -- SDL_KEYDOWN\n");
142 #endif
143                                 if (event.key.keysym.sym == SDLK_F5)
144                                         exitGUI = true;
145
146                                 if (mainWindow)
147                                         mainWindow->HandleKey(event.key.keysym.sym);
148                                 else
149                                         mainMenu->HandleKey(event.key.keysym.sym);
150                         }
151                         else if (event.type == SDL_MOUSEMOTION)
152                         {
153 #ifdef DEBUG_MAIN_LOOP
154 WriteLog(" -- SDL_MOUSEMOTION\n");
155 #endif
156                                 oldMouseX = mouseX, oldMouseY = mouseY;
157                                 mouseX = event.motion.x, mouseY = event.motion.y;
158
159                                 if (mainWindow)
160                                         mainWindow->HandleMouseMove(mouseX, mouseY);
161                                 else
162                                         mainMenu->HandleMouseMove(mouseX, mouseY);
163                         }
164                         else if (event.type == SDL_MOUSEBUTTONDOWN)
165                         {
166 #ifdef DEBUG_MAIN_LOOP
167 WriteLog(" -- SDL_MOSEBUTTONDOWN\n");
168 #endif
169                                 uint32 mx = event.button.x, my = event.button.y;
170
171                                 if (mainWindow)
172                                         mainWindow->HandleMouseButton(mx, my, true);
173                                 else
174                                         mainMenu->HandleMouseButton(mx, my, true);
175                         }
176                         else if (event.type == SDL_MOUSEBUTTONUP)
177                         {
178 #ifdef DEBUG_MAIN_LOOP
179 WriteLog(" -- SDL_MOUSEBUTTONUP\n");
180 #endif
181                                 uint32 mx = event.button.x, my = event.button.y;
182
183                                 if (mainWindow)
184                                         mainWindow->HandleMouseButton(mx, my, false);
185                                 else
186                                         mainMenu->HandleMouseButton(mx, my, false);
187                         }
188 #ifdef DEBUG_MAIN_LOOP
189 else
190         WriteLog(" -- Unknown event\n");
191 #endif
192
193                         if (Element::ScreenNeedsRefreshing())
194                         {
195 #ifdef DEBUG_MAIN_LOOP
196 WriteLog("Screen refresh called!\n");
197 #endif
198                                 RenderScreenBuffer();
199                                 Element::ScreenWasRefreshed();
200                         }
201                 }
202         }
203
204         SDL_EnableKeyRepeat(0, 0);
205 //      return false;
206 }
207
208 void GUI::Stop(void)
209 {
210         exitGUI = true;
211 }