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 25const uint32 kMsgUpdateLook = 'uplk'; 26const uint32 kMsgUpdateFeel = 'upfe'; 27const uint32 kMsgUpdateFlags = 'upfl'; 28 29const uint32 kMsgAddWindow = 'adwn'; 30const uint32 kMsgAddSubsetWindow = 'adsw'; 31 32 33int32 gNormalWindowCount = 0; 34 35 36class 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 53Window::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 222Window::~Window() 223{ 224} 225 226 227void 228Window::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 315bool 316Window::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 328BMessage* 329Window::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 344BString 345Window::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 395void 396Window::_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 421class Application : public BApplication { 422 public: 423 Application(); 424 425 virtual void ReadyToRun(); 426}; 427 428 429Application::Application() 430 : BApplication("application/x-vnd.haiku-looknfeel") 431{ 432} 433 434 435void 436Application::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 447int 448main(int argc, char **argv) 449{ 450 Application app;// app; 451 452 app.Run(); 453 return 0; 454} 455