Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/samples/winrt/ImageManipulations/common/LayoutAwarePage.cpp
16344 views
1
//*********************************************************
2
//
3
// Copyright (c) Microsoft. All rights reserved.
4
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
5
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
6
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
7
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
8
//
9
//*********************************************************
10
11
#include "pch.h"
12
#include "LayoutAwarePage.h"
13
#include "SuspensionManager.h"
14
15
using namespace SDKSample::Common;
16
17
using namespace Platform;
18
using namespace Platform::Collections;
19
using namespace Windows::Foundation;
20
using namespace Windows::Foundation::Collections;
21
using namespace Windows::System;
22
using namespace Windows::UI::Core;
23
using namespace Windows::UI::ViewManagement;
24
using namespace Windows::UI::Xaml;
25
using namespace Windows::UI::Xaml::Controls;
26
using namespace Windows::UI::Xaml::Interop;
27
using namespace Windows::UI::Xaml::Navigation;
28
29
/// <summary>
30
/// Initializes a new instance of the <see cref="LayoutAwarePage"/> class.
31
/// </summary>
32
LayoutAwarePage::LayoutAwarePage()
33
{
34
if (Windows::ApplicationModel::DesignMode::DesignModeEnabled)
35
{
36
return;
37
}
38
39
// Create an empty default view model
40
DefaultViewModel = ref new Map<String^, Object^>(std::less<String^>());
41
42
// When this page is part of the visual tree make two changes:
43
// 1) Map application view state to visual state for the page
44
// 2) Handle keyboard and mouse navigation requests
45
Loaded += ref new RoutedEventHandler(this, &LayoutAwarePage::OnLoaded);
46
47
// Undo the same changes when the page is no longer visible
48
Unloaded += ref new RoutedEventHandler(this, &LayoutAwarePage::OnUnloaded);
49
}
50
51
static DependencyProperty^ _defaultViewModelProperty =
52
DependencyProperty::Register("DefaultViewModel",
53
TypeName(IObservableMap<String^, Object^>::typeid), TypeName(LayoutAwarePage::typeid), nullptr);
54
55
/// <summary>
56
/// Identifies the <see cref="DefaultViewModel"/> dependency property.
57
/// </summary>
58
DependencyProperty^ LayoutAwarePage::DefaultViewModelProperty::get()
59
{
60
return _defaultViewModelProperty;
61
}
62
63
/// <summary>
64
/// Gets an implementation of <see cref="IObservableMap&lt;String, Object&gt;"/> designed to be
65
/// used as a trivial view model.
66
/// </summary>
67
IObservableMap<String^, Object^>^ LayoutAwarePage::DefaultViewModel::get()
68
{
69
return safe_cast<IObservableMap<String^, Object^>^>(GetValue(DefaultViewModelProperty));
70
}
71
72
/// <summary>
73
/// Sets an implementation of <see cref="IObservableMap&lt;String, Object&gt;"/> designed to be
74
/// used as a trivial view model.
75
/// </summary>
76
void LayoutAwarePage::DefaultViewModel::set(IObservableMap<String^, Object^>^ value)
77
{
78
SetValue(DefaultViewModelProperty, value);
79
}
80
81
/// <summary>
82
/// Invoked when the page is part of the visual tree
83
/// </summary>
84
/// <param name="sender">Instance that triggered the event.</param>
85
/// <param name="e">Event data describing the conditions that led to the event.</param>
86
void LayoutAwarePage::OnLoaded(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
87
{
88
this->StartLayoutUpdates(sender, e);
89
90
// Keyboard and mouse navigation only apply when occupying the entire window
91
if (this->ActualHeight == Window::Current->Bounds.Height &&
92
this->ActualWidth == Window::Current->Bounds.Width)
93
{
94
// Listen to the window directly so focus isn't required
95
_acceleratorKeyEventToken = Window::Current->CoreWindow->Dispatcher->AcceleratorKeyActivated +=
96
ref new TypedEventHandler<CoreDispatcher^, AcceleratorKeyEventArgs^>(this,
97
&LayoutAwarePage::CoreDispatcher_AcceleratorKeyActivated);
98
_pointerPressedEventToken = Window::Current->CoreWindow->PointerPressed +=
99
ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this,
100
&LayoutAwarePage::CoreWindow_PointerPressed);
101
_navigationShortcutsRegistered = true;
102
}
103
}
104
105
/// <summary>
106
/// Invoked when the page is removed from visual tree
107
/// </summary>
108
/// <param name="sender">Instance that triggered the event.</param>
109
/// <param name="e">Event data describing the conditions that led to the event.</param>
110
void LayoutAwarePage::OnUnloaded(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
111
{
112
if (_navigationShortcutsRegistered)
113
{
114
Window::Current->CoreWindow->Dispatcher->AcceleratorKeyActivated -= _acceleratorKeyEventToken;
115
Window::Current->CoreWindow->PointerPressed -= _pointerPressedEventToken;
116
_navigationShortcutsRegistered = false;
117
}
118
StopLayoutUpdates(sender, e);
119
}
120
121
#pragma region Navigation support
122
123
/// <summary>
124
/// Invoked as an event handler to navigate backward in the page's associated <see cref="Frame"/>
125
/// until it reaches the top of the navigation stack.
126
/// </summary>
127
/// <param name="sender">Instance that triggered the event.</param>
128
/// <param name="e">Event data describing the conditions that led to the event.</param>
129
void LayoutAwarePage::GoHome(Object^ sender, RoutedEventArgs^ e)
130
{
131
(void) sender; // Unused parameter
132
(void) e; // Unused parameter
133
134
// Use the navigation frame to return to the topmost page
135
if (Frame != nullptr)
136
{
137
while (Frame->CanGoBack)
138
{
139
Frame->GoBack();
140
}
141
}
142
}
143
144
/// <summary>
145
/// Invoked as an event handler to navigate backward in the navigation stack
146
/// associated with this page's <see cref="Frame"/>.
147
/// </summary>
148
/// <param name="sender">Instance that triggered the event.</param>
149
/// <param name="e">Event data describing the conditions that led to the event.</param>
150
void LayoutAwarePage::GoBack(Object^ sender, RoutedEventArgs^ e)
151
{
152
(void) sender; // Unused parameter
153
(void) e; // Unused parameter
154
155
// Use the navigation frame to return to the previous page
156
if (Frame != nullptr && Frame->CanGoBack)
157
{
158
Frame->GoBack();
159
}
160
}
161
162
/// <summary>
163
/// Invoked as an event handler to navigate forward in the navigation stack
164
/// associated with this page's <see cref="Frame"/>.
165
/// </summary>
166
/// <param name="sender">Instance that triggered the event.</param>
167
/// <param name="e">Event data describing the conditions that led to the event.</param>
168
void LayoutAwarePage::GoForward(Object^ sender, RoutedEventArgs^ e)
169
{
170
(void) sender; // Unused parameter
171
(void) e; // Unused parameter
172
173
// Use the navigation frame to advance to the next page
174
if (Frame != nullptr && Frame->CanGoForward)
175
{
176
Frame->GoForward();
177
}
178
}
179
180
/// <summary>
181
/// Invoked on every keystroke, including system keys such as Alt key combinations, when
182
/// this page is active and occupies the entire window. Used to detect keyboard navigation
183
/// between pages even when the page itself doesn't have focus.
184
/// </summary>
185
/// <param name="sender">Instance that triggered the event.</param>
186
/// <param name="args">Event data describing the conditions that led to the event.</param>
187
void LayoutAwarePage::CoreDispatcher_AcceleratorKeyActivated(CoreDispatcher^ sender, AcceleratorKeyEventArgs^ args)
188
{
189
auto virtualKey = args->VirtualKey;
190
191
// Only investigate further when Left, Right, or the dedicated Previous or Next keys
192
// are pressed
193
if ((args->EventType == CoreAcceleratorKeyEventType::SystemKeyDown ||
194
args->EventType == CoreAcceleratorKeyEventType::KeyDown) &&
195
(virtualKey == VirtualKey::Left || virtualKey == VirtualKey::Right ||
196
(int)virtualKey == 166 || (int)virtualKey == 167))
197
{
198
auto coreWindow = Window::Current->CoreWindow;
199
auto downState = Windows::UI::Core::CoreVirtualKeyStates::Down;
200
bool menuKey = (coreWindow->GetKeyState(VirtualKey::Menu) & downState) == downState;
201
bool controlKey = (coreWindow->GetKeyState(VirtualKey::Control) & downState) == downState;
202
bool shiftKey = (coreWindow->GetKeyState(VirtualKey::Shift) & downState) == downState;
203
bool noModifiers = !menuKey && !controlKey && !shiftKey;
204
bool onlyAlt = menuKey && !controlKey && !shiftKey;
205
206
if (((int)virtualKey == 166 && noModifiers) ||
207
(virtualKey == VirtualKey::Left && onlyAlt))
208
{
209
// When the previous key or Alt+Left are pressed navigate back
210
args->Handled = true;
211
GoBack(this, ref new RoutedEventArgs());
212
}
213
else if (((int)virtualKey == 167 && noModifiers) ||
214
(virtualKey == VirtualKey::Right && onlyAlt))
215
{
216
// When the next key or Alt+Right are pressed navigate forward
217
args->Handled = true;
218
GoForward(this, ref new RoutedEventArgs());
219
}
220
}
221
}
222
223
/// <summary>
224
/// Invoked on every mouse click, touch screen tap, or equivalent interaction when this
225
/// page is active and occupies the entire window. Used to detect browser-style next and
226
/// previous mouse button clicks to navigate between pages.
227
/// </summary>
228
/// <param name="sender">Instance that triggered the event.</param>
229
/// <param name="args">Event data describing the conditions that led to the event.</param>
230
void LayoutAwarePage::CoreWindow_PointerPressed(CoreWindow^ sender, PointerEventArgs^ args)
231
{
232
auto properties = args->CurrentPoint->Properties;
233
234
// Ignore button chords with the left, right, and middle buttons
235
if (properties->IsLeftButtonPressed || properties->IsRightButtonPressed ||
236
properties->IsMiddleButtonPressed) return;
237
238
// If back or forward are pressed (but not both) navigate appropriately
239
bool backPressed = properties->IsXButton1Pressed;
240
bool forwardPressed = properties->IsXButton2Pressed;
241
if (backPressed ^ forwardPressed)
242
{
243
args->Handled = true;
244
if (backPressed) GoBack(this, ref new RoutedEventArgs());
245
if (forwardPressed) GoForward(this, ref new RoutedEventArgs());
246
}
247
}
248
249
#pragma endregion
250
251
#pragma region Visual state switching
252
253
/// <summary>
254
/// Invoked as an event handler, typically on the <see cref="Loaded"/> event of a
255
/// <see cref="Control"/> within the page, to indicate that the sender should start receiving
256
/// visual state management changes that correspond to application view state changes.
257
/// </summary>
258
/// <param name="sender">Instance of <see cref="Control"/> that supports visual state management
259
/// corresponding to view states.</param>
260
/// <param name="e">Event data that describes how the request was made.</param>
261
/// <remarks>The current view state will immediately be used to set the corresponding visual state
262
/// when layout updates are requested. A corresponding <see cref="Unloaded"/> event handler
263
/// connected to <see cref="StopLayoutUpdates"/> is strongly encouraged. Instances of
264
/// <see cref="LayoutAwarePage"/> automatically invoke these handlers in their Loaded and Unloaded
265
/// events.</remarks>
266
/// <seealso cref="DetermineVisualState"/>
267
/// <seealso cref="InvalidateVisualState"/>
268
void LayoutAwarePage::StartLayoutUpdates(Object^ sender, RoutedEventArgs^ e)
269
{
270
(void) e; // Unused parameter
271
272
auto control = safe_cast<Control^>(sender);
273
if (_layoutAwareControls == nullptr)
274
{
275
// Start listening to view state changes when there are controls interested in updates
276
_layoutAwareControls = ref new Vector<Control^>();
277
_windowSizeEventToken = Window::Current->SizeChanged += ref new WindowSizeChangedEventHandler(this, &LayoutAwarePage::WindowSizeChanged);
278
279
// Page receives notifications for children. Protect the page until we stopped layout updates for all controls.
280
_this = this;
281
}
282
_layoutAwareControls->Append(control);
283
284
// Set the initial visual state of the control
285
VisualStateManager::GoToState(control, DetermineVisualState(ApplicationView::Value), false);
286
}
287
288
void LayoutAwarePage::WindowSizeChanged(Object^ sender, Windows::UI::Core::WindowSizeChangedEventArgs^ e)
289
{
290
(void) sender; // Unused parameter
291
(void) e; // Unused parameter
292
293
InvalidateVisualState();
294
}
295
296
/// <summary>
297
/// Invoked as an event handler, typically on the <see cref="Unloaded"/> event of a
298
/// <see cref="Control"/>, to indicate that the sender should start receiving visual state
299
/// management changes that correspond to application view state changes.
300
/// </summary>
301
/// <param name="sender">Instance of <see cref="Control"/> that supports visual state management
302
/// corresponding to view states.</param>
303
/// <param name="e">Event data that describes how the request was made.</param>
304
/// <remarks>The current view state will immediately be used to set the corresponding visual state
305
/// when layout updates are requested.</remarks>
306
/// <seealso cref="StartLayoutUpdates"/>
307
void LayoutAwarePage::StopLayoutUpdates(Object^ sender, RoutedEventArgs^ e)
308
{
309
(void) e; // Unused parameter
310
311
auto control = safe_cast<Control^>(sender);
312
unsigned int index;
313
if (_layoutAwareControls != nullptr && _layoutAwareControls->IndexOf(control, &index))
314
{
315
_layoutAwareControls->RemoveAt(index);
316
if (_layoutAwareControls->Size == 0)
317
{
318
// Stop listening to view state changes when no controls are interested in updates
319
Window::Current->SizeChanged -= _windowSizeEventToken;
320
_layoutAwareControls = nullptr;
321
// Last control has received the Unload notification.
322
_this = nullptr;
323
}
324
}
325
}
326
327
/// <summary>
328
/// Translates <see cref="ApplicationViewState"/> values into strings for visual state management
329
/// within the page. The default implementation uses the names of enum values. Subclasses may
330
/// override this method to control the mapping scheme used.
331
/// </summary>
332
/// <param name="viewState">View state for which a visual state is desired.</param>
333
/// <returns>Visual state name used to drive the <see cref="VisualStateManager"/></returns>
334
/// <seealso cref="InvalidateVisualState"/>
335
String^ LayoutAwarePage::DetermineVisualState(ApplicationViewState viewState)
336
{
337
switch (viewState)
338
{
339
case ApplicationViewState::Filled:
340
return "Filled";
341
case ApplicationViewState::Snapped:
342
return "Snapped";
343
case ApplicationViewState::FullScreenPortrait:
344
return "FullScreenPortrait";
345
case ApplicationViewState::FullScreenLandscape:
346
default:
347
return "FullScreenLandscape";
348
}
349
}
350
351
/// <summary>
352
/// Updates all controls that are listening for visual state changes with the correct visual
353
/// state.
354
/// </summary>
355
/// <remarks>
356
/// Typically used in conjunction with overriding <see cref="DetermineVisualState"/> to
357
/// signal that a different value may be returned even though the view state has not changed.
358
/// </remarks>
359
void LayoutAwarePage::InvalidateVisualState()
360
{
361
if (_layoutAwareControls != nullptr)
362
{
363
String^ visualState = DetermineVisualState(ApplicationView::Value);
364
auto controlIterator = _layoutAwareControls->First();
365
while (controlIterator->HasCurrent)
366
{
367
auto control = controlIterator->Current;
368
VisualStateManager::GoToState(control, visualState, false);
369
controlIterator->MoveNext();
370
}
371
}
372
}
373
374
#pragma endregion
375
376
#pragma region Process lifetime management
377
378
/// <summary>
379
/// Invoked when this page is about to be displayed in a Frame.
380
/// </summary>
381
/// <param name="e">Event data that describes how this page was reached. The Parameter
382
/// property provides the group to be displayed.</param>
383
void LayoutAwarePage::OnNavigatedTo(NavigationEventArgs^ e)
384
{
385
// Returning to a cached page through navigation shouldn't trigger state loading
386
if (_pageKey != nullptr) return;
387
388
auto frameState = SuspensionManager::SessionStateForFrame(Frame);
389
_pageKey = "Page-" + Frame->BackStackDepth;
390
391
if (e->NavigationMode == NavigationMode::New)
392
{
393
// Clear existing state for forward navigation when adding a new page to the
394
// navigation stack
395
auto nextPageKey = _pageKey;
396
int nextPageIndex = Frame->BackStackDepth;
397
while (frameState->HasKey(nextPageKey))
398
{
399
frameState->Remove(nextPageKey);
400
nextPageIndex++;
401
nextPageKey = "Page-" + nextPageIndex;
402
}
403
404
// Pass the navigation parameter to the new page
405
LoadState(e->Parameter, nullptr);
406
}
407
else
408
{
409
// Pass the navigation parameter and preserved page state to the page, using
410
// the same strategy for loading suspended state and recreating pages discarded
411
// from cache
412
LoadState(e->Parameter, safe_cast<IMap<String^, Object^>^>(frameState->Lookup(_pageKey)));
413
}
414
}
415
416
/// <summary>
417
/// Invoked when this page will no longer be displayed in a Frame.
418
/// </summary>
419
/// <param name="e">Event data that describes how this page was reached. The Parameter
420
/// property provides the group to be displayed.</param>
421
void LayoutAwarePage::OnNavigatedFrom(NavigationEventArgs^ e)
422
{
423
auto frameState = SuspensionManager::SessionStateForFrame(Frame);
424
auto pageState = ref new Map<String^, Object^>();
425
SaveState(pageState);
426
frameState->Insert(_pageKey, pageState);
427
}
428
429
/// <summary>
430
/// Populates the page with content passed during navigation. Any saved state is also
431
/// provided when recreating a page from a prior session.
432
/// </summary>
433
/// <param name="navigationParameter">The parameter value passed to
434
/// <see cref="Frame.Navigate(Type, Object)"/> when this page was initially requested.
435
/// </param>
436
/// <param name="pageState">A map of state preserved by this page during an earlier
437
/// session. This will be null the first time a page is visited.</param>
438
void LayoutAwarePage::LoadState(Object^ navigationParameter, IMap<String^, Object^>^ pageState)
439
{
440
}
441
442
/// <summary>
443
/// Preserves state associated with this page in case the application is suspended or the
444
/// page is discarded from the navigation cache. Values must conform to the serialization
445
/// requirements of <see cref="SuspensionManager.SessionState"/>.
446
/// </summary>
447
/// <param name="pageState">An empty map to be populated with serializable state.</param>
448
void LayoutAwarePage::SaveState(IMap<String^, Object^>^ pageState)
449
{
450
}
451
452
#pragma endregion
453
454