YSTest: menu.cpp 源文件

YSTest PreAlpha_b500_20140530 The YSLib Test Project

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

- 文件列表
- 文件成员

全部 类 命名空间 文件 函数 变量 类型定义 枚举 枚举值 友元 宏定义 组 页
menu.cpp
浏览该文件的文档.
1 /*
2 © 2011-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_Menu
30 #include YFM_YSLib_UI_YWindow
31 #include YFM_YSLib_UI_YBrush
32 #include YFM_YSLib_Service_TextRenderer
33
34 namespace YSLib
35 {
36
37 using namespace Drawing;
38
39 namespace UI
40 {
41
42 Menu::Menu(const Rect& r, const shared_ptr<ListType>& h, ID id)
43 : TextList(r, h, FetchGUIState().Colors.GetPair(Styles::Highlight,
44 Styles::HighlightText)),
45 id(id), pParent(nullptr), mSubMenus(), vDisabled(h ? h->size() : 0)
46 {
47 Background = SolidBrush(FetchGUIState().Colors[Styles::Panel]),
48 Margin = Padding(6, 18, 4, 4);
49 CyclicTraverse = true;
50 yunseq(
51 FetchEvent<KeyDown>(*this) += [this](KeyEventArgs&& e){
52 if(pHost)
53 {
54 const auto& k(e.GetKeys());
55
56 if(k.count() == 1)
57 {
58 if(k[KeyCodes::Right])
59 {
60 if(IsSelected())
61 if(const auto p_mnu = ShowSub(GetSelectedIndex()))
62 p_mnu->SelectFirst();
63 }
64 else if(k[KeyCodes::Left] || k[KeyCodes::Esc])
65 {
66 if(const auto p_mnu = GetParentPtr())
67 RequestFocus(*p_mnu);
68 else if(k[KeyCodes::Esc])
69 Hide();
70 }
71 }
72 }
73 },
74 FetchEvent<LostFocus>(*this) += [this](UIEventArgs&& e){
75 if(pHost)
76 {
77 {
78 const auto i(pHost->Roots.find(&e.GetSender()));
79
80 if(i != pHost->Roots.end())
81 {
82 auto p_mnu(this);
83
84 while(const auto pParent = p_mnu->GetParentPtr())
85 p_mnu = pParent;
86 if(i->second == p_mnu->id)
87 return;
88 }
89 }
90 if(const auto p_mnu = dynamic_cast<Menu*>(&e.GetSender()))
91 {
92 if(p_mnu->GetParentPtr() != this)
93 pHost->HideUnrelated(*this, *p_mnu);
94 }
95 else
96 pHost->HideAll();
97 }
98 },
99 Confirmed += [this](IndexEventArgs&& e){
100 if(Contains(e) && pHost && !ShowSub(e.Value))
101 pHost->HideAll();
102 }
103 );
104 //刷新文本状态，防止第一次绘制前不确定文本间距，无法正确根据内容重设大小。
105 RefreshTextState();
106 }
107
108 void
109 Menu::operator+=(const ValueType& val)
110 {
111 if(val.second && IsInInterval(val.first, GetList().size()))
112 {
113 val.second->pParent = this;
114 mSubMenus.insert(val);
115 }
116 }
117
118 bool
119 Menu::operator-=(IndexType idx)
120 {
121 if(IsInInterval(idx, GetList().size()))
122 {
123 const auto i(mSubMenus.find(idx));
124
125 if(i != mSubMenus.end() && i->second)
126 {
127 i->second->pParent = {};
128 mSubMenus.erase(i);
129 return true;
130 }
131 return false;
132 }
133 return false;
134 }
135
136 bool
137 Menu::IsItemEnabled(ListType::size_type idx) const
138 {
139 YAssert(IsInInterval(idx, GetList().size()), "Index is out of range.");
140 AdjustSize();
141 return !vDisabled[idx];
142 }
143
144 void
145 Menu::SetItemEnabled(Menu::ListType::size_type idx, bool b)
146 {
147 YAssert(IsInInterval(idx, GetList().size()), "Index is out of range.");
148 AdjustSize();
149 vDisabled[idx] = !b;
150 }
151
152 void
153 Menu::AdjustSize() const
154 {
155 const auto list_size(GetList().size());
156
157 if(vDisabled.size() != list_size)
158 vDisabled.resize(list_size);
159 }
160
161 bool
162 Menu::CheckConfirmed(Menu::ListType::size_type idx) const
163 {
164 return TextList::CheckConfirmed(idx) && IsItemEnabled(idx);
165 }
166
167 bool
168 Menu::Show(ZOrderType z)
169 {
170 if(pHost)
171 {
172 pHost->Show(id, z);
173 return true;
174 }
175 return false;
176 }
177
178 Menu*
179 Menu::ShowSub(IndexType idx, ZOrderType z)
180 {
181 if(pHost)
182 {
183 const auto i(mSubMenus.find(idx));
184
185 if(i != mSubMenus.end())
186 {
187 auto& mnu(*i->second);
188
189 LocateMenu(mnu, *this, idx);
190 mnu.Show(z);
191 return &mnu;
192 }
193 }
194 return nullptr;
195 }
196
197 bool
198 Menu::Hide()
199 {
200 if(pHost)
201 {
202 pHost->Hide(id);
203 return true;
204 }
205 return false;
206 }
207
208 void
209 Menu::DrawItem(const Graphics& g, const Rect& mask, const Rect& unit,
210 ListType::size_type i)
211 {
212 Color t(tsList.Color);
213
214 // TODO: Handle different highlight text colors.
215
216 if(!IsItemEnabled(i))
217 tsList.Color = FetchGUIState().Colors[Styles::GrayText];
218 TextList::DrawItem(g, mask, unit, i);
219 tsList.Color = t;
220 if(YB_LIKELY(unit.Width > 16))
221 if(ystdex::exists(mSubMenus, i))
222 DrawArrow(g, Rect(unit.X + unit.Width - 16, unit.Y, 16,
223 unit.Height) & mask, 4, RDeg0, ForeColor);
224 }
225
226
227 void
228 LocateMenu(Menu& dst, const Menu& src, Menu::IndexType idx)
229 {
230 SetLocationOf(dst, Point(src.GetX() + src.GetWidth(),
231 src.GetY() + src.GetItemHeight() * idx));
232 }
233
234
235 MenuHost::MenuHost(Window& frm)
236 : Frame(frm), mMenus(), Roots()
237 {}
238 MenuHost::~MenuHost()
239 {
240 HideAll();
241 Clear();
242 }
243
244 void
245 MenuHost::operator+=(const ValueType& val)
246 {
247 YAssertNonnull(val.second);
248 yunseq(mMenus[val.first] = val.second,
249 val.second->id = val.first, val.second->pHost = this);
250 }
251
252 void
253 MenuHost::operator+=(Menu& mnu)
254 {
255 mMenus[mnu.id] = &mnu;
256 mnu.pHost = this;
257 }
258
259 bool
260 MenuHost::operator-=(Menu::ID id)
261 {
262 const auto i(mMenus.find(id));
263
264 if(i != mMenus.end())
265 {
266 auto& mnu(*i->second);
267
268 mnu.pHost = {};
269 mMenus.erase(i);
270 return true;
271 }
272 return false;
273 }
274
275 bool
276 MenuHost::IsShowing(Menu::ID id)
277 {
278 const auto i(mMenus.find(id));
279
280 return i == mMenus.end() ? false : Frame.Contains(*i->second);
281 }
282
283 bool
284 MenuHost::Contains(Menu& mnu)
285 {
286 using ystdex::get_value;
287
288 return std::find(mMenus.begin() | get_value, mMenus.end() | get_value, &mnu)
289 != mMenus.end();
290 }
291
292 void
293 MenuHost::Clear()
294 {
295 std::for_each(mMenus.begin(), mMenus.end(), delete_second_mem());
296 mMenus.clear();
297 }
298
299 void
300 MenuHost::Show(Menu::ID id, ZOrderType z)
301 {
302 const auto i(mMenus.find(id));
303
304 if(i != mMenus.end())
305 ShowRaw(*i->second, z);
306 }
307
308 void
309 MenuHost::ShowAll(ZOrderType z)
310 {
311 using ystdex::get_value;
312
313 std::for_each(mMenus.cbegin() | get_value, mMenus.cend() | get_value,
314 [this, z](const ItemType& p_mnu){
315 if(p_mnu)
316 ShowRaw(*p_mnu, z);
317 });
318 }
319
320 void
321 MenuHost::ShowRaw(Menu& mnu, ZOrderType z)
322 {
323 Frame.Add(mnu, z);
324 //依赖于 mnu 的 GotFocus 事件默认会调用自身的 Invalidate 函数。
325 // Invalidate(mnu);
326 RequestFocus(mnu);
327 }
328
329 void
330 MenuHost::Hide(Menu::ID id)
331 {
332 const auto i(mMenus.find(id));
333
334 if(i != mMenus.end())
335 HideRaw(*i->second);
336 }
337
338 void
339 MenuHost::HideAll()
340 {
341 using ystdex::get_value;
342
343 std::for_each(mMenus.cbegin() | get_value, mMenus.cend() | get_value,
344 [this](const ItemType& p_mnu){
345 if(p_mnu)
346 HideRaw(*p_mnu);
347 });
348 }
349
350 void
351 MenuHost::HideRaw(Menu& mnu)
352 {
353 ReleaseFocus(mnu);
354 if(IsVisible(mnu))
355 Invalidate(mnu);
356 Frame -= mnu;
357 }
358
359 void
360 MenuHost::HideUnrelated(Menu& mnu, Menu& mnuParent)
361 {
362 if(Contains(mnuParent))
363 {
364 auto p_mnu(&mnu);
365
366 while(p_mnu && p_mnu != &mnuParent)
367 {
368 const auto i(mMenus.find(p_mnu->GetID()));
369
370 if(i != mMenus.end())
371 HideRaw(*i->second);
372 p_mnu = p_mnu->GetParentPtr();
373 }
374 if(!p_mnu)
375 HideAll();
376 }
377 else
378 HideAll();
379 }
380
381 } // namespace UI;
382
383 } // namespace YSLib;
384
YSLib::UI::Menu::operator-=
bool operator-=(IndexType)
向菜单组移除指定子菜单索引项。
Definition: menu.cpp:119
YSLib::UI::BorderArea::Right
YSLib::UI::MenuHost::Hide
void Hide(Menu::ID)
隐藏菜单组中菜单标识指定的菜单。
Definition: menu.cpp:330
YSLib::UI::Menu::DrawItem
void DrawItem(const Graphics &, const Rect &mask, const Rect &, ListType::size_type) override
绘制菜单项。
Definition: menu.cpp:209
YModules.h
YSLib::UI::SetLocationOf
YF_API void SetLocationOf(IWidget &, const Point &)
设置部件左上角所在位置（相对于容器的偏移坐标）。
Definition: ywidget.cpp:73
YSLib::UI::FetchGUIState
YF_API GUIState & FetchGUIState()
取默认图形用户界面公共状态。
Definition: ygui.cpp:442
YSLib::UI::KeyEventArgs
按键输入事件参数类。
Definition: ywgtevt.h:167
YSLib::UI::Invalidate
YF_API void Invalidate(IWidget &, const Rect &)
无效化：使相对于部件的指定区域在直接和间接的窗口缓冲区中无效。
Definition: ywidget.cpp:111
YSLib::UI::MenuHost::Frame
Window & Frame
框架窗口。
Definition: menu.h:191
YSLib::UI::MUIContainer::Contains
bool Contains(IWidget &)
判断是否包含指定部件。
Definition: yuicont.cpp:222
YSLib::UI::IsVisible
IsVisible
Definition: ywidget.h:96
delete_second_mem
#define delete_second_mem
Definition: ycutil.h:439
YSLib::UI::Menu::Show
bool Show(ZOrderType=DefaultMenuZOrder)
按指定 Z 顺序显示菜单。
Definition: menu.cpp:168
ystdex::nullptr
const class ystdex::nullptr_t nullptr
YSLib::UI::LocateMenu
YF_API void LocateMenu(Menu &, const Menu &, Menu::IndexType)
定位菜单：以第二个参数作为参考父菜单，按指定参考偏移索引定位菜单。
Definition: menu.cpp:228
YSLib::Drawing::Size::Height
SDst Height
宽和高。
Definition: ygdibase.h:258
YSLib::UI::Window
窗口。
Definition: ywindow.h:44
YSLib::UI::UIEventArgs
用户界面事件参数基类。
Definition: ywgtevt.h:59
YSLib::UI::Menu::SetItemEnabled
Menu pParent void SetItemEnabled(ListType::size_type idx, bool=true)
设置 idx 指定的菜单项的可用性。
Definition: menu.cpp:145
YSLib::UI::Menu::IsItemEnabled
bool IsItemEnabled(ListType::size_type) const
判断菜单项是否有效。
Definition: menu.cpp:137
YSLib::UI::MenuHost::ShowRaw
Menu is not ShowRaw(mnu, z)) void ShowAll(ZOrderType
按指定 Z 顺序显示菜单组中的所有菜单。
YSLib::UI::Window::Add
void Add(IWidget &, ZOrderType=DefaultZOrder) override
Definition: ywindow.cpp:86
YSLib::UI::Menu::Hide
bool Hide()
隐藏菜单。
Definition: menu.cpp:198
YSLib::UI::CheckConfirmed
virtual bool CheckConfirmed(ListType::size_type) const
检查列表中的指定项是否有效。
YSLib::UI::Menu::CheckConfirmed
bool CheckConfirmed(ListType::size_type) const override
检查列表中的指定项是否可用。
Definition: menu.cpp:162
YSLib::UI::Menu::ID
size_t ID
菜单标识类型。
Definition: menu.h:55
YSLib::UI::MenuHost::HideUnrelated
void HideUnrelated(Menu &mnu, Menu &mnuParent)
隐藏从 mnu 起向上层遍历菜单树的过程中不相关的菜单。
Definition: menu.cpp:360
ystdex::get_value
const second_tag get_value
Definition: iterator.hpp:785
YSLib::UI::CyclicTraverse
bool CyclicTraverse
循环选择遍历。
Definition: textlist.h:83
YSLib::Drawing::Point
GBinaryGroup< SPos > Point
屏幕二维点（直角坐标表示）。
Definition: ygdibase.h:235
yunseq
#define yunseq
无序列依赖表达式组求值。
Definition: ydef.h:748
YSLib::UI::MenuHost::operator+=
void operator+=(const ValueType &)
向菜单组添加标识和指针指定的菜单。
Definition: menu.cpp:245
YSLib::UI::MenuHost::ValueType
MenuMap::value_type ValueType
Definition: menu.h:189
YSLib::UI::MenuHost::~MenuHost
virtual ~MenuHost()
析构。
Definition: menu.cpp:238
YSLib::Drawing::GBinaryGroup::Y
_type Y
分量。
Definition: ygdibase.h:59
YSLib::UI::MenuHost::Show
void Show(Menu::ID, ZOrderType=DefaultMenuZOrder)
按指定 Z 顺序显示菜单组中菜单标识指定的菜单。
Definition: menu.cpp:300
YSLib::Drawing::Rect
屏幕标准矩形：表示屏幕矩形区域。
Definition: ygdibase.h:416
YSLib::UI::Styles::Highlight
高亮背景。
Definition: ystyle.h:190
YSLib::UI::MenuHost::Roots
map< IWidget *, Menu::ID > Roots
根菜单关联映射。
Definition: menu.h:203
YSLib::UI::MenuHost::ItemType
Menu * ItemType
菜单组项目类型：记录菜单控件指针。
Definition: menu.h:187
YSLib::UI::MenuHost::HideRaw
Menu is not HideRaw(mnu)) void HideAll()
隐藏菜单组中的所有菜单。
YSLib::UI::Menu::pParent
Menu * pParent
父菜单指针。
Definition: menu.h:64
YSLib::UI::ZOrderType
u8 ZOrderType
Definition: yuicont.h:146
YSLib::UI::GUIState::Colors
Styles::Palette Colors
调色板。
Definition: ygui.h:124
YAssertNonnull
#define YAssertNonnull(_expr)
Definition: cassert.h:81
YSLib::UI::Styles::Panel
面板背景。
Definition: ystyle.h:183
YSLib::UI::MenuHost::Clear
PDefHOp(Menu &,[], Menu::ID id) ImplRet(*mMenus.at(id)) bool IsShowing(Menu PDefH(bool, Contains, Menu::ID id) ImplRet(ystdex voi Clear)()
访问菜单标识指定的菜单。 异常中立：由 at 抛出。
Definition: menu.h:262
YSLib::UI::DrawItem
virtual void DrawItem(const Graphics &, const Rect &mask, const Rect &, ListType::size_type)
绘制列表项。
YSLib::Drawing::GBinaryGroup::X
_type X
Definition: ygdibase.h:59
YSLib::UI::Menu::ShowSub
Menu * ShowSub(IndexType, ZOrderType=DefaultMenuZOrder)
按指定 Z 顺序显示索引指定的子菜单。
Definition: menu.cpp:179
YSLib::Drawing::Graphics
二维图形接口上下文。
Definition: ygdibase.h:721
YSLib::UI::MenuHost::operator-=
bool operator-=(Menu::ID)
从菜单组移除菜单标识指定的菜单。
Definition: menu.cpp:260
YSLib::UI::GValueEventArgs
简单 UI 事件参数类。
Definition: ywgtevt.h:252
YSLib::UI::Menu::vDisabled
vector< bool > vDisabled
未启用菜单项。
Definition: menu.h:66
YSLib::UI::MenuHost::mMenus
MenuMap mMenus
菜单组：存储非空菜单指针。
Definition: menu.h:194
YSLib::UI::Contains
Selected const shared_ptr< ListType > const pair< Color, Color > viewer Contains
Definition: textlist.h:124
YSLib::Drawing::RDeg0
Definition: ygdibase.h:870
YSLib::UI::Menu
文本菜单。
Definition: menu.h:50
YSLib::UI::BorderArea::Left
YSLib::UI::Menu::pHost
MenuHost * pHost
宿主指针。
Definition: menu.h:63
YSLib::Drawing::Padding
空白样式。
Definition: ygdi.h:46
YSLib::Drawing::DrawArrow
YF_API void DrawArrow(const Graphics &, const Rect &, SDst=4, Rotation=RDeg0, Color=ColorSpace::Black)
在指定图形接口上下文上描画箭头。
Definition: ystyle.cpp:100
YSLib::UI::MenuHost::MenuHost
MenuHost(Window &)
Definition: menu.cpp:235
YSLib::UI::SolidBrush
单色画刷。
Definition: YBrush.h:46
YSLib::Drawing::r
bounds & r
Definition: ydraw.h:220
ystdex::exists
bool exists(const _tCon &con, const _tKey &key)
判断指定的容器中存在指定的键。
Definition: container.hpp:373
YSLib::Drawing::g
c yconstfn g
Definition: ystyle.h:104
YB_LIKELY
#define YB_LIKELY(expr)
Definition: ydef.h:297
YSLib::UI::Menu::AdjustSize
void AdjustSize() const
调整 vDisabled 大小。
Definition: menu.cpp:153
platform::Color
颜色。
Definition: Video.h:339
YSLib::UI::Menu::id
ID id
菜单标识。
Definition: menu.h:60
YSLib::UI::Styles::HighlightText
Definition: ystyle.h:198
YSLib::IsInInterval
bool IsInInterval(_type i, _type b) ynothrow
判断 i 是否在左闭右开区间 [FetchZero<_type>(), b) 中。
Definition: ycutil.h:140
YSLib::Drawing::Size::Width
SDst Width
Definition: ygdibase.h:258
YSLib::UI::Menu::mSubMenus
SubMap mSubMenus
子菜单映射表：存储非空子菜单指针。
Definition: menu.h:65
YAssert
#define YAssert(_expr, _msg)
Definition: cassert.h:73
YSLib::UI::Styles::Frame
框架背景。
Definition: ystyle.h:189
YSLib::UI::Menu::Menu
Menu(const Rect &={}, const shared_ptr< ListType > &={}, ID=0)
构造：使用指定边界、文本列表和菜单标识。
Definition: menu.cpp:42
YSLib::UI::Styles::GrayText
Definition: ystyle.h:201