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