1 ////////////////////////////////////////////////////////////////////////////////////////
2 //
3 // Nestopia - NES/Famicom emulator written in C++
4 //
5 // Copyright (C) 2003-2008 Martin Freij
6 //
7 // This file is part of Nestopia.
8 //
9 // Nestopia is free software; you can redistribute it and/or modify
10 // it under the terms of the GNU General Public License as published by
11 // the Free Software Foundation; either version 2 of the License, or
12 // (at your option) any later version.
13 //
14 // Nestopia is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 // GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with Nestopia; if not, write to the Free Software
21 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22 //
23 ////////////////////////////////////////////////////////////////////////////////////////
24 
25 #ifndef NST_WINDOW_MENU_H
26 #define NST_WINDOW_MENU_H
27 
28 #pragma once
29 
30 #include "language/resource.h"
31 #include "NstResourceMenu.hpp"
32 #include "NstSystemAccelerator.hpp"
33 #include "NstWindowCustom.hpp"
34 
35 namespace Nestopia
36 {
37 	namespace Window
38 	{
39 		class Menu
40 		{
41 		public:
42 
43 			explicit Menu(uint);
44 			~Menu();
45 
46 			void Hook(Custom&);
47 			void Unhook();
48 			uint Height() const;
49 			bool Visible() const;
50 			void Show(bool=true) const;
51 			bool Toggle() const;
52 			void EnableAccelerator(bool);
53 			void SetKeys(const ACCEL*,uint);
54 			void SetColor(COLORREF) const;
55 			void ResetColor() const;
56 			void ToggleModeless(bool) const;
57 
58 			class Item;
59 
60 			void Insert(const Item&,uint,GenericString) const;
61 
62 		private:
63 
64 			static void Clear(HMENU);
65 			static uint NumItems(HMENU);
66 			static void Redraw(const Custom*);
67 
68 		public:
69 
Redraw() const70 			void Redraw() const
71 			{
72 				Redraw( window );
73 			}
74 
75 			class Item
76 			{
77 				friend class Menu;
78 
79 				class Stream
80 				{
81 					friend class Menu;
82 					friend class Item;
83 
84 					const Item& item;
85 
86 					uint GetLength() const;
87 					bool GetFullString(wchar_t*,uint) const;
88 					void SetFullString(wcstring) const;
89 
90 					template<typename T>
GetFullString(T & string) const91 					void GetFullString(T& string) const
92 					{
93 						string.Resize( GetLength() );
94 						GetFullString( string.Ptr(), string.Length() );
95 					}
96 
Stream(const Item & i)97 					explicit Stream(const Item& i)
98 					: item(i) {}
99 
100 				public:
101 
102 					void operator << (const GenericString&) const;
103 
104 					template<typename T>
operator >>(T & string) const105 					uint operator >> (T& string) const
106 					{
107 						GetFullString( string );
108 						string.FirstOf( '\t' ).Clear();
109 						return string.Length();
110 					}
111 				};
112 
113 			public:
114 
115 				enum Type
116 				{
117 					NONE,
118 					SUBMENU,
119 					COMMAND,
120 					SEPARATOR
121 				};
122 
123 				Type GetType() const;
124 
125 				bool Enable (bool=true) const;
126 				bool Check  (bool=true) const;
127 				void Check  (uint,uint,bool) const;
128 				void Check  (uint,uint) const;
129 
130 				bool Enabled () const;
131 				bool Checked () const;
132 
Disabled() const133 				bool Disabled  () const { return !Enabled(); }
Unchecked() const134 				bool Unchecked () const { return !Checked(); }
135 
ToggleCheck() const136 				bool ToggleCheck()  const { return !Check( Unchecked() ); }
ToggleEnable() const137 				bool ToggleEnable() const { return !Enable( Disabled() ); }
138 
Disable() const139 				bool Disable () const { return Enable (false); }
Uncheck() const140 				bool Uncheck () const { return Check  (false); }
141 
142 				uint GetCommand() const;
143 				void Remove() const;
144 				void Clear() const;
145 				uint NumItems() const;
146 				bool Exists() const;
147 
Text() const148 				Stream Text() const
149 				{
150 					return Stream( *this );
151 				}
152 
153 			private:
154 
155 				inline uint Flag() const;
156 
157 				HMENU hMenu;
158 				uint pos;
159 				const Custom* const window;
160 
161 			public:
162 
Item(const Custom * w,HMENU h=NULL,uint p=0)163 				Item(const Custom* w,HMENU h=NULL,uint p=0)
164 				: hMenu(h), pos(p), window(w) {}
165 
GetHandle() const166 				HMENU GetHandle() const
167 				{
168 					return hMenu;
169 				}
170 
operator [](uint subPos) const171 				Item operator [] (uint subPos) const
172 				{
173 					return Item( window, ::GetSubMenu( hMenu, pos ), subPos );
174 				}
175 			};
176 
177 			typedef Collection::Router<void,uint> CmdHandler;
178 
179 			class PopupHandler
180 			{
181 				friend class Menu;
182 
183 				struct Key
184 				{
185 					HMENU const hKey;
186 					const Item item;
187 
KeyNestopia::Window::Menu::PopupHandler::Key188 					Key(const Custom* w,HMENU h,uint p)
189 					: hKey(::GetSubMenu(h,p)), item(w,h,p) {}
190 
KeyNestopia::Window::Menu::PopupHandler::Key191 					explicit Key(WPARAM wParam)
192 					: hKey(reinterpret_cast<HMENU>(wParam)), item(NULL) {}
193 
operator HMENUNestopia::Window::Menu::PopupHandler::Key194 					operator HMENU() const
195 					{
196 						return hKey;
197 					}
198 				};
199 
200 				Menu& menu;
201 
202 			public:
203 
204 				template<uint A,uint B=UINT_MAX,uint C=UINT_MAX,uint D=UINT_MAX> struct Pos
205 				{
206 					enum { ID = A | (B + 1) << 8 | (C + 2) << 16 | (D + 3) << 24 };
207 				};
208 
209 				template<uint A> struct Pos<A,UINT_MAX,UINT_MAX,UINT_MAX>
210 				{
211 					enum { ID = A };
212 				};
213 
214 				template<uint A,uint B> struct Pos<A,B,UINT_MAX,UINT_MAX>
215 				{
216 					enum { ID = A | (B + 1) << 8 };
217 				};
218 
219 				template<uint A,uint B,uint C> struct Pos<A,B,C,UINT_MAX>
220 				{
221 					enum { ID = A | (B + 1) << 8 | (C + 2) << 16 };
222 				};
223 
224 				struct Param
225 				{
226 					Item menu;
227 					bool show;
228 
ParamNestopia::Window::Menu::PopupHandler::Param229 					Param(const Item& i,bool s)
230 					: menu(i), show(s) {}
231 				};
232 
233 				template<typename Data> struct Entry
234 				{
235 					typedef void (Data::*Function)(const Param&);
236 
237 					uint id;
238 					Function function;
239 				};
240 
241 			private:
242 
243 				typedef Collection::Router<void,const Param&,Key> Handler;
244 
245 				Key GetKey(uint) const;
246 
247 				template<typename Data>
248 				void Add(Data*,const Entry<Data>*,uint);
249 
PopupHandler(Menu & m)250 				PopupHandler(Menu& m)
251 				: menu(m) {}
252 
253 			public:
254 
255 				template<typename Data,uint COUNT>
Add(Data * data,const Entry<Data> (& list)[COUNT])256 				void Add(Data* data,const Entry<Data>(&list)[COUNT])
257 				{
258 					Add( data, list, COUNT );
259 				}
260 
Remove(const void * data)261 				void Remove(const void* data)
262 				{
263 					menu.popupHandler.Hooks().Remove( data );
264 				}
265 			};
266 
267 		private:
268 
269 			ibool OnCommand         (Param&);
270 			ibool OnInitMenuPopup   (Param&);
271 			ibool OnUninitMenuPopup (Param&);
272 			void  OnCreate          (Param&);
273 			void  OnDestroy         (Param&);
274 
275 			enum {IDM_OFFSET = 100};
276 
277 			Resource::Menu handle;
278 			Custom* window;
279 			System::Accelerator accelerator;
280 			CmdHandler cmdHandler;
281 			MsgHandler::Callback cmdCallback;
282 			PopupHandler::Handler popupHandler;
283 			bool acceleratorEnabled;
284 
285 			class Instances
286 			{
287 			public:
288 
289 				static void Update(Menu*);
290 				static void Remove(Menu*);
291 				static void EnableAccelerators(bool);
292 
293 			private:
294 
295 				static void Update();
296 				static bool TranslateNone   (MSG&);
297 				static bool TranslateSingle (MSG&);
298 				static bool TranslateMulti  (MSG&);
299 
300 				typedef Collection::Vector<const Menu*> Menus;
301 				typedef bool (*Translator)(MSG&);
302 
303 				static Translator translator;
304 				static Menus menus;
305 				static bool acceleratorsEnabled;
306 
307 			public:
308 
TransAccelerator(MSG & msg)309 				static bool TransAccelerator(MSG& msg)
310 				{
311 					return translator( msg );
312 				}
313 			};
314 
315 		public:
316 
GetHandle() const317 			HMENU GetHandle() const
318 			{
319 				return handle;
320 			}
321 
NumItems() const322 			uint NumItems() const
323 			{
324 				return NumItems( handle );
325 			}
326 
operator [](uint pos) const327 			Item operator [] (uint pos) const
328 			{
329 				return Item( window, handle, pos );
330 			}
331 
Hide() const332 			void Hide() const
333 			{
334 				Show( false );
335 			}
336 
Clear() const337 			void Clear() const
338 			{
339 				Clear( handle );
340 			}
341 
Commands()342 			CmdHandler& Commands()
343 			{
344 				return cmdHandler;
345 			}
346 
Popups()347 			PopupHandler Popups()
348 			{
349 				return *this;
350 			}
351 
TransAccelerator(MSG & msg)352 			static bool TransAccelerator(MSG& msg)
353 			{
354 				return Instances::TransAccelerator( msg );
355 			}
356 
EnableAccelerators(bool enable)357 			static void EnableAccelerators(bool enable)
358 			{
359 				Instances::EnableAccelerators( enable );
360 			}
361 		};
362 
363 		template<typename Data>
Add(Data * const data,const Entry<Data> * list,const uint count)364 		void Menu::PopupHandler::Add(Data* const data,const Entry<Data>* list,const uint count)
365 		{
366 			for (const Entry<Data>* const end = list + count; list != end; ++list)
367 				menu.popupHandler.Hooks().Add( GetKey(list->id), data, list->function );
368 		}
369 	}
370 }
371 
372 #endif
373