YSTest: TextBox.cpp 源文件

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,
45 InvalidationUpdater::Invalidator inv)
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 }
63 Caret::~Caret()
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)
76 && CaretTimer.RefreshRemainder() < CaretTimer.Interval / 2;
77 }
78 return {};
79 }
80
81 void
82 Caret::Stop()
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)
120 ek = FindFirstKeyInCategroy(k, Navigation);
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;
171 Selection.Collapse();
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
211 TextSelection::Position
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
224 TextBox::DrawClippedText(const Graphics& g, const Rect& mask, TextState& ts)
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
256 TextBox::Refresh(PaintEventArgs&& e)
257 {
258 DrawText(GetSizeOf(*this), ForeColor, e);
259 }
260
261 bool
262 TextBox::InvalidateDefaultCaret(IWidget& wgt)
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
277 TextBox::ReplaceSelection(const String& text)
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(),
287 Selection.Collapse();
288 }
289
290 void
291 TextBox::PaintDefaultCaret(PaintEventArgs&& e)
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
YSLib::Drawing::DrawVLineSeg
void DrawVLineSeg(const Graphics &g, const Rect &bounds, SPos x, SPos y1, SPos y2, Color c)
描画竖直线段。
Definition: ydraw.h:153
YSLib::UI::BorderArea::Right
YSLib::UI::TextSelection::Collapse
Collapse
Definition: TextBox.h:116
YSLib::UI::GetSizeOf
pt pt Y const IWidget &wgt const IWidget &wgt GetSizeOf
无效化：使相对于部件的子部件的指定区域在直接和间接的窗口缓冲区中无效。
Definition: ywidget.h:156
YSLib::Drawing::FetchStringWidth
SDst FetchStringWidth(const Font &fnt, _tIter s)
取迭代器指定的单行字符串在字体指定、无边界限制时的显示宽度。
Definition: TextLayout.h:192
YSLib::UI::OnKeyHeld
YF_API void OnKeyHeld(KeyEventArgs &&)
处理键接触保持事件。
Definition: ycontrol.cpp:108
YSLib::UI::TextBox::Refresh
void Refresh(PaintEventArgs &&) override
刷新：按指定参数绘制界面并更新状态。
Definition: TextBox.cpp:256
YModules.h
YSLib::UI::TextSelection::Position
GBinaryGroup< size_t > Position
位置：横坐标和纵坐标。
Definition: TextBox.h:96
YSLib::Drawing::FetchStringOffsets
pair< size_t, SDst > FetchStringOffsets(size_t max_width, const Font &fnt, _tIter s)
取迭代器指定的单行字符串在指定字体和宽度时的最多能显示的字符数和宽。
Definition: TextLayout.h:110
YSLib::Drawing::FetchMargin
YF_API Padding FetchMargin(const Rect &, const Size &)
取内边界相对于外边界的边距。
Definition: ygdi.cpp:51
YSLib::UI::FetchGUIState
YF_API GUIState & FetchGUIState()
取默认图形用户界面公共状态。
Definition: ygui.cpp:442
YSLib::UI::MLabel::Font
Drawing::Font Font
字体。
Definition: label.h:61
YSLib::Drawing::GetVerticalOf
SDst GetVerticalOf(const Padding &m)
取竖直边距和。
Definition: ygdi.h:116
YSLib::Drawing::TextRenderer::ClipArea
Rect ClipArea
Definition: TextRenderer.h:366
YSLib::UI::KeyEventArgs
按键输入事件参数类。
Definition: ywgtevt.h:167
YSLib::Drawing::FillRect
YF_API void FillRect(const Graphics &g, const Rect &, Color c)
填充标准矩形。
Definition: ydraw.cpp:146
YSLib::UI::Invalidate
YF_API void Invalidate(IWidget &, const Rect &)
无效化：使相对于部件的指定区域在直接和间接的窗口缓冲区中无效。
Definition: ywidget.cpp:111
YSLib::UI::MHilightText::HilightTextColor
Color HilightTextColor
高亮文本色。
Definition: label.h:249
YSLib::UI::Caret::CaretTimer
Timers::Timer CaretTimer
决定是否显示插入符的计时器。
Definition: TextBox.h:59
YSLib::UI::PaintEventArgs
部件绘制参数。
Definition: ywgtevt.h:276
YSLib::UI::TextBox::Selection
TextSelection Selection
选择区域：结束位置指示插入符光标逻辑位置。
Definition: TextBox.h:146
YSLib::UI::Caret::CaretBrush
HBrush CaretBrush
插入符画刷。 484
Definition: TextBox.h:64
platform::KeyCategory::Editing
表示编辑键（如回车、空格、退格、插入、删除和制表符）
Definition: Keys.h:121
YSLib::Timers::Timer::RefreshRemainder
Duration RefreshRemainder()
刷新：对于非零时间间隔判断有效性并都更新时间基点。
Definition: ytimer.cpp:106
YSLib::UI::TextSelection::Range
Span Range
选择的范围。
Definition: TextBox.h:104
YSLib::UI::UIEventArgs
用户界面事件参数基类。
Definition: ywgtevt.h:59
platform::SDst
std::uint16_t SDst
屏幕坐标距离。
Definition: Video.h:39
YSLib::UI::Caret::CursorInvalidator
InvalidationUpdater::Invalidator CursorInvalidator
供闪烁动画使用的指定无效化区域的光标位置刷新器。
Definition: TextBox.h:69
YSLib::UI::Restart
_fCallable void Restart(_tAnimation &ani, IWidget &wgt, _fCallable f)
Definition: Animation.h:177
YSLib::UI::MHilightText::HilightBackColor
Color HilightBackColor
高亮背景色。
Definition: label.h:247
YSLib::Timers::Timer::Interval
Duration Interval
重复刷新有效的最小时间间隔。
Definition: ytimer.h:111
YSLib::UI::Control
控件。
Definition: ycontrol.h:275
YSLib::Drawing::CustomTextRenderer
定制文本渲染器：使用自定义的渲染函数替代的 TextRenderer 。
Definition: TextRenderer.h:416
YSLib::UI::IsFocusedCascade
YF_API bool IsFocusedCascade(const IWidget &, const IWidget *={})
判断部件相对于指针指定的部件是否具有级联焦点。
Definition: yfocus.cpp:122
YSLib::UI::TextBox::PaintDefaultCaret
void PaintDefaultCaret(PaintEventArgs &&)
绘制默认插入符。
Definition: TextBox.cpp:291
YSLib::UI::TextBox
文本框。
Definition: TextBox.h:128
YSLib::UI::MLabel::Text
String Text
标签文本。
Definition: label.h:76
ystdex::swap
void swap(any &x, any &y)
交换对象。
Definition: any.h:729
cast.hpp
C++ 转换模板。
YSLib::UI::MLabel::DrawClippedText
const PaintContext &virtual void DrawClippedText(const Graphics &, const Rect &, Drawing::TextState &)
绘制剪切文本：使用指定的图形接口上下文、相对于部件的边界和文本状态。
Definition: label.cpp:100
YSLib::Drawing::FetchCharWidth
YF_API SDst FetchCharWidth(const Font &, ucs4_t)
取指定的字符使用指定字体的显示宽度。
Definition: TextLayout.cpp:71
YSLib::Text::String
YSLib 标准字符串（使用 UCS-2 作为内部编码）。
Definition: ystring.h:47
YSLib::UI::InvalidateVisible
YF_API void InvalidateVisible(IWidget &, const Rect &)
无效化：使相对于可见的部件的指定区域在直接和间接的窗口缓冲区中无效。
Definition: ywidget.cpp:151
YSLib::Drawing::Point
GBinaryGroup< SPos > Point
屏幕二维点（直角坐标表示）。
Definition: ygdibase.h:235
yunseq
#define yunseq
无序列依赖表达式组求值。
Definition: ydef.h:748
YSLib::UI::wgt
_tWidget & wgt
Definition: ywgtevt.h:596
YSLib::Drawing::DrawText
YF_API void DrawText(const Graphics &g, TextState &ts, const String &str, bool line_wrap)
绘制文本。
Definition: TextRenderer.cpp:236
YSLib::Drawing::TextState
文本状态。
Definition: TextBase.h:87
YSLib::UI::TextBox::TextBox
TextBox(const Rect &={}, const Drawing::Font &={}, const pair< Drawing::Color, Drawing::Color > &=FetchGUIState().Colors.GetPair(Styles::Highlight, Styles::HighlightText))
构造：使用指定边界、字体和高亮背景色/文本色对。
Definition: TextBox.cpp:90
YSLib::Drawing::TextRenderer
文本渲染器：简单实现。
Definition: TextRenderer.h:361
YSLib::Drawing::Rect
屏幕标准矩形：表示屏幕矩形区域。
Definition: ygdibase.h:416
YSLib::UI::RoutedEventArgs::Direct
直接事件：仅当遍历至目标控件时触发。
Definition: ywgtevt.h:104
YSLib::UI::Caret::Caret
Caret(IWidget &, HBrush, InvalidationUpdater::Invalidator)
构造：注册插入符光标动画的事件处理器和画刷。
Definition: TextBox.cpp:44
YSLib::Drawing::PenStyle::Color
Drawing::Color Color
笔颜色。
Definition: TextBase.h:58
YSLib::Drawing::GBinaryGroup::X
_type X
Definition: ygdibase.h:59
YSLib::UI::HBrush
std::function< void(PaintEventArgs &&)> HBrush
画刷回调函数。
Definition: YComponent.h:104
YSLib::UI::LocateForWidget
YF_API Point LocateForWidget(const IWidget &, const IWidget &)
取第二参数指定的部件相对于第一参数指定的部件的偏移坐标。
Definition: yuicont.cpp:74
YSLib::UI::MLabel::AutoWrapLine
bool AutoWrapLine
启用自动换行。
Definition: label.h:73
YSLib::Drawing::Graphics
二维图形接口上下文。
Definition: ygdibase.h:721
YSLib::UI::Caret::Stop
static void Stop()
停止插入符光标动画。
Definition: TextBox.cpp:82
YSLib::UI::Caret::Check
bool Check(IWidget &)
检查是否需要对指定部件进行绘制。
Definition: TextBox.cpp:69
YSLib::UI::TextBox::InvalidateDefaultCaret
static bool InvalidateDefaultCaret(IWidget &)
无效化默认插入符。
Definition: TextBox.cpp:262
YSLib::UI::IsEnabled
bool IsEnabled(const IWidget &wgt)
判断部件是否为可用的控件。
Definition: ycontrol.h:86
YSLib::UI::MLabel::Margin
Drawing::Padding Margin
文本和容器的间距。
Definition: label.h:62
YSLib::UI::TextBox::h_offset
SDst h_offset
文字区域水平基准负偏移：文本内容在光标回退方向超出的未显示部分大小。
Definition: TextBox.h:158
YSLib::UI::TextBox::ReplaceSelection
void ReplaceSelection(const String &)
替换选中文本。
Definition: TextBox.cpp:277
YSLib::Drawing::Padding::Left
SPos Left
Definition: ygdi.h:52
YSLib::UI::BorderArea::Left
YSLib::UI::MHilightText
高亮文本模块。
Definition: label.h:243
YSLib::UI::TextBox::DrawClippedText
DefDeMoveCtor(TextBox) TextSelection void DrawClippedText(const Graphics &, const Rect &, TextState &) override
取指定点所在的插入符光标逻辑位置。
Definition: TextBox.cpp:224
YSLib::UI::InvalidationUpdater::Invalidator
std::function< bool(IWidget &)> Invalidator
Definition: Animation.h:128
platform::KeyCategory::FindFirstKeyInCategroy
YF_API KeyIndex FindFirstKeyInCategroy(const KeyInput &, KeyIndex) ynothrow
找到第一个在指定类别的按键编码。
Definition: Keys.cpp:594
CHRLib::ucs4_t
char32_t ucs4_t
UCS-4 字符类型。
Definition: chrdef.h:45
YSLib::Drawing::r
bounds & r
Definition: ydraw.h:220
YSLib::Drawing::PutText
void PutText(bool multi, _tParams &&...args)
打印文本。
Definition: TextRenderer.h:281
YSLib::UI::MLabel
标签模块。
Definition: label.h:58
YSLib::Drawing::g
c yconstfn g
Definition: ystyle.h:104
YSLib::Drawing::Font
字体：字模，包含字型、样式和大小。
Definition: Font.h:546
YSLib::UI::Widget::ForeColor
Color ForeColor
默认前景色。
Definition: ywidget.h:375
CHRLib::c
c
Definition: chrproc.h:76
platform::KeyCategory::Navigation
表示导航键（如方向键和 PgUp ）、菜单键和 Esc 。
Definition: Keys.h:119
YSLib::Drawing::Font::GetHeight
FontSize GetHeight() const ynothrow
取字体对应的字符高度。
Definition: Font.cpp:527
YSLib::IsInInterval
bool IsInInterval(_type i, _type b) ynothrow
判断 i 是否在左闭右开区间 [FetchZero<_type>(), b) 中。
Definition: ycutil.h:140
YSLib::UI::Caret::caret_animation
static GAnimationSession< InvalidationUpdater > caret_animation
插入符闪烁动画。
Definition: TextBox.h:55
YSLib::UI::CursorEventArgs
指针设备输入事件参数类。
Definition: ywgtevt.h:183
YAssert
#define YAssert(_expr, _msg)
Definition: cassert.h:73
YSLib::UI::BackgroundPriority
yconstexpr EventPriority BackgroundPriority(0xC0)
用户界面绘制优先级。
YSLib::UI::Caret::~Caret
~Caret()
Definition: TextBox.cpp:63