#include "CodyCam.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define VIDEO_SIZE_X 320 #define VIDEO_SIZE_Y 240 #define WINDOW_SIZE_X (VIDEO_SIZE_X + 80) #define WINDOW_SIZE_Y (VIDEO_SIZE_Y + 230) #define WINDOW_OFFSET_X 28 #define WINDOW_OFFSET_Y 28 const int32 kBtnHeight = 20; const int32 kBtnWidth = 60; const int32 kBtnBuffer = 25; const int32 kXBuffer = 10; const int32 kYBuffer = 10; const int32 kMenuHeight = 15; const int32 kButtonHeight = 15; const int32 kSliderViewRectHeight = 40; const rgb_color kViewGray = {216, 216, 216, 255}; static void ErrorAlert(const char* message, status_t err); static status_t AddTranslationItems(BMenu* intoMenu, uint32 fromType); #define CALL printf #define ERROR printf #define FTPINFO printf #define INFO printf // Utility functions static void ErrorAlert(const char* message, status_t err) { (new BAlert("", message, "Quit"))->Go(); printf("%s\n%s [%lx]", message, strerror(err), err); be_app->PostMessage(B_QUIT_REQUESTED); } status_t AddTranslationItems(BMenu* intoMenu, uint32 fromType) { BTranslatorRoster* use; char* translatorTypeName; const char* translatorIdName; use = BTranslatorRoster::Default(); translatorIdName = "be:translator"; translatorTypeName = "be:type"; translator_id* ids = NULL; int32 count = 0; status_t err = use->GetAllTranslators(&ids, &count); if (err < B_OK) return err; for (int tix = 0; tix < count; tix++) { const translation_format* formats = NULL; int32 num_formats = 0; bool ok = false; err = use->GetInputFormats(ids[tix], &formats, &num_formats); if (err == B_OK) for (int iix = 0; iix < num_formats; iix++) { if (formats[iix].type == fromType) { ok = true; break; } } if (!ok) continue; err = use->GetOutputFormats(ids[tix], &formats, &num_formats); if (err == B_OK) for (int oix = 0; oix < num_formats; oix++) { if (formats[oix].type != fromType) { BMessage* itemmsg; itemmsg = new BMessage(msg_translate); itemmsg->AddInt32(translatorIdName, ids[tix]); itemmsg->AddInt32(translatorTypeName, formats[oix].type); intoMenu->AddItem(new BMenuItem(formats[oix].name, itemmsg)); } } } delete[] ids; return B_OK; } // #pragma mark - CodyCam::CodyCam() : BApplication("application/x-vnd.Be.CodyCam"), fMediaRoster(NULL), fVideoConsumer(NULL), fWindow(NULL), fPort(0), fVideoControlWindow(NULL) { chdir("/boot/home"); } CodyCam::~CodyCam() { CALL("CodyCam::~CodyCam\n"); // release the video consumer node // the consumer node cleans up the window if (fVideoConsumer) { fVideoConsumer->Release(); fVideoConsumer = NULL; } CALL("CodyCam::~CodyCam - EXIT\n"); } void CodyCam::ReadyToRun() { /* create the window for the app */ fWindow = new VideoWindow(BRect(28, 28, 28 + (WINDOW_SIZE_X - 1), 28 + (WINDOW_SIZE_Y - 1)), (const char*)"CodyCam", B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE, &fPort); /* set up the node connections */ status_t status = _SetUpNodes(); if (status != B_OK) { // This error is not needed because _SetUpNodes handles displaying any // errors it runs into. // ErrorAlert("Error setting up nodes", status); return; } ((VideoWindow*)fWindow)->ApplyControls(); } bool CodyCam::QuitRequested() { _TearDownNodes(); snooze(100000); return true; } void CodyCam::MessageReceived(BMessage *message) { switch (message->what) { case msg_start: { BTimeSource* timeSource = fMediaRoster->MakeTimeSourceFor(fTimeSourceNode); bigtime_t real = BTimeSource::RealTime(); bigtime_t perf = timeSource->PerformanceTimeFor(real) + 10000; status_t status = fMediaRoster->StartNode(fProducerNode, perf); if (status != B_OK) ERROR("error starting producer!"); timeSource->Release(); break; } case msg_stop: fMediaRoster->StopNode(fProducerNode, 0, true); break; case msg_video: { if (fVideoControlWindow) { fVideoControlWindow->Activate(); break; } BParameterWeb* web = NULL; BView* view = NULL; media_node node = fProducerNode; status_t err = fMediaRoster->GetParameterWebFor(node, &web); if (err >= B_OK && web != NULL) { view = BMediaTheme::ViewFor(web); fVideoControlWindow = new ControlWindow( BRect(2 * WINDOW_OFFSET_X + WINDOW_SIZE_X, WINDOW_OFFSET_Y, 2 * WINDOW_OFFSET_X + WINDOW_SIZE_X + view->Bounds().right, WINDOW_OFFSET_Y + view->Bounds().bottom), view, node); fMediaRoster->StartWatching(BMessenger(NULL, fVideoControlWindow), node, B_MEDIA_WEB_CHANGED); fVideoControlWindow->Show(); } break; } case msg_about: (new BAlert("About CodyCam", "CodyCam\n\nThe Original BeOS WebCam", "Close"))->Go(); break; case msg_control_win: // our control window is being asked to go away // set our pointer to NULL fVideoControlWindow = NULL; break; default: BApplication::MessageReceived(message); break; } } status_t CodyCam::_SetUpNodes() { status_t status = B_OK; /* find the media roster */ fMediaRoster = BMediaRoster::Roster(&status); if (status != B_OK) { ErrorAlert("Can't find the media roster", status); return status; } /* find the time source */ status = fMediaRoster->GetTimeSource(&fTimeSourceNode); if (status != B_OK) { ErrorAlert("Can't get a time source", status); return status; } /* find a video producer node */ INFO("CodyCam acquiring VideoInput node\n"); status = fMediaRoster->GetVideoInput(&fProducerNode); if (status != B_OK) { ErrorAlert("Can't find a video source. You need a webcam to use CodyCam.", status); return status; } /* create the video consumer node */ fVideoConsumer = new VideoConsumer("CodyCam", ((VideoWindow*)fWindow)->VideoView(), ((VideoWindow*)fWindow)->StatusLine(), NULL, 0); if (!fVideoConsumer) { ErrorAlert("Can't create a video window", B_ERROR); return B_ERROR; } /* register the node */ status = fMediaRoster->RegisterNode(fVideoConsumer); if (status != B_OK) { ErrorAlert("Can't register the video window", status); return status; } fPort = fVideoConsumer->ControlPort(); /* find free producer output */ int32 cnt = 0; status = fMediaRoster->GetFreeOutputsFor(fProducerNode, &fProducerOut, 1, &cnt, B_MEDIA_RAW_VIDEO); if (status != B_OK || cnt < 1) { status = B_RESOURCE_UNAVAILABLE; ErrorAlert("Can't find an available video stream", status); return status; } /* find free consumer input */ cnt = 0; status = fMediaRoster->GetFreeInputsFor(fVideoConsumer->Node(), &fConsumerIn, 1, &cnt, B_MEDIA_RAW_VIDEO); if (status != B_OK || cnt < 1) { status = B_RESOURCE_UNAVAILABLE; ErrorAlert("Can't find an available connection to the video window", status); return status; } /* Connect The Nodes!!! */ media_format format; format.type = B_MEDIA_RAW_VIDEO; media_raw_video_format vid_format = {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}}; format.u.raw_video = vid_format; /* connect producer to consumer */ status = fMediaRoster->Connect(fProducerOut.source, fConsumerIn.destination, &format, &fProducerOut, &fConsumerIn); if (status != B_OK) { ErrorAlert("Can't connect the video source to the video window", status); return status; } /* set time sources */ status = fMediaRoster->SetTimeSourceFor(fProducerNode.node, fTimeSourceNode.node); if (status != B_OK) { ErrorAlert("Can't set the timesource for the video source", status); return status; } status = fMediaRoster->SetTimeSourceFor(fVideoConsumer->ID(), fTimeSourceNode.node); if (status != B_OK) { ErrorAlert("Can't set the timesource for the video window", status); return status; } /* figure out what recording delay to use */ bigtime_t latency = 0; status = fMediaRoster->GetLatencyFor(fProducerNode, &latency); status = fMediaRoster->SetProducerRunModeDelay(fProducerNode, latency); /* start the nodes */ bigtime_t initLatency = 0; status = fMediaRoster->GetInitialLatencyFor(fProducerNode, &initLatency); if (status < B_OK) { ErrorAlert("error getting initial latency for fCaptureNode", status); return status; } initLatency += estimate_max_scheduling_latency(); BTimeSource* timeSource = fMediaRoster->MakeTimeSourceFor(fProducerNode); bool running = timeSource->IsRunning(); /* workaround for people without sound cards */ /* because the system time source won't be running */ bigtime_t real = BTimeSource::RealTime(); if (!running) { status = fMediaRoster->StartTimeSource(fTimeSourceNode, real); if (status != B_OK) { timeSource->Release(); ErrorAlert("cannot start time source!", status); return status; } status = fMediaRoster->SeekTimeSource(fTimeSourceNode, 0, real); if (status != B_OK) { timeSource->Release(); ErrorAlert("cannot seek time source!", status); return status; } } bigtime_t perf = timeSource->PerformanceTimeFor(real + latency + initLatency); timeSource->Release(); /* start the nodes */ status = fMediaRoster->StartNode(fProducerNode, perf); if (status != B_OK) { ErrorAlert("Can't start the video source", status); return status; } status = fMediaRoster->StartNode(fVideoConsumer->Node(), perf); if (status != B_OK) { ErrorAlert("Can't start the video window", status); return status; } return status; } void CodyCam::_TearDownNodes() { CALL("CodyCam::_TearDownNodes\n"); if (!fMediaRoster) return; if (fVideoConsumer) { /* stop */ INFO("stopping nodes!\n"); // fMediaRoster->StopNode(fProducerNode, 0, true); fMediaRoster->StopNode(fVideoConsumer->Node(), 0, true); /* disconnect */ fMediaRoster->Disconnect(fProducerOut.node.node, fProducerOut.source, fConsumerIn.node.node, fConsumerIn.destination); if (fProducerNode != media_node::null) { INFO("CodyCam releasing fProducerNode\n"); fMediaRoster->ReleaseNode(fProducerNode); fProducerNode = media_node::null; } fMediaRoster->ReleaseNode(fVideoConsumer->Node()); fVideoConsumer = NULL; } } // #pragma mark - Video Window Class VideoWindow::VideoWindow (BRect frame, const char* title, window_type type, uint32 flags, port_id* consumerPort) : BWindow(frame,title,type,flags), fPortPtr(consumerPort), fView(NULL), fVideoView(NULL) { fFtpInfo.port = 0; fFtpInfo.rate = 0x7fffffff; fFtpInfo.imageFormat = 0; fFtpInfo.translator = 0; fFtpInfo.passiveFtp = true; fFtpInfo.uploadClient = 0; strcpy(fFtpInfo.fileNameText, "filename"); strcpy(fFtpInfo.serverText, "server"); strcpy(fFtpInfo.loginText, "login"); strcpy(fFtpInfo.passwordText, "password"); strcpy(fFtpInfo.directoryText, "directory"); _SetUpSettings("codycam", ""); BMenuBar* menuBar = new BMenuBar(BRect(0, 0, 0, 0), "menu bar"); AddChild(menuBar); BMenuItem* menuItem; BMenu* menu = new BMenu("File"); menuItem = new BMenuItem("Video Preferences", new BMessage(msg_video), 'P'); menuItem->SetTarget(be_app); menu->AddItem(menuItem); menu->AddSeparatorItem(); menuItem = new BMenuItem("Start Video", new BMessage(msg_start), 'A'); menuItem->SetTarget(be_app); menu->AddItem(menuItem); menuItem = new BMenuItem("Stop Video", new BMessage(msg_stop), 'O'); menuItem->SetTarget(be_app); menu->AddItem(menuItem); menu->AddSeparatorItem(); menuItem = new BMenuItem("About Codycam", new BMessage(msg_about), 'B'); menuItem->SetTarget(be_app); menu->AddItem(menuItem); menu->AddSeparatorItem(); menuItem = new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED), 'Q'); menuItem->SetTarget(be_app); menu->AddItem(menuItem); menuBar->AddItem(menu); /* give it a gray background view */ BRect aRect; aRect = Frame(); aRect.OffsetTo(B_ORIGIN); aRect.top += menuBar->Frame().Height() + 1; fView = new BView(aRect, "Background View", B_FOLLOW_ALL, B_WILL_DRAW); fView->SetViewColor(kViewGray); AddChild(fView); /* add some controls */ _BuildCaptureControls(fView); /* add another view to hold the video image */ aRect = BRect(0, 0, VIDEO_SIZE_X - 1, VIDEO_SIZE_Y - 1); aRect.OffsetBy((WINDOW_SIZE_X - VIDEO_SIZE_X) / 2, kYBuffer); fVideoView = new BView(aRect, "Video View", B_FOLLOW_ALL, B_WILL_DRAW); fView->AddChild(fVideoView); Show(); } VideoWindow::~VideoWindow() { _QuitSettings(); } bool VideoWindow::QuitRequested() { be_app->PostMessage(B_QUIT_REQUESTED); return false; } void VideoWindow::MessageReceived(BMessage* message) { BControl* control; control = NULL; message->FindPointer((const char*)"source", (void **)&control); switch (message->what) { case msg_filename: if (control != NULL) { strncpy(fFtpInfo.fileNameText, ((BTextControl*)control)->Text(), 63); FTPINFO("file is '%s'\n", fFtpInfo.fileNameText); } break; case msg_rate_15s: FTPINFO("fifteen seconds\n"); fFtpInfo.rate = (bigtime_t)(15 * 1000000); break; case msg_rate_30s: FTPINFO("thirty seconds\n"); fFtpInfo.rate = (bigtime_t)(30 * 1000000); break; case msg_rate_1m: FTPINFO("one minute\n"); fFtpInfo.rate = (bigtime_t)(1 * 60 * 1000000); break; case msg_rate_5m: FTPINFO("five minute\n"); fFtpInfo.rate = (bigtime_t)(5 * 60 * 1000000); break; case msg_rate_10m: FTPINFO("ten minute\n"); fFtpInfo.rate = (bigtime_t)(10 * 60 * 1000000); break; case msg_rate_15m: FTPINFO("fifteen minute\n"); fFtpInfo.rate = (bigtime_t)(15 * 60 * 1000000); break; case msg_rate_30m: FTPINFO("thirty minute\n"); fFtpInfo.rate = (bigtime_t)(30 * 60 * 1000000); break; case msg_rate_1h: FTPINFO("one hour\n"); fFtpInfo.rate = (bigtime_t)(60LL * 60LL * 1000000LL); break; case msg_rate_2h: FTPINFO("two hour\n"); fFtpInfo.rate = (bigtime_t)(2LL * 60LL * 60LL * 1000000LL); break; case msg_rate_4h: FTPINFO("four hour\n"); fFtpInfo.rate = (bigtime_t)(4LL * 60LL * 60LL * 1000000LL); break; case msg_rate_8h: FTPINFO("eight hour\n"); fFtpInfo.rate = (bigtime_t)(8LL * 60LL * 60LL * 1000000LL); break; case msg_rate_24h: FTPINFO("24 hour\n"); fFtpInfo.rate = (bigtime_t)(24LL * 60LL * 60LL * 1000000LL); break; case msg_rate_never: FTPINFO("never\n"); fFtpInfo.rate = (bigtime_t)(B_INFINITE_TIMEOUT); break; case msg_translate: message->FindInt32("be:type", (int32*)&(fFtpInfo.imageFormat)); message->FindInt32("be:translator", &(fFtpInfo.translator)); break; case msg_upl_client: if (control != NULL) { message->FindInt32("client", &(fFtpInfo.uploadClient)); FTPINFO("upl client = %ld\n", fFtpInfo.uploadClient); } break; case msg_server: if (control != NULL) { strncpy(fFtpInfo.serverText, ((BTextControl*)control)->Text(), 64); FTPINFO("server = '%s'\n", fFtpInfo.serverText); } break; case msg_login: if (control != NULL) { strncpy(fFtpInfo.loginText, ((BTextControl*)control)->Text(), 64); FTPINFO("login = '%s'\n", fFtpInfo.loginText); } break; case msg_password: if (control != NULL) { strncpy(fFtpInfo.passwordText, ((BTextControl*)control)->Text(), 64); FTPINFO("password = '%s'\n", fFtpInfo.passwordText); if (Lock()) { ((BTextControl*)control)->SetText(""); Unlock(); } } break; case msg_directory: if (control != NULL) { strncpy(fFtpInfo.directoryText, ((BTextControl*)control)->Text(), 64); FTPINFO("directory = '%s'\n", fFtpInfo.directoryText); } break; case msg_passiveftp: if (control != NULL) { fFtpInfo.passiveFtp = ((BCheckBox*)control)->Value(); if (fFtpInfo.passiveFtp) FTPINFO("using passive ftp\n"); } break; default: BWindow::MessageReceived(message); return; } if (*fPortPtr) write_port(*fPortPtr, FTP_INFO, (void*)&fFtpInfo, sizeof(ftp_msg_info)); } BView* VideoWindow::VideoView() { return fVideoView; } BStringView* VideoWindow::StatusLine() { return fStatusLine; } void VideoWindow::_BuildCaptureControls(BView* theView) { BRect aFrame, theFrame; theFrame = theView->Bounds(); theFrame.top += VIDEO_SIZE_Y + 2 * kYBuffer + 40; theFrame.left += kXBuffer; theFrame.right -= (WINDOW_SIZE_X / 2 + 5); theFrame.bottom -= kXBuffer; fCaptureSetupBox = new BBox(theFrame, "Capture Controls", B_FOLLOW_ALL, B_WILL_DRAW); fCaptureSetupBox->SetLabel("Capture Controls"); theView->AddChild(fCaptureSetupBox); aFrame = fCaptureSetupBox->Bounds(); aFrame.InsetBy(kXBuffer, kYBuffer); aFrame.top += kYBuffer / 2; aFrame.bottom = aFrame.top + kMenuHeight; fFileName = new BTextControl(aFrame, "File Name", "File Name:", fFilenameSetting->Value(), new BMessage(msg_filename)); fFileName->SetTarget(BMessenger(NULL, this)); fFileName->SetDivider(fFileName->Divider() - 30); fCaptureSetupBox->AddChild(fFileName); aFrame.top = aFrame.bottom + kYBuffer; aFrame.bottom = aFrame.top + kMenuHeight; fImageFormatMenu = new BPopUpMenu("Image Format Menu"); AddTranslationItems(fImageFormatMenu, B_TRANSLATOR_BITMAP); fImageFormatMenu->SetTargetForItems(this); if (fImageFormatSettings->Value() && fImageFormatMenu->FindItem(fImageFormatSettings->Value()) != NULL) fImageFormatMenu->FindItem(fImageFormatSettings->Value())->SetMarked(true); else if (fImageFormatMenu->FindItem("JPEG Image") != NULL) fImageFormatMenu->FindItem("JPEG Image")->SetMarked(true); else if (fImageFormatMenu->FindItem("JPEG image") != NULL) fImageFormatMenu->FindItem("JPEG image")->SetMarked(true); else fImageFormatMenu->ItemAt(0)->SetMarked(true); fImageFormatSelector = new BMenuField(aFrame, "Format", "Format:", fImageFormatMenu); fImageFormatSelector->SetDivider(fImageFormatSelector->Divider() - 30); fCaptureSetupBox->AddChild(fImageFormatSelector); aFrame.top = aFrame.bottom + kYBuffer; aFrame.bottom = aFrame.top + kMenuHeight; fCaptureRateMenu = new BPopUpMenu("Capture Rate Menu"); fCaptureRateMenu->AddItem(new BMenuItem("Every 15 seconds", new BMessage(msg_rate_15s))); fCaptureRateMenu->AddItem(new BMenuItem("Every 30 seconds", new BMessage(msg_rate_30s))); fCaptureRateMenu->AddItem(new BMenuItem("Every minute", new BMessage(msg_rate_1m))); fCaptureRateMenu->AddItem(new BMenuItem("Every 5 minutes", new BMessage(msg_rate_5m))); fCaptureRateMenu->AddItem(new BMenuItem("Every 10 minutes", new BMessage(msg_rate_10m))); fCaptureRateMenu->AddItem(new BMenuItem("Every 15 minutes", new BMessage(msg_rate_15m))); fCaptureRateMenu->AddItem(new BMenuItem("Every 30 minutes", new BMessage(msg_rate_30m))); fCaptureRateMenu->AddItem(new BMenuItem("Every hour", new BMessage(msg_rate_1h))); fCaptureRateMenu->AddItem(new BMenuItem("Every 2 hours", new BMessage(msg_rate_2h))); fCaptureRateMenu->AddItem(new BMenuItem("Every 4 hours", new BMessage(msg_rate_4h))); fCaptureRateMenu->AddItem(new BMenuItem("Every 8 hours", new BMessage(msg_rate_8h))); fCaptureRateMenu->AddItem(new BMenuItem("Every 24 hours", new BMessage(msg_rate_24h))); fCaptureRateMenu->AddItem(new BMenuItem("Never", new BMessage(msg_rate_never))); fCaptureRateMenu->SetTargetForItems(this); fCaptureRateMenu->FindItem(fCaptureRateSetting->Value())->SetMarked(true); fCaptureRateSelector = new BMenuField(aFrame, "Rate", "Rate:", fCaptureRateMenu); fCaptureRateSelector->SetDivider(fCaptureRateSelector->Divider() - 30); fCaptureSetupBox->AddChild(fCaptureRateSelector); aFrame = theView->Bounds(); aFrame.top += VIDEO_SIZE_Y + 2 * kYBuffer + 40; aFrame.left += WINDOW_SIZE_X / 2 + 5; aFrame.right -= kXBuffer; aFrame.bottom -= kYBuffer; fFtpSetupBox = new BBox(aFrame, "Ftp Setup", B_FOLLOW_ALL, B_WILL_DRAW); fUploadClientMenu = new BPopUpMenu("Send to" B_UTF8_ELLIPSIS); for (int i = 0; kUploadClient[i]; i++) { BMessage *m = new BMessage(msg_upl_client); m->AddInt32("client", i); fUploadClientMenu->AddItem(new BMenuItem(kUploadClient[i], m)); } fUploadClientMenu->SetTargetForItems(this); fUploadClientMenu->FindItem(fUploadClientSetting->Value())->SetMarked(true); fUploadClientSelector = new BMenuField(aFrame, "UploadClient", "", fUploadClientMenu); fUploadClientSelector->SetDivider(0.0); fFtpSetupBox->SetLabel(fUploadClientSelector); theView->AddChild(fFtpSetupBox); aFrame = fFtpSetupBox->Bounds(); aFrame.InsetBy(kXBuffer,kYBuffer); aFrame.top += kYBuffer/2; aFrame.bottom = aFrame.top + kMenuHeight; aFrame.right = aFrame.left + 160; fServerName = new BTextControl(aFrame, "Server", "Server:", fServerSetting->Value(), new BMessage(msg_server)); fServerName->SetTarget(this); fServerName->SetDivider(fServerName->Divider() - 30); fFtpSetupBox->AddChild(fServerName); aFrame.top = aFrame.bottom + kYBuffer; aFrame.bottom = aFrame.top + kMenuHeight; fLoginId = new BTextControl(aFrame, "Login", "Login:", fLoginSetting->Value(), new BMessage(msg_login)); fLoginId->SetTarget(this); fLoginId->SetDivider(fLoginId->Divider() - 30); fFtpSetupBox->AddChild(fLoginId); aFrame.top = aFrame.bottom + kYBuffer; aFrame.bottom = aFrame.top + kMenuHeight; fPassword = new BTextControl(aFrame, "Password", "Password:", fPasswordSetting->Value(), new BMessage(msg_password)); fPassword->SetTarget(this); fPassword->SetDivider(fPassword->Divider() - 30); fFtpSetupBox->AddChild(fPassword); aFrame.top = aFrame.bottom + kYBuffer; aFrame.bottom = aFrame.top + kMenuHeight; fDirectory = new BTextControl(aFrame, "Directory", "Directory:", fDirectorySetting->Value(), new BMessage(msg_directory)); fDirectory->SetTarget(this); fDirectory->SetDivider(fDirectory->Divider() - 30); fFtpSetupBox->AddChild(fDirectory); aFrame.top = aFrame.bottom + kYBuffer; aFrame.bottom = aFrame.top + kMenuHeight; fPassiveFtp = new BCheckBox(aFrame, "Passive ftp", "Passive ftp", new BMessage(msg_passiveftp)); fPassiveFtp->SetTarget(this); fPassiveFtp->SetValue(fPassiveFtpSetting->Value()); fFtpSetupBox->AddChild(fPassiveFtp); aFrame = theView->Bounds(); aFrame.top += VIDEO_SIZE_Y + 2 * kYBuffer; aFrame.left += kXBuffer; aFrame.right -= kXBuffer; aFrame.bottom = aFrame.top + kMenuHeight + 2 * kYBuffer; fStatusBox = new BBox(aFrame, "Status", B_FOLLOW_ALL, B_WILL_DRAW); fStatusBox->SetLabel("Status"); theView->AddChild(fStatusBox); aFrame = fStatusBox->Bounds(); aFrame.InsetBy(kXBuffer, kYBuffer); fStatusLine = new BStringView(aFrame, "Status Line", "Waiting" B_UTF8_ELLIPSIS); fStatusBox->AddChild(fStatusLine); } void VideoWindow::ApplyControls() { // apply controls fFileName->Invoke(); PostMessage(fImageFormatMenu->FindMarked()->Message()); PostMessage(fCaptureRateMenu->FindMarked()->Message()); PostMessage(fUploadClientMenu->FindMarked()->Message()); fServerName->Invoke(); fLoginId->Invoke(); fPassword->Invoke(); fDirectory->Invoke(); fPassiveFtp->Invoke(); } void VideoWindow::_SetUpSettings(const char* filename, const char* dirname) { fSettings = new Settings(filename, dirname); fSettings->Add(fServerSetting = new StringValueSetting("Server", "ftp.my.server", "server address expected", "")); fSettings->Add(fLoginSetting = new StringValueSetting("Login", "loginID", "login ID expected", "")); fSettings->Add(fPasswordSetting = new StringValueSetting("Password", "password", "password expected", "")); fSettings->Add(fDirectorySetting = new StringValueSetting("Directory", "web/images", "destination directory expected", "")); fSettings->Add(fPassiveFtpSetting = new BooleanValueSetting("PassiveFtp", 1)); fSettings->Add(fFilenameSetting = new StringValueSetting("StillImageFilename", "codycam.jpg", "still image filename expected", "")); fSettings->Add(fImageFormatSettings = new StringValueSetting("ImageFileFormat", "JPEG Image", "image file format expected", "")); fSettings->Add(fCaptureRateSetting = new EnumeratedStringValueSetting("CaptureRate", "Every 5 minutes", kCaptureRate, "capture rate expected", "unrecognized capture rate specified")); fSettings->Add(fUploadClientSetting = new EnumeratedStringValueSetting("UploadClient", "FTP", kUploadClient, "upload client name expected", "unrecognized upload client specified")); fSettings->TryReadingSettings(); } void VideoWindow::_QuitSettings() { fServerSetting->ValueChanged(fServerName->Text()); fLoginSetting->ValueChanged(fLoginId->Text()); fPasswordSetting->ValueChanged(fFtpInfo.passwordText); fDirectorySetting->ValueChanged(fDirectory->Text()); fPassiveFtpSetting->ValueChanged(fPassiveFtp->Value()); fFilenameSetting->ValueChanged(fFileName->Text()); fImageFormatSettings->ValueChanged(fImageFormatMenu->FindMarked()->Label()); fCaptureRateSetting->ValueChanged(fCaptureRateMenu->FindMarked()->Label()); fUploadClientSetting->ValueChanged(fUploadClientMenu->FindMarked()->Label()); fSettings->SaveSettings(); delete fSettings; } // #pragma mark - ControlWindow::ControlWindow(const BRect& frame, BView* controls, media_node node) : BWindow(frame, "Video Preferences", B_TITLED_WINDOW, B_ASYNCHRONOUS_CONTROLS) { fView = controls; fNode = node; AddChild(fView); } void ControlWindow::MessageReceived(BMessage* message) { BParameterWeb* web = NULL; status_t err; switch (message->what) { case B_MEDIA_WEB_CHANGED: { // If this is a tab view, find out which tab // is selected BTabView* tabView = dynamic_cast(fView); int32 tabNum = -1; if (tabView) tabNum = tabView->Selection(); RemoveChild(fView); delete fView; err = BMediaRoster::Roster()->GetParameterWebFor(fNode, &web); if (err >= B_OK && web != NULL) { fView = BMediaTheme::ViewFor(web); AddChild(fView); // Another tab view? Restore previous selection if (tabNum > 0) { BTabView* newTabView = dynamic_cast(fView); if (newTabView) newTabView->Select(tabNum); } } break; } default: BWindow::MessageReceived(message); } } bool ControlWindow::QuitRequested() { be_app->PostMessage(msg_control_win); return true; } // #pragma mark - int main() { CodyCam app; app.Run(); return 0; }