diff --git a/MainPage.xaml.cpp b/MainPage.xaml.cpp index 6d78153e599cdb843f2b4cbddde46033ab4110fb..5afabbeb87d50ca402c3d925827353df525c07fe 100644 --- a/MainPage.xaml.cpp +++ b/MainPage.xaml.cpp @@ -104,7 +104,7 @@ MainPage::MainPage() _loadingStatus_->Foreground = brush; }); - RingD::instance->toggleFullScreen += ref new RingClientUWP::ToggleFullScreen(this, &RingClientUWP::MainPage::OnToggleFullScreen); + RingD::instance->fullScreenToggled += ref new RingClientUWP::FullScreenToggled(this, &RingClientUWP::MainPage::OnFullScreenToggled); } void @@ -182,6 +182,7 @@ RingClientUWP::MainPage::showLoadingOverlay(bool load, bool modal) void RingClientUWP::MainPage::OnResize(Platform::Object^ sender, Windows::UI::Core::WindowSizeChangedEventArgs^ e) { + RingD::instance->raiseWindowResized(); } void @@ -382,7 +383,7 @@ void RingClientUWP::MainPage::OnvolatileDetailsChanged(const std::string &accoun showLoadingOverlay(false, false); } -void RingClientUWP::MainPage::OnToggleFullScreen(bool state) +void RingClientUWP::MainPage::OnFullScreenToggled(bool state) { static bool openState; if (state == true) { diff --git a/MainPage.xaml.h b/MainPage.xaml.h index 4c8a5b25a830cba003b86e071f3592556dbb1222..a24b11a54bb09cec2001cd6c0b429282a20b8a35 100644 --- a/MainPage.xaml.h +++ b/MainPage.xaml.h @@ -64,7 +64,7 @@ private: void _toggleSmartBoxButton__Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); void showFrame(Windows::UI::Xaml::Controls::Frame^ frame); void OnsummonMessageTextPage(); - void OnToggleFullScreen(bool state); + void OnFullScreenToggled(bool state); void OnsummonWelcomePage(); void OnsummonPreviewPage(); void OnhidePreviewPage(); diff --git a/RingD.cpp b/RingD.cpp index ab8f832b7955f89b6738374288503ac86a047f48..18e75bab51b22dad0e003d35cad27d235f7b091f 100644 --- a/RingD.cpp +++ b/RingD.cpp @@ -275,6 +275,11 @@ void RingClientUWP::RingD::unPauseCall(const std::string & callId) tasksList_.push(task); } +void RingClientUWP::RingD::raiseWindowResized() +{ + windowResized(); +} + void RingClientUWP::RingD::cancelOutGoingCall2(String ^ callId) { MSG_("$1 cancelOutGoingCall2 : " + Utils::toString(callId)); @@ -950,7 +955,7 @@ RingD::dequeueTasks() break; case Request::PlaceCall: { - auto callId = DRing::placeCall(task->_accountId_new, "ring:" + task->_ringId_new); + auto callId = DRing::placeCall(task->_accountId_new, std::string("ring:" + task->_ringId_new)); CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(CoreDispatcherPriority::High, ref new DispatchedHandler([=]() { @@ -1367,21 +1372,28 @@ Vector<String^>^ RingClientUWP::RingD::translateKnownRingDevices(const std::map< return devicesList; } -void RingClientUWP::RingD::raiseToggleFullScreen() +void RingClientUWP::RingD::setFullScreenMode() { - ApplicationView^ view = ApplicationView::GetForCurrentView(); - if (view->IsFullScreenMode) { - view->ExitFullScreenMode(); - toggleFullScreen(false); - MSG_("Successfully exited fullscreen"); + if (ApplicationView::GetForCurrentView()->TryEnterFullScreenMode()) { + MSG_("TryEnterFullScreenMode succeeded"); + fullScreenToggled(true); } else { - if (view->TryEnterFullScreenMode()) { - MSG_("Successfully entered fullscreen"); - toggleFullScreen(true); - } - else { - ERR_("Unsuccessfully entered fullscreen"); - } + ERR_("TryEnterFullScreenMode failed"); } } + +void RingClientUWP::RingD::setWindowedMode() +{ + ApplicationView::GetForCurrentView()->ExitFullScreenMode(); + MSG_("ExitFullScreenMode"); + fullScreenToggled(false); +} + +void RingClientUWP::RingD::toggleFullScreen() +{ + if (isFullScreen) + setWindowedMode(); + else + setFullScreenMode(); +} diff --git a/RingD.h b/RingD.h index c31bbd969d4504fe2dc73f8f7cfb7de40e609f11..98dfa120ecb7a7ff0a214f101405047c91093f2b 100644 --- a/RingD.h +++ b/RingD.h @@ -25,6 +25,7 @@ using namespace concurrency; using namespace Windows::UI::Notifications; using namespace Windows::Data::Xml::Dom; +using namespace Windows::UI::ViewManagement; namespace RingClientUWP { @@ -54,7 +55,8 @@ delegate void CallsListRecieved(const std::vector<std::string>& callsList); delegate void AudioMuted(const std::string& callId, bool state); delegate void VideoMuted(const std::string& callId, bool state); delegate void NameRegistred(bool status); -delegate void ToggleFullScreen(bool state); +delegate void FullScreenToggled(bool state); +delegate void WindowResized(); delegate void VolatileDetailsChanged(const std::string& accountId, const std::map<std::string, std::string>& details); using SharedCallback = std::shared_ptr<DRing::CallbackWrapperBase>; @@ -64,6 +66,7 @@ public ref class RingD sealed { public: /* functions */ + void raiseWindowResized(); /* properties */ static property RingD^ instance @@ -91,6 +94,14 @@ public: } } + property bool isFullScreen + { + bool get() + { + return ApplicationView::GetForCurrentView()->IsFullScreenMode; + } + } + property bool isOnXBox { bool get() @@ -140,7 +151,9 @@ internal: String^ getUserName(); Vector<String^>^ translateKnownRingDevices(const std::map<std::string, std::string> devices); - void raiseToggleFullScreen(); + void toggleFullScreen(); + void setWindowedMode(); + void setFullScreenMode(); void hangUpCall2(String^ callId); void pauseCall(String ^ callId); @@ -186,7 +199,8 @@ internal: event AudioMuted^ audioMuted; event VideoMuted^ videoMuted; event NameRegistred^ nameRegistred; - event ToggleFullScreen^ toggleFullScreen; + event FullScreenToggled^ fullScreenToggled; + event WindowResized^ windowResized; event VolatileDetailsChanged^ volatileDetailsChanged; private: diff --git a/SmartPanelItemsViewModel.cpp b/SmartPanelItemsViewModel.cpp index df4fb560e97b350636f5776b94e28e33d64fde5c..4aa3c88e6ce771ecd513dfa7d712e57851145f3c 100644 --- a/SmartPanelItemsViewModel.cpp +++ b/SmartPanelItemsViewModel.cpp @@ -37,6 +37,19 @@ SmartPanelItemsViewModel::SmartPanelItemsViewModel() RingD::instance->stateChange += ref new RingClientUWP::StateChange(this, &RingClientUWP::ViewModel::SmartPanelItemsViewModel::OnstateChange); } +bool +SmartPanelItemsViewModel::isInCall() +{ + bool isInCall = false; + for (auto item : itemsList) { + if (item->_callId && item->_callStatus == CallStatus::IN_PROGRESS) { + isInCall = true; + break; + } + } + return isInCall; +} + SmartPanelItem^ SmartPanelItemsViewModel::findItem(String^ callId) { diff --git a/SmartPanelItemsViewModel.h b/SmartPanelItemsViewModel.h index 9fdf3af137185fff03b42350b06fff14af29538a..ce15d10656004be3c5fe6a5b26f9e858a09819ef 100644 --- a/SmartPanelItemsViewModel.h +++ b/SmartPanelItemsViewModel.h @@ -30,6 +30,9 @@ namespace ViewModel { public ref class SmartPanelItemsViewModel sealed { +public: + bool isInCall(); + internal: /* singleton */ static property SmartPanelItemsViewModel^ instance diff --git a/VideoCaptureManager.cpp b/VideoCaptureManager.cpp index 26ccbc27c4206e31d52e4da1044e4ef84d67c69d..583c43c1b8f3057372571552bbd8a3a9512fd9fd 100644 --- a/VideoCaptureManager.cpp +++ b/VideoCaptureManager.cpp @@ -64,6 +64,13 @@ VideoCaptureManager::VideoCaptureManager(): captureTaskTokenSource = new cancellation_token_source(); } +double +VideoCaptureManager::aspectRatio() +{ + auto resolution = activeDevice->currentResolution(); + return static_cast<double>(resolution->width()) / static_cast<double>(resolution->height()); +} + Map<String^,String^>^ VideoCaptureManager::getSettings(String^ device) { diff --git a/VideoCaptureManager.h b/VideoCaptureManager.h index 067601420dd7b8a62d60a2b583125d5c8473479f..96f071e806969bb6e27b2cc9956cb30fe3ccf520 100644 --- a/VideoCaptureManager.h +++ b/VideoCaptureManager.h @@ -40,12 +40,16 @@ namespace Video public ref class VideoCaptureManager sealed { +public: + double aspectRatio(); + internal: property bool isPreviewing { bool get() { return isPreviewing_; } void set(bool value) { isPreviewing_ = value; } } + property bool isSettingsPreviewing { bool get() { return isSettingsPreviewing_; } diff --git a/VideoPage.xaml b/VideoPage.xaml index 57672003643974d63460d098fb90c512f7b96b84..8b7afdb4d07454418c357ef1f5edf56e0c810ffc 100644 --- a/VideoPage.xaml +++ b/VideoPage.xaml @@ -125,7 +125,6 @@ IsTabStop="False" AutomationProperties.AccessibilityView="Raw" ZoomMode="Disabled" /> - <Button x:Name="_sendBtn_" Background="Transparent" BorderThickness="0" @@ -152,7 +151,7 @@ <Frame x:Name="_chatPanel_"/> </SplitView.Pane> <SplitView.Content> - <Grid> + <Grid x:Name="_videoContent_"> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition x:Name="_rowChatBx_" Height="0"/> @@ -162,6 +161,7 @@ PointerMoved="_videoControl__PointerMoved"> <StackPanel x:Name="_headerBar_" Background="{StaticResource SemiTransparentBlack}" + Canvas.ZIndex="99999" HorizontalAlignment="Stretch" VerticalAlignment="Top" Height="50"> @@ -172,7 +172,7 @@ </StackPanel> <!-- video --> - <Image Name="IncomingVideoImage" + <Image Name="_IncomingVideoImage_" Grid.Column="0" Canvas.ZIndex="-1" DoubleTapped="IncomingVideoImage_DoubleTapped" @@ -189,12 +189,24 @@ Canvas.ZIndex="-1"/> <!--camera preview--> - <CaptureElement Name="PreviewImage" - Width="200" - VerticalAlignment="Center" - HorizontalAlignment="Right" - Stretch="Uniform" - Grid.Column="0"/> + <Canvas Name="_PreviewImageRect_" + HorizontalAlignment="Right" + VerticalAlignment="Bottom" + PointerReleased="PreviewImage_PointerReleased" + PointerCaptureLost="PreviewImage_PointerReleased"> + <Polygon Name="_PreviewImageResizer_" + Visibility="Collapsed" + Fill="#FF3BC1D3" + Points="0,0,20,0,0,20" + Canvas.ZIndex="99999" + ManipulationMode="TranslateY"/> + <CaptureElement Name="_PreviewImage_" + Visibility="Collapsed" + Stretch="Uniform" + Width="20" + Height="20" + ManipulationMode="All"/> + </Canvas> <StackPanel x:Name="_controlsBar_" HorizontalAlignment="Center" @@ -323,7 +335,6 @@ Tapped="_btnSwitch__Tapped" Visibility="Collapsed"> <SymbolIcon Symbol="Switch"/> </Button> - <!--Tapped="_btnMicrophone__Tapped"--> <Button x:Name="_btnMicrophone_" PointerEntered="btnAny_entered" PointerExited="btnAny_exited" diff --git a/VideoPage.xaml.cpp b/VideoPage.xaml.cpp index d8842a0089b6e1710549d5766b1beed1ce3356bf..411d2f62a93c31c37deeac4825c2790a2b1172e9 100644 --- a/VideoPage.xaml.cpp +++ b/VideoPage.xaml.cpp @@ -50,6 +50,8 @@ using namespace Windows::UI::Xaml::Media::Imaging; using namespace Windows::Media::Capture; using namespace Windows::Devices::Sensors; +using namespace Windows::UI::Input; + VideoPage::VideoPage() { InitializeComponent(); @@ -88,29 +90,43 @@ VideoPage::VideoPage() VideoManager::instance->captureManager()->startPreviewing += ref new StartPreviewing([this]() { - PreviewImage->Visibility = Windows::UI::Xaml::Visibility::Visible; - PreviewImage->FlowDirection = VideoManager::instance->captureManager()->mirroringPreview ? + _PreviewImage_->Visibility = Windows::UI::Xaml::Visibility::Visible; + _PreviewImageResizer_->Visibility = Windows::UI::Xaml::Visibility::Visible; + _PreviewImage_->FlowDirection = VideoManager::instance->captureManager()->mirroringPreview ? Windows::UI::Xaml::FlowDirection::RightToLeft : Windows::UI::Xaml::FlowDirection::LeftToRight; + + double aspectRatio = VideoManager::instance->captureManager()->aspectRatio(); + + _PreviewImage_->Height = ( _videoContent_->ActualHeight / 4 ); + _PreviewImage_->Width = _PreviewImage_->Height * aspectRatio; + _PreviewImageRect_->Width = _PreviewImage_->Width; + _PreviewImageRect_->Height = _PreviewImage_->Height; }); VideoManager::instance->captureManager()->stopPreviewing += ref new StopPreviewing([this]() { - PreviewImage->Source = nullptr; - PreviewImage->Visibility = Windows::UI::Xaml::Visibility::Collapsed; + _PreviewImage_->Source = nullptr; + _PreviewImage_->Visibility = Windows::UI::Xaml::Visibility::Collapsed; + _PreviewImageResizer_->Visibility = Windows::UI::Xaml::Visibility::Collapsed; }); VideoManager::instance->captureManager()->getSink += ref new GetSink([this]() { - return PreviewImage; + return _PreviewImage_; }); VideoManager::instance->rendererManager()->clearRenderTarget += ref new ClearRenderTarget([this]() { - IncomingVideoImage->Source = nullptr; + _IncomingVideoImage_->Source = nullptr; + }); + + RingD::instance->windowResized += + ref new WindowResized([&]() + { }); RingD::instance->incomingAccountMessage += @@ -130,16 +146,16 @@ VideoPage::VideoPage() RingD::instance->pauseCall(Utils::toString(it->_callId)); _callPaused_->Visibility = Windows::UI::Xaml::Visibility::Collapsed; - IncomingVideoImage->Visibility = Windows::UI::Xaml::Visibility::Visible; -// PreviewImage->Visibility = Windows::UI::Xaml::Visibility::Visible; + _IncomingVideoImage_->Visibility = Windows::UI::Xaml::Visibility::Visible; +// _PreviewImage_->Visibility = Windows::UI::Xaml::Visibility::Visible; break; } case CallStatus::ENDED: { Video::VideoManager::instance->rendererManager()->raiseClearRenderTarget(); - if (Windows::UI::ViewManagement::ApplicationView::GetForCurrentView()->IsFullScreen) - RingD::instance->raiseToggleFullScreen(); + if (RingD::instance->isFullScreen) + RingD::instance->setWindowedMode(); /* "close" the chat panel */ _rowChatBx_->Height = 0; @@ -149,8 +165,8 @@ VideoPage::VideoPage() case CallStatus::PEER_PAUSED: case CallStatus::PAUSED: _callPaused_->Visibility = Windows::UI::Xaml::Visibility::Visible; - IncomingVideoImage->Visibility = Windows::UI::Xaml::Visibility::Collapsed; -// PreviewImage->Visibility = Windows::UI::Xaml::Visibility::Collapsed; + _IncomingVideoImage_->Visibility = Windows::UI::Xaml::Visibility::Collapsed; +// _PreviewImage_->Visibility = Windows::UI::Xaml::Visibility::Collapsed; break; } }); @@ -161,6 +177,20 @@ VideoPage::VideoPage() VideoManager::instance->captureManager()->stopPreviewing += ref new RingClientUWP::StopPreviewing(this, &RingClientUWP::Views::VideoPage::OnstopPreviewing); RingD::instance->audioMuted += ref new RingClientUWP::AudioMuted(this, &RingClientUWP::Views::VideoPage::OnaudioMuted); RingD::instance->videoMuted += ref new RingClientUWP::VideoMuted(this, &RingClientUWP::Views::VideoPage::OnvideoMuted); + + InitManipulationTransforms(); + + _PreviewImage_->ManipulationDelta += ref new ManipulationDeltaEventHandler(this, &VideoPage::PreviewImage_ManipulationDelta); + _PreviewImage_->ManipulationCompleted += ref new ManipulationCompletedEventHandler(this, &VideoPage::PreviewImage_ManipulationCompleted); + + _PreviewImageResizer_->ManipulationDelta += ref new ManipulationDeltaEventHandler(this, &VideoPage::PreviewImageResizer_ManipulationDelta); + _PreviewImageResizer_->ManipulationCompleted += ref new ManipulationCompletedEventHandler(this, &VideoPage::PreviewImageResizer_ManipulationCompleted); + + _PreviewImage_->ManipulationMode = + ManipulationModes::TranslateX | + ManipulationModes::TranslateY; + + _PreviewImageResizer_->ManipulationMode = ManipulationModes::TranslateY; } void @@ -185,6 +215,56 @@ void RingClientUWP::Views::VideoPage::updatePageContent() scrollDown(); } +void +VideoPage::updatePreviewFrameDimensions() +{ + double aspectRatio = VideoManager::instance->captureManager()->aspectRatio(); + + TransformGroup^ transforms = ref new TransformGroup(); + + double scaleValue = 1 + userPreviewHeightModifier / _PreviewImage_->Height; + + scaleValue = max(min(1.75, scaleValue), 0.5); + + userPreviewHeightModifier = _PreviewImage_->Height * (scaleValue - 1); + + ScaleTransform^ scale = ref new ScaleTransform(); + scale->ScaleX = scaleValue; + scale->ScaleY = scaleValue; + + TranslateTransform^ translate = ref new TranslateTransform(); + switch (quadrant) + { + case 0: + translate->Y = -userPreviewHeightModifier; + translate->X = translate->Y * aspectRatio; + break; + case 1: + translate->Y = -userPreviewHeightModifier; + translate->X = 0; + break; + case 2: + translate->Y = 0; + translate->X = 0; + break; + case 3: + translate->Y = 0; + translate->X = -userPreviewHeightModifier * aspectRatio; + break; + default: + break; + } + + transforms->Children->Append(scale); + transforms->Children->Append(translate); + + _PreviewImage_->RenderTransform = transforms; + + _PreviewImageResizer_->RenderTransform = translate; + + arrangeResizer(); +} + void RingClientUWP::Views::VideoPage::scrollDown() { _scrollView_->UpdateLayout(); @@ -196,12 +276,14 @@ void RingClientUWP::Views::VideoPage::screenVideo(bool state) if (state) { Video::VideoManager::instance->rendererManager()->raiseClearRenderTarget(); _callPaused_->Visibility = Windows::UI::Xaml::Visibility::Collapsed; - IncomingVideoImage->Visibility = Windows::UI::Xaml::Visibility::Visible; - PreviewImage->Visibility = Windows::UI::Xaml::Visibility::Visible; + _IncomingVideoImage_->Visibility = Windows::UI::Xaml::Visibility::Visible; + _PreviewImage_->Visibility = Windows::UI::Xaml::Visibility::Visible; + _PreviewImageResizer_->Visibility = Windows::UI::Xaml::Visibility::Visible; } else { _callPaused_->Visibility = Windows::UI::Xaml::Visibility::Visible; - IncomingVideoImage->Visibility = Windows::UI::Xaml::Visibility::Collapsed; - PreviewImage->Visibility = Windows::UI::Xaml::Visibility::Collapsed; + _IncomingVideoImage_->Visibility = Windows::UI::Xaml::Visibility::Collapsed; + _PreviewImage_->Visibility = Windows::UI::Xaml::Visibility::Collapsed; + _PreviewImageResizer_->Visibility = Windows::UI::Xaml::Visibility::Collapsed; } @@ -254,6 +336,8 @@ void RingClientUWP::Views::VideoPage::_btnHangUp__Tapped(Platform::Object^ sende auto item = SmartPanelItemsViewModel::instance->_selectedItem; if (item) { + _PreviewImage_->Visibility = Windows::UI::Xaml::Visibility::Collapsed; + _PreviewImageResizer_->Visibility = Windows::UI::Xaml::Visibility::Collapsed; RingD::instance->hangUpCall2(item->_callId); pressHangUpCall(); } @@ -379,7 +463,7 @@ VideoPage::WriteFrameAsSoftwareBitmapAsync(String^ id, uint8_t* buf, int width, .then([this, sbSource]() { try { - IncomingVideoImage->Source = sbSource; + _IncomingVideoImage_->Source = sbSource; } catch (Exception^ e) { WriteException(e); @@ -411,7 +495,7 @@ void RingClientUWP::Views::VideoPage::OnincomingVideoMuted(Platform::String ^cal ? Windows::UI::Xaml::Visibility::Visible : Windows::UI::Xaml::Visibility::Collapsed;*/ - IncomingVideoImage->Visibility = (state) + _IncomingVideoImage_->Visibility = (state) ? Windows::UI::Xaml::Visibility::Collapsed : Windows::UI::Xaml::Visibility::Visible; } @@ -419,13 +503,15 @@ void RingClientUWP::Views::VideoPage::OnincomingVideoMuted(Platform::String ^cal void RingClientUWP::Views::VideoPage::OnstartPreviewing() { - PreviewImage->Visibility = Windows::UI::Xaml::Visibility::Visible; + _PreviewImage_->Visibility = Windows::UI::Xaml::Visibility::Visible; + _PreviewImageResizer_->Visibility = Windows::UI::Xaml::Visibility::Visible; } void RingClientUWP::Views::VideoPage::OnstopPreviewing() { - PreviewImage->Visibility = Windows::UI::Xaml::Visibility::Collapsed; + _PreviewImage_->Visibility = Windows::UI::Xaml::Visibility::Collapsed; + _PreviewImageResizer_->Visibility = Windows::UI::Xaml::Visibility::Collapsed; } @@ -458,5 +544,195 @@ void RingClientUWP::Views::VideoPage::OnvideoMuted(const std::string &callId, bo void RingClientUWP::Views::VideoPage::IncomingVideoImage_DoubleTapped(Platform::Object^ sender, Windows::UI::Xaml::Input::DoubleTappedRoutedEventArgs^ e) { - RingD::instance->raiseToggleFullScreen(); -} \ No newline at end of file + RingD::instance->toggleFullScreen(); + anchorPreview(); +} + + +void RingClientUWP::Views::VideoPage::InitManipulationTransforms() +{ + PreviewImage_transforms = ref new TransformGroup(); + PreviewImage_previousTransform = ref new MatrixTransform(); + PreviewImage_previousTransform->Matrix = Matrix::Identity; + PreviewImage_deltaTransform = ref new CompositeTransform(); + + PreviewImage_transforms->Children->Append(PreviewImage_previousTransform); + PreviewImage_transforms->Children->Append(PreviewImage_deltaTransform); + + _PreviewImageRect_->RenderTransform = PreviewImage_transforms; +} + +void RingClientUWP::Views::VideoPage::PreviewImage_ManipulationDelta(Platform::Object^ sender, ManipulationDeltaRoutedEventArgs^ e) +{ + _PreviewImageRect_->RenderTransform = PreviewImage_transforms; + + PreviewImage_previousTransform->Matrix = PreviewImage_transforms->Value; + + PreviewImage_deltaTransform->TranslateX = e->Delta.Translation.X; + PreviewImage_deltaTransform->TranslateY = e->Delta.Translation.Y; + + computeQuadrant(); +} + +void +RingClientUWP::Views::VideoPage::computeQuadrant() +{ + // Compute center coordinate of _videoContent_ + Point centerOfVideoFrame = Point( static_cast<float>(_videoContent_->ActualWidth) / 2, + static_cast<float>(_videoContent_->ActualHeight) / 2 ); + + // Compute the center coordinate of _PreviewImage_ relative to _videoContent_ + Point centerOfPreview = Point( static_cast<float>(_PreviewImage_->ActualWidth) / 2, + static_cast<float>(_PreviewImage_->ActualHeight) / 2 ); + UIElement^ container = dynamic_cast<UIElement^>(VisualTreeHelper::GetParent(_videoContent_)); + GeneralTransform^ transform = _PreviewImage_->TransformToVisual(container); + Point relativeCenterOfPreview = transform->TransformPoint(centerOfPreview); + + // Compute the difference between the center of _videoContent_ + // and the relative scaled center of _PreviewImageRect_ + Point diff = Point( centerOfVideoFrame.X - relativeCenterOfPreview.X, + centerOfVideoFrame.Y - relativeCenterOfPreview.Y ); + + lastQuadrant = quadrant; + if (diff.X > 0) + quadrant = diff.Y > 0 ? 2 : 1; + else + quadrant = diff.Y > 0 ? 3 : 0; + + if (lastQuadrant != quadrant) { + arrangeResizer(); + } +} + +void +RingClientUWP::Views::VideoPage::arrangeResizer() +{ + double scaleValue = (userPreviewHeightModifier + _PreviewImage_->Height) / _PreviewImage_->Height; + float scaledWidth = static_cast<float>(scaleValue * _PreviewImage_->ActualWidth); + float scaledHeight = static_cast<float>(scaleValue * _PreviewImage_->ActualHeight); + + float rSize = 20; // the size of the square UIElement used to resize the preview + float xOffset, yOffset; + PointCollection^ resizeTrianglePoints = ref new PointCollection(); + switch (quadrant) + { + case 0: + xOffset = 0; + yOffset = 0; + resizeTrianglePoints->Append(Point(xOffset, yOffset)); + resizeTrianglePoints->Append(Point(xOffset + rSize, yOffset)); + resizeTrianglePoints->Append(Point(xOffset, yOffset + rSize)); + break; + case 1: + xOffset = scaledWidth - rSize; + yOffset = 0; + resizeTrianglePoints->Append(Point(xOffset, yOffset)); + resizeTrianglePoints->Append(Point(xOffset + rSize, yOffset)); + resizeTrianglePoints->Append(Point(xOffset + rSize, yOffset + rSize)); + break; + case 2: + xOffset = scaledWidth - rSize; + yOffset = scaledHeight - rSize; + resizeTrianglePoints->Append(Point(xOffset + rSize, yOffset)); + resizeTrianglePoints->Append(Point(xOffset + rSize, yOffset + rSize)); + resizeTrianglePoints->Append(Point(xOffset, yOffset + rSize)); + break; + case 3: + xOffset = 0; + yOffset = scaledHeight - rSize; + resizeTrianglePoints->Append(Point(xOffset, yOffset + rSize)); + resizeTrianglePoints->Append(Point(xOffset + rSize, yOffset + rSize)); + resizeTrianglePoints->Append(Point(xOffset, yOffset)); + break; + default: + break; + } + _PreviewImageResizer_->Points = resizeTrianglePoints; +} + +void RingClientUWP::Views::VideoPage::PreviewImage_ManipulationCompleted(Platform::Object^ sender, ManipulationCompletedRoutedEventArgs^ e) +{ + anchorPreview(); + updatePreviewFrameDimensions(); +} + +void RingClientUWP::Views::VideoPage::anchorPreview() +{ + PreviewImage_previousTransform->Matrix = Matrix::Identity; + _PreviewImageRect_->RenderTransform = nullptr; + + switch (quadrant) + { + case 0: + _PreviewImageRect_->HorizontalAlignment = Windows::UI::Xaml::HorizontalAlignment::Right; + _PreviewImageRect_->VerticalAlignment = Windows::UI::Xaml::VerticalAlignment::Bottom; + break; + case 1: + _PreviewImageRect_->HorizontalAlignment = Windows::UI::Xaml::HorizontalAlignment::Left; + _PreviewImageRect_->VerticalAlignment = Windows::UI::Xaml::VerticalAlignment::Bottom; + break; + case 2: + _PreviewImageRect_->HorizontalAlignment = Windows::UI::Xaml::HorizontalAlignment::Left; + _PreviewImageRect_->VerticalAlignment = Windows::UI::Xaml::VerticalAlignment::Top; + break; + case 3: + _PreviewImageRect_->HorizontalAlignment = Windows::UI::Xaml::HorizontalAlignment::Right; + _PreviewImageRect_->VerticalAlignment = Windows::UI::Xaml::VerticalAlignment::Top; + break; + default: + break; + }; +} + +void +VideoPage::PreviewImageResizer_ManipulationDelta(Platform::Object^ sender, ManipulationDeltaRoutedEventArgs^ e) +{ + isResizingPreview = true; + if (quadrant > 1) + userPreviewHeightModifier += e->Delta.Translation.Y; + else + userPreviewHeightModifier -= e->Delta.Translation.Y; + + updatePreviewFrameDimensions(); +} + +void +VideoPage::PreviewImageResizer_ManipulationCompleted(Platform::Object^ sender, ManipulationCompletedRoutedEventArgs^ e) +{ + isResizingPreview = false; +} + +void +VideoPage::PreviewImage_PointerReleased(Platform::Object^ sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs^ e) +{ + // For some reason, PreviewImage_ManipulationCompleted doesn't always fire when it should + anchorPreview(); + updatePreviewFrameDimensions(); +} + +void +VideoPage::PreviewImageResizer_PointerEntered(Platform::Object^ sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs^ e) +{ + switch (quadrant) + { + case 0: + case 2: + CoreApplication::MainView->CoreWindow->PointerCursor = ref new Windows::UI::Core::CoreCursor(Windows::UI::Core::CoreCursorType::SizeNorthwestSoutheast, 0); + break; + case 1: + case 3: + CoreApplication::MainView->CoreWindow->PointerCursor = ref new Windows::UI::Core::CoreCursor(Windows::UI::Core::CoreCursorType::SizeNortheastSouthwest, 0); + break; + default: + break; + } +} + + +void +VideoPage::PreviewImageResizer_PointerExited(Platform::Object^ sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs^ e) +{ + if (!isResizingPreview) { + CoreApplication::MainView->CoreWindow->PointerCursor = ref new Windows::UI::Core::CoreCursor(Windows::UI::Core::CoreCursorType::Arrow, 0); + } +} diff --git a/VideoPage.xaml.h b/VideoPage.xaml.h index e7b5a7d960f78f80e097dc42fe7f5bc84a3f5bea..1dae05041bd5c85037b2b981566ba3b3199f59e6 100644 --- a/VideoPage.xaml.h +++ b/VideoPage.xaml.h @@ -21,13 +21,15 @@ #include "VideoPage.g.h" #include "MessageTextPage.xaml.h" +using namespace Platform; +using namespace Concurrency; using namespace Windows::Media::Capture; using namespace Windows::UI::Xaml::Navigation; - using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Media; using namespace Windows::ApplicationModel::Core; using namespace Windows::Devices::Enumeration; - +using namespace Windows::UI::Xaml::Input; namespace RingClientUWP { @@ -51,16 +53,9 @@ public: VideoPage(); void updatePageContent(); - property bool barFading - { - bool get() - { - return barFading_; - } - void set(bool value) - { - barFading_ = value; - } + property bool barFading { + bool get(){ return barFading_; } + void set(bool value) { barFading_ = value; } } void scrollDown(); @@ -84,35 +79,56 @@ internal: private: bool barFading_; - void _sendBtn__Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); - void _messageTextBox__KeyDown(Platform::Object^ sender, Windows::UI::Xaml::Input::KeyRoutedEventArgs^ e); - void sendMessage(); + // For transforming the preview image + double userPreviewHeightModifier = 0.0; + bool isResizingPreview = false; + int lastQuadrant = 0; + int quadrant = 0; + TransformGroup^ PreviewImage_transforms; + MatrixTransform^ PreviewImage_previousTransform; + CompositeTransform^ PreviewImage_deltaTransform; Concurrency::task<void> WriteFrameAsSoftwareBitmapAsync(String^ id, uint8_t* buf, int width, int height); - - void Button_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); - void _btnCancel__Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); - void _btnHangUp__Tapped(Platform::Object^ sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs^ e); - void _btnPause__Tapped(Platform::Object^ sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs^ e); - void _btnChat__Tapped(Platform::Object^ sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs^ e); - void _btnAddFriend__Tapped(Platform::Object^ sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs^ e); - void _btnSwitch__Tapped(Platform::Object^ sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs^ e); - void _btnMicrophone__Tapped(Platform::Object^ sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs^ e); - void _btnMemo__Tapped(Platform::Object^ sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs^ e); - void _btnHQ__Tapped(Platform::Object^ sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs^ e); - void _btnVideo__Tapped(Platform::Object^ sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs^ e); - void _videoControl__PointerMoved(Platform::Object^ sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs^ e); - void btnAny_entered(Platform::Object^ sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs^ e); - void btnAny_exited(Platform::Object^ sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs^ e); - void OnincomingMessage(Platform::String ^callId, Platform::String ^payload); - void _btnVideo__Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); - void OnincomingVideoMuted(Platform::String ^callId, bool state); + void _sendBtn__Click(Platform::Object^ sender, RoutedEventArgs^ e); + void _messageTextBox__KeyDown(Object^ sender, KeyRoutedEventArgs^ e); + void sendMessage(); + void Button_Click(Object^ sender, RoutedEventArgs^ e); + void _btnCancel__Click(Object^ sender, RoutedEventArgs^ e); + void _btnHangUp__Tapped(Object^ sender, TappedRoutedEventArgs^ e); + void _btnPause__Tapped(Object^ sender, TappedRoutedEventArgs^ e); + void _btnChat__Tapped(Object^ sender, TappedRoutedEventArgs^ e); + void _btnAddFriend__Tapped(Object^ sender, TappedRoutedEventArgs^ e); + void _btnSwitch__Tapped(Object^ sender, TappedRoutedEventArgs^ e); + void _btnMicrophone__Tapped(Object^ sender, TappedRoutedEventArgs^ e); + void _btnMemo__Tapped(Object^ sender, TappedRoutedEventArgs^ e); + void _btnHQ__Tapped(Object^ sender, TappedRoutedEventArgs^ e); + void _btnVideo__Tapped(Object^ sender, TappedRoutedEventArgs^ e); + void _videoControl__PointerMoved(Object^ sender, PointerRoutedEventArgs^ e); + void btnAny_entered(Object^ sender, PointerRoutedEventArgs^ e); + void btnAny_exited(Object^ sender, PointerRoutedEventArgs^ e); + void _btnVideo__Click(Object^ sender, RoutedEventArgs^ e); + void _btnMicrophone__Click(Object^ sender, RoutedEventArgs^ e); + void IncomingVideoImage_DoubleTapped(Object^ sender, DoubleTappedRoutedEventArgs^ e); + void OnincomingMessage(String ^callId, String ^payload); + void OnincomingVideoMuted(String ^callId, bool state); void OnstartPreviewing(); void OnstopPreviewing(); - void _btnMicrophone__Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e); void OnaudioMuted(const std::string &callId, bool state); void OnvideoMuted(const std::string &callId, bool state); - void IncomingVideoImage_DoubleTapped(Platform::Object^ sender, Windows::UI::Xaml::Input::DoubleTappedRoutedEventArgs^ e); + + // For transforming the preview image + void computeQuadrant(); + void arrangeResizer(); + void anchorPreview(); + void updatePreviewFrameDimensions(); + void InitManipulationTransforms(); + void PreviewImage_ManipulationDelta(Object^ sender, ManipulationDeltaRoutedEventArgs^ e); + void PreviewImage_ManipulationCompleted(Object^ sender, ManipulationCompletedRoutedEventArgs^ e); + void PreviewImageResizer_ManipulationDelta(Object^ sender, ManipulationDeltaRoutedEventArgs^ e); + void PreviewImageResizer_ManipulationCompleted(Object^ sender, ManipulationCompletedRoutedEventArgs^ e); + void PreviewImage_PointerReleased(Object^ sender, PointerRoutedEventArgs^ e); + void PreviewImageResizer_PointerEntered(Object^ sender, PointerRoutedEventArgs^ e); + void PreviewImageResizer_PointerExited(Object^ sender, PointerRoutedEventArgs^ e); }; } } \ No newline at end of file diff --git a/ring-client-uwp.vcxproj b/ring-client-uwp.vcxproj index 42a0f6379f245d7d0ca7602f481e0b9967896645..77a8e3e187a3c7d7b10f8fba6c7b3e5727821e18 100644 --- a/ring-client-uwp.vcxproj +++ b/ring-client-uwp.vcxproj @@ -162,7 +162,7 @@ <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration> </Link> <Link> - <AdditionalOptions>/nodefaultlib:libcmt.lib /ignore:4006,4049,4099 %(AdditionalOptions)</AdditionalOptions> + <AdditionalOptions>/nodefaultlib:libcmt.lib /ignore:4006,4049,4099,4078 %(AdditionalOptions)</AdditionalOptions> <GenerateWindowsMetadata>true</GenerateWindowsMetadata> <WindowsMetadataFile>$(OutDir)RingClientUWP.winmd</WindowsMetadataFile> </Link>