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