YSTest: ygui.cpp 源文件

YSTest PreAlpha_b500_20140530 The YSLib Test Project

- 首页
- 相关页面
- 模块
- 命名空间
- 类
- 文件

- 文件列表
- 文件成员

全部 类 命名空间 文件 函数 变量 类型定义 枚举 枚举值 友元 宏定义 组 页
ygui.cpp
浏览该文件的文档.
1 /*
2 © 2009-2014 FrankHB.
3
4 This file is part of the YSLib project, and may only be used,
5 modified, and distributed under the terms of the YSLib project
6 license, LICENSE.TXT. By continuing to use, modify, or distribute
7 this file you indicate that you have read the license and
8 understand and accept it fully.
9 */
10
28 #include "YSLib/UI/YModules.h"
29 #include YFM_YSLib_UI_YGUI
30 #include YFM_YSLib_UI_YDesktop
31 #include <ystdex/cast.hpp> // for ystdex::polymorphic_downcast;
32
33 namespace YSLib
34 {
35
36 using namespace Drawing;
37
38 namespace UI
39 {
40
41 namespace
42 {
43
45 IWidget*
46 FetchTopEnabledAndVisibleWidgetPtr(IWidget& con, const Point& pt)
47 {
48 for(auto pr(con.GetChildren()); pr.first != pr.second; ++pr.first)
49 {
50 IWidget& wgt(*pr.first);
51
52 if(Contains(wgt, pt) && IsEnabled(wgt) && IsVisible(wgt))
53 return &wgt;
54 }
55 return {};
56 }
57
59 IWidget*
60 FetchVisibleEnabledFocusingPtr(IWidget& con)
61 {
62 if(const auto p = FetchFocusingPtr(con))
63 if(IsVisible(*p) && IsEnabled(*p))
64 return p;
65 return {};
66 }
67
68 } // unnamed namespace;
69
70
71 InputTimer::InputTimer(const Duration& d)
72 : Timer(d)
73 {}
74
75 bool
76 InputTimer::RefreshHeld(HeldStateType& s, const Duration& initial_delay,
77 const Duration& repeated_delay)
78 {
79 switch(s)
80 {
81 case Free:
82 yunseq(s = Pressed, Interval = initial_delay);
83 Activate(*this);
84 break;
85 case Pressed:
86 case Held:
87 if(YB_UNLIKELY(CheckTimeout(*this)))
88 {
89 if(s == Pressed)
90 yunseq(s = Held, Interval = repeated_delay);
91 return true;
92 }
93 break;
94 }
95 return false;
96 }
97
98 size_t
99 InputTimer::RefreshClick(size_t s, const Duration& delay)
100 {
101 if(s == 0 || YB_UNLIKELY(!CheckTimeout(*this)))
102 Interval = delay;
103 else
104 return 0;
105 Activate(*this);
106 return s + 1;
107 }
108
109 void
110 InputTimer::ResetInput()
111 {
112 Interval = Timers::TimeSpan(1000);
113 }
114
115
116 bool
117 RepeatHeld(InputTimer& tmr, InputTimer::HeldStateType& st,
118 const Timers::Duration& initial_delay,
119 const Timers::Duration& repeated_delay)
120 {
121 const bool b(st == InputTimer::Free);
122
123 return tmr.RefreshHeld(st, initial_delay, repeated_delay) || b;
124 }
125
126
127 GUIState::GUIState() ynothrow
128 : KeyHeldState(InputTimer::Free), TouchHeldState(InputTimer::Free),
129 DraggingOffset(Vec::Invalid), HeldTimer(), CursorLocation(Point::Invalid),
130 Colors(), Styles()
131 {}
132
133 bool
134 GUIState::CheckHeldState(const KeyInput& keys, InputTimer::HeldStateType& s)
135 {
136 if(checked_held.none())
137 checked_held = keys;
138 else if(checked_held != keys)
139 {
140 yunseq(checked_held |= keys, s = InputTimer::Free);
141 return true;
142 }
143 return {};
144 }
145
146 bool
147 GUIState::CheckDraggingOffset(IWidget* p)
148 {
149 if(!p)
150 p = p_indp_focus;
151 if(p)
152 {
153 if(DraggingOffset == Vec::Invalid)
154 DraggingOffset = GetLocationOf(*p) - CursorLocation;
155 else
156 return true;
157 }
158 return false;
159 }
160
161 void
162 GUIState::CleanupReferences(IWidget& wgt)
163 {
164 if(p_CursorOver == &wgt)
165 p_CursorOver = {};
166 if(p_indp_focus == &wgt)
167 p_indp_focus = {};
168 if(p_cascade_focus == &wgt)
169 p_cascade_focus = {};
170 }
171
172 void
173 GUIState::HandleCascade(RoutedEventArgs& e, IWidget& wgt)
174 {
175 if(p_cascade_focus != &wgt && IsFocused(e.GetSender()))
176 {
177 if(p_cascade_focus)
178 CallEvent<LostFocus>(*p_cascade_focus, e);
179 p_cascade_focus = &wgt;
180 CallEvent<GotFocus>(*p_cascade_focus, e);
181 }
182 }
183
184 void
185 GUIState::Reset()
186 {
187 yunseq(KeyHeldState = InputTimer::Free, TouchHeldState = InputTimer::Free,
188 DraggingOffset = Vec::Invalid),
189 HeldTimer.ResetInput(),
190 checked_held = {};
191 yunseq(CursorLocation = Point::Invalid, p_CursorOver = {},
192 p_indp_focus = {}, p_cascade_focus = {}, entered = {});
193 }
194
195 void
196 GUIState::ResetHeldState(InputTimer::HeldStateType& s, const KeyInput& k)
197 {
198 checked_held &= ~k;
199 if(checked_held.none())
200 {
201 s = InputTimer::Free,
202 HeldTimer.ResetInput();
203 }
204 }
205
206 void
207 GUIState::ResponseKey(KeyEventArgs& e, UI::VisualEvent op)
208 {
209 auto p(&e.GetSender());
210 IWidget* p_con;
211
212 e.Strategy = UI::RoutedEventArgs::Tunnel;
213 while(true)
214 {
215 if(!(IsVisible(*p) && IsEnabled(*p)) || e.Handled)
216 return;
217 p_con = p;
218
219 const auto t(FetchVisibleEnabledFocusingPtr(*p_con));
220
221 if(!t || t == p_con)
222 {
223 if(e.Handled)
224 return;
225 else
226 break;
227 }
228 e.SetSender(*p);
229 ResponseKeyBase(e, op);
230 p = t;
231 }
232 YAssertNonnull(p);
233 e.Strategy = UI::RoutedEventArgs::Direct;
234 e.SetSender(*p);
235 ResponseKeyBase(e, op);
236 if(op == KeyDown)
237 HandleCascade(e, *p);
238 e.Strategy = UI::RoutedEventArgs::Bubble;
239 while(!e.Handled && (p_con = FetchContainerPtr(*p)))
240 {
241 e.SetSender(*(p = p_con));
242 ResponseKeyBase(e, op);
243 }
244 }
245
246 void
247 GUIState::ResponseKeyBase(KeyEventArgs& e, UI::VisualEvent op)
248 {
249 YAssert(op == KeyUp || op == KeyDown || op == KeyHeld,
250 "Invalid operation found.");
251 DoEvent<HKeyEvent>(e.GetSender().GetController(), op, std::move(e));
252 }
253
254 void
255 GUIState::ResponseCursor(CursorEventArgs& e, UI::VisualEvent op)
256 {
257 CursorLocation = e;
258
259 auto p(&e.GetSender());
260 IWidget* p_con;
261
262 e.Strategy = UI::RoutedEventArgs::Tunnel;
263 while(true)
264 {
265 if(!(IsVisible(*p) && IsEnabled(*p)) || e.Handled)
266 return;
267 p_con = p;
268
269 const auto t(FetchTopEnabledAndVisibleWidgetPtr(*p_con, e));
270
271 if(!t || t == p_con)
272 {
273 if(e.Handled)
274 return;
275 else
276 break;
277 }
278 e.SetSender(*p);
279 ResponseCursorBase(e, op);
280 p = t;
281 e.Position -= GetLocationOf(*p);
282 };
283 YAssertNonnull(p);
284 e.Strategy = UI::RoutedEventArgs::Direct;
285 e.SetSender(*p);
286 ResponseCursorBase(e, op);
287 if(op == TouchDown)
288 HandleCascade(e, *p);
289 e.Strategy = UI::RoutedEventArgs::Bubble;
290 while(!e.Handled && (p_con = FetchContainerPtr(*p)))
291 {
292 e.Position += GetLocationOf(*p);
293 e.SetSender(*(p = p_con));
294 ResponseCursorBase(e, op);
295 }
296 }
297
298 void
299 GUIState::ResponseCursorBase(CursorEventArgs& e, UI::VisualEvent op)
300 {
301 auto& controller(e.GetSender().GetController());
302
303 switch(op)
304 {
305 case TouchHeld:
306 if(e.Strategy == RoutedEventArgs::Direct && p_indp_focus)
307 CallEvent<TouchHeld>(*p_indp_focus, e);
308 break;
309 case TouchUp:
310 case TouchDown:
311 case CursorOver:
312 DoEvent<HCursorEvent>(controller, op, std::move(e));
313 break;
314 case CursorWheel:
315 DoEvent<HCursorWheelEvent>(controller, CursorWheel,
316 std::move(ystdex::polymorphic_downcast<CursorWheelEventArgs&>(e)));
317 break;
318 default:
319 YAssert(false, "Invalid operation found.");
320 }
321 }
322
323 void
324 GUIState::TryEntering(CursorEventArgs&& e)
325 {
326 if(!entered)
327 {
328 CallEvent<Enter>(e.GetSender(), e);
329 entered = true;
330 }
331 }
332
333 void
334 GUIState::TryLeaving(CursorEventArgs&& e)
335 {
336 if(entered)
337 {
338 CallEvent<Leave>(e.GetSender(), e);
339 entered = {};
340 }
341 }
342
343 char
344 GUIState::UpdateChar(KeyInput& keys)
345 {
346 if(keys != checked_held)
347 {
348 master_key = FindFirstKeyInCategroy(keys, KeyCategory::Character);
349
350 yunseq(keys = checked_held |= keys, KeyHeldState = InputTimer::Free);
351 }
352 return MapKeyChar(checked_held, master_key);
353 }
354
355 void
356 GUIState::Wrap(IWidget& wgt)
357 {
358 auto& controller(wgt.GetController());
359
360 yunseq(
361 FetchEvent<KeyUp>(controller).Add([this](KeyEventArgs&& e){
362 auto& wgt(e.GetSender());
363
364 master_key = FindFirstKeyInCategroy(checked_held, KeyCategory::Character);
365
366 ResetHeldState(KeyHeldState, e.Keys);
367 if(p_indp_focus == &wgt)
368 CallEvent<KeyPress>(wgt, e);
369 p_indp_focus = {};
370 }, 0x00),
371 FetchEvent<KeyDown>(controller).Add([this](KeyEventArgs&& e){
372 p_indp_focus = &e.GetSender();
373 }, 0xFF),
374 FetchEvent<CursorOver>(controller).Add([this](CursorEventArgs&& e){
375 if(e.Strategy == RoutedEventArgs::Direct)
376 {
377 e.Keys.reset();
378
379 auto& wgt(e.GetSender());
380
381 if(p_CursorOver != &wgt)
382 {
383 if(p_CursorOver)
384 CallEvent<Leave>(*p_CursorOver, CursorEventArgs(
385 *p_CursorOver, e.Keys, e.Position - LocateForWidget(wgt,
386 *p_CursorOver)));
387 CallEvent<Enter>(e.GetSender(), CursorEventArgs(e));
388 p_CursorOver = &wgt;
389 }
390 }
391 }, 0xFF),
392 FetchEvent<TouchUp>(controller).Add([this](CursorEventArgs&& e){
393 if(e.Strategy == RoutedEventArgs::Direct)
394 {
395 auto& wgt(e.GetSender());
396
397 if(p_indp_focus)
398 {
399 e.SetSender(*p_indp_focus);
400 TryLeaving(std::move(e));
401 e.SetSender(e.GetSender());
402 }
403 ResetHeldState(TouchHeldState, e.Keys),
404 DraggingOffset = Vec::Invalid;
405 if(p_indp_focus == &wgt)
406 CallEvent<Click>(wgt, e);
407 else if(p_indp_focus)
408 CallEvent<ClickAcross>(*p_indp_focus, e);
409 p_indp_focus = {};
410 }
411 }, 0x00),
412 FetchEvent<TouchDown>(controller).Add([this](CursorEventArgs&& e){
413 if(e.Strategy == RoutedEventArgs::Direct)
414 {
415 p_indp_focus = &e.GetSender();
416 TryEntering(std::move(e));
417 }
418 }, 0xFF),
419 FetchEvent<TouchHeld>(controller).Add([this](CursorEventArgs&& e){
420 if(e.Strategy == RoutedEventArgs::Direct)
421 {
422 auto& wgt(e.GetSender());
423
424 if(p_indp_focus == &wgt)
425 TryEntering(CursorEventArgs(e));
426 // else
427 // TryLeaving(CursorEventArgs(*p_indp_focus, e.Keys,
428 // e.Position - LocateForWidget(wgt, *p_indp_focus)));
429 else if(entered)
430 {
431 CallEvent<Leave>(*p_indp_focus, CursorEventArgs(*p_indp_focus,
432 e.Keys, e.Position - LocateForWidget(wgt, *p_indp_focus)));
433 entered = {};
434 }
435 }
436 }, 0xFF)
437 );
438 }
439
440
441 GUIState&
442 FetchGUIState()
443 {
444 static GUIState* pState(new GUIState());
445
446 return *pState;
447 }
448
449 } // namespace UI;
450
451 } // namespace YSLib;
452
YSLib::UI::GUIState::GUIState
GUIState() ynothrow
Definition: ygui.cpp:127
YSLib::UI::GUIState::ResponseCursor
void ResponseCursor(CursorEventArgs &, VisualEvent)
响应屏幕接触状态。
Definition: ygui.cpp:255
platform::MapKeyChar
yconstexpr MapKeyChar
Definition: Keys.h:190
YSLib::UI::GUIState::DraggingOffset
Drawing::Vec DraggingOffset
拖放偏移量。
Definition: ygui.h:113
YSLib::UI::GetLocationOf
pt pt Y const IWidget &wgt GetLocationOf
Definition: ywidget.h:148
YModules.h
YSLib::UI::InputTimer::Free
Definition: ygui.h:58
YSLib::UI::FetchGUIState
YF_API GUIState & FetchGUIState()
取默认图形用户界面公共状态。
Definition: ygui.cpp:442
YSLib::UI::GUIState::CursorLocation
Drawing::Point CursorLocation
最近的指针设备操作时的控件全局位置（相对于顶层部件的坐标）。
Definition: ygui.h:123
YSLib::UI::GUIState::TryLeaving
void TryLeaving(CursorEventArgs &&)
Definition: ygui.cpp:334
YSLib::UI::GUIState::p_cascade_focus
IWidget * p_cascade_focus
级联焦点指针：缓冲最后一次通过直接策略路由事件的进入的部件状态。
Definition: ygui.h:146
YSLib::UI::KeyEventArgs
按键输入事件参数类。
Definition: ywgtevt.h:167
YSLib::UI::IsVisible
IsVisible
Definition: ywidget.h:96
YSLib::UI::GUIState::ResetHeldState
void ResetHeldState(InputTimer::HeldStateType &, const KeyInput &)
复位接触保持状态。
Definition: ygui.cpp:196
YSLib::Timers::Timer::Activate
virtual nBase YF_API friend void Activate(Timer &)
激活：当时间间隔非零时同步时间基点。
Definition: ytimer.cpp:118
YSLib::UI::InputTimer::Duration
Timers::Duration Duration
Definition: ygui.h:51
YSLib::Drawing::GBinaryGroup< SPos >::Invalid
static const GBinaryGroup Invalid
无效（不在屏幕坐标系中）对象。
Definition: ygdibase.h:57
YSLib::UI::GUIState::master_key
size_t master_key
记录需要映射的主要字符的按键编码。
Definition: ygui.h:165
YSLib::UI::RoutedEventArgs::Handled
bool Handled
事件已经被处理。
Definition: ywgtevt.h:108
YSLib::UI::GUIState::p_CursorOver
IWidget * p_CursorOver
光标设备指针对应的部件。
Definition: ygui.h:136
YSLib::UI::GUIState::TouchHeldState
InputTimer::HeldStateType TouchHeldState
Definition: ygui.h:112
YSLib::UI::GUIState::CheckDraggingOffset
bool CheckDraggingOffset(IWidget *={})
若拖放偏移量无效则按指定部件的屏幕坐标更新拖放偏移量。
Definition: ygui.cpp:147
YSLib::Timers::Timer::Interval
Duration Interval
重复刷新有效的最小时间间隔。
Definition: ytimer.h:111
YSLib::UI::InputTimer
输入计时器。
Definition: ygui.h:48
YSLib::UI::InputTimer::ResetInput
void ResetInput()
复位输入计时状态。
Definition: ygui.cpp:110
YSLib::UI::GUIState::UpdateChar
char UpdateChar(KeyInput &)
当指定按键状态和按键保持状态不同时按需更新映射的字符和参数。
Definition: ygui.cpp:344
YSLib::UI::InputTimer::InputTimer
InputTimer(const Duration &=Timers::TimeSpan(1000U))
Definition: ygui.cpp:71
cast.hpp
C++ 转换模板。
YB_UNLIKELY
#define YB_UNLIKELY(expr)
分支预测提示。
Definition: ydef.h:298
YSLib::Drawing::Point
GBinaryGroup< SPos > Point
屏幕二维点（直角坐标表示）。
Definition: ygdibase.h:235
yunseq
#define yunseq
无序列依赖表达式组求值。
Definition: ydef.h:748
YSLib::UI::IsFocused
YF_API bool IsFocused(const IWidget &)
判断部件是否取得焦点。
Definition: yfocus.cpp:38
YSLib::UI::GUIState::checked_held
KeyInput checked_held
记录检查时的按键输入。
Definition: ygui.h:158
YSLib::UI::RoutedEventArgs::Strategy
RoutingStrategy Strategy
事件路由策略。
Definition: ywgtevt.h:107
YSLib::UI::wgt
_tWidget & wgt
Definition: ywgtevt.h:596
ynothrow
#define ynothrow
YSLib 无异常抛出保证：若支持 noexcept 关键字， 指定特定的 noexcept 异常规范。
Definition: ydef.h:514
YSLib::UI::RoutedEventArgs::Direct
直接事件：仅当遍历至目标控件时触发。
Definition: ywgtevt.h:104
YSLib::UI::InputTimer::RefreshClick
size_t RefreshClick(size_t, const Duration &=Timers::TimeSpan(400))
重复检测连续点击状态。
Definition: ygui.cpp:99
YSLib::Drawing::GBinaryGroup< SPos >
YAssertNonnull
#define YAssertNonnull(_expr)
Definition: cassert.h:81
YSLib::UI::CursorEventArgs::Position
InputType Position
Definition: ywgtevt.h:189
YSLib::UI::GUIState::ResponseKey
void ResponseKey(KeyEventArgs &, VisualEvent)
响应标准按键状态。
Definition: ygui.cpp:207
YSLib::UI::GUIState::KeyHeldState
InputTimer::HeldStateType KeyHeldState
输入接触状态。
Definition: ygui.h:112
platform::KeyCategory::Character
表示产生字符的键。
Definition: Keys.h:109
YSLib::UI::InputTimer::RefreshHeld
bool RefreshHeld(HeldStateType &, const Duration &=Timers::TimeSpan(240), const Duration &=Timers::TimeSpan(120))
重复检测输入接触保持状态。
Definition: ygui.cpp:76
YSLib::UI::IsEnabled
bool IsEnabled(const IWidget &wgt)
判断部件是否为可用的控件。
Definition: ycontrol.h:86
YSLib::UI::GUIState::CleanupReferences
void CleanupReferences(IWidget &)
清除状态对指定部件的引用。
Definition: ygui.cpp:162
YSLib::UI::Contains
Selected const shared_ptr< ListType > const pair< Color, Color > viewer Contains
Definition: textlist.h:124
YSLib::UI::GUIState::p_indp_focus
IWidget * p_indp_focus
独立焦点指针：自由状态时即时输入（按下）状态捕获的部件指针。
Definition: ygui.h:141
platform_ex::Windows::s
return s
Definition: MinGW32.cpp:49
YSLib::UI::GUIState::HandleCascade
void HandleCascade(RoutedEventArgs &, IWidget &)
处理级联焦点指针，保证指向的部件具有焦点。
Definition: ygui.cpp:173
YSLib::UI::GUIState::Wrap
void Wrap(IWidget &)
包装部件响应 Enter/Leave 事件。
Definition: ygui.cpp:356
YSLib::UI::RoutedEventArgs
路由事件参数基类。
Definition: ywgtevt.h:93
platform::KeyCategory::FindFirstKeyInCategroy
YF_API KeyIndex FindFirstKeyInCategroy(const KeyInput &, KeyIndex) ynothrow
找到第一个在指定类别的按键编码。
Definition: Keys.cpp:594
YSLib::UI::GUIState::HeldTimer
InputTimer HeldTimer
输入接触保持计时器。
Definition: ygui.h:118
YSLib::UI::RoutedEventArgs::Bubble
气泡事件：向上遍历视图树时触发。
Definition: ywgtevt.h:102
YSLib::Timers::Duration
HighResolutionClock::duration Duration
高精度时间间隔。
Definition: ytimer.h:72
YSLib::UI::InputTimer::Held
Definition: ygui.h:60
YSLib::UI::InputTimer::HeldStateType
HeldStateType
输入保持状态。
Definition: ygui.h:56
YSLib::UI::GUIState::TryEntering
void TryEntering(CursorEventArgs &&)
Definition: ygui.cpp:324
YSLib::UI::GUIState
图形用户界面公共状态。
Definition: ygui.h:105
YSLib::Timers::TimeSpan
std::chrono::milliseconds TimeSpan
低精度时间间隔。
Definition: ytimer.h:85
YSLib::UI::RoutedEventArgs::Tunnel
隧道事件：向下遍历视图树时触发。
Definition: ywgtevt.h:103
YSLib::UI::GUIState::CheckHeldState
const KeyInput checked_held IWidget p_indp_focus KeyHeldState bool CheckHeldState(const KeyInput &, InputTimer::HeldStateType &)
Definition: ygui.cpp:134
YSLib::UI::GUIState::Reset
void Reset()
复位图形用户界面状态。
Definition: ygui.cpp:185
YSLib::UI::GUIState::entered
bool entered
记录按键时的光标是否在部件内部。
Definition: ygui.h:151
YSLib::UI::FetchFocusingPtr
pt pt Y FetchFocusingPtr
Definition: ywidget.h:140
YSLib::UI::CursorEventArgs
指针设备输入事件参数类。
Definition: ywgtevt.h:183
platform::KeyInput
std::bitset< KeyBitsetWidth > KeyInput
按键并行位宽。
Definition: Keys.h:68
YSLib::UI::InputTimer::Pressed
Definition: ygui.h:59
YSLib::UI::GUIState::ResponseKeyBase
void ResponseKeyBase(KeyEventArgs &, VisualEvent)
响应标准按键状态。
Definition: ygui.cpp:247
YSLib::UI::GUIState::ResponseCursorBase
void ResponseCursorBase(CursorEventArgs &, VisualEvent)
响应标准指针设备状态。
Definition: ygui.cpp:299
YAssert
#define YAssert(_expr, _msg)
Definition: cassert.h:73
YSLib::UI::RepeatHeld
YF_API bool RepeatHeld(InputTimer &, InputTimer::HeldStateType &, const Timers::Duration &, const Timers::Duration &)
向指定计时器传递参数，根据状态重复按键。
Definition: ygui.cpp:117