1 #include "CodyCam.h" 2 3 #include <Alert.h> 4 #include <stdio.h> 5 #include <string.h> 6 #include <Button.h> 7 #include <TabView.h> 8 #include <Menu.h> 9 #include <MenuItem.h> 10 #include <MenuBar.h> 11 #include <PopUpMenu.h> 12 #include <MediaDefs.h> 13 #include <MediaNode.h> 14 #include <scheduler.h> 15 #include <MediaTheme.h> 16 #include <TimeSource.h> 17 #include <MediaRoster.h> 18 #include <TextControl.h> 19 #include <TranslationKit.h> 20 #include <unistd.h> 21 22 23 #define VIDEO_SIZE_X 320 24 #define VIDEO_SIZE_Y 240 25 26 #define WINDOW_SIZE_X (VIDEO_SIZE_X + 80) 27 #define WINDOW_SIZE_Y (VIDEO_SIZE_Y + 230) 28 29 #define WINDOW_OFFSET_X 28 30 #define WINDOW_OFFSET_Y 28 31 32 const int32 kBtnHeight = 20; 33 const int32 kBtnWidth = 60; 34 const int32 kBtnBuffer = 25; 35 const int32 kXBuffer = 10; 36 const int32 kYBuffer = 10; 37 const int32 kMenuHeight = 15; 38 const int32 kButtonHeight = 15; 39 const int32 kSliderViewRectHeight = 40; 40 41 const rgb_color kViewGray = { 216, 216, 216, 255}; 42 43 static void ErrorAlert(const char * message, status_t err); 44 static status_t AddTranslationItems( BMenu * intoMenu, uint32 from_type); 45 46 #define CALL printf 47 #define ERROR printf 48 #define FTPINFO printf 49 #define INFO printf 50 51 //--------------------------------------------------------------- 52 // The Application 53 //--------------------------------------------------------------- 54 55 int main() { 56 chdir("/boot/home"); 57 CodyCam app; 58 app.Run(); 59 return 0; 60 } 61 62 //--------------------------------------------------------------- 63 64 CodyCam::CodyCam() : 65 BApplication("application/x-vnd.Be.CodyCam"), 66 fMediaRoster(NULL), 67 fVideoConsumer(NULL), 68 fWindow(NULL), 69 fPort(0), 70 mVideoControlWindow(NULL) 71 { 72 } 73 74 //--------------------------------------------------------------- 75 76 CodyCam::~CodyCam() 77 { 78 CALL("CodyCam::~CodyCam\n"); 79 80 // release the video consumer node 81 // the consumer node cleans up the window 82 if (fVideoConsumer) { 83 fVideoConsumer->Release(); 84 fVideoConsumer = NULL; 85 } 86 87 CALL("CodyCam::~CodyCam - EXIT\n"); 88 } 89 90 //--------------------------------------------------------------- 91 92 void 93 CodyCam::ReadyToRun() 94 { 95 /* create the window for the app */ 96 fWindow = new VideoWindow(BRect(28, 28, 28 + (WINDOW_SIZE_X-1), 28 + (WINDOW_SIZE_Y-1)), 97 (const char *)"CodyCam", B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE, &fPort); 98 99 /* set up the node connections */ 100 status_t status = SetUpNodes(); 101 if (status != B_OK) 102 { 103 // This error is not needed because SetUpNodes handles displaying any 104 // errors it runs into. 105 // ErrorAlert("Error setting up nodes", status); 106 return; 107 } 108 109 ((VideoWindow *)fWindow)->ApplyControls(); 110 111 } 112 113 //--------------------------------------------------------------- 114 115 bool 116 CodyCam::QuitRequested() 117 { 118 TearDownNodes(); 119 snooze(100000); 120 121 return true; 122 } 123 124 //--------------------------------------------------------------- 125 126 void 127 CodyCam::MessageReceived(BMessage *message) 128 { 129 switch (message->what) 130 { 131 case msg_start: 132 { 133 BTimeSource *timeSource = fMediaRoster->MakeTimeSourceFor(fTimeSourceNode); 134 bigtime_t real = BTimeSource::RealTime(); 135 bigtime_t perf = timeSource->PerformanceTimeFor(real) + 10000; 136 status_t status = fMediaRoster->StartNode(fProducerNode, perf); 137 if (status != B_OK) 138 ERROR("error starting producer!"); 139 timeSource->Release(); 140 break; 141 } 142 case msg_stop: 143 fMediaRoster->StopNode(fProducerNode, 0, true); 144 break; 145 case msg_video: 146 { 147 if (mVideoControlWindow) { 148 mVideoControlWindow->Activate(); 149 break; 150 } 151 BParameterWeb * web = NULL; 152 BView * view = NULL; 153 media_node node = fProducerNode; 154 status_t err = fMediaRoster->GetParameterWebFor(node, &web); 155 if ((err >= B_OK) && 156 (web != NULL)) 157 { 158 view = BMediaTheme::ViewFor(web); 159 mVideoControlWindow = new ControlWindow( 160 BRect(2*WINDOW_OFFSET_X + WINDOW_SIZE_X, WINDOW_OFFSET_Y, 161 2*WINDOW_OFFSET_X + WINDOW_SIZE_X + view->Bounds().right, WINDOW_OFFSET_Y + view->Bounds().bottom), 162 view, node); 163 fMediaRoster->StartWatching(BMessenger(NULL, mVideoControlWindow), node, B_MEDIA_WEB_CHANGED); 164 mVideoControlWindow->Show(); 165 } 166 break; 167 } 168 case msg_about: 169 { 170 (new BAlert("About CodyCam", "CodyCam\n\nThe Original BeOS WebCam", "Close"))->Go(); 171 break; 172 } 173 174 case msg_control_win: 175 { 176 // our control window is being asked to go away 177 // set our pointer to NULL 178 mVideoControlWindow = NULL; 179 break; 180 181 } 182 183 default: 184 BApplication::MessageReceived(message); 185 break; 186 } 187 } 188 189 //--------------------------------------------------------------- 190 191 status_t 192 CodyCam::SetUpNodes() 193 { 194 status_t status = B_OK; 195 196 /* find the media roster */ 197 fMediaRoster = BMediaRoster::Roster(&status); 198 if (status != B_OK) { 199 ErrorAlert("Can't find the media roster", status); 200 return status; 201 } 202 /* find the time source */ 203 status = fMediaRoster->GetTimeSource(&fTimeSourceNode); 204 if (status != B_OK) { 205 ErrorAlert("Can't get a time source", status); 206 return status; 207 } 208 /* find a video producer node */ 209 INFO("CodyCam acquiring VideoInput node\n"); 210 status = fMediaRoster->GetVideoInput(&fProducerNode); 211 if (status != B_OK) { 212 ErrorAlert("Can't find a video source. You need a webcam to use CodyCam.", status); 213 return status; 214 } 215 216 /* create the video consumer node */ 217 fVideoConsumer = new VideoConsumer("CodyCam", ((VideoWindow *)fWindow)->VideoView(), ((VideoWindow *)fWindow)->StatusLine(), NULL, 0); 218 if (!fVideoConsumer) { 219 ErrorAlert("Can't create a video window", B_ERROR); 220 return B_ERROR; 221 } 222 223 /* register the node */ 224 status = fMediaRoster->RegisterNode(fVideoConsumer); 225 if (status != B_OK) { 226 ErrorAlert("Can't register the video window", status); 227 return status; 228 } 229 fPort = fVideoConsumer->ControlPort(); 230 231 /* find free producer output */ 232 int32 cnt = 0; 233 status = fMediaRoster->GetFreeOutputsFor(fProducerNode, &fProducerOut, 1, &cnt, B_MEDIA_RAW_VIDEO); 234 if (status != B_OK || cnt < 1) { 235 status = B_RESOURCE_UNAVAILABLE; 236 ErrorAlert("Can't find an available video stream", status); 237 return status; 238 } 239 240 /* find free consumer input */ 241 cnt = 0; 242 status = fMediaRoster->GetFreeInputsFor(fVideoConsumer->Node(), &fConsumerIn, 1, &cnt, B_MEDIA_RAW_VIDEO); 243 if (status != B_OK || cnt < 1) { 244 status = B_RESOURCE_UNAVAILABLE; 245 ErrorAlert("Can't find an available connection to the video window", status); 246 return status; 247 } 248 249 /* Connect The Nodes!!! */ 250 media_format format; 251 format.type = B_MEDIA_RAW_VIDEO; 252 media_raw_video_format vid_format = 253 { 0, 1, 0, 239, B_VIDEO_TOP_LEFT_RIGHT, 1, 1, {B_RGB32, VIDEO_SIZE_X, VIDEO_SIZE_Y, VIDEO_SIZE_X*4, 0, 0}}; 254 format.u.raw_video = vid_format; 255 256 /* connect producer to consumer */ 257 status = fMediaRoster->Connect(fProducerOut.source, fConsumerIn.destination, 258 &format, &fProducerOut, &fConsumerIn); 259 if (status != B_OK) { 260 ErrorAlert("Can't connect the video source to the video window", status); 261 return status; 262 } 263 264 /* set time sources */ 265 status = fMediaRoster->SetTimeSourceFor(fProducerNode.node, fTimeSourceNode.node); 266 if (status != B_OK) { 267 ErrorAlert("Can't set the timesource for the video source", status); 268 return status; 269 } 270 271 status = fMediaRoster->SetTimeSourceFor(fVideoConsumer->ID(), fTimeSourceNode.node); 272 if (status != B_OK) { 273 ErrorAlert("Can't set the timesource for the video window", status); 274 return status; 275 } 276 277 /* figure out what recording delay to use */ 278 bigtime_t latency = 0; 279 status = fMediaRoster->GetLatencyFor(fProducerNode, &latency); 280 status = fMediaRoster->SetProducerRunModeDelay(fProducerNode, latency); 281 282 /* start the nodes */ 283 bigtime_t initLatency = 0; 284 status = fMediaRoster->GetInitialLatencyFor(fProducerNode, &initLatency); 285 if (status < B_OK) { 286 ErrorAlert("error getting initial latency for fCaptureNode", status); 287 } 288 initLatency += estimate_max_scheduling_latency(); 289 290 BTimeSource *timeSource = fMediaRoster->MakeTimeSourceFor(fProducerNode); 291 bool running = timeSource->IsRunning(); 292 293 /* workaround for people without sound cards */ 294 /* because the system time source won't be running */ 295 bigtime_t real = BTimeSource::RealTime(); 296 if (!running) 297 { 298 status = fMediaRoster->StartTimeSource(fTimeSourceNode, real); 299 if (status != B_OK) { 300 timeSource->Release(); 301 ErrorAlert("cannot start time source!", status); 302 return status; 303 } 304 status = fMediaRoster->SeekTimeSource(fTimeSourceNode, 0, real); 305 if (status != B_OK) { 306 timeSource->Release(); 307 ErrorAlert("cannot seek time source!", status); 308 return status; 309 } 310 } 311 312 bigtime_t perf = timeSource->PerformanceTimeFor(real + latency + initLatency); 313 timeSource->Release(); 314 315 /* start the nodes */ 316 status = fMediaRoster->StartNode(fProducerNode, perf); 317 if (status != B_OK) { 318 ErrorAlert("Can't start the video source", status); 319 return status; 320 } 321 status = fMediaRoster->StartNode(fVideoConsumer->Node(), perf); 322 if (status != B_OK) { 323 ErrorAlert("Can't start the video window", status); 324 return status; 325 } 326 327 return status; 328 } 329 330 //--------------------------------------------------------------- 331 332 void 333 CodyCam::TearDownNodes() 334 { 335 CALL("CodyCam::TearDownNodes\n"); 336 if (!fMediaRoster) 337 return; 338 339 if (fVideoConsumer) 340 { 341 /* stop */ 342 INFO("stopping nodes!\n"); 343 // fMediaRoster->StopNode(fProducerNode, 0, true); 344 fMediaRoster->StopNode(fVideoConsumer->Node(), 0, true); 345 346 /* disconnect */ 347 fMediaRoster->Disconnect(fProducerOut.node.node, fProducerOut.source, 348 fConsumerIn.node.node, fConsumerIn.destination); 349 350 if (fProducerNode != media_node::null) { 351 INFO("CodyCam releasing fProducerNode\n"); 352 fMediaRoster->ReleaseNode(fProducerNode); 353 fProducerNode = media_node::null; 354 } 355 fMediaRoster->ReleaseNode(fVideoConsumer->Node()); 356 fVideoConsumer = NULL; 357 } 358 } 359 360 //--------------------------------------------------------------- 361 // Utility functions 362 //--------------------------------------------------------------- 363 364 static void 365 ErrorAlert(const char * message, status_t err) 366 { 367 (new BAlert("", message, "Quit"))->Go(); 368 369 printf("%s\n%s [%lx]", message, strerror(err), err); 370 be_app->PostMessage(B_QUIT_REQUESTED); 371 } 372 373 //--------------------------------------------------------------- 374 375 status_t 376 AddTranslationItems( BMenu * intoMenu, uint32 from_type) 377 { 378 379 BTranslatorRoster * use; 380 char * translator_type_name; 381 const char * translator_id_name; 382 383 use = BTranslatorRoster::Default(); 384 translator_id_name = "be:translator"; 385 translator_type_name = "be:type"; 386 translator_id * ids = NULL; 387 int32 count = 0; 388 389 status_t err = use->GetAllTranslators(&ids, &count); 390 if (err < B_OK) return err; 391 for (int tix=0; tix<count; tix++) { 392 const translation_format * formats = NULL; 393 int32 num_formats = 0; 394 bool ok = false; 395 err = use->GetInputFormats(ids[tix], &formats, &num_formats); 396 if (err == B_OK) for (int iix=0; iix<num_formats; iix++) { 397 if (formats[iix].type == from_type) { 398 ok = true; 399 break; 400 } 401 } 402 if (!ok) continue; 403 err = use->GetOutputFormats(ids[tix], &formats, &num_formats); 404 if (err == B_OK) for (int oix=0; oix<num_formats; oix++) { 405 if (formats[oix].type != from_type) { 406 BMessage * itemmsg; 407 itemmsg = new BMessage(msg_translate); 408 itemmsg->AddInt32(translator_id_name, ids[tix]); 409 itemmsg->AddInt32(translator_type_name, formats[oix].type); 410 intoMenu->AddItem(new BMenuItem(formats[oix].name, itemmsg)); 411 } 412 } 413 } 414 delete[] ids; 415 return B_OK; 416 } 417 418 //--------------------------------------------------------------- 419 // Video Window Class 420 //--------------------------------------------------------------- 421 422 VideoWindow::VideoWindow (BRect frame, const char *title, window_type type, uint32 flags, port_id * consumerport) : 423 BWindow(frame,title,type,flags), 424 fPortPtr(consumerport), 425 fView(NULL), 426 fVideoView(NULL) 427 { 428 fFtpInfo.port = 0; 429 fFtpInfo.rate = 0x7fffffff; 430 fFtpInfo.imageFormat = 0; 431 fFtpInfo.translator = 0; 432 fFtpInfo.passiveFtp = true; 433 strcpy(fFtpInfo.fileNameText, "filename"); 434 strcpy(fFtpInfo.serverText, "server"); 435 strcpy(fFtpInfo.loginText, "login"); 436 strcpy(fFtpInfo.passwordText, "password"); 437 strcpy(fFtpInfo.directoryText, "directory"); 438 439 SetUpSettings("codycam", ""); 440 441 BMenuBar* menuBar = new BMenuBar(BRect(0,0,0,0), "menu bar"); 442 AddChild(menuBar); 443 444 BMenuItem* menuItem; 445 BMenu* menu = new BMenu("File"); 446 447 menuItem = new BMenuItem("Video Preferences", new BMessage(msg_video), 'P'); 448 menuItem->SetTarget(be_app); 449 menu->AddItem(menuItem); 450 451 menu->AddSeparatorItem(); 452 453 menuItem = new BMenuItem("Start Video", new BMessage(msg_start), 'A'); 454 menuItem->SetTarget(be_app); 455 menu->AddItem(menuItem); 456 457 menuItem = new BMenuItem("Stop Video", new BMessage(msg_stop), 'O'); 458 menuItem->SetTarget(be_app); 459 menu->AddItem(menuItem); 460 461 menu->AddSeparatorItem(); 462 463 menuItem = new BMenuItem("About Codycam", new BMessage(msg_about), 'B'); 464 menuItem->SetTarget(be_app); 465 menu->AddItem(menuItem); 466 467 menu->AddSeparatorItem(); 468 469 menuItem = new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED), 'Q'); 470 menuItem->SetTarget(be_app); 471 menu->AddItem(menuItem); 472 473 menuBar->AddItem(menu); 474 475 /* give it a gray background view */ 476 BRect aRect; 477 aRect = Frame(); 478 aRect.OffsetTo(B_ORIGIN); 479 aRect.top += menuBar->Frame().Height() + 1; 480 fView = new BView(aRect, "Background View", B_FOLLOW_ALL, B_WILL_DRAW); 481 fView->SetViewColor(kViewGray); 482 AddChild(fView); 483 484 /* add some controls */ 485 BuildCaptureControls(fView); 486 487 /* add another view to hold the video image */ 488 aRect = BRect(0, 0, VIDEO_SIZE_X - 1, VIDEO_SIZE_Y - 1); 489 aRect.OffsetBy((WINDOW_SIZE_X - VIDEO_SIZE_X)/2, kYBuffer); 490 491 fVideoView = new BView(aRect, "Video View", B_FOLLOW_ALL, B_WILL_DRAW); 492 fView->AddChild(fVideoView); 493 494 Show(); 495 } 496 497 //--------------------------------------------------------------- 498 499 VideoWindow::~VideoWindow() 500 { 501 QuitSettings(); 502 } 503 504 //--------------------------------------------------------------- 505 506 bool 507 VideoWindow::QuitRequested() 508 { 509 be_app->PostMessage(B_QUIT_REQUESTED); 510 return false; 511 } 512 513 //--------------------------------------------------------------- 514 515 void 516 VideoWindow::MessageReceived(BMessage *message) 517 { 518 BControl *p; 519 520 p = NULL; 521 message->FindPointer((const char *)"source",(void **)&p); 522 523 switch (message->what) 524 { 525 case msg_filename: 526 if (p != NULL) 527 { 528 strncpy(fFtpInfo.fileNameText, ((BTextControl *)p)->Text(), 63); 529 FTPINFO("file is '%s'\n", fFtpInfo.fileNameText); 530 } 531 break; 532 case msg_rate_15s: 533 FTPINFO("fifteen seconds\n"); 534 fFtpInfo.rate = (bigtime_t)(15 * 1000000); 535 break; 536 case msg_rate_30s: 537 FTPINFO("thirty seconds\n"); 538 fFtpInfo.rate = (bigtime_t)(30 * 1000000); 539 break; 540 case msg_rate_1m: 541 FTPINFO("one minute\n"); 542 fFtpInfo.rate = (bigtime_t)(1 * 60 * 1000000); 543 break; 544 case msg_rate_5m: 545 FTPINFO("five minute\n"); 546 fFtpInfo.rate = (bigtime_t)(5 * 60 * 1000000); 547 break; 548 case msg_rate_10m: 549 FTPINFO("ten minute\n"); 550 fFtpInfo.rate = (bigtime_t)(10 * 60 * 1000000); 551 break; 552 case msg_rate_15m: 553 FTPINFO("fifteen minute\n"); 554 fFtpInfo.rate = (bigtime_t)(15 * 60 * 1000000); 555 break; 556 case msg_rate_30m: 557 FTPINFO("thirty minute\n"); 558 fFtpInfo.rate = (bigtime_t)(30 * 60 * 1000000); 559 break; 560 case msg_rate_1h: 561 FTPINFO("one hour\n"); 562 fFtpInfo.rate = (bigtime_t)(60LL * 60LL * 1000000LL); 563 break; 564 case msg_rate_2h: 565 FTPINFO("two hour\n"); 566 fFtpInfo.rate = (bigtime_t)(2LL * 60LL * 60LL * 1000000LL); 567 break; 568 case msg_rate_4h: 569 FTPINFO("four hour\n"); 570 fFtpInfo.rate = (bigtime_t)(4LL * 60LL * 60LL * 1000000LL); 571 break; 572 case msg_rate_8h: 573 FTPINFO("eight hour\n"); 574 fFtpInfo.rate = (bigtime_t)(8LL * 60LL * 60LL * 1000000LL); 575 break; 576 case msg_rate_24h: 577 FTPINFO("24 hour\n"); 578 fFtpInfo.rate = (bigtime_t)(24LL * 60LL * 60LL * 1000000LL); 579 break; 580 case msg_rate_never: 581 FTPINFO("never\n"); 582 fFtpInfo.rate = (bigtime_t)(B_INFINITE_TIMEOUT); 583 break; 584 case msg_translate: 585 message->FindInt32("be:type", (int32 *)&(fFtpInfo.imageFormat)); 586 message->FindInt32("be:translator", &(fFtpInfo.translator)); 587 break; 588 case msg_server: 589 if (p != NULL) 590 { 591 strncpy(fFtpInfo.serverText, ((BTextControl *)p)->Text(), 64); 592 FTPINFO("server = '%s'\n", fFtpInfo.serverText); 593 } 594 break; 595 case msg_login: 596 if (p != NULL) 597 { 598 strncpy(fFtpInfo.loginText, ((BTextControl *)p)->Text(), 64); 599 FTPINFO("login = '%s'\n", fFtpInfo.loginText); 600 } 601 break; 602 case msg_password: 603 if (p != NULL) 604 { 605 strncpy(fFtpInfo.passwordText, ((BTextControl *)p)->Text(), 64); 606 FTPINFO("password = '%s'\n", fFtpInfo.passwordText); 607 if (Lock()) 608 { 609 ((BTextControl *)p)->SetText("<HIDDEN>"); 610 Unlock(); 611 } 612 } 613 break; 614 case msg_directory: 615 if (p != NULL) 616 { 617 strncpy(fFtpInfo.directoryText, ((BTextControl *)p)->Text(), 64); 618 FTPINFO("directory = '%s'\n", fFtpInfo.directoryText); 619 } 620 break; 621 case msg_passiveftp: 622 if (p != NULL) 623 { 624 fFtpInfo.passiveFtp = ((BCheckBox *)p)->Value(); 625 if (fFtpInfo.passiveFtp) 626 FTPINFO("using passive ftp\n"); 627 } 628 break; 629 default: 630 BWindow::MessageReceived(message); 631 return; 632 } 633 634 if (*fPortPtr) 635 write_port(*fPortPtr, FTP_INFO, (void *)&fFtpInfo, sizeof(ftp_msg_info)); 636 637 } 638 639 //--------------------------------------------------------------- 640 641 BView * 642 VideoWindow::VideoView() 643 { 644 return fVideoView; 645 } 646 647 //--------------------------------------------------------------- 648 649 BStringView * 650 VideoWindow::StatusLine() 651 { 652 return fStatusLine; 653 } 654 655 //--------------------------------------------------------------- 656 657 void 658 VideoWindow::BuildCaptureControls(BView *theView) 659 { 660 BRect aFrame, theFrame; 661 662 theFrame = theView->Bounds(); 663 theFrame.top += VIDEO_SIZE_Y + 2*kYBuffer + 40; 664 theFrame.left += kXBuffer; 665 theFrame.right -= (WINDOW_SIZE_X/2 + 5); 666 theFrame.bottom -= kXBuffer; 667 668 fCaptureSetupBox = new BBox( theFrame, "Capture Controls", B_FOLLOW_ALL, B_WILL_DRAW); 669 fCaptureSetupBox->SetLabel("Capture Controls"); 670 theView->AddChild(fCaptureSetupBox); 671 672 aFrame = fCaptureSetupBox->Bounds(); 673 aFrame.InsetBy(kXBuffer,kYBuffer); 674 aFrame.top += kYBuffer/2; 675 aFrame.bottom = aFrame.top + kMenuHeight; 676 677 fFileName = new BTextControl(aFrame, "File Name", "File Name:", fFilenameSetting->Value(), new BMessage(msg_filename)); 678 679 fFileName->SetTarget(BMessenger(NULL, this)); 680 fFileName->SetDivider(fFileName->Divider() - 30); 681 fCaptureSetupBox->AddChild(fFileName); 682 683 aFrame.top = aFrame.bottom + kYBuffer; 684 aFrame.bottom = aFrame.top + kMenuHeight; 685 686 fImageFormatMenu = new BPopUpMenu("Image Format Menu"); 687 AddTranslationItems(fImageFormatMenu, B_TRANSLATOR_BITMAP); 688 fImageFormatMenu->SetTargetForItems(this); 689 if (fImageFormatMenu->FindItem("JPEG Image") != NULL) 690 fImageFormatMenu->FindItem("JPEG Image")->SetMarked(true); 691 else 692 fImageFormatMenu->ItemAt(0)->SetMarked(true); 693 fImageFormatSelector = new BMenuField(aFrame, "Format", "Format:", fImageFormatMenu); 694 fImageFormatSelector->SetDivider(fImageFormatSelector->Divider() - 30); 695 fCaptureSetupBox->AddChild(fImageFormatSelector); 696 697 aFrame.top = aFrame.bottom + kYBuffer; 698 aFrame.bottom = aFrame.top + kMenuHeight; 699 700 fCaptureRateMenu = new BPopUpMenu("Capture Rate Menu"); 701 fCaptureRateMenu->AddItem(new BMenuItem("Every 15 seconds",new BMessage(msg_rate_15s))); 702 fCaptureRateMenu->AddItem(new BMenuItem("Every 30 seconds",new BMessage(msg_rate_30s))); 703 fCaptureRateMenu->AddItem(new BMenuItem("Every minute",new BMessage(msg_rate_1m))); 704 fCaptureRateMenu->AddItem(new BMenuItem("Every 5 minutes",new BMessage(msg_rate_5m))); 705 fCaptureRateMenu->AddItem(new BMenuItem("Every 10 minutes",new BMessage(msg_rate_10m))); 706 fCaptureRateMenu->AddItem(new BMenuItem("Every 15 minutes",new BMessage(msg_rate_15m))); 707 fCaptureRateMenu->AddItem(new BMenuItem("Every 30 minutes",new BMessage(msg_rate_30m))); 708 fCaptureRateMenu->AddItem(new BMenuItem("Every hour",new BMessage(msg_rate_1h))); 709 fCaptureRateMenu->AddItem(new BMenuItem("Every 2 hours",new BMessage(msg_rate_2h))); 710 fCaptureRateMenu->AddItem(new BMenuItem("Every 4 hours",new BMessage(msg_rate_4h))); 711 fCaptureRateMenu->AddItem(new BMenuItem("Every 8 hours",new BMessage(msg_rate_8h))); 712 fCaptureRateMenu->AddItem(new BMenuItem("Every 24 hours",new BMessage(msg_rate_24h))); 713 fCaptureRateMenu->AddItem(new BMenuItem("Never",new BMessage(msg_rate_never))); 714 fCaptureRateMenu->SetTargetForItems(this); 715 fCaptureRateMenu->FindItem(fCaptureRateSetting->Value())->SetMarked(true); 716 fCaptureRateSelector = new BMenuField(aFrame, "Rate", "Rate:", fCaptureRateMenu); 717 fCaptureRateSelector->SetDivider(fCaptureRateSelector->Divider() - 30); 718 fCaptureSetupBox->AddChild(fCaptureRateSelector); 719 720 aFrame = theView->Bounds(); 721 aFrame.top += VIDEO_SIZE_Y + 2*kYBuffer + 40; 722 aFrame.left += WINDOW_SIZE_X/2 + 5; 723 aFrame.right -= kXBuffer; 724 aFrame.bottom -= kYBuffer; 725 726 fFtpSetupBox = new BBox( aFrame, "Ftp Setup", B_FOLLOW_ALL, B_WILL_DRAW); 727 fFtpSetupBox->SetLabel("Ftp Setup"); 728 theView->AddChild(fFtpSetupBox); 729 730 aFrame = fFtpSetupBox->Bounds(); 731 aFrame.InsetBy(kXBuffer,kYBuffer); 732 aFrame.top += kYBuffer/2; 733 aFrame.bottom = aFrame.top + kMenuHeight; 734 aFrame.right = aFrame.left + 160; 735 736 fServerName = new BTextControl(aFrame, "Server", "Server:", fServerSetting->Value(), new BMessage(msg_server)); 737 fServerName->SetTarget(this); 738 fServerName->SetDivider(fServerName->Divider() - 30); 739 fFtpSetupBox->AddChild(fServerName); 740 741 aFrame.top = aFrame.bottom + kYBuffer; 742 aFrame.bottom = aFrame.top + kMenuHeight; 743 744 fLoginId = new BTextControl(aFrame, "Login", "Login:", fLoginSetting->Value(), new BMessage(msg_login)); 745 fLoginId->SetTarget(this); 746 fLoginId->SetDivider(fLoginId->Divider() - 30); 747 fFtpSetupBox->AddChild(fLoginId); 748 749 aFrame.top = aFrame.bottom + kYBuffer; 750 aFrame.bottom = aFrame.top + kMenuHeight; 751 752 fPassword = new BTextControl(aFrame, "Password", "Password:", fPasswordSetting->Value(), new BMessage(msg_password)); 753 fPassword->SetTarget(this); 754 fPassword->SetDivider(fPassword->Divider() - 30); 755 fFtpSetupBox->AddChild(fPassword); 756 757 aFrame.top = aFrame.bottom + kYBuffer; 758 aFrame.bottom = aFrame.top + kMenuHeight; 759 760 fDirectory = new BTextControl(aFrame, "Directory", "Directory:", fDirectorySetting->Value(), new BMessage(msg_directory)); 761 fDirectory->SetTarget(this); 762 fDirectory->SetDivider(fDirectory->Divider() - 30); 763 fFtpSetupBox->AddChild(fDirectory); 764 765 aFrame.top = aFrame.bottom + kYBuffer; 766 aFrame.bottom = aFrame.top + kMenuHeight; 767 768 fPassiveFtp = new BCheckBox(aFrame, "Passive ftp", "Passive ftp", new BMessage(msg_passiveftp)); 769 fPassiveFtp->SetTarget(this); 770 fPassiveFtp->SetValue(fPassiveFtpSetting->Value()); 771 fFtpSetupBox->AddChild(fPassiveFtp); 772 773 aFrame = theView->Bounds(); 774 aFrame.top += VIDEO_SIZE_Y + 2*kYBuffer; 775 aFrame.left += kXBuffer; 776 aFrame.right -= kXBuffer; 777 aFrame.bottom = aFrame.top + kMenuHeight + 2*kYBuffer; 778 779 fStatusBox = new BBox( aFrame, "Status", B_FOLLOW_ALL, B_WILL_DRAW); 780 fStatusBox->SetLabel("Status"); 781 theView->AddChild(fStatusBox); 782 783 aFrame = fStatusBox->Bounds(); 784 aFrame.InsetBy(kXBuffer,kYBuffer); 785 786 fStatusLine = new BStringView(aFrame,"Status Line","Waiting ..."); 787 fStatusBox->AddChild(fStatusLine); 788 } 789 790 //--------------------------------------------------------------- 791 792 void 793 VideoWindow::ApplyControls() 794 { 795 // apply controls 796 fFileName->Invoke(); 797 PostMessage(fImageFormatMenu->FindMarked()->Message()); 798 PostMessage(fCaptureRateMenu->FindMarked()->Message()); 799 fServerName->Invoke(); 800 fLoginId->Invoke(); 801 fPassword->Invoke(); 802 fDirectory->Invoke(); 803 fPassiveFtp->Invoke(); 804 } 805 806 //--------------------------------------------------------------- 807 808 void 809 VideoWindow::SetUpSettings(const char *filename, const char *dirname) 810 { 811 fSettings = new Settings(filename, dirname); 812 813 fSettings->Add(fServerSetting = new StringValueSetting("Server", "ftp.my.server", 814 "server address expected", "")); 815 fSettings->Add(fLoginSetting = new StringValueSetting("Login", "loginID", 816 "login ID expected", "")); 817 fSettings->Add(fPasswordSetting = new StringValueSetting("Password", "password", 818 "password expected", "")); 819 fSettings->Add(fDirectorySetting = new StringValueSetting("Directory", "web/images", 820 "destination directory expected", "")); 821 fSettings->Add(fPassiveFtpSetting = new BooleanValueSetting("PassiveFtp", 1)); 822 fSettings->Add(fFilenameSetting = new StringValueSetting("StillImageFilename", "codycam.jpg", 823 "still image filename expected", "")); 824 fSettings->Add(fCaptureRateSetting = new EnumeratedStringValueSetting("CaptureRate", "Every 5 minutes", kCaptureRate, 825 "capture rate expected", "unrecognized capture rate specified")); 826 827 fSettings->TryReadingSettings(); 828 } 829 830 //--------------------------------------------------------------- 831 832 void 833 VideoWindow::QuitSettings() 834 { 835 fServerSetting->ValueChanged(fServerName->Text()); 836 fLoginSetting->ValueChanged(fLoginId->Text()); 837 fPasswordSetting->ValueChanged(fFtpInfo.passwordText); 838 fDirectorySetting->ValueChanged(fDirectory->Text()); 839 fPassiveFtpSetting->ValueChanged(fPassiveFtp->Value()); 840 fFilenameSetting->ValueChanged(fFileName->Text()); 841 fCaptureRateSetting->ValueChanged(fCaptureRateMenu->FindMarked()->Label()); 842 843 fSettings->SaveSettings(); 844 delete fSettings; 845 } 846 847 //--------------------------------------------------------------- 848 849 ControlWindow::ControlWindow( 850 const BRect & frame, 851 BView * controls, 852 media_node node) : 853 BWindow(frame, "Video Preferences", B_TITLED_WINDOW, B_ASYNCHRONOUS_CONTROLS) 854 { 855 fView = controls; 856 fNode = node; 857 858 AddChild(fView); 859 } 860 861 //--------------------------------------------------------------- 862 863 void 864 ControlWindow::MessageReceived(BMessage * message) 865 { 866 BParameterWeb * web = NULL; 867 status_t err; 868 869 switch (message->what) 870 { 871 case B_MEDIA_WEB_CHANGED: 872 { 873 // If this is a tab view, find out which tab 874 // is selected 875 BTabView *tabView = dynamic_cast<BTabView*>(fView); 876 int32 tabNum = -1; 877 if (tabView) 878 tabNum = tabView->Selection(); 879 880 RemoveChild(fView); 881 delete fView; 882 883 err = BMediaRoster::Roster()->GetParameterWebFor(fNode, &web); 884 885 if ((err >= B_OK) && 886 (web != NULL)) 887 { 888 fView = BMediaTheme::ViewFor(web); 889 AddChild(fView); 890 891 // Another tab view? Restore previous selection 892 if (tabNum > 0) 893 { 894 BTabView *newTabView = dynamic_cast<BTabView*>(fView); 895 if (newTabView) 896 newTabView->Select(tabNum); 897 } 898 } 899 break; 900 } 901 default: 902 BWindow::MessageReceived(message); 903 } 904 } 905 906 //--------------------------------------------------------------- 907 908 bool 909 ControlWindow::QuitRequested() 910 { 911 be_app->PostMessage(msg_control_win); 912 return true; 913 } 914 915 916 917