/***********************************************************************
* fmenu.h - Widget FMenu *
* *
* This file is part of the Final Cut widget toolkit *
* *
* Copyright 2015-2020 Markus Gans *
* *
* The Final Cut is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public License *
* as published by the Free Software Foundation; either version 3 of *
* the License, or (at your option) any later version. *
* *
* The Final Cut is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this program. If not, see *
* . *
***********************************************************************/
/* Inheritance diagram
* ═══════════════════
*
* ▕▔▔▔▔▔▔▔▔▔▏ ▕▔▔▔▔▔▔▔▔▔▏
* ▕ FVTerm ▏ ▕ FObject ▏
* ▕▁▁▁▁▁▁▁▁▁▏ ▕▁▁▁▁▁▁▁▁▁▏
* ▲ ▲
* │ │ *▕▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▏
* └─────┬─────┘ ┌ - -▕ FRadioMenuItem ▏
* │ : ▕▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▏
* ▕▔▔▔▔▔▔▔▔▔▏ :
* ▕ FWidget ▏ : *▕▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▏
* ▕▁▁▁▁▁▁▁▁▁▏ ├ - -▕ FCheckMenuItem ▏
* ▲ : ▕▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▏
* │ 1 :
* ▕▔▔▔▔▔▔▔▔▔▏ ▕▔▔▔▔▔▔▔▔▔▔▔▏- ┘ ▕▔▔▔▔▔▔▔▔▔▔▔▏
* ▕ FWindow ▏ ▕ FMenuList ▏- - - -▕ FMenuItem ▏
* ▕▁▁▁▁▁▁▁▁▁▏ ▕▁▁▁▁▁▁▁▁▁▁▁▏1 *▕▁▁▁▁▁▁▁▁▁▁▁▏
* ▲ ▲ 1:
* │ │ :
* └─────┬─────┘ :
* │ 1 :
* ▕▔▔▔▔▔▔▔▏- - - ┘ ▕▔▔▔▔▔▔▔▔▔▔▔▏
* ▕ FMenu ▏- - - - - - - -▕ FMenuItem ▏
* ▕▁▁▁▁▁▁▁▏1 1▕▁▁▁▁▁▁▁▁▁▁▁▏
*/
#ifndef FMENU_H
#define FMENU_H
#if !defined (USE_FINAL_H) && !defined (COMPILE_FINAL_CUT)
#error "Only can be included directly."
#endif
#include "final/fwindow.h"
#include "final/fmenulist.h"
namespace finalcut
{
// class forward declaration
class FMenuBar;
class FMenuItem;
//----------------------------------------------------------------------
// class FMenu
//----------------------------------------------------------------------
class FMenu : public FWindow, public FMenuList
{
public:
// Using-declaration
using FMenuList::getItem;
using FMenuList::isSelected;
// Constructor
explicit FMenu (FWidget* = nullptr);
explicit FMenu (const FString&, FWidget* = nullptr);
// Disable copy constructor
FMenu (const FMenu&) = delete;
// Destructor
~FMenu() override;
// Disable copy assignment operator (=)
FMenu& operator = (const FMenu&) = delete;
// Accessors
const FString getClassName() const override;
FString getText() const;
FMenuItem* getItem();
// Mutators
bool setEnable (bool) override;
bool setEnable() override;
bool unsetEnable() override;
bool setDisable() override;
void setSelected();
void unsetSelected();
bool setMenuWidget (bool);
bool setMenuWidget();
bool unsetMenuWidget();
void setStatusbarMessage (const FString&) override;
void setMenu (FMenu*);
void setText (const FString&);
// Inquiries
bool isSelected() const;
bool hasHotkey() const;
bool hasMenu() const;
// Methods
void show() override;
void hide() override;
// Event handlers
void onKeyPress (FKeyEvent*) override;
void onMouseDown (FMouseEvent*) override;
void onMouseUp (FMouseEvent*) override;
void onMouseMove (FMouseEvent*) override;
void onAccel (FAccelEvent*) override;
// Callback method
void cb_menuitemEnabled (const FWidget*, const FDataPtr);
void cb_menuitemDisabled (const FWidget*, const FDataPtr);
void cb_menuitemToggled (FWidget*, const FDataPtr);
private:
// Constants
static constexpr std::size_t NOT_SET = static_cast(-1);
static constexpr bool SELECT_ITEM = true;
// Typedef
typedef struct
{
uChar focus_changed : 1;
uChar hide_sub_menu : 1;
uChar mouse_over_menu : 1;
uChar mouse_over_submenu : 1;
uChar mouse_over_supermenu : 1;
uChar mouse_over_menubar : 1;
uChar : 2; // padding bits
} mouseStates;
typedef struct
{
FString text;
std::size_t hotkeypos;
bool no_underline;
} menuText;
// Accessors
FWidget* getSuperMenu() const;
// Mutators
void setSuperMenu (FWidget*);
// Inquiries
bool isDialog (const FWidget*) const;
bool isMenuBar (const FWidget*) const;
bool isMenu (const FWidget*) const;
bool isRadioMenuItem (const FWidget*) const;
bool isSubMenu() const;
bool isDialogMenu() const;
bool isMouseOverMenu (const FPoint&);
bool isMouseOverSubMenu (const FPoint&);
bool isMouseOverSuperMenu (const FPoint&);
bool isMouseOverMenuBar (const FPoint&);
// Methods
void init(FWidget*);
void initCallbacks();
void calculateDimensions();
void adjustItems();
int adjustX(int);
void openSubMenu (FMenu*, bool = false);
void closeOpenedSubMenu();
void hideSubMenus();
void hideSuperMenus();
bool mouseDownOverList (const FPoint&);
void mouseDownSubmenu (const FMenuItem*);
void mouseDownSelection (FMenuItem*, bool&);
bool mouseUpOverList (const FPoint&);
void mouseMoveOverList (const FPoint&, mouseStates&);
void mouseMoveSelection (FMenuItem*, mouseStates&);
void mouseMoveDeselection (FMenuItem*, mouseStates&);
void mouseUpOverBorder();
void mouseMoveOverBorder (mouseStates&);
void passEventToSubMenu (FMouseEvent* const&);
void passEventToSuperMenu (FMouseEvent* const&);
void passEventToMenuBar (FMouseEvent* const&);
bool containsMenuStructure (const FPoint&);
bool containsMenuStructure (int, int);
FMenu* superMenuAt (const FPoint&);
FMenu* superMenuAt (int, int);
bool selectNextItem();
bool selectPrevItem();
void keypressMenuBar (FKeyEvent*);
bool hotkeyMenu (FKeyEvent*);
void draw() override;
void drawItems();
void drawSeparator (int);
void drawMenuLine (FMenuItem*, int);
void drawCheckMarkPrefix (const FMenuItem*);
void drawMenuText (menuText&);
void drawSubMenuIndicator (std::size_t&);
void drawAcceleratorKey (std::size_t&, FKey);
void drawTrailingSpaces (std::size_t);
void setLineAttributes (const FMenuItem*, int);
void setCursorToHotkeyPosition (FMenuItem*);
void selectPrevMenu (FKeyEvent*);
void selectNextMenu (FKeyEvent*);
void acceptSelection();
void closeMenu();
void processActivate();
// Data members
FMenuItem menuitem{};
FWidget* super_menu{nullptr};
FMenu* opened_sub_menu{nullptr};
FMenu* shown_sub_menu{nullptr};
std::size_t max_item_width{0};
std::size_t hotkeypos{NOT_SET};
bool mouse_down{false};
bool has_checkable_items{false};
// Friend functions
friend std::tuple closeOpenMenus (FMenu*, const FPoint&);
// Friend classes
friend class FCheckMenuItem;
friend class FDialog;
friend class FMenuBar;
friend class FMenuItem;
friend class FRadioMenuItem;
};
// non-member function forward declarations
//----------------------------------------------------------------------
std::tuple closeOpenMenus (FMenu*, const FPoint&);
// FMenu inline functions
//----------------------------------------------------------------------
inline const FString FMenu::getClassName() const
{ return "FMenu"; }
//----------------------------------------------------------------------
inline FString FMenu::getText() const
{ return menuitem.getText(); }
//----------------------------------------------------------------------
inline FMenuItem* FMenu::getItem()
{ return &menuitem; }
//----------------------------------------------------------------------
inline bool FMenu::setEnable (bool enable)
{ return menuitem.setEnable(enable); }
//----------------------------------------------------------------------
inline bool FMenu::setEnable()
{ return menuitem.setEnable(); }
//----------------------------------------------------------------------
inline bool FMenu::unsetEnable()
{ return menuitem.unsetEnable(); }
//----------------------------------------------------------------------
inline bool FMenu::setDisable()
{ return menuitem.setDisable(); }
//----------------------------------------------------------------------
inline void FMenu::setSelected()
{ menuitem.setSelected(); }
//----------------------------------------------------------------------
inline void FMenu::unsetSelected()
{ menuitem.unsetSelected(); }
//----------------------------------------------------------------------
inline bool FMenu::setMenuWidget()
{ return setMenuWidget(true); }
//----------------------------------------------------------------------
inline bool FMenu::unsetMenuWidget()
{ return setMenuWidget(false); }
//----------------------------------------------------------------------
inline void FMenu::setMenu (FMenu* m)
{ menuitem.setMenu(m); }
//----------------------------------------------------------------------
inline void FMenu::setText (const FString& txt)
{ menuitem.setText(txt); }
//----------------------------------------------------------------------
inline bool FMenu::isSelected() const
{ return menuitem.isSelected(); }
//----------------------------------------------------------------------
inline bool FMenu::hasHotkey() const
{ return menuitem.hasHotkey(); }
//----------------------------------------------------------------------
inline bool FMenu::hasMenu() const
{ return menuitem.hasMenu(); }
//----------------------------------------------------------------------
inline FWidget* FMenu::getSuperMenu() const
{ return super_menu; }
//----------------------------------------------------------------------
inline void FMenu::setSuperMenu (FWidget* smenu)
{ super_menu = smenu; }
//----------------------------------------------------------------------
inline bool FMenu::containsMenuStructure (const FPoint& p)
{ return containsMenuStructure (p.getX(), p.getY()); }
//----------------------------------------------------------------------
inline FMenu* FMenu::superMenuAt (const FPoint& p)
{ return superMenuAt (p.getX(), p.getY()); }
//----------------------------------------------------------------------
inline void FMenu::onAccel (FAccelEvent* ev)
{ menuitem.onAccel(ev); }
} // namespace finalcut
#endif // FMENU_H