YSTest  PreAlpha_b500_20140530
The YSLib Test Project
 全部  命名空间 文件 函数 变量 类型定义 枚举 枚举值 友元 宏定义  
TextBox.cpp
浏览该文件的文档.
1 /*
2  © 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_TextBox
30 #include YFM_YSLib_UI_Border
31 #include YFM_YSLib_UI_YGUI
32 #include YFM_YSLib_Service_TextLayout
33 #include YFM_YSLib_UI_YUIContainer // for LocateForWidget;
34 #include <ystdex/cast.hpp>
35 
36 namespace YSLib
37 {
38 
39 namespace UI
40 {
41 
42 GAnimationSession<InvalidationUpdater> Caret::caret_animation;
43 
44 Caret::Caret(IWidget& wgt, HBrush caret_brush,
46  : CaretBrush(caret_brush), CursorInvalidator(inv)
47 {
48  yunseq(
49  FetchEvent<Paint>(wgt) += [this](PaintEventArgs&& e){
50  if(Check(e.GetSender()))
51  CaretBrush(std::move(e));
52  },
53  FetchEvent<GotFocus>(wgt) += [this](UIEventArgs&& e){
54  // NOTE: Necessary cleanup.
55  Stop();
56  Restart(caret_animation, e.GetSender(), CursorInvalidator);
57  },
58  FetchEvent<LostFocus>(wgt) += [this]{
59  Stop();
60  }
61  );
62 }
64 {
65  Stop();
66 }
67 
68 bool
69 Caret::Check(IWidget& sender)
70 {
71  if(caret_animation.GetConnectionPtr()
72  && caret_animation.GetConnectionRef().Ready)
73  {
74  YAssert(IsFocusedCascade(sender), "Wrong focus state found.");
75  return IsEnabled(sender)
77  }
78  return {};
79 }
80 
81 void
83 {
84  // TODO: Consider possible per-object optimization.
85  if(auto p = caret_animation.GetConnectionPtr())
86  p->Ready = {};
87 }
88 
89 
90 TextBox::TextBox(const Rect& r, const Drawing::Font& fnt,
91  const pair<Color, Color>& hilight_pair)
92  : Control(r, MakeBlankBrush()), MLabel(fnt), MHilightText(hilight_pair),
93  Selection(), CursorCaret(*this, std::bind(&TextBox::PaintDefaultCaret, this,
94  std::placeholders::_1), InvalidateDefaultCaret), h_offset()
95 {
96  yunseq(
97  FetchEvent<KeyDown>(*this) += [this](KeyEventArgs&& e){
98  if(e.Strategy == RoutedEventArgs::Direct)
99  {
100  using namespace KeyCategory;
101  using namespace KeyCodes;
102  const auto& k(e.GetKeys());
103  const char c(FetchGUIState().UpdateChar(e.Keys));
104  auto& sender(e.GetSender());
105 
106  // TODO: Proper multiple keys handling for non-alphabetical.
107  if(c != char())
108  {
109  const ucs2_t buf[]{ucs2_t(c), u'\0'};
110 
111  CallEvent<TextInput>(sender,
112  TextInputEventArgs(sender, String(buf), k));
113  Invalidate(e.GetSender());
114  return;
115  }
116 
117  auto ek(FindFirstKeyInCategroy(k, Editing));
118 
119  if(ek == KeyBitsetWidth)
121  if(ek != KeyBitsetWidth)
122  {
123  const bool shifted(k[Shift]);
124  auto& range(Selection.Range);
125 
126  switch(ek)
127  {
128  case Backspace:
129  case Delete:
130  if(Selection.IsEmpty())
131  {
132  if(ek == Backspace)
133  {
134  if(range.second.X == 0)
135  break;
136  --range.second.X;
137  }
138  else
139  {
140  if(range.second.X >= Text.length())
141  break;
142  ++range.second.X;
143  }
144  }
145  ReplaceSelection(u"");
146  break;
147  case Left:
148  case Right:
149  if(Selection.IsEmpty() || shifted)
150  {
151  if(ek == Left)
152  {
153  if(range.second.X == 0)
154  break;
155  --range.second.X;
156  if(shifted)
157  break;
158  }
159  else
160  {
161  if(range.second.X >= Text.length())
162  break;
163  ++range.second.X;
164  if(shifted)
165  break;
166  }
167  }
168  else
169  range.second.X = (ek == Left) == (range.first.X
170  < range.second.X) ? range.first.X : range.second.X;
172  break;
173  case Space:
174  ReplaceSelection(u" ");
175  }
176  Invalidate(e.GetSender());
177  return;
178  }
179  }
180  },
181  FetchEvent<KeyHeld>(*this) += OnKeyHeld,
182  FetchEvent<TouchDown>(*this) += [this](CursorEventArgs&& e){
183  Selection.Range.second = GetCaretPosition(e.Position);
184  Selection.Collapse();
185  },
186  FetchEvent<TouchHeld>(*this) += [this](CursorEventArgs&& e){
187  if(FetchGUIState().GetIndependentFocusPtr() == this)
188  {
189  const auto& sender(e.GetSender());
190 
191  Selection.Range.second = GetCaretPosition(&sender == this
192  ? e.Position : LocateForWidget(*this, sender) + e.Position);
193  // XXX: Optimization for block.
194  Invalidate(*this);
195  }
196  },
197  FetchEvent<TextInput>(*this) += [this](TextInputEventArgs&& e){
198  ReplaceSelection(e.Text);
199  },
200  FetchEvent<Paint>(*this).Add(BorderBrush(), BackgroundPriority),
201  FetchEvent<GotFocus>(*this) += [this]{
202  Invalidate(*this);
203  },
204  FetchEvent<LostFocus>(*this) += [this]{
205  Selection.Collapse();
206  Invalidate(*this);
207  }
208  );
209 }
210 
212 TextBox::GetCaretPosition(const Point& pt)
213 {
214  const SDst max_w(max(pt.X + h_offset - Margin.Left, 0));
215  auto pr(FetchStringOffsets(max_w, Font, Text));
216 
217  if(pr.first > 0
218  && FetchCharWidth(Font, Text[pr.first - 1]) / 2 < pr.second - max_w)
219  --pr.first;
220  return {pr.first, 0};
221 }
222 
223 void
225 {
226  auto p(&Text[0]);
227  auto x1(Selection.Range.first.X), x2(Selection.Range.second.X);
228 
229  if(x1 == x2)
230  MLabel::DrawClippedText(g, mask, ts);
231  else
232  {
233  if(x2 < x1)
234  std::swap(x1, x2);
235 
236  // TODO: Use C++14 lambda initializers to simplify implementation.
237  const auto q1(p + x1), q2(p + x2);
238  CustomTextRenderer ctr([&, q1, q2](TextRenderer& tr, ucs4_t c){
239  if(IsInInterval(p, q1, q2))
240  {
241  // TODO: Use colors from %Styles::Palette.
242  FillRect(g, tr.ClipArea, ts.GetCharBounds(c), HilightBackColor);
243  ts.Color = HilightTextColor;
244  }
245  else
246  ts.Color = ForeColor;
247  tr(c);
248  ++p;
249  }, ts, g, mask);
250 
251  PutText(AutoWrapLine, ctr, p);
252  }
253 }
254 
255 void
257 {
258  DrawText(GetSizeOf(*this), ForeColor, e);
259 }
260 
261 bool
263 {
264  auto& tb(ystdex::polymorphic_downcast<TextBox&>(wgt));
265  const Rect inner_bounds(Rect(GetSizeOf(wgt)) + tb.Margin);
266  const auto lh(tb.Font.GetHeight());
267  const auto& cur_pos(tb.Selection.Range.second);
268  const auto
269  x(inner_bounds.X + FetchStringWidth(tb.Font, tb.Text, cur_pos.X));
270  const auto y(cur_pos.Y * lh + inner_bounds.X);
271 
272  InvalidateVisible(tb, Rect(x, y, 1, lh + GetVerticalOf(tb.Margin)));
273  return true;
274 }
275 
276 void
278 {
279  auto& r(Selection.Range);
280 
281  // XXX: Make it correct for multiline input.
282  if(r.second.X < r.first.X)
283  std::swap(r.first, r.second);
284  Text = Text.substr(0, r.first.X) + text
285  + Text.substr(min(Text.length(), r.second.X));
286  r.second.X = r.first.X + text.length(),
288 }
289 
290 void
292 {
293  const Rect inner_bounds(Rect(e.Location, GetSizeOf(*this)) + Margin);
294  const auto lh(Font.GetHeight());
295  const auto mask(FetchMargin(inner_bounds, e.Target.GetSize()));
296  const auto& cur_pos(Selection.Range.second);
297 
298  DrawVLineSeg(e.Target, e.ClipArea, inner_bounds.X + FetchStringWidth(Font,
299  Text, cur_pos.X) - h_offset, cur_pos.Y * lh + mask.Top,
300  cur_pos.Y * lh + lh + mask.Top, ForeColor);
301 }
302 
303 } // namespace UI;
304 
305 } // namespace YSLib;
306 
void DrawVLineSeg(const Graphics &g, const Rect &bounds, SPos x, SPos y1, SPos y2, Color c)
描画竖直线段。
Definition: ydraw.h:153
pt pt Y const IWidget &wgt const IWidget &wgt GetSizeOf
无效化:使相对于部件的子部件的指定区域在直接和间接的窗口缓冲区中无效。
Definition: ywidget.h:156
SDst FetchStringWidth(const Font &fnt, _tIter s)
取迭代器指定的单行字符串在字体指定、无边界限制时的显示宽度。
Definition: TextLayout.h:192
YF_API void OnKeyHeld(KeyEventArgs &&)
处理键接触保持事件。
Definition: ycontrol.cpp:108
void Refresh(PaintEventArgs &&) override
刷新:按指定参数绘制界面并更新状态。
Definition: TextBox.cpp:256
GBinaryGroup< size_t > Position
位置:横坐标和纵坐标。
Definition: TextBox.h:96
pair< size_t, SDst > FetchStringOffsets(size_t max_width, const Font &fnt, _tIter s)
取迭代器指定的单行字符串在指定字体和宽度时的最多能显示的字符数和宽。
Definition: TextLayout.h:110
YF_API Padding FetchMargin(const Rect &, const Size &)
取内边界相对于外边界的边距。
Definition: ygdi.cpp:51
YF_API GUIState & FetchGUIState()
取默认图形用户界面公共状态。
Definition: ygui.cpp:442
Drawing::Font Font
字体。
Definition: label.h:61
SDst GetVerticalOf(const Padding &m)
取竖直边距和。
Definition: ygdi.h:116
按键输入事件参数类。
Definition: ywgtevt.h:167
YF_API void FillRect(const Graphics &g, const Rect &, Color c)
填充标准矩形。
Definition: ydraw.cpp:146
YF_API void Invalidate(IWidget &, const Rect &)
无效化:使相对于部件的指定区域在直接和间接的窗口缓冲区中无效。
Definition: ywidget.cpp:111
Color HilightTextColor
高亮文本色。
Definition: label.h:249
Timers::Timer CaretTimer
决定是否显示插入符的计时器。
Definition: TextBox.h:59
部件绘制参数。
Definition: ywgtevt.h:276
TextSelection Selection
选择区域:结束位置指示插入符光标逻辑位置。
Definition: TextBox.h:146
HBrush CaretBrush
插入符画刷。 484
Definition: TextBox.h:64
表示编辑键(如回车、空格、退格、插入、删除和制表符)
Definition: Keys.h:121
Duration RefreshRemainder()
刷新:对于非零时间间隔判断有效性并都更新时间基点。
Definition: ytimer.cpp:106
Span Range
选择的范围。
Definition: TextBox.h:104
用户界面事件参数基类。
Definition: ywgtevt.h:59
std::uint16_t SDst
屏幕坐标距离。
Definition: Video.h:39
InvalidationUpdater::Invalidator CursorInvalidator
供闪烁动画使用的指定无效化区域的光标位置刷新器。
Definition: TextBox.h:69
_fCallable void Restart(_tAnimation &ani, IWidget &wgt, _fCallable f)
Definition: Animation.h:177
Color HilightBackColor
高亮背景色。
Definition: label.h:247
Duration Interval
重复刷新有效的最小时间间隔。
Definition: ytimer.h:111
控件。
Definition: ycontrol.h:275
定制文本渲染器:使用自定义的渲染函数替代的 TextRenderer 。
Definition: TextRenderer.h:416
YF_API bool IsFocusedCascade(const IWidget &, const IWidget *={})
判断部件相对于指针指定的部件是否具有级联焦点。
Definition: yfocus.cpp:122
void PaintDefaultCaret(PaintEventArgs &&)
绘制默认插入符。
Definition: TextBox.cpp:291
文本框。
Definition: TextBox.h:128
String Text
标签文本。
Definition: label.h:76
void swap(any &x, any &y)
交换对象。
Definition: any.h:729
C++ 转换模板。
const PaintContext &virtual void DrawClippedText(const Graphics &, const Rect &, Drawing::TextState &)
绘制剪切文本:使用指定的图形接口上下文、相对于部件的边界和文本状态。
Definition: label.cpp:100
YF_API SDst FetchCharWidth(const Font &, ucs4_t)
取指定的字符使用指定字体的显示宽度。
Definition: TextLayout.cpp:71
YSLib 标准字符串(使用 UCS-2 作为内部编码)。
Definition: ystring.h:47
YF_API void InvalidateVisible(IWidget &, const Rect &)
无效化:使相对于可见的部件的指定区域在直接和间接的窗口缓冲区中无效。
Definition: ywidget.cpp:151
GBinaryGroup< SPos > Point
屏幕二维点(直角坐标表示)。
Definition: ygdibase.h:235
#define yunseq
无序列依赖表达式组求值。
Definition: ydef.h:748
_tWidget & wgt
Definition: ywgtevt.h:596
YF_API void DrawText(const Graphics &g, TextState &ts, const String &str, bool line_wrap)
绘制文本。
文本状态。
Definition: TextBase.h:87
TextBox(const Rect &={}, const Drawing::Font &={}, const pair< Drawing::Color, Drawing::Color > &=FetchGUIState().Colors.GetPair(Styles::Highlight, Styles::HighlightText))
构造:使用指定边界、字体和高亮背景色/文本色对。
Definition: TextBox.cpp:90
文本渲染器:简单实现。
Definition: TextRenderer.h:361
屏幕标准矩形:表示屏幕矩形区域。
Definition: ygdibase.h:416
直接事件:仅当遍历至目标控件时触发。
Definition: ywgtevt.h:104
Caret(IWidget &, HBrush, InvalidationUpdater::Invalidator)
构造:注册插入符光标动画的事件处理器和画刷。
Definition: TextBox.cpp:44
Drawing::Color Color
笔颜色。
Definition: TextBase.h:58
std::function< void(PaintEventArgs &&)> HBrush
画刷回调函数。
Definition: YComponent.h:104
YF_API Point LocateForWidget(const IWidget &, const IWidget &)
取第二参数指定的部件相对于第一参数指定的部件的偏移坐标。
Definition: yuicont.cpp:74
bool AutoWrapLine
启用自动换行。
Definition: label.h:73
二维图形接口上下文。
Definition: ygdibase.h:721
static void Stop()
停止插入符光标动画。
Definition: TextBox.cpp:82
bool Check(IWidget &)
检查是否需要对指定部件进行绘制。
Definition: TextBox.cpp:69
static bool InvalidateDefaultCaret(IWidget &)
无效化默认插入符。
Definition: TextBox.cpp:262
bool IsEnabled(const IWidget &wgt)
判断部件是否为可用的控件。
Definition: ycontrol.h:86
Drawing::Padding Margin
文本和容器的间距。
Definition: label.h:62
SDst h_offset
文字区域水平基准负偏移:文本内容在光标回退方向超出的未显示部分大小。
Definition: TextBox.h:158
void ReplaceSelection(const String &)
替换选中文本。
Definition: TextBox.cpp:277
高亮文本模块。
Definition: label.h:243
DefDeMoveCtor(TextBox) TextSelection void DrawClippedText(const Graphics &, const Rect &, TextState &) override
取指定点所在的插入符光标逻辑位置。
Definition: TextBox.cpp:224
std::function< bool(IWidget &)> Invalidator
Definition: Animation.h:128
YF_API KeyIndex FindFirstKeyInCategroy(const KeyInput &, KeyIndex) ynothrow
找到第一个在指定类别的按键编码。
Definition: Keys.cpp:594
char32_t ucs4_t
UCS-4 字符类型。
Definition: chrdef.h:45
bounds & r
Definition: ydraw.h:220
void PutText(bool multi, _tParams &&...args)
打印文本。
Definition: TextRenderer.h:281
标签模块。
Definition: label.h:58
c yconstfn g
Definition: ystyle.h:104
字体:字模,包含字型、样式和大小。
Definition: Font.h:546
Color ForeColor
默认前景色。
Definition: ywidget.h:375
表示导航键(如方向键和 PgUp )、菜单键和 Esc 。
Definition: Keys.h:119
FontSize GetHeight() const ynothrow
取字体对应的字符高度。
Definition: Font.cpp:527
bool IsInInterval(_type i, _type b) ynothrow
判断 i 是否在左闭右开区间 [FetchZero<_type>(), b) 中。
Definition: ycutil.h:140
static GAnimationSession< InvalidationUpdater > caret_animation
插入符闪烁动画。
Definition: TextBox.h:55
指针设备输入事件参数类。
Definition: ywgtevt.h:183
#define YAssert(_expr, _msg)
Definition: cassert.h:73
yconstexpr EventPriority BackgroundPriority(0xC0)
用户界面绘制优先级。