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
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
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
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 
236  : Frame(frm), mMenus(), Roots()
237 {}
239 {
240  HideAll();
241  Clear();
242 }
243 
244 void
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
254 {
255  mMenus[mnu.id] = &mnu;
256  mnu.pHost = this;
257 }
258 
259 bool
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
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
294 {
295  std::for_each(mMenus.begin(), mMenus.end(), delete_second_mem());
296  mMenus.clear();
297 }
298 
299 void
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
322 {
323  Frame.Add(mnu, z);
324 //依赖于 mnu 的 GotFocus 事件默认会调用自身的 Invalidate 函数。
325 // Invalidate(mnu);
326  RequestFocus(mnu);
327 }
328 
329 void
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
352 {
353  ReleaseFocus(mnu);
354  if(IsVisible(mnu))
355  Invalidate(mnu);
356  Frame -= mnu;
357 }
358 
359 void
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 
bool operator-=(IndexType)
向菜单组移除指定子菜单索引项。
Definition: menu.cpp:119
void Hide(Menu::ID)
隐藏菜单组中菜单标识指定的菜单。
Definition: menu.cpp:330
void DrawItem(const Graphics &, const Rect &mask, const Rect &, ListType::size_type) override
绘制菜单项。
Definition: menu.cpp:209
YF_API void SetLocationOf(IWidget &, const Point &)
设置部件左上角所在位置(相对于容器的偏移坐标)。
Definition: ywidget.cpp:73
YF_API GUIState & FetchGUIState()
取默认图形用户界面公共状态。
Definition: ygui.cpp:442
按键输入事件参数类。
Definition: ywgtevt.h:167
YF_API void Invalidate(IWidget &, const Rect &)
无效化:使相对于部件的指定区域在直接和间接的窗口缓冲区中无效。
Definition: ywidget.cpp:111
Window & Frame
框架窗口。
Definition: menu.h:191
bool Contains(IWidget &)
判断是否包含指定部件。
Definition: yuicont.cpp:222
#define delete_second_mem
Definition: ycutil.h:439
bool Show(ZOrderType=DefaultMenuZOrder)
按指定 Z 顺序显示菜单。
Definition: menu.cpp:168
const class ystdex::nullptr_t nullptr
YF_API void LocateMenu(Menu &, const Menu &, Menu::IndexType)
定位菜单:以第二个参数作为参考父菜单,按指定参考偏移索引定位菜单。
Definition: menu.cpp:228
SDst Height
宽和高。
Definition: ygdibase.h:258
窗口。
Definition: ywindow.h:44
用户界面事件参数基类。
Definition: ywgtevt.h:59
Menu pParent void SetItemEnabled(ListType::size_type idx, bool=true)
设置 idx 指定的菜单项的可用性。
Definition: menu.cpp:145
bool IsItemEnabled(ListType::size_type) const
判断菜单项是否有效。
Definition: menu.cpp:137
Menu is not ShowRaw(mnu, z)) void ShowAll(ZOrderType
按指定 Z 顺序显示菜单组中的所有菜单。
void Add(IWidget &, ZOrderType=DefaultZOrder) override
Definition: ywindow.cpp:86
bool Hide()
隐藏菜单。
Definition: menu.cpp:198
virtual bool CheckConfirmed(ListType::size_type) const
检查列表中的指定项是否有效。
bool CheckConfirmed(ListType::size_type) const override
检查列表中的指定项是否可用。
Definition: menu.cpp:162
size_t ID
菜单标识类型。
Definition: menu.h:55
void HideUnrelated(Menu &mnu, Menu &mnuParent)
隐藏从 mnu 起向上层遍历菜单树的过程中不相关的菜单。
Definition: menu.cpp:360
const second_tag get_value
Definition: iterator.hpp:785
bool CyclicTraverse
循环选择遍历。
Definition: textlist.h:83
GBinaryGroup< SPos > Point
屏幕二维点(直角坐标表示)。
Definition: ygdibase.h:235
#define yunseq
无序列依赖表达式组求值。
Definition: ydef.h:748
void operator+=(const ValueType &)
向菜单组添加标识和指针指定的菜单。
Definition: menu.cpp:245
MenuMap::value_type ValueType
Definition: menu.h:189
virtual ~MenuHost()
析构。
Definition: menu.cpp:238
void Show(Menu::ID, ZOrderType=DefaultMenuZOrder)
按指定 Z 顺序显示菜单组中菜单标识指定的菜单。
Definition: menu.cpp:300
屏幕标准矩形:表示屏幕矩形区域。
Definition: ygdibase.h:416
高亮背景。
Definition: ystyle.h:190
map< IWidget *, Menu::ID > Roots
根菜单关联映射。
Definition: menu.h:203
Menu * ItemType
菜单组项目类型:记录菜单控件指针。
Definition: menu.h:187
Menu is not HideRaw(mnu)) void HideAll()
隐藏菜单组中的所有菜单。
Menu * pParent
父菜单指针。
Definition: menu.h:64
u8 ZOrderType
Definition: yuicont.h:146
Styles::Palette Colors
调色板。
Definition: ygui.h:124
#define YAssertNonnull(_expr)
Definition: cassert.h:81
面板背景。
Definition: ystyle.h:183
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
virtual void DrawItem(const Graphics &, const Rect &mask, const Rect &, ListType::size_type)
绘制列表项。
Menu * ShowSub(IndexType, ZOrderType=DefaultMenuZOrder)
按指定 Z 顺序显示索引指定的子菜单。
Definition: menu.cpp:179
二维图形接口上下文。
Definition: ygdibase.h:721
bool operator-=(Menu::ID)
从菜单组移除菜单标识指定的菜单。
Definition: menu.cpp:260
简单 UI 事件参数类。
Definition: ywgtevt.h:252
vector< bool > vDisabled
未启用菜单项。
Definition: menu.h:66
MenuMap mMenus
菜单组:存储非空菜单指针。
Definition: menu.h:194
Selected const shared_ptr< ListType > const pair< Color, Color > viewer Contains
Definition: textlist.h:124
文本菜单。
Definition: menu.h:50
MenuHost * pHost
宿主指针。
Definition: menu.h:63
空白样式。
Definition: ygdi.h:46
YF_API void DrawArrow(const Graphics &, const Rect &, SDst=4, Rotation=RDeg0, Color=ColorSpace::Black)
在指定图形接口上下文上描画箭头。
Definition: ystyle.cpp:100
MenuHost(Window &)
Definition: menu.cpp:235
单色画刷。
Definition: YBrush.h:46
bounds & r
Definition: ydraw.h:220
bool exists(const _tCon &con, const _tKey &key)
判断指定的容器中存在指定的键。
Definition: container.hpp:373
c yconstfn g
Definition: ystyle.h:104
#define YB_LIKELY(expr)
Definition: ydef.h:297
void AdjustSize() const
调整 vDisabled 大小。
Definition: menu.cpp:153
颜色。
Definition: Video.h:339
ID id
菜单标识。
Definition: menu.h:60
bool IsInInterval(_type i, _type b) ynothrow
判断 i 是否在左闭右开区间 [FetchZero<_type>(), b) 中。
Definition: ycutil.h:140
SubMap mSubMenus
子菜单映射表:存储非空子菜单指针。
Definition: menu.h:65
#define YAssert(_expr, _msg)
Definition: cassert.h:73
框架背景。
Definition: ystyle.h:189
Menu(const Rect &={}, const shared_ptr< ListType > &={}, ID=0)
构造:使用指定边界、文本列表和菜单标识。
Definition: menu.cpp:42