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 
72  : Timer(d)
73 {}
74 
75 bool
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
111 {
112  Interval = Timers::TimeSpan(1000);
113 }
114 
115 
116 bool
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 
128  : KeyHeldState(InputTimer::Free), TouchHeldState(InputTimer::Free),
129  DraggingOffset(Vec::Invalid), HeldTimer(), CursorLocation(Point::Invalid),
130  Colors(), Styles()
131 {}
132 
133 bool
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
148 {
149  if(!p)
150  p = p_indp_focus;
151  if(p)
152  {
155  else
156  return true;
157  }
158  return false;
159 }
160 
161 void
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
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
186 {
190  checked_held = {};
192  p_indp_focus = {}, p_cascade_focus = {}, entered = {});
193 }
194 
195 void
197 {
198  checked_held &= ~k;
199  if(checked_held.none())
200  {
201  s = InputTimer::Free,
203  }
204 }
205 
206 void
207 GUIState::ResponseKey(KeyEventArgs& e, UI::VisualEvent op)
208 {
209  auto p(&e.GetSender());
210  IWidget* p_con;
211 
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);
234  e.SetSender(*p);
235  ResponseKeyBase(e, op);
236  if(op == KeyDown)
237  HandleCascade(e, *p);
239  while(!e.Handled && (p_con = FetchContainerPtr(*p)))
240  {
241  e.SetSender(*(p = p_con));
242  ResponseKeyBase(e, op);
243  }
244 }
245 
246 void
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
256 {
257  CursorLocation = e;
258 
259  auto p(&e.GetSender());
260  IWidget* p_con;
261 
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);
285  e.SetSender(*p);
286  ResponseCursorBase(e, op);
287  if(op == TouchDown)
288  HandleCascade(e, *p);
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
300 {
301  auto& controller(e.GetSender().GetController());
302 
303  switch(op)
304  {
305  case TouchHeld:
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
325 {
326  if(!entered)
327  {
328  CallEvent<Enter>(e.GetSender(), e);
329  entered = true;
330  }
331 }
332 
333 void
335 {
336  if(entered)
337  {
338  CallEvent<Leave>(e.GetSender(), e);
339  entered = {};
340  }
341 }
342 
343 char
345 {
346  if(keys != checked_held)
347  {
349 
351  }
353 }
354 
355 void
357 {
358  auto& controller(wgt.GetController());
359 
360  yunseq(
361  FetchEvent<KeyUp>(controller).Add([this](KeyEventArgs&& e){
362  auto& wgt(e.GetSender());
363 
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&
443 {
444  static GUIState* pState(new GUIState());
445 
446  return *pState;
447 }
448 
449 } // namespace UI;
450 
451 } // namespace YSLib;
452 
GUIState() ynothrow
Definition: ygui.cpp:127
void ResponseCursor(CursorEventArgs &, VisualEvent)
响应屏幕接触状态。
Definition: ygui.cpp:255
yconstexpr MapKeyChar
Definition: Keys.h:190
Drawing::Vec DraggingOffset
拖放偏移量。
Definition: ygui.h:113
pt pt Y const IWidget &wgt GetLocationOf
Definition: ywidget.h:148
YF_API GUIState & FetchGUIState()
取默认图形用户界面公共状态。
Definition: ygui.cpp:442
Drawing::Point CursorLocation
最近的指针设备操作时的控件全局位置(相对于顶层部件的坐标)。
Definition: ygui.h:123
void TryLeaving(CursorEventArgs &&)
Definition: ygui.cpp:334
IWidget * p_cascade_focus
级联焦点指针:缓冲最后一次通过直接策略路由事件的进入的部件状态。
Definition: ygui.h:146
按键输入事件参数类。
Definition: ywgtevt.h:167
void ResetHeldState(InputTimer::HeldStateType &, const KeyInput &)
复位接触保持状态。
Definition: ygui.cpp:196
virtual nBase YF_API friend void Activate(Timer &)
激活:当时间间隔非零时同步时间基点。
Definition: ytimer.cpp:118
Timers::Duration Duration
Definition: ygui.h:51
static const GBinaryGroup Invalid
无效(不在屏幕坐标系中)对象。
Definition: ygdibase.h:57
size_t master_key
记录需要映射的主要字符的按键编码。
Definition: ygui.h:165
bool Handled
事件已经被处理。
Definition: ywgtevt.h:108
IWidget * p_CursorOver
光标设备指针对应的部件。
Definition: ygui.h:136
InputTimer::HeldStateType TouchHeldState
Definition: ygui.h:112
bool CheckDraggingOffset(IWidget *={})
若拖放偏移量无效则按指定部件的屏幕坐标更新拖放偏移量。
Definition: ygui.cpp:147
Duration Interval
重复刷新有效的最小时间间隔。
Definition: ytimer.h:111
输入计时器。
Definition: ygui.h:48
void ResetInput()
复位输入计时状态。
Definition: ygui.cpp:110
char UpdateChar(KeyInput &)
当指定按键状态和按键保持状态不同时按需更新映射的字符和参数。
Definition: ygui.cpp:344
InputTimer(const Duration &=Timers::TimeSpan(1000U))
Definition: ygui.cpp:71
C++ 转换模板。
#define YB_UNLIKELY(expr)
分支预测提示。
Definition: ydef.h:298
GBinaryGroup< SPos > Point
屏幕二维点(直角坐标表示)。
Definition: ygdibase.h:235
#define yunseq
无序列依赖表达式组求值。
Definition: ydef.h:748
YF_API bool IsFocused(const IWidget &)
判断部件是否取得焦点。
Definition: yfocus.cpp:38
KeyInput checked_held
记录检查时的按键输入。
Definition: ygui.h:158
RoutingStrategy Strategy
事件路由策略。
Definition: ywgtevt.h:107
_tWidget & wgt
Definition: ywgtevt.h:596
#define ynothrow
YSLib 无异常抛出保证:若支持 noexcept 关键字, 指定特定的 noexcept 异常规范。
Definition: ydef.h:514
直接事件:仅当遍历至目标控件时触发。
Definition: ywgtevt.h:104
size_t RefreshClick(size_t, const Duration &=Timers::TimeSpan(400))
重复检测连续点击状态。
Definition: ygui.cpp:99
#define YAssertNonnull(_expr)
Definition: cassert.h:81
void ResponseKey(KeyEventArgs &, VisualEvent)
响应标准按键状态。
Definition: ygui.cpp:207
InputTimer::HeldStateType KeyHeldState
输入接触状态。
Definition: ygui.h:112
表示产生字符的键。
Definition: Keys.h:109
bool RefreshHeld(HeldStateType &, const Duration &=Timers::TimeSpan(240), const Duration &=Timers::TimeSpan(120))
重复检测输入接触保持状态。
Definition: ygui.cpp:76
bool IsEnabled(const IWidget &wgt)
判断部件是否为可用的控件。
Definition: ycontrol.h:86
void CleanupReferences(IWidget &)
清除状态对指定部件的引用。
Definition: ygui.cpp:162
Selected const shared_ptr< ListType > const pair< Color, Color > viewer Contains
Definition: textlist.h:124
IWidget * p_indp_focus
独立焦点指针:自由状态时即时输入(按下)状态捕获的部件指针。
Definition: ygui.h:141
void HandleCascade(RoutedEventArgs &, IWidget &)
处理级联焦点指针,保证指向的部件具有焦点。
Definition: ygui.cpp:173
void Wrap(IWidget &)
包装部件响应 Enter/Leave 事件。
Definition: ygui.cpp:356
路由事件参数基类。
Definition: ywgtevt.h:93
YF_API KeyIndex FindFirstKeyInCategroy(const KeyInput &, KeyIndex) ynothrow
找到第一个在指定类别的按键编码。
Definition: Keys.cpp:594
InputTimer HeldTimer
输入接触保持计时器。
Definition: ygui.h:118
气泡事件:向上遍历视图树时触发。
Definition: ywgtevt.h:102
HighResolutionClock::duration Duration
高精度时间间隔。
Definition: ytimer.h:72
HeldStateType
输入保持状态。
Definition: ygui.h:56
void TryEntering(CursorEventArgs &&)
Definition: ygui.cpp:324
图形用户界面公共状态。
Definition: ygui.h:105
std::chrono::milliseconds TimeSpan
低精度时间间隔。
Definition: ytimer.h:85
隧道事件:向下遍历视图树时触发。
Definition: ywgtevt.h:103
const KeyInput checked_held IWidget p_indp_focus KeyHeldState bool CheckHeldState(const KeyInput &, InputTimer::HeldStateType &)
Definition: ygui.cpp:134
void Reset()
复位图形用户界面状态。
Definition: ygui.cpp:185
bool entered
记录按键时的光标是否在部件内部。
Definition: ygui.h:151
pt pt Y FetchFocusingPtr
Definition: ywidget.h:140
指针设备输入事件参数类。
Definition: ywgtevt.h:183
std::bitset< KeyBitsetWidth > KeyInput
按键并行位宽。
Definition: Keys.h:68
void ResponseKeyBase(KeyEventArgs &, VisualEvent)
响应标准按键状态。
Definition: ygui.cpp:247
void ResponseCursorBase(CursorEventArgs &, VisualEvent)
响应标准指针设备状态。
Definition: ygui.cpp:299
#define YAssert(_expr, _msg)
Definition: cassert.h:73
YF_API bool RepeatHeld(InputTimer &, InputTimer::HeldStateType &, const Timers::Duration &, const Timers::Duration &)
向指定计时器传递参数,根据状态重复按键。
Definition: ygui.cpp:117