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-2026 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  // Predicates
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  // Using-declaration
143  using KeyMap = std::unordered_map<FKey, std::function<void(FKeyEvent*)>, EnumHash<FKey>>;
144 
145  // Enumeration
146  enum class SelectItem : bool { No, Yes };
147 
148  struct MouseStates
149  {
150  uChar focus_changed : 1;
151  uChar hide_sub_menu : 1;
152  uChar mouse_over_menu : 1;
153  uChar mouse_over_submenu : 1;
154  uChar mouse_over_supermenu : 1;
155  uChar mouse_over_menubar : 1;
156  uChar : 2; // padding bits
157  };
158 
159  struct MenuText
160  {
161  FString text;
162  std::size_t hotkeypos;
163  bool no_underline;
164  };
165 
166  // Constants
167  static constexpr auto NOT_SET = static_cast<std::size_t>(-1);
168 
169  // Accessors
170  auto getSuperMenu() const -> FWidget*;
171 
172  // Mutators
173  void setSuperMenu (FWidget*);
174 
175  // Predicates
176  auto isDialog (const FWidget*) const -> bool;
177  auto isMenuBar (const FWidget*) const -> bool;
178  auto isMenu (const FWidget*) const -> bool;
179  auto isRadioMenuItem (const FWidget*) const -> bool;
180  auto isSubMenu() const -> bool;
181  auto isDialogMenu() const -> bool;
182  auto isMouseOverMenu (const FPoint&) -> bool;
183  auto isMouseOverSubMenu (const FPoint&) -> bool;
184  auto isMouseOverSuperMenu (const FPoint&) -> bool;
185  auto isMouseOverMenuBar (const FPoint&) const -> bool;
186  auto isMetaNumberKey (const FKey&) const -> bool;
187 
188  // Methods
189  void init();
190  void handleParentWidget();
191  void initCallbacks();
192  void mapKeyFunctions();
193  void calculateDimensions();
194  auto calculateMaxItemWidth() const -> std::size_t;
195  void setPositionsOfAllItems() const;
196  void adjustItems() const;
197  auto adjustX (int) const -> int;
198  void openSubMenu (FMenu*, SelectItem);
199  void closeOpenedSubMenu();
200  void hideSubMenus();
201  void hideSuperMenus() const;
202  auto isMouseOverItem (const FPoint&, const FMenuItem*) const -> bool;
203  auto mouseDownOverList (const FPoint&) -> bool;
204  void mouseDownSubmenu (const FMenuItem*);
205  void mouseDownSelection (FMenuItem*, bool&);
206  auto mouseUpOverList (const FPoint&) -> bool;
207  auto initializeMouseStates (const FMouseEvent*) -> MouseStates;
208  void handleCloseSubMenu (const MouseStates&);
209  void handleMouseMoveEvent (const FMouseEvent*);
210  void mouseMoveOverList (const FPoint&, MouseStates&);
211  auto handleMenuHierarchyEvents (const MouseStates&, const FMouseEvent*) -> bool;
212  void processMenuBorderEvents (MouseStates&) const;
213  void mouseMoveSelection (FMenuItem*, MouseStates&);
214  void mouseMoveDeselection (FMenuItem*, MouseStates&);
215  void mouseUpOverBorder();
216  void mouseMoveOverBorder (MouseStates&) const;
217  auto handleSubMenuEvent (const MouseStates&, const FMouseEvent&) const -> bool;
218  void passEventToSubMenu (const FMouseEvent&) const;
219  auto handleSuperMenuEvent (const MouseStates&, const FMouseEvent&) -> bool;
220  void passEventToSuperMenu (const FMouseEvent&);
221  auto handleMenuBarEvent (const MouseStates&, const FMouseEvent&) const -> bool;
222  void passEventToMenuBar (const FMouseEvent&) const;
223  template <typename WidgetT>
224  void passEventToWidget (WidgetT, const FMouseEvent&) const;
225  auto containsMenuStructure (const FPoint&) -> bool;
226  auto containsMenuStructure (int, int) -> bool;
227  auto superMenuAt (const FPoint&) -> FMenu*;
228  auto superMenuAt (int, int) -> FMenu*;
229  void selectItem_PostProcessing (FMenuItem*) override;
230  void keypressMenuBar (FKeyEvent*) const;
231  auto hotkeyFound (FKey, const FKeyEvent&) const -> bool;
232  auto hotkeyMenu (FKeyEvent*) -> bool;
233  void draw() override;
234  void drawItems();
235  void drawSeparator (int);
236  void drawMenuLine (FMenuItem*, int);
237  void drawCheckMarkPrefix (const FMenuItem*);
238  void printChecked (bool);
239  void printUnchecked();
240  void printBullet();
241  void printCheckMark();
242  void drawMenuText (MenuText&);
243  auto isCharacterInvalid (wchar_t) const -> bool;
244  void printHotkey (const MenuText&, wchar_t);
245  void drawSubMenuIndicator (std::size_t&);
246  void drawAcceleratorKey (std::size_t&, FKey);
247  void drawTrailingSpaces (std::size_t);
248  void setLineAttributes (const FMenuItem*, int);
249  void setCursorToHotkeyPosition (FMenuItem*) const;
250  void selectPrevMenu (FKeyEvent*);
251  void selectNextMenu (FKeyEvent*);
252  void acceptSelection();
253  void closeMenu();
254  void processActivate() const;
255 
256  // Data members
257  KeyMap key_map{};
258  FMenuItem menuitem{};
259  FWidget* super_menu{nullptr};
260  FMenu* opened_sub_menu{nullptr};
261  FMenu* shown_sub_menu{nullptr};
262  std::size_t max_item_width{0};
263  std::size_t hotkeypos{NOT_SET};
264  bool mouse_down{false};
265  bool has_checkable_items{false};
266 
267  // Friend functions
268  friend auto closeOpenMenus (FMenu*, const FPoint&) -> std::tuple<bool, bool>;
269 
270  // Friend classes
271  friend class FCheckMenuItem;
272  friend class FDialog;
273  friend class FDialogListMenu;
274  friend class FMenuBar;
275  friend class FMenuItem;
276  friend class FRadioMenuItem;
277 };
278 
279 // non-member function forward declarations
280 //----------------------------------------------------------------------
281 auto closeOpenMenus (FMenu*, const FPoint&) -> std::tuple<bool, bool>;
282 
283 
284 // FMenu inline functions
285 //----------------------------------------------------------------------
286 inline auto FMenu::getClassName() const -> FString
287 { return "FMenu"; }
288 
289 //----------------------------------------------------------------------
290 inline auto FMenu::getText() const -> FString
291 { return menuitem.getText(); }
292 
293 //----------------------------------------------------------------------
294 inline auto FMenu::getItem() -> FMenuItem*
295 { return &menuitem; }
296 
297 //----------------------------------------------------------------------
298 inline void FMenu::setEnable (bool enable)
299 { menuitem.setEnable(enable); }
300 
301 //----------------------------------------------------------------------
302 inline void FMenu::unsetEnable()
303 { menuitem.unsetEnable(); }
304 
305 //----------------------------------------------------------------------
306 inline void FMenu::setDisable()
307 { menuitem.setDisable(); }
308 
309 //----------------------------------------------------------------------
310 inline void FMenu::setSelected()
311 { menuitem.setSelected(); }
312 
313 //----------------------------------------------------------------------
314 inline void FMenu::unsetSelected()
315 { menuitem.unsetSelected(); }
316 
317 //----------------------------------------------------------------------
318 inline void FMenu::unsetMenuWidget()
319 { setMenuWidget(false); }
320 
321 //----------------------------------------------------------------------
322 inline void FMenu::setMenu (FMenu* m)
323 { menuitem.setMenu(m); }
324 
325 //----------------------------------------------------------------------
326 inline void FMenu::setText (const FString& txt)
327 { menuitem.setText(txt); }
328 
329 //----------------------------------------------------------------------
330 inline auto FMenu::isSelected() const -> bool
331 { return menuitem.isSelected(); }
332 
333 //----------------------------------------------------------------------
334 inline auto FMenu::hasHotkey() const -> bool
335 { return menuitem.hasHotkey(); }
336 
337 //----------------------------------------------------------------------
338 inline auto FMenu::hasMenu() const -> bool
339 { return menuitem.hasMenu(); }
340 
341 //----------------------------------------------------------------------
342 inline auto FMenu::getSuperMenu() const -> FWidget*
343 { return super_menu; }
344 
345 //----------------------------------------------------------------------
346 inline void FMenu::setSuperMenu (FWidget* smenu)
347 { super_menu = smenu; }
348 
349 //----------------------------------------------------------------------
350 template <typename WidgetT>
351 inline void FMenu::passEventToWidget (WidgetT widget, const FMouseEvent& ev) const
352 {
353  // Mouse event handover to given widget
354 
355  const auto& type = ev.getType();
356  const auto& tpos = ev.getTermPos();
357  const auto& par = widget->termToWidgetPos(tpos);
358  const MouseButton btn = ev.getButton();
359  const auto& new_ev = \
360  std::make_shared<FMouseEvent>(type, par, tpos, btn);
361  setClickedWidget(widget);
362  widget->mouse_down = true;
363  widget->onMouseMove(new_ev.get());
364 }
365 
366 //----------------------------------------------------------------------
367 inline auto FMenu::containsMenuStructure (const FPoint& p) -> bool
368 { return containsMenuStructure (p.getX(), p.getY()); }
369 
370 //----------------------------------------------------------------------
371 inline auto FMenu::superMenuAt (const FPoint& p) -> FMenu*
372 { return superMenuAt (p.getX(), p.getY()); }
373 
374 //----------------------------------------------------------------------
375 inline void FMenu::onAccel (FAccelEvent* ev)
376 { menuitem.onAccel(ev); }
377 
378 } // namespace finalcut
379 
380 #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:82
Definition: fradiomenuitem.h:64
Definition: fdialog.h:69
Definition: fwidget.h:129
Definition: fcheckmenuitem.h:66
Definition: fevent.h:231
Definition: fevent.h:124
Definition: ftypes.h:161