1 /* 2 * Copyright 2003-2008, Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Jérôme Duval 7 * Oliver Ruiz Dorantes 8 * Atsushi Takamatsu 9 */ 10 11 12 #include "HWindow.h" 13 #include "HEventList.h" 14 #include "HEventItem.h" 15 16 #include <stdio.h> 17 18 #include <Alert.h> 19 #include <Application.h> 20 #include <Beep.h> 21 #include <Box.h> 22 #include <Button.h> 23 #include <ClassInfo.h> 24 #include <FindDirectory.h> 25 #include <fs_attr.h> 26 #include <MediaFiles.h> 27 #include <MenuBar.h> 28 #include <MenuField.h> 29 #include <MenuItem.h> 30 #include <Node.h> 31 #include <NodeInfo.h> 32 #include <Path.h> 33 #include <Roster.h> 34 #include <ScrollView.h> 35 #include <StringView.h> 36 #include <Sound.h> 37 38 39 HWindow::HWindow(BRect rect, const char *name) 40 : _inherited(rect, name, B_TITLED_WINDOW, 0), 41 fFilePanel(NULL), 42 fPlayer(NULL) 43 { 44 InitGUI(); 45 float min_width, min_height, max_width, max_height; 46 GetSizeLimits(&min_width, &max_width, &min_height, &max_height); 47 min_width = 300; 48 min_height = 200; 49 SetSizeLimits(min_width, max_width, min_height, max_height); 50 51 fFilePanel = new BFilePanel(); 52 fFilePanel->SetTarget(this); 53 54 fEventList->Select(0); 55 } 56 57 58 HWindow::~HWindow() 59 { 60 delete fFilePanel; 61 delete fPlayer; 62 } 63 64 65 void 66 HWindow::InitGUI() 67 { 68 BRect rect = Bounds(); 69 rect.bottom -= 106; 70 BView *listView = new BView(rect, "", B_FOLLOW_NONE, B_WILL_DRAW | B_PULSE_NEEDED); 71 listView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 72 AddChild(listView); 73 74 BRect stringRect(16, 5, 60, 22); 75 BStringView *stringView = new BStringView(stringRect, "event", "Event"); 76 stringView->SetFont(be_bold_font); 77 stringView->ResizeToPreferred(); 78 listView->AddChild(stringView); 79 80 stringRect.OffsetBy(120, 0); 81 stringView = new BStringView(stringRect, "sound", "Sound"); 82 stringView->SetFont(be_bold_font); 83 stringView->ResizeToPreferred(); 84 listView->AddChild(stringView); 85 86 rect.left += 13; 87 rect.right -= B_V_SCROLL_BAR_WIDTH + 13; 88 rect.top += 28; 89 rect.bottom -= 7; 90 fEventList = new HEventList(rect); 91 fEventList->SetType(BMediaFiles::B_SOUNDS); 92 93 BScrollView *scrollView = new BScrollView("", fEventList, B_FOLLOW_ALL, 0, 94 false, true); 95 listView->AddChild(scrollView); 96 97 rect = Bounds(); 98 rect.top = rect.bottom - 105; 99 BView *view = new BView(rect, "", B_FOLLOW_NONE, B_WILL_DRAW | B_PULSE_NEEDED); 100 view->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 101 AddChild(view); 102 rect = view->Bounds().InsetBySelf(12, 12); 103 BBox *box = new BBox(rect, "", B_FOLLOW_ALL); 104 view->AddChild(box); 105 rect = box->Bounds(); 106 rect.top += 10; 107 rect.left += 15; 108 rect.right -= 10; 109 rect.bottom = rect.top + 20; 110 BMenu *menu = new BMenu("file"); 111 menu->SetRadioMode(true); 112 menu->SetLabelFromMarked(true); 113 menu->AddSeparatorItem(); 114 115 menu->AddItem(new BMenuItem("<none>", new BMessage(M_NONE_MESSAGE))); 116 menu->AddItem(new BMenuItem("Other" B_UTF8_ELLIPSIS, new BMessage(M_OTHER_MESSAGE))); 117 BMenuField *menuField = new BMenuField(rect, "filemenu", "Sound File:", menu, 118 B_FOLLOW_TOP | B_FOLLOW_LEFT); 119 menuField->SetDivider(menuField->StringWidth("Sound File:") + 10); 120 box->AddChild(menuField); 121 rect.OffsetBy(-2, menuField->Bounds().Height() + 15); 122 BButton *button = new BButton(rect, "stop", "Stop", new BMessage(M_STOP_MESSAGE), 123 B_FOLLOW_RIGHT | B_FOLLOW_TOP); 124 button->ResizeToPreferred(); 125 button->SetEnabled(false); 126 button->MoveTo(box->Bounds().right - button->Bounds().Width() - 15, rect.top); 127 box->AddChild(button); 128 129 rect = button->Frame(); 130 view->ResizeTo(view->Bounds().Width(), 24 + rect.bottom + 12); 131 box->ResizeTo(box->Bounds().Width(), rect.bottom + 12); 132 133 button->SetResizingMode(B_FOLLOW_RIGHT | B_FOLLOW_TOP); 134 button = new BButton(rect, "play", "Play", new BMessage(M_PLAY_MESSAGE), 135 B_FOLLOW_RIGHT | B_FOLLOW_TOP); 136 button->ResizeToPreferred(); 137 button->SetEnabled(false); 138 button->MoveTo(rect.left - button->Bounds().Width() - 15, rect.top); 139 box->AddChild(button); 140 141 view->MoveTo(0, listView->Frame().bottom); 142 ResizeTo(Bounds().Width(), listView->Frame().bottom + view->Bounds().Height()); 143 listView->SetResizingMode(B_FOLLOW_ALL); 144 view->SetResizingMode(B_FOLLOW_LEFT_RIGHT | B_FOLLOW_BOTTOM); 145 146 // setup file menu 147 SetupMenuField(); 148 menu->FindItem("<none>")->SetMarked(true); 149 } 150 151 152 void 153 HWindow::MessageReceived(BMessage *message) 154 { 155 switch (message->what) { 156 case M_OTHER_MESSAGE: 157 { 158 BMenuField *menufield = cast_as(FindView("filemenu"), BMenuField); 159 BMenu *menu = menufield->Menu(); 160 161 int32 sel = fEventList->CurrentSelection(); 162 if (sel >= 0) { 163 HEventItem *item = cast_as(fEventList->ItemAt(sel), HEventItem); 164 BPath path(item->Path()); 165 if (path.InitCheck() != B_OK) { 166 BMenuItem *item = menu->FindItem("<none>"); 167 if (item) 168 item->SetMarked(true); 169 } else { 170 BMenuItem *item = menu->FindItem(path.Leaf()); 171 if (item) 172 item->SetMarked(true); 173 } 174 } 175 fFilePanel->Show(); 176 break; 177 } 178 179 case B_SIMPLE_DATA: 180 case B_REFS_RECEIVED: 181 { 182 entry_ref ref; 183 int32 sel = fEventList->CurrentSelection(); 184 if (message->FindRef("refs", &ref) == B_OK && sel >= 0) { 185 BMenuField *menufield = cast_as(FindView("filemenu"), BMenuField); 186 BMenu *menu = menufield->Menu(); 187 188 // check audio file 189 BNode node(&ref); 190 BNodeInfo ninfo(&node); 191 char type[B_MIME_TYPE_LENGTH + 1]; 192 ninfo.GetType(type); 193 BMimeType mtype(type); 194 BMimeType superType; 195 mtype.GetSupertype(&superType); 196 if (superType.Type() == NULL || strcmp(superType.Type(), "audio") != 0) { 197 beep(); 198 (new BAlert("", "This is not a audio file.", "OK", NULL, NULL, 199 B_WIDTH_AS_USUAL, B_STOP_ALERT))->Go(); 200 break; 201 } 202 203 // add file item 204 BMessage *msg = new BMessage(M_ITEM_MESSAGE); 205 BPath path(&ref); 206 msg->AddRef("refs", &ref); 207 BMenuItem *menuitem = menu->FindItem(path.Leaf()); 208 if (!menuitem) 209 menu->AddItem(menuitem = new BMenuItem(path.Leaf(), msg), 0); 210 // refresh item 211 fEventList->SetPath(BPath(&ref).Path()); 212 // check file menu 213 if (menuitem) 214 menuitem->SetMarked(true); 215 } 216 break; 217 } 218 219 case M_PLAY_MESSAGE: 220 { 221 int32 sel = fEventList->CurrentSelection(); 222 if (sel >= 0) { 223 HEventItem *item = cast_as(fEventList->ItemAt(sel), HEventItem); 224 const char *path = item->Path(); 225 if (path) { 226 entry_ref ref; 227 ::get_ref_for_path(path, &ref); 228 delete fPlayer; 229 fPlayer = new BFileGameSound(&ref, false); 230 fPlayer->StartPlaying(); 231 } 232 } 233 break; 234 } 235 236 case M_STOP_MESSAGE: 237 { 238 if (!fPlayer) 239 break; 240 if (fPlayer->IsPlaying()) { 241 fPlayer->StopPlaying(); 242 delete fPlayer; 243 fPlayer = NULL; 244 } 245 break; 246 } 247 248 case M_EVENT_CHANGED: 249 { 250 const char *path; 251 BMenuField *menufield = cast_as(FindView("filemenu"), BMenuField); 252 BMenu *menu = menufield->Menu(); 253 254 if (message->FindString("path", &path) == B_OK) { 255 BPath path(path); 256 if (path.InitCheck() != B_OK) { 257 BMenuItem *item = menu->FindItem("<none>"); 258 if (item) 259 item->SetMarked(true); 260 } else { 261 BMenuItem *item = menu->FindItem(path.Leaf()); 262 if (item) 263 item->SetMarked(true); 264 } 265 } 266 break; 267 } 268 269 case M_ITEM_MESSAGE: 270 { 271 entry_ref ref; 272 if (message->FindRef("refs", &ref) == B_OK) 273 fEventList->SetPath(BPath(&ref).Path()); 274 break; 275 } 276 277 case M_NONE_MESSAGE: 278 { 279 fEventList->SetPath(NULL); 280 break; 281 } 282 283 default: 284 _inherited::MessageReceived(message); 285 } 286 } 287 288 289 void 290 HWindow::SetupMenuField() 291 { 292 BMenuField *menufield = cast_as(FindView("filemenu"), BMenuField); 293 BMenu *menu = menufield->Menu(); 294 int32 count = fEventList->CountItems(); 295 for (int32 i = 0; i < count; i++) { 296 HEventItem *item = cast_as(fEventList->ItemAt(i), HEventItem); 297 if (!item) 298 continue; 299 300 BPath path(item->Path()); 301 if (path.InitCheck() != B_OK) 302 continue; 303 if (menu->FindItem(path.Leaf())) 304 continue; 305 306 BMessage *msg = new BMessage(M_ITEM_MESSAGE); 307 entry_ref ref; 308 ::get_ref_for_path(path.Path(), &ref); 309 msg->AddRef("refs", &ref); 310 menu->AddItem(new BMenuItem(path.Leaf(), msg), 0); 311 } 312 313 BPath path; 314 BDirectory dir; 315 BEntry entry; 316 BPath item_path; 317 318 status_t err = find_directory(B_BEOS_SOUNDS_DIRECTORY, &path); 319 if (err == B_OK) 320 err = dir.SetTo(path.Path()); 321 while (err == B_OK) { 322 err = dir.GetNextEntry((BEntry*)&entry, true); 323 if (entry.InitCheck() != B_NO_ERROR) 324 break; 325 326 entry.GetPath(&item_path); 327 328 if (menu->FindItem(item_path.Leaf())) 329 continue; 330 331 BMessage *msg = new BMessage(M_ITEM_MESSAGE); 332 entry_ref ref; 333 ::get_ref_for_path(item_path.Path(), &ref); 334 msg->AddRef("refs", &ref); 335 menu->AddItem(new BMenuItem(item_path.Leaf(), msg), 0); 336 } 337 338 err = find_directory(B_USER_SOUNDS_DIRECTORY, &path); 339 if (err == B_OK) 340 err = dir.SetTo(path.Path()); 341 while (err == B_OK) { 342 err = dir.GetNextEntry((BEntry*)&entry, true); 343 if (entry.InitCheck() != B_NO_ERROR) 344 break; 345 346 entry.GetPath(&item_path); 347 348 if (menu->FindItem(item_path.Leaf())) 349 continue; 350 351 BMessage *msg = new BMessage(M_ITEM_MESSAGE); 352 entry_ref ref; 353 354 ::get_ref_for_path(item_path.Path(), &ref); 355 msg->AddRef("refs", &ref); 356 menu->AddItem(new BMenuItem(item_path.Leaf(), msg), 0); 357 } 358 359 err = find_directory(B_COMMON_SOUNDS_DIRECTORY, &path); 360 if (err == B_OK) 361 err = dir.SetTo(path.Path()); 362 while (err == B_OK) { 363 err = dir.GetNextEntry((BEntry*)&entry, true); 364 if (entry.InitCheck() != B_NO_ERROR) 365 break; 366 367 entry.GetPath(&item_path); 368 369 if (menu->FindItem(item_path.Leaf())) 370 continue; 371 372 BMessage *msg = new BMessage(M_ITEM_MESSAGE); 373 entry_ref ref; 374 375 ::get_ref_for_path(item_path.Path(), &ref); 376 msg->AddRef("refs", &ref); 377 menu->AddItem(new BMenuItem(item_path.Leaf(), msg), 0); 378 } 379 380 } 381 382 383 void 384 HWindow::Pulse() 385 { 386 int32 sel = fEventList->CurrentSelection(); 387 BMenuField *menufield = cast_as(FindView("filemenu"), BMenuField); 388 BButton *button = cast_as(FindView("play"), BButton); 389 BButton *stop = cast_as(FindView("stop"), BButton); 390 391 if (!menufield) 392 return; 393 394 if (sel >= 0) { 395 menufield->SetEnabled(true); 396 397 HEventItem *item = cast_as(fEventList->ItemAt(sel), HEventItem); 398 const char *path = item->Path(); 399 if (path && strcmp(path, "")) 400 button->SetEnabled(true); 401 else 402 button->SetEnabled(false); 403 } else { 404 menufield->SetEnabled(false); 405 button->SetEnabled(false); 406 } 407 408 if (fPlayer) { 409 if (fPlayer->IsPlaying()) 410 stop->SetEnabled(true); 411 else 412 stop->SetEnabled(false); 413 } else 414 stop->SetEnabled(false); 415 } 416 417 418 void 419 HWindow::DispatchMessage(BMessage *message, BHandler *handler) 420 { 421 if (message->what == B_PULSE) 422 Pulse(); 423 BWindow::DispatchMessage(message, handler); 424 } 425 426 427 bool 428 HWindow::QuitRequested() 429 { 430 fEventList->RemoveAll(); 431 be_app->PostMessage(B_QUIT_REQUESTED); 432 return true; 433 } 434