FINAL CUT
fmenu.h
1 /***********************************************************************
2 * fmenu.h - Widget FMenu *
3 * *
4 * This file is part of the FINAL CUT widget toolkit *
5 * *
6 * Copyright 2015-2023 Markus Gans *
7 * *
8 * FINAL CUT is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU Lesser General Public License as *
10 * published by the Free Software Foundation; either version 3 of *
11 * the License, or (at your option) any later version. *
12 * *
13 * FINAL CUT is distributed in the hope that it will be useful, but *
14 * WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU Lesser General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU Lesser General Public *
19 * License along with this program. If not, see *
20 * <http://www.gnu.org/licenses/>. *
21 ***********************************************************************/
22 
23 /* Inheritance diagram
24  * ═══════════════════
25  *
26  * ▕▔▔▔▔▔▔▔▔▔▏ ▕▔▔▔▔▔▔▔▔▔▏
27  * ▕ FVTerm ▏ ▕ FObject ▏
28  * ▕▁▁▁▁▁▁▁▁▁▏ ▕▁▁▁▁▁▁▁▁▁▏
29  * ▲ ▲
30  * │ │ *▕▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▏
31  * └─────┬─────┘ ┌ - -▕ FRadioMenuItem ▏
32  * │ : ▕▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▏
33  * ▕▔▔▔▔▔▔▔▔▔▏ :
34  * ▕ FWidget ▏ : *▕▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▏
35  * ▕▁▁▁▁▁▁▁▁▁▏ ├ - -▕ FCheckMenuItem ▏
36  * ▲ : ▕▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▏
37  * │ 1 :
38  * ▕▔▔▔▔▔▔▔▔▔▏ ▕▔▔▔▔▔▔▔▔▔▔▔▏- ┘ ▕▔▔▔▔▔▔▔▔▔▔▔▏
39  * ▕ FWindow ▏ ▕ FMenuList ▏- - - -▕ FMenuItem ▏
40  * ▕▁▁▁▁▁▁▁▁▁▏ ▕▁▁▁▁▁▁▁▁▁▁▁▏1 *▕▁▁▁▁▁▁▁▁▁▁▁▏
41  * ▲ ▲ 1:
42  * │ │ :
43  * └─────┬─────┘ :
44  * │ 1 :
45  * ▕▔▔▔▔▔▔▔▏- - - ┘ ▕▔▔▔▔▔▔▔▔▔▔▔▏
46  * ▕ FMenu ▏- - - - - - - -▕ FMenuItem ▏
47  * ▕▁▁▁▁▁▁▁▏1 1▕▁▁▁▁▁▁▁▁▁▁▁▏
48  */
49 
50 #ifndef FMENU_H
51 #define FMENU_H
52 
53 #if !defined (USE_FINAL_H) && !defined (COMPILE_FINAL_CUT)
54  #error "Only <final/final.h> can be included directly."
55 #endif
56 
57 #include <memory>
58 #include <tuple>
59 
60 #include "final/fevent.h"
61 #include "final/menu/fmenulist.h"
62 #include "final/widget/fwindow.h"
63 
64 namespace finalcut
65 {
66 
67 // class forward declaration
68 class FMenuBar;
69 class FMenuItem;
70 
71 //----------------------------------------------------------------------
72 // class FMenu
73 //----------------------------------------------------------------------
74 
75 class FMenu : public FWindow
76  , public FMenuList
77 {
78  public:
79  // Using-declaration
80  using FMenuList::getItem;
81  using FMenuList::isSelected;
82 
83  // Constructor
84  explicit FMenu (FWidget* = nullptr);
85  explicit FMenu (FString&&, FWidget* = nullptr);
86 
87  // Disable copy constructor
88  FMenu (const FMenu&) = delete;
89 
90  // Disable move constructor
91  FMenu (FMenu&&) noexcept = delete;
92 
93  // Destructor
94  ~FMenu() override;
95 
96  // Disable copy assignment operator (=)
97  auto operator = (const FMenu&) -> FMenu& = delete;
98 
99  // Disable move assignment operator (=)
100  auto operator = (FMenu&&) noexcept -> FMenu& = delete;
101 
102  // Accessors
103  auto getClassName() const -> FString override;
104  auto getText() const -> FString;
105  auto getItem() -> FMenuItem*;
106 
107  // Mutators
108  void setEnable (bool = true) override;
109  void unsetEnable() override;
110  void setDisable() override;
111  void setSelected();
112  void unsetSelected();
113  void setMenuWidget (bool = true);
114  void unsetMenuWidget();
115  void setStatusbarMessage (const FString&) override;
116  void setMenu (FMenu*);
117  void setText (const FString&);
118  void resetColors() override;
119 
120  // Inquiries
121  auto isSelected() const -> bool;
122  auto hasHotkey() const -> bool;
123  auto hasMenu() const -> bool;
124 
125  // Methods
126  void show() override;
127  void hide() override;
128 
129  // Event handlers
130  void onKeyPress (FKeyEvent*) override;
131  void onMouseDown (FMouseEvent*) override;
132  void onMouseUp (FMouseEvent*) override;
133  void onMouseMove (FMouseEvent*) override;
134  void onAccel (FAccelEvent*) override;
135 
136  // Callback method
137  void cb_menuitemEnabled();
138  void cb_menuitemDisabled();
139  void cb_menuitemToggled (const FMenuItem*) const;
140 
141  private:
142  // Enumeration
143  enum class SelectItem { No, Yes };
144 
145  struct MouseStates
146  {
147  uChar focus_changed : 1;
148  uChar hide_sub_menu : 1;
149  uChar mouse_over_menu : 1;
150  uChar mouse_over_submenu : 1;
151  uChar mouse_over_supermenu : 1;
152  uChar mouse_over_menubar : 1;
153  uChar : 2; // padding bits
154  };
155 
156  struct MenuText
157  {
158  FString text;
159  std::size_t hotkeypos;
160  bool no_underline;
161  };
162 
163  // Constants
164  static constexpr auto NOT_SET = static_cast<std::size_t>(-1);
165 
166  // Accessors
167  auto getSuperMenu() const -> FWidget*;
168 
169  // Mutators
170  void setSuperMenu (FWidget*);
171 
172  // Inquiries
173  auto isDialog (const FWidget*) const -> bool;
174  auto isMenuBar (const FWidget*) const -> bool;
175  auto isMenu (const FWidget*) const -> bool;
176  auto isRadioMenuItem (const FWidget*) const -> bool;
177  auto isSubMenu() const -> bool;
178  auto isDialogMenu() const -> bool;
179  auto isMouseOverMenu (const FPoint&) -> bool;
180  auto isMouseOverSubMenu (const FPoint&) -> bool;
181  auto isMouseOverSuperMenu (const FPoint&) -> bool;
182  auto isMouseOverMenuBar (const FPoint&) const -> bool;
183 
184  // Methods
185  void init();
186  void initCallbacks();
187  void calculateDimensions();
188  void adjustItems() const;
189  auto adjustX(int) const -> int;
190  void openSubMenu (FMenu*, SelectItem);
191  void closeOpenedSubMenu();
192  void hideSubMenus();
193  void hideSuperMenus() const;
194  auto isMouseOverItem (const FPoint&, const FMenuItem*) const -> bool;
195  auto mouseDownOverList (const FPoint&) -> bool;
196  void mouseDownSubmenu (const FMenuItem*);
197  void mouseDownSelection (FMenuItem*, bool&);
198  auto mouseUpOverList (const FPoint&) -> bool;
199  auto initializeMouseStates (const FMouseEvent*) -> MouseStates;
200  void handleCloseSubMenu (const MouseStates& ms);
201  void mouseMoveOverList (const FPoint&, MouseStates&);
202  void mouseMoveSelection (FMenuItem*, MouseStates&);
203  void mouseMoveDeselection (FMenuItem*, MouseStates&);
204  void mouseUpOverBorder();
205  void mouseMoveOverBorder (MouseStates&) const;
206  auto handleSubMenuEvent (const MouseStates&, const FMouseEvent&) const -> bool;
207  void passEventToSubMenu (const FMouseEvent&) const;
208  auto handleSuperMenuEvent (const MouseStates&, const FMouseEvent&) -> bool;
209  void passEventToSuperMenu (const FMouseEvent&);
210  auto handleMenuBarEvent (const MouseStates&, const FMouseEvent&) const -> bool;
211  void passEventToMenuBar (const FMouseEvent&) const;
212  template <typename WidgetT>
213  void passEventToWidget (WidgetT, const FMouseEvent&) const;
214  auto containsMenuStructure (const FPoint&) -> bool;
215  auto containsMenuStructure (int, int) -> bool;
216  auto superMenuAt (const FPoint&) -> FMenu*;
217  auto superMenuAt (int, int) -> FMenu*;
218  void selectItem_PostProcessing (FMenuItem*) override;
219  void keypressMenuBar (FKeyEvent*) const;
220  auto hotkeyFound (FKey, const FKeyEvent&) const -> bool;
221  auto hotkeyMenu (FKeyEvent*) -> bool;
222  void draw() override;
223  void drawItems();
224  void drawSeparator (int);
225  void drawMenuLine (FMenuItem*, int);
226  void drawCheckMarkPrefix (const FMenuItem*);
227  void drawMenuText (MenuText&);
228  void drawSubMenuIndicator (std::size_t&);
229  void drawAcceleratorKey (std::size_t&, FKey);
230  void drawTrailingSpaces (std::size_t);
231  void setLineAttributes (const FMenuItem*, int);
232  void setCursorToHotkeyPosition (FMenuItem*) const;
233  void selectPrevMenu (FKeyEvent*);
234  void selectNextMenu (FKeyEvent*);
235  void acceptSelection();
236  void closeMenu();
237  void processActivate() const;
238 
239  // Data members
240  FMenuItem menuitem{};
241  FWidget* super_menu{nullptr};
242  FMenu* opened_sub_menu{nullptr};
243  FMenu* shown_sub_menu{nullptr};
244  std::size_t max_item_width{0};
245  std::size_t hotkeypos{NOT_SET};
246  bool mouse_down{false};
247  bool has_checkable_items{false};
248 
249  // Friend functions
250  friend auto closeOpenMenus (FMenu*, const FPoint&) -> std::tuple<bool, bool>;
251 
252  // Friend classes
253  friend class FCheckMenuItem;
254  friend class FDialog;
255  friend class FDialogListMenu;
256  friend class FMenuBar;
257  friend class FMenuItem;
258  friend class FRadioMenuItem;
259 };
260 
261 // non-member function forward declarations
262 //----------------------------------------------------------------------
263 auto closeOpenMenus (FMenu*, const FPoint&) -> std::tuple<bool, bool>;
264 
265 
266 // FMenu inline functions
267 //----------------------------------------------------------------------
268 inline auto FMenu::getClassName() const -> FString
269 { return "FMenu"; }
270 
271 //----------------------------------------------------------------------
272 inline auto FMenu::getText() const -> FString
273 { return menuitem.getText(); }
274 
275 //----------------------------------------------------------------------
276 inline auto FMenu::getItem() -> FMenuItem*
277 { return &menuitem; }
278 
279 //----------------------------------------------------------------------
280 inline void FMenu::setEnable (bool enable)
281 { menuitem.setEnable(enable); }
282 
283 //----------------------------------------------------------------------
284 inline void FMenu::unsetEnable()
285 { menuitem.unsetEnable(); }
286 
287 //----------------------------------------------------------------------
288 inline void FMenu::setDisable()
289 { menuitem.setDisable(); }
290 
291 //----------------------------------------------------------------------
292 inline void FMenu::setSelected()
293 { menuitem.setSelected(); }
294 
295 //----------------------------------------------------------------------
296 inline void FMenu::unsetSelected()
297 { menuitem.unsetSelected(); }
298 
299 //----------------------------------------------------------------------
300 inline void FMenu::unsetMenuWidget()
301 { setMenuWidget(false); }
302 
303 //----------------------------------------------------------------------
304 inline void FMenu::setMenu (FMenu* m)
305 { menuitem.setMenu(m); }
306 
307 //----------------------------------------------------------------------
308 inline void FMenu::setText (const FString& txt)
309 { menuitem.setText(txt); }
310 
311 //----------------------------------------------------------------------
312 inline auto FMenu::isSelected() const -> bool
313 { return menuitem.isSelected(); }
314 
315 //----------------------------------------------------------------------
316 inline auto FMenu::hasHotkey() const -> bool
317 { return menuitem.hasHotkey(); }
318 
319 //----------------------------------------------------------------------
320 inline auto FMenu::hasMenu() const -> bool
321 { return menuitem.hasMenu(); }
322 
323 //----------------------------------------------------------------------
324 inline auto FMenu::getSuperMenu() const -> FWidget*
325 { return super_menu; }
326 
327 //----------------------------------------------------------------------
328 inline void FMenu::setSuperMenu (FWidget* smenu)
329 { super_menu = smenu; }
330 
331 //----------------------------------------------------------------------
332 template <typename WidgetT>
333 inline void FMenu::passEventToWidget (WidgetT widget, const FMouseEvent& ev) const
334 {
335  // Mouse event handover to given widget
336 
337  const auto& type = ev.getType();
338  const auto& tpos = ev.getTermPos();
339  const auto& par = widget->termToWidgetPos(tpos);
340  const MouseButton btn = ev.getButton();
341  const auto& new_ev = \
342  std::make_shared<FMouseEvent>(type, par, tpos, btn);
343  setClickedWidget(widget);
344  widget->mouse_down = true;
345  widget->onMouseMove(new_ev.get());
346 }
347 
348 //----------------------------------------------------------------------
349 inline auto FMenu::containsMenuStructure (const FPoint& p) -> bool
350 { return containsMenuStructure (p.getX(), p.getY()); }
351 
352 //----------------------------------------------------------------------
353 inline auto FMenu::superMenuAt (const FPoint& p) -> FMenu*
354 { return superMenuAt (p.getX(), p.getY()); }
355 
356 //----------------------------------------------------------------------
357 inline void FMenu::onAccel (FAccelEvent* ev)
358 { menuitem.onAccel(ev); }
359 
360 } // namespace finalcut
361 
362 #endif // FMENU_H
Definition: fwindow.h:67
Definition: fmenulist.h:58
Definition: fevent.h:144
Definition: fmenu.h:75
Definition: fmenubar.h:70
Definition: class_template.cpp:25
Definition: fpoint.h:50
Definition: fmenuitem.h:68
Definition: fdialoglistmenu.h:70
Definition: fstring.h:79
Definition: fradiomenuitem.h:64
Definition: fdialog.h:69
Definition: fwidget.h:129
Definition: fcheckmenuitem.h:66
Definition: fevent.h:220
Definition: fevent.h:124