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 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 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 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 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 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 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 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 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 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 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 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 306 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 327 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 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