1 //--------------------------------------------------------------------
2 //
3 // MenuWindow.cpp
4 //
5 // Written by: Owen Smith
6 //
7 //--------------------------------------------------------------------
8
9 /*
10 Copyright 1999, Be Incorporated. All Rights Reserved.
11 This file may be used under the terms of the Be Sample Code License.
12 */
13
14 #include <Application.h>
15 #include <Box.h>
16 #include <CheckBox.h>
17 #include <Menu.h>
18 #include <MenuBar.h>
19 #include <MenuItem.h>
20 #include <StringView.h>
21 #include <stdio.h>
22 #include <string.h>
23
24 #include "constants.h"
25 #include "MenuView.h"
26 #include "MenuWindow.h"
27 #include "stddlg.h"
28
29 //====================================================================
30 // MenuWindow Implementation
31
32 #define MAX_TEST_STATUS_CHARS 25
33
34
35 //--------------------------------------------------------------------
36 // MenuWindow constructors, destructors, operators
37
MenuWindow(const char * name)38 MenuWindow::MenuWindow(const char* name)
39 : BWindow(BRect(60,60,60,60), name, B_TITLED_WINDOW,
40 B_NOT_RESIZABLE | B_NOT_ZOOMABLE)
41 {
42 m_bUsingFullMenuBar = true;
43
44 // menu bars
45 BRect dummyFrame(0, 0, 0, 0);
46 m_pFullMenuBar = new BMenuBar(dummyFrame, "Full Menu Bar");
47 m_pHiddenMenuBar = new BMenuBar(dummyFrame, "Menu Bar w. Hidden User Menus");
48
49 // File menu
50 BMenu* pMenu = BuildFileMenu();
51 if (pMenu) {
52 m_pFullMenuBar->AddItem(pMenu);
53 }
54 pMenu = BuildFileMenu();
55 if (pMenu) {
56 m_pHiddenMenuBar->AddItem(pMenu);
57 }
58
59 // Test menu
60 pMenu = m_testMenuBuilder.BuildTestMenu(B_MINI_ICON);
61 if (pMenu) {
62 m_pFullMenuBar->AddItem(pMenu);
63 }
64 pMenu = m_testMenuBuilder.BuildTestMenu(B_MINI_ICON);
65 if (pMenu) {
66 m_pHiddenMenuBar->AddItem(pMenu);
67 }
68
69 // add child after menus are added so its initially
70 // calculated app_server bounds take added menus into
71 // account
72 AddChild(m_pFullMenuBar);
73
74 float menuHeight = m_pFullMenuBar->Bounds().Height();
75
76 // Menu view
77 m_pMenuView = new MenuView(B_FOLLOW_NONE); // don't follow window just yet!
78 m_pMenuView->MoveBy(0, menuHeight + 1);
79 AddChild(m_pMenuView);
80
81 // Status view
82 BRect menuViewRect = m_pMenuView->Frame();
83 float top = menuViewRect.bottom + 1;
84 font_height plainHeight;
85 be_plain_font->GetHeight(&plainHeight);
86
87 // Simulate a vertical divider by making a BBox where only the top side
88 // can be seen in the window.
89 BRect boxFrame;
90 boxFrame.Set(menuViewRect.left - 2,
91 top,
92 menuViewRect.right + 2,
93 top + plainHeight.ascent + plainHeight.descent + plainHeight.leading + 4);
94
95 BBox* pStatusBox = new BBox(boxFrame);
96 AddChild(pStatusBox);
97
98 BRect statusFrame = pStatusBox->Bounds();
99 statusFrame.InsetBy(2,2);
100 m_pStatusView = new BStringView(statusFrame, "Status View", STR_STATUS_DEFAULT,
101 B_FOLLOW_ALL); // don't follow window just yet!
102 m_pStatusView->SetViewColor(BKG_GREY);
103 pStatusBox->AddChild(m_pStatusView);
104
105 // Resize window dynamically to fit MenuView (and Status View)
106 float windowWidth = m_pMenuView->Frame().right;
107 float windowHeight = boxFrame.bottom - 4;
108 ResizeTo(windowWidth, windowHeight);
109 }
110
111
112
113 //--------------------------------------------------------------------
114 // MenuWindow virtual function overrides
115
MenusBeginning(void)116 void MenuWindow::MenusBeginning(void)
117 {
118 if ((! Valid()) || (! m_bUsingFullMenuBar)) {
119 return;
120 }
121
122 int32 len = m_pFullMenuBar->CountItems();
123 for (int32 i = 2; i < len; i++) // skipping File and Test menus
124 {
125 BMenu* pMenu = m_pFullMenuBar->SubmenuAt(i);
126 if (pMenu) {
127 m_pMenuView->PopulateUserMenu(pMenu, i - 2);
128 }
129 }
130 }
131
MessageReceived(BMessage * message)132 void MenuWindow::MessageReceived(BMessage* message)
133 {
134 switch (message->what) {
135 case MSG_WIN_ADD_MENU:
136 AddMenu(message);
137 break;
138 case MSG_WIN_DELETE_MENU:
139 DeleteMenu(message);
140 break;
141 case MSG_TEST_ITEM:
142 TestMenu(message);
143 break;
144 case MSG_USER_ITEM:
145 UserMenu(message);
146 break;
147 case MSG_WIN_HIDE_USER_MENUS:
148 ToggleUserMenus(message);
149 break;
150 case MSG_WIN_LARGE_TEST_ICONS:
151 ToggleTestIcons(message);
152 break;
153 default:
154 BWindow::MessageReceived(message);
155 break;
156 }
157 }
158
QuitRequested(void)159 bool MenuWindow::QuitRequested(void)
160 {
161 be_app->PostMessage(B_QUIT_REQUESTED);
162 return true;
163 }
164
165
166
167 //--------------------------------------------------------------------
168 // MenuWindow operations
169
UpdateStatus(const char * str1,const char * str2)170 void MenuWindow::UpdateStatus(const char* str1, const char* str2)
171 {
172 uint32 lenTotal = 0, len1 = 0, len2 = 0;
173
174 if (str1)
175 len1 = strlen(str1);
176 if (str2)
177 len2 = strlen(str2);
178
179 lenTotal = len1 + len2;
180 char* updateText = new char[lenTotal+1];
181 updateText[0] = '\0'; // in case str1 and str2 are both NULL
182
183 if (str1)
184 strcpy(updateText, str1);
185 if (str2)
186 strcpy(updateText + len1, str2);
187
188 if (Lock() && Valid()) {
189 m_pStatusView->SetText(updateText);
190 Unlock();
191 }
192
193 delete [] updateText;
194 }
195
196
197
198 //--------------------------------------------------------------------
199 // MenuWindow message handlers
200
AddMenu(BMessage * message)201 void MenuWindow::AddMenu(BMessage* message)
202 {
203 if (! Valid()) {
204 return;
205 }
206
207 const char* menuName;
208 if (message->FindString("Menu Name", &menuName) == B_OK) {
209 m_pFullMenuBar->AddItem(new BMenu(menuName));
210 UpdateStatus(STR_STATUS_ADD_MENU, menuName);
211 }
212 }
213
DeleteMenu(BMessage * message)214 void MenuWindow::DeleteMenu(BMessage* message)
215 {
216 if (! Valid()) {
217 return;
218 }
219
220 int32 i;
221 if (message->FindInt32("Menu Index", &i) == B_OK) {
222 BMenuItem* pItem = m_pFullMenuBar->ItemAt(i+2);
223 if (pItem) {
224 // menu index is the above index + 2 (for File and Test menus)
225 m_pFullMenuBar->RemoveItem(pItem);
226 UpdateStatus(STR_STATUS_DELETE_MENU, pItem->Label());
227 delete pItem;
228 }
229 }
230 }
231
TestMenu(BMessage * message)232 void MenuWindow::TestMenu(BMessage* message)
233 {
234 if (! Valid()) {
235 return;
236 }
237
238 int32 i;
239 if (message->FindInt32("Item Index", &i) == B_OK) {
240 char numText[3];
241 sprintf(numText, "%ld", i);
242 UpdateStatus(STR_STATUS_TEST, numText);
243 }
244 }
245
UserMenu(BMessage * message)246 void MenuWindow::UserMenu(BMessage* message)
247 {
248 if (! Valid()) {
249 return;
250 }
251
252 const char* itemName;
253 if (message->FindString("Item Name", &itemName) == B_OK) {
254 UpdateStatus(STR_STATUS_USER, itemName);
255 }
256 }
257
ToggleUserMenus(BMessage * message)258 void MenuWindow::ToggleUserMenus(BMessage* message)
259 {
260 if (! Valid()) {
261 return;
262 }
263
264 void* pSrc;
265 bool useFullMenus = false;
266
267 if (message->FindPointer("source", &pSrc) == B_OK) {
268 BCheckBox* pCheckBox = reinterpret_cast<BCheckBox*>(pSrc);
269 useFullMenus = (pCheckBox->Value() == B_CONTROL_OFF);
270 }
271
272 if ((! useFullMenus) && m_bUsingFullMenuBar) {
273 RemoveChild(m_pFullMenuBar);
274 AddChild(m_pHiddenMenuBar);
275 m_bUsingFullMenuBar = false;
276 } else if (useFullMenus && (! m_bUsingFullMenuBar)) {
277 RemoveChild(m_pHiddenMenuBar);
278 AddChild(m_pFullMenuBar);
279 m_bUsingFullMenuBar = true;
280 }
281 }
282
ToggleTestIcons(BMessage * message)283 void MenuWindow::ToggleTestIcons(BMessage* message)
284 {
285 if (! Valid()) {
286 return;
287 }
288
289 void* pSrc;
290 icon_size size = B_MINI_ICON;
291
292 if (message->FindPointer("source", &pSrc) == B_OK) {
293 BCheckBox* pCheckBox = reinterpret_cast<BCheckBox*>(pSrc);
294 size = (pCheckBox->Value() == B_CONTROL_ON) ? B_LARGE_ICON : B_MINI_ICON;
295 }
296
297 ReplaceTestMenu(m_pFullMenuBar, size);
298 ReplaceTestMenu(m_pHiddenMenuBar, size);
299 }
300
301
302
303 //--------------------------------------------------------------------
304 // MenuWindow implementation member functions
305
Valid(void) const306 bool MenuWindow::Valid(void) const
307 {
308 if (! m_pFullMenuBar) {
309 ierror(STR_NO_FULL_MENU_BAR);
310 return false;
311 }
312 if (! m_pHiddenMenuBar) {
313 ierror(STR_NO_HIDDEN_MENU_BAR);
314 return false;
315 }
316 if (! m_pMenuView) {
317 ierror(STR_NO_MENU_VIEW);
318 return false;
319 }
320 if (! m_pStatusView) {
321 ierror(STR_NO_STATUS_VIEW);
322 return false;
323 }
324 return true;
325 }
326
BuildFileMenu(void) const327 BMenu* MenuWindow::BuildFileMenu(void) const
328 {
329 BMenu* pMenu = new BMenu(STR_MNU_FILE);
330
331 BMenuItem* pAboutItem = new BMenuItem(STR_MNU_FILE_ABOUT,
332 new BMessage(B_ABOUT_REQUESTED));
333 pAboutItem->SetTarget(NULL, be_app);
334 pMenu->AddItem(pAboutItem);
335
336 pMenu->AddSeparatorItem();
337
338 pMenu->AddItem(new BMenuItem(STR_MNU_FILE_CLOSE,
339 new BMessage(B_QUIT_REQUESTED), CMD_FILE_CLOSE));
340
341 return pMenu;
342 }
343
ReplaceTestMenu(BMenuBar * pMenuBar,icon_size size)344 void MenuWindow::ReplaceTestMenu(BMenuBar* pMenuBar, icon_size size)
345 {
346 if (! pMenuBar) {
347 return;
348 }
349
350 BMenu* pTestMenu = m_testMenuBuilder.BuildTestMenu(size);
351 if (pTestMenu) {
352 BMenuItem* pPrevItem = pMenuBar->RemoveItem(1);
353 if (pPrevItem) {
354 delete pPrevItem;
355 }
356 pMenuBar->AddItem(pTestMenu, 1);
357 }
358 }
359