1 /* 2 * Copyright 2005-2009, Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler, axeld@pinc-software.de 7 */ 8 9 10 #include <Alert.h> 11 #include <Application.h> 12 #include <Button.h> 13 #include <MenuField.h> 14 #include <MenuItem.h> 15 #include <PopUpMenu.h> 16 #include <String.h> 17 #include <Window.h> 18 19 #include <WindowPrivate.h> 20 21 #include <stdio.h> 22 #include <string.h> 23 24 25 const uint32 kMsgUpdateLook = 'uplk'; 26 const uint32 kMsgUpdateFeel = 'upfe'; 27 const uint32 kMsgUpdateFlags = 'upfl'; 28 29 const uint32 kMsgAddWindow = 'adwn'; 30 const uint32 kMsgAddSubsetWindow = 'adsw'; 31 32 33 int32 gNormalWindowCount = 0; 34 35 36 class Window : public BWindow { 37 public: 38 Window(BRect frame, window_look look, window_feel feel); 39 virtual ~Window(); 40 41 virtual void MessageReceived(BMessage* message); 42 virtual bool QuitRequested(); 43 44 private: 45 BMessage* AddWindowMessage(window_look look, window_feel feel); 46 BString TitleForFeel(window_feel feel); 47 void _UpdateFlagsMenuLabel(); 48 49 BMenuField* fFlagsField; 50 }; 51 52 53 Window::Window(BRect frame, window_look look, window_feel feel) 54 : BWindow(frame, TitleForFeel(feel).String(), look, feel, 55 B_ASYNCHRONOUS_CONTROLS) 56 { 57 BRect rect(Bounds()); 58 BView *view = new BView(rect, NULL, B_FOLLOW_ALL, B_WILL_DRAW); 59 view->SetViewUIColor(B_PANEL_BACKGROUND_COLOR); 60 AddChild(view); 61 62 if (!IsModal() && !IsFloating()) 63 gNormalWindowCount++; 64 65 float labelWidth = view->StringWidth("Flags:") + 5.f; 66 67 BPopUpMenu* menu = new BPopUpMenu("looks"); 68 const struct { const char* name; int32 look; } looks[] = { 69 {"Titled", B_TITLED_WINDOW_LOOK}, {"Document", B_DOCUMENT_WINDOW_LOOK}, 70 {"Floating", B_FLOATING_WINDOW_LOOK}, {"Modal", B_MODAL_WINDOW_LOOK}, 71 {"Bordered", B_BORDERED_WINDOW_LOOK}, {"No Border", B_NO_BORDER_WINDOW_LOOK}, 72 {"Left Titled", kLeftTitledWindowLook}, {"Desktop", kDesktopWindowLook} 73 }; 74 for (uint32 i = 0; i < sizeof(looks) / sizeof(looks[0]); i++) { 75 BMessage* message = new BMessage(kMsgUpdateLook); 76 message->AddInt32("look", looks[i].look); 77 BMenuItem* item = new BMenuItem(looks[i].name, message); 78 if (looks[i].look == (int32)Look()) 79 item->SetMarked(true); 80 81 menu->AddItem(item); 82 } 83 84 rect.InsetBy(10, 10); 85 BMenuField* menuField = new BMenuField(rect, "look", "Look:", menu); 86 menuField->ResizeToPreferred(); 87 menuField->SetDivider(labelWidth); 88 view->AddChild(menuField); 89 90 menu = new BPopUpMenu("feels"); 91 const struct { const char* name; int32 feel; } feels[] = { 92 {"Normal", B_NORMAL_WINDOW_FEEL}, 93 {"Modal Subset", B_MODAL_SUBSET_WINDOW_FEEL}, 94 {"App Modal", B_MODAL_APP_WINDOW_FEEL}, 95 {"All Modal", B_MODAL_ALL_WINDOW_FEEL}, 96 {"Floating Subset", B_FLOATING_SUBSET_WINDOW_FEEL}, 97 {"App Floating", B_FLOATING_APP_WINDOW_FEEL}, 98 {"All Floating", B_FLOATING_ALL_WINDOW_FEEL}, 99 {"Menu", kMenuWindowFeel}, 100 {"WindowScreen", kWindowScreenFeel}, 101 {"Desktop", kDesktopWindowFeel}, 102 }; 103 for (uint32 i = 0; i < sizeof(feels) / sizeof(feels[0]); i++) { 104 BMessage* message = new BMessage(kMsgUpdateFeel); 105 message->AddInt32("feel", feels[i].feel); 106 BMenuItem* item = new BMenuItem(feels[i].name, message); 107 if (feels[i].feel == (int32)Feel()) 108 item->SetMarked(true); 109 110 menu->AddItem(item); 111 } 112 113 rect.OffsetBy(0, menuField->Bounds().Height() + 10); 114 menuField = new BMenuField(rect, "feel", "Feel:", menu); 115 menuField->ResizeToPreferred(); 116 menuField->SetDivider(labelWidth); 117 view->AddChild(menuField); 118 119 menu = new BPopUpMenu("none", false, false); 120 const struct { const char* name; uint32 flag; } flags[] = { 121 {"Not Zoomable", B_NOT_ZOOMABLE}, 122 {"Not Closable", B_NOT_CLOSABLE}, 123 {"Not Movable", B_NOT_MOVABLE}, 124 {"Not Horizontally Resizable", B_NOT_H_RESIZABLE}, 125 {"Not Vertically Resizable", B_NOT_V_RESIZABLE}, 126 {"Outline Resize", B_OUTLINE_RESIZE}, 127 {"Accept First Click", B_WILL_ACCEPT_FIRST_CLICK}, 128 {"Not Anchored On Activate", B_NOT_ANCHORED_ON_ACTIVATE}, 129 {"Avoid Front", B_AVOID_FRONT}, 130 #if defined(__HAIKU__) || defined(HAIKU_TARGET_PLATFORM_LIBBE_TEST) 131 {"Same Position In All Workspaces", B_SAME_POSITION_IN_ALL_WORKSPACES}, 132 #endif 133 }; 134 for (uint32 i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) { 135 BMessage* message = new BMessage(kMsgUpdateFlags); 136 message->AddInt32("flag", flags[i].flag); 137 BMenuItem* item = new BMenuItem(flags[i].name, message); 138 139 menu->AddItem(item); 140 } 141 142 rect.OffsetBy(0, menuField->Bounds().Height() + 10); 143 fFlagsField = new BMenuField(rect, "flags", "Flags:", menu); 144 fFlagsField->ResizeToPreferred(); 145 fFlagsField->SetDivider(labelWidth); 146 view->AddChild(fFlagsField); 147 148 // normal 149 150 rect.OffsetBy(0, menuField->Bounds().Height() + 10); 151 BButton* button = new BButton(rect, "normal", "Add Normal Window", 152 AddWindowMessage(B_TITLED_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL), 153 B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP, 154 B_WILL_DRAW | B_NAVIGABLE | B_FULL_UPDATE_ON_RESIZE); 155 float width, height; 156 button->GetPreferredSize(&width, &height); 157 button->ResizeTo(rect.Width(), height); 158 view->AddChild(button); 159 160 // modal 161 162 rect = button->Frame(); 163 rect.OffsetBy(0, rect.Height() + 5); 164 button = new BButton(rect, "modal_subset", "Add Modal Subset", 165 AddWindowMessage(B_MODAL_WINDOW_LOOK, B_MODAL_SUBSET_WINDOW_FEEL), 166 B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP, 167 B_WILL_DRAW | B_NAVIGABLE | B_FULL_UPDATE_ON_RESIZE); 168 view->AddChild(button); 169 170 rect.OffsetBy(0, rect.Height() + 5); 171 button = new BButton(rect, "app_modal", "Add Application Modal", 172 AddWindowMessage(B_MODAL_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL), 173 B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP, 174 B_WILL_DRAW | B_NAVIGABLE | B_FULL_UPDATE_ON_RESIZE); 175 view->AddChild(button); 176 177 rect.OffsetBy(0, rect.Height() + 5); 178 button = new BButton(rect, "all_modal", "Add All Modal", 179 AddWindowMessage(B_MODAL_WINDOW_LOOK, B_MODAL_ALL_WINDOW_FEEL), 180 B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP, 181 B_WILL_DRAW | B_NAVIGABLE | B_FULL_UPDATE_ON_RESIZE); 182 view->AddChild(button); 183 184 // floating 185 186 rect = button->Frame(); 187 rect.OffsetBy(0, rect.Height() + 5); 188 button = new BButton(rect, "floating_subset", "Add Floating Subset", 189 AddWindowMessage(B_FLOATING_WINDOW_LOOK, B_FLOATING_SUBSET_WINDOW_FEEL), 190 B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP, 191 B_WILL_DRAW | B_NAVIGABLE | B_FULL_UPDATE_ON_RESIZE); 192 view->AddChild(button); 193 194 rect.OffsetBy(0, rect.Height() + 5); 195 button = new BButton(rect, "app_floating", "Add Application Floating", 196 AddWindowMessage(B_FLOATING_WINDOW_LOOK, B_FLOATING_APP_WINDOW_FEEL), 197 B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP, 198 B_WILL_DRAW | B_NAVIGABLE | B_FULL_UPDATE_ON_RESIZE); 199 view->AddChild(button); 200 201 rect.OffsetBy(0, rect.Height() + 5); 202 button = new BButton(rect, "all_floating", "Add All Floating", 203 AddWindowMessage(B_FLOATING_WINDOW_LOOK, B_FLOATING_ALL_WINDOW_FEEL), 204 B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP, 205 B_WILL_DRAW | B_NAVIGABLE | B_FULL_UPDATE_ON_RESIZE); 206 view->AddChild(button); 207 208 // close 209 210 rect.OffsetBy(0, rect.Height() + 15); 211 button = new BButton(rect, "close", "Close Window", 212 new BMessage(B_QUIT_REQUESTED), B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP, 213 B_WILL_DRAW | B_NAVIGABLE | B_FULL_UPDATE_ON_RESIZE); 214 button->ResizeToPreferred(); 215 button->MoveTo((rect.Width() - button->Bounds().Width()) / 2, rect.top); 216 view->AddChild(button); 217 218 ResizeTo(Bounds().Width(), button->Frame().bottom + 10); 219 } 220 221 222 Window::~Window() 223 { 224 } 225 226 227 void 228 Window::MessageReceived(BMessage* message) 229 { 230 switch (message->what) { 231 case kMsgUpdateLook: 232 { 233 int32 look; 234 if (message->FindInt32("look", &look) != B_OK) 235 break; 236 237 SetLook((window_look)look); 238 break; 239 } 240 241 case kMsgUpdateFeel: 242 { 243 int32 feel; 244 if (message->FindInt32("feel", &feel) != B_OK) 245 break; 246 247 if (!IsModal() && !IsFloating()) 248 gNormalWindowCount--; 249 250 SetFeel((window_feel)feel); 251 SetTitle(TitleForFeel((window_feel)feel).String()); 252 253 if (!IsModal() && !IsFloating()) 254 gNormalWindowCount++; 255 break; 256 } 257 258 case kMsgUpdateFlags: 259 { 260 uint32 flag; 261 if (message->FindInt32("flag", (int32*)&flag) != B_OK) 262 break; 263 264 BMenuItem* item; 265 if (message->FindPointer("source", (void**)&item) != B_OK) 266 break; 267 268 item->SetMarked(!item->IsMarked()); 269 270 uint32 flags = Flags(); 271 if (item->IsMarked()) 272 flags |= flag; 273 else 274 flags &= ~flag; 275 276 SetFlags(flags); 277 _UpdateFlagsMenuLabel(); 278 break; 279 } 280 281 case kMsgAddWindow: 282 case kMsgAddSubsetWindow: 283 { 284 int32 look, feel; 285 if (message->FindInt32("look", &look) != B_OK 286 || message->FindInt32("feel", &feel) != B_OK) 287 break; 288 289 BWindow* window = new Window(Frame().OffsetByCopy(20, 20), 290 (window_look)look, (window_feel)feel); 291 292 if (message->what == kMsgAddSubsetWindow) { 293 status_t status = window->AddToSubset(this); 294 if (status != B_OK) { 295 char text[512]; 296 snprintf(text, sizeof(text), 297 "Window could not be added to subset:\n\n\%s", strerror(status)); 298 (new BAlert("Alert", text, "OK"))->Go(NULL); 299 300 delete window; 301 break; 302 } 303 } 304 305 window->Show(); 306 break; 307 } 308 309 default: 310 BWindow::MessageReceived(message); 311 } 312 } 313 314 315 bool 316 Window::QuitRequested() 317 { 318 if (!IsModal() && !IsFloating()) 319 gNormalWindowCount--; 320 321 if (gNormalWindowCount < 1) 322 be_app->PostMessage(B_QUIT_REQUESTED); 323 324 return true; 325 } 326 327 328 BMessage* 329 Window::AddWindowMessage(window_look look, window_feel feel) 330 { 331 BMessage* message = new BMessage(kMsgAddWindow); 332 333 if (feel == B_FLOATING_SUBSET_WINDOW_FEEL 334 || feel == B_MODAL_SUBSET_WINDOW_FEEL) 335 message->what = kMsgAddSubsetWindow; 336 337 message->AddInt32("look", look); 338 message->AddInt32("feel", feel); 339 340 return message; 341 } 342 343 344 BString 345 Window::TitleForFeel(window_feel feel) 346 { 347 BString title = "Look&Feel - "; 348 349 switch ((uint32)feel) { 350 case B_NORMAL_WINDOW_FEEL: 351 title += "Normal"; 352 break; 353 354 // modal feels 355 356 case B_MODAL_SUBSET_WINDOW_FEEL: 357 title += "Modal Subset"; 358 break; 359 case B_MODAL_APP_WINDOW_FEEL: 360 title += "Application Modal"; 361 break; 362 case B_MODAL_ALL_WINDOW_FEEL: 363 title += "All Modal"; 364 break; 365 366 // floating feels 367 368 case B_FLOATING_SUBSET_WINDOW_FEEL: 369 title += "Floating Subset"; 370 break; 371 case B_FLOATING_APP_WINDOW_FEEL: 372 title += "Application Floating"; 373 break; 374 case B_FLOATING_ALL_WINDOW_FEEL: 375 title += "All Floating"; 376 break; 377 378 // special/private feels 379 380 case kMenuWindowFeel: 381 title += "Menu"; 382 break; 383 case kWindowScreenFeel: 384 title += "WindowScreen"; 385 break; 386 case kDesktopWindowFeel: 387 title += "Desktop"; 388 break; 389 } 390 391 return title; 392 } 393 394 395 void 396 Window::_UpdateFlagsMenuLabel() 397 { 398 BString label; 399 BMenu* menu = fFlagsField->Menu(); 400 401 for (int32 i = 0; i < menu->CountItems(); i++) { 402 BMenuItem* item = menu->ItemAt(i); 403 404 if (item->IsMarked()) { 405 if (label != "") 406 label += " + "; 407 label += item->Label(); 408 } 409 } 410 411 if (label == "") 412 label = "none"; 413 414 menu->Superitem()->SetLabel(label.String()); 415 } 416 417 418 // #pragma mark - 419 420 421 class Application : public BApplication { 422 public: 423 Application(); 424 425 virtual void ReadyToRun(); 426 }; 427 428 429 Application::Application() 430 : BApplication("application/x-vnd.haiku-looknfeel") 431 { 432 } 433 434 435 void 436 Application::ReadyToRun() 437 { 438 Window *window = new Window(BRect(100, 100, 400, 420), 439 B_TITLED_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL); 440 window->Show(); 441 } 442 443 444 // #pragma mark - 445 446 447 int 448 main(int argc, char **argv) 449 { 450 Application app;// app; 451 452 app.Run(); 453 return 0; 454 } 455