1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #ifndef INCLUDED_VCL_MENU_HXX
21 #define INCLUDED_VCL_MENU_HXX
24 #include <string_view>
26 #include <vcl/vclenum.hxx>
27 #include <tools/link.hxx>
28 #include <tools/long.hxx>
29 #include <vcl/dllapi.h>
30 #include <vcl/keycod.hxx>
31 #include <vcl/vclptr.hxx>
32 #include <vcl/vclreferencebase.hxx>
33 #include <com/sun/star/uno/Reference.hxx>
34 #include <o3tl/typed_flags_set.hxx>
42 namespace tools
{ class Rectangle
; }
48 class MenuFloatingWindow
;
52 struct SystemMenuData
;
53 enum class FloatWinPopupFlags
;
54 enum class VclEventId
;
56 namespace com::sun::star::awt
{ class XPopupMenu
; }
57 namespace com::sun::star::accessibility
{ class XAccessible
; }
62 struct MenuLayoutData
;
63 typedef OutputDevice RenderContext
; // same as in include/vcl/outdev.hxx
64 class ILibreOfficeKitNotifier
;
67 constexpr sal_uInt16 MENU_APPEND
= 0xFFFF;
68 constexpr sal_uInt16 MENU_ITEM_NOTFOUND
= 0xFFFF;
70 // Must match the definitions in css::awt::PopupMenuDirection.idl
71 enum class PopupMenuFlags
76 ExecuteRight
= 0x0008,
77 NoMouseUpClose
= 0x0010,
82 template<> struct typed_flags
<PopupMenuFlags
> : is_typed_flags
<PopupMenuFlags
, 0x001b> {};
88 NoAutoMnemonics
= 0x0001,
89 HideDisabledEntries
= 0x0002,
90 // overrides default hiding of disabled entries in popup menus
91 AlwaysShowDisabledEntries
= 0x0004,
96 template<> struct typed_flags
<MenuFlags
> : is_typed_flags
<MenuFlags
, 0x0007> {};
99 /// Invalid menu item id
100 constexpr auto ITEMPOS_INVALID
= 0xFFFF;
102 struct ImplMenuDelData
104 ImplMenuDelData
* mpNext
;
105 VclPtr
<const Menu
> mpMenu
;
107 explicit ImplMenuDelData( const Menu
* );
110 bool isDeleted() const { return mpMenu
== nullptr; }
113 typedef void (*MenuUserDataReleaseFunction
)(void*);
115 class VCL_DLLPUBLIC Menu
: public VclReferenceBase
117 friend class MenuBar
;
118 friend class MenuBarWindow
;
119 friend class MenuButton
;
120 friend class MenuFloatingWindow
;
121 friend class PopupMenu
;
122 friend class SystemWindow
;
123 friend struct ImplMenuDelData
;
125 ImplMenuDelData
* mpFirstDel
;
126 std::unique_ptr
<MenuItemList
> pItemList
; // list with MenuItems
127 VclPtr
<Menu
> pStartedFrom
;
128 VclPtr
<vcl::Window
> pWindow
;
130 Link
<Menu
*, bool> aActivateHdl
; // Active-Handler
131 Link
<Menu
*, bool> aDeactivateHdl
; // Deactivate-Handler
132 Link
<Menu
*, bool> aSelectHdl
; // Select-Handler
134 std::list
<Link
<VclMenuEvent
&,void> > maEventListeners
;
138 OUString aTitleText
; // PopupMenu text
139 sal_uInt16 nTitleHeight
;
141 ImplSVEvent
* nEventId
;
142 sal_uInt16 mnHighlightedItemPos
; // for native menus: keeps track of the highlighted item
143 MenuFlags nMenuFlags
;
144 sal_uInt16 nSelectedId
;
145 OUString sSelectedIdent
;
148 sal_uInt16 nImgOrChkPos
;
151 bool bCanceled
: 1; ///< Terminated during a callback
152 bool bInCallback
: 1; ///< In Activate/Deactivate
153 bool bKilled
: 1; ///< Killed
155 css::uno::Reference
<css::accessibility::XAccessible
> mxAccessible
;
156 mutable std::unique_ptr
<vcl::MenuLayoutData
> mpLayoutData
;
157 std::unique_ptr
<SalMenu
> mpSalMenu
;
159 // Stores the help ID of the menu
160 OUString m_sMenuHelpId
;
163 SAL_DLLPRIVATE Menu
* ImplGetStartMenu();
164 SAL_DLLPRIVATE Menu
* ImplFindSelectMenu();
165 SAL_DLLPRIVATE Menu
* ImplFindMenu( sal_uInt16 nId
);
166 SAL_DLLPRIVATE Size
ImplCalcSize( vcl::Window
* pWin
);
167 SAL_DLLPRIVATE
bool ImplIsVisible( sal_uInt16 nPos
) const;
168 SAL_DLLPRIVATE
bool ImplCurrentlyHiddenOnGUI(sal_uInt16 nPos
) const;
169 SAL_DLLPRIVATE
bool ImplIsSelectable( sal_uInt16 nPos
) const;
170 SAL_DLLPRIVATE sal_uInt16
ImplGetVisibleItemCount() const;
171 SAL_DLLPRIVATE sal_uInt16
ImplGetFirstVisible() const;
172 SAL_DLLPRIVATE sal_uInt16
ImplGetPrevVisible( sal_uInt16 nPos
) const;
173 SAL_DLLPRIVATE sal_uInt16
ImplGetNextVisible( sal_uInt16 nPos
) const;
174 SAL_DLLPRIVATE
void ImplPaint(vcl::RenderContext
& rRenderContext
, Size
const & rSize
,
175 sal_uInt16 nBorder
, tools::Long nOffY
= 0, MenuItemData
const * pThisDataOnly
= nullptr,
176 bool bHighlighted
= false, bool bLayout
= false, bool bRollover
= false ) const;
177 SAL_DLLPRIVATE
void ImplPaintMenuTitle(vcl::RenderContext
&, const tools::Rectangle
& rRect
) const;
178 SAL_DLLPRIVATE
void ImplSelect();
179 SAL_DLLPRIVATE
void ImplCallHighlight( sal_uInt16 nHighlightItem
);
180 SAL_DLLPRIVATE
void ImplCallEventListeners( VclEventId nEvent
, sal_uInt16 nPos
);
181 DECL_DLLPRIVATE_LINK(ImplCallSelect
, void*, void );
183 SAL_DLLPRIVATE
void ImplFillLayoutData() const;
184 SAL_DLLPRIVATE SalMenu
* ImplGetSalMenu() { return mpSalMenu
.get(); }
185 SAL_DLLPRIVATE OUString
ImplGetHelpText( sal_uInt16 nItemId
) const;
187 // returns native check and option menu symbol height in rCheckHeight and rRadioHeight
188 // return value is maximum width and height of checkboxes and radiobuttons
189 SAL_DLLPRIVATE Size
ImplGetNativeCheckAndRadioSize(vcl::RenderContext
const & rRenderContext
, tools::Long
& rCheckHeight
, tools::Long
& rRadioHeight
) const;
191 // returns native submenu arrow size and spacing from right border
192 // return value is whether it's supported natively
193 SAL_DLLPRIVATE
static bool ImplGetNativeSubmenuArrowSize(vcl::RenderContext
const & rRenderContext
, Size
& rArrowSize
, tools::Long
& rArrowSpacing
);
195 SAL_DLLPRIVATE
void ImplAddDel( ImplMenuDelData
&rDel
);
196 SAL_DLLPRIVATE
void ImplRemoveDel( ImplMenuDelData
&rDel
);
198 SAL_DLLPRIVATE MenuItemData
* NbcInsertItem(sal_uInt16 nId
, MenuItemBits nBits
,
199 const OUString
& rStr
, Menu
* pMenu
,
200 size_t nPos
, const OUString
&rIdent
);
202 /// Close the 'pStartedFrom' menu window.
203 virtual void ClosePopup(Menu
* pMenu
) = 0;
205 /// Forward the KeyInput call to the MenuBar.
206 virtual void MenuBarKeyInput(const KeyEvent
& rEvent
);
209 SAL_DLLPRIVATE
void ImplKillLayoutData() const;
211 SAL_DLLPRIVATE
vcl::Window
* ImplGetWindow() const { return pWindow
; }
213 void ImplSelectWithStart( Menu
* pStartMenu
= nullptr );
218 /** The Menu constructor is protected.
220 The callers are supposed to instantiate either PopupMenu or MenuBar, but
226 virtual ~Menu() override
;
227 virtual void dispose() override
;
233 void InsertItem(sal_uInt16 nItemId
, const OUString
& rStr
,
234 MenuItemBits nItemBits
= MenuItemBits::NONE
,
235 const OUString
&rIdent
= {},
236 sal_uInt16 nPos
= MENU_APPEND
);
237 void InsertItem(sal_uInt16 nItemId
, const Image
& rImage
,
238 MenuItemBits nItemBits
= MenuItemBits::NONE
,
239 const OUString
&rIdent
= {},
240 sal_uInt16 nPos
= MENU_APPEND
);
241 void InsertItem(sal_uInt16 nItemId
,
242 const OUString
& rString
, const Image
& rImage
,
243 MenuItemBits nItemBits
= MenuItemBits::NONE
,
244 const OUString
&rIdent
= {},
245 sal_uInt16 nPos
= MENU_APPEND
);
246 void InsertSeparator(const OUString
&rIdent
= {}, sal_uInt16 nPos
= MENU_APPEND
);
247 void RemoveItem( sal_uInt16 nPos
);
250 void CreateAutoMnemonics();
252 void SetMenuFlags( MenuFlags nFlags
) { nMenuFlags
= nFlags
; }
253 MenuFlags
GetMenuFlags() const { return nMenuFlags
; }
255 bool HasValidEntries(bool bCheckPopups
) const;
256 sal_uInt16
GetItemCount() const;
257 sal_uInt16
GetItemId(sal_uInt16 nPos
) const;
258 sal_uInt16
GetItemId(std::u16string_view rIdent
) const;
259 sal_uInt16
GetItemPos( sal_uInt16 nItemId
) const;
260 OUString
GetItemIdent(sal_uInt16 nItemId
) const;
261 MenuItemType
GetItemType( sal_uInt16 nPos
) const;
262 sal_uInt16
GetCurItemId() const { return nSelectedId
;}
263 OUString
const & GetCurItemIdent() const { return sSelectedIdent
; }
264 void SetItemBits( sal_uInt16 nItemId
, MenuItemBits nBits
);
265 MenuItemBits
GetItemBits( sal_uInt16 nItemId
) const;
267 void SetUserValue(sal_uInt16 nItemId
, void* nUserValue
, MenuUserDataReleaseFunction aFunc
=nullptr);
268 void* GetUserValue(sal_uInt16 nItemId
) const;
270 void SetPopupMenu( sal_uInt16 nItemId
, PopupMenu
* pMenu
);
271 PopupMenu
* GetPopupMenu( sal_uInt16 nItemId
) const;
273 void SetAccelKey( sal_uInt16 nItemId
, const vcl::KeyCode
& rKeyCode
);
274 vcl::KeyCode
GetAccelKey( sal_uInt16 nItemId
) const;
276 void CheckItem( sal_uInt16 nItemId
, bool bCheck
= true );
277 void CheckItem( std::u16string_view rIdent
, bool bCheck
= true );
278 bool IsItemCheckable(sal_uInt16 nItemId
) const;
279 bool IsItemChecked( sal_uInt16 nItemId
) const;
281 virtual void SelectItem(sal_uInt16 nItemId
) = 0;
283 void EnableItem( sal_uInt16 nItemId
, bool bEnable
= true );
284 void EnableItem(std::u16string_view rIdent
, bool bEnable
= true)
286 EnableItem(GetItemId(rIdent
), bEnable
);
288 bool IsItemEnabled( sal_uInt16 nItemId
) const;
290 void ShowItem( sal_uInt16 nItemId
, bool bVisible
= true );
291 void HideItem( sal_uInt16 nItemId
) { ShowItem( nItemId
, false ); }
293 bool IsItemPosVisible( sal_uInt16 nItemPos
) const;
294 bool IsMenuVisible() const;
295 virtual bool IsMenuBar() const = 0;
297 void RemoveDisabledEntries( bool bRemoveEmptyPopups
= false );
299 void UpdateNativeMenu();
301 void SetItemText( sal_uInt16 nItemId
, const OUString
& rStr
);
302 OUString
GetItemText( sal_uInt16 nItemId
) const;
304 void SetItemImage( sal_uInt16 nItemId
, const Image
& rImage
);
305 Image
GetItemImage( sal_uInt16 nItemId
) const;
307 void SetItemCommand( sal_uInt16 nItemId
, const OUString
& rCommand
);
308 OUString
GetItemCommand( sal_uInt16 nItemId
) const;
310 void SetHelpText( sal_uInt16 nItemId
, const OUString
& rString
);
311 OUString
GetHelpText( sal_uInt16 nItemId
) const;
313 void SetTipHelpText( sal_uInt16 nItemId
, const OUString
& rString
);
314 OUString
GetTipHelpText( sal_uInt16 nItemId
) const;
316 void SetHelpCommand( sal_uInt16 nItemId
, const OUString
& rString
);
317 OUString
GetHelpCommand( sal_uInt16 nItemId
) const;
319 void SetHelpId( sal_uInt16 nItemId
, const OUString
& rHelpId
);
320 OUString
GetHelpId( sal_uInt16 nItemId
) const;
322 void SetHelpId( const OUString
& rHelpId
) { m_sMenuHelpId
= rHelpId
; }
323 OUString
GetHelpId() const { return m_sMenuHelpId
; }
325 void SetActivateHdl( const Link
<Menu
*, bool>& rLink
)
327 aActivateHdl
= rLink
;
330 void SetDeactivateHdl( const Link
<Menu
*, bool>& rLink
)
332 aDeactivateHdl
= rLink
;
335 void SetSelectHdl( const Link
<Menu
*,bool>& rLink
)
340 sal_uInt16
GetTitleHeight() const
345 void AddEventListener( const Link
<VclMenuEvent
&,void>& rEventListener
);
346 void RemoveEventListener( const Link
<VclMenuEvent
&,void>& rEventListener
);
348 Menu
& operator =( const Menu
& rMenu
);
350 // for menu functions
351 MenuItemList
* GetItemList() const
353 return pItemList
.get();
356 // returns the system's menu handle if native menus are supported
357 // pData must point to a SystemMenuData structure
358 void GetSystemMenuData( SystemMenuData
* pData
) const;
360 // accessibility helpers
362 // returns the bounding box for the character at index nIndex
363 // where nIndex is relative to the starting index of the item
364 // with id nItemId (in coordinates of the displaying window)
365 tools::Rectangle
GetCharacterBounds( sal_uInt16 nItemId
, tools::Long nIndex
) const;
366 // -1 is returned if no character is at that point
367 // if an index is found the corresponding item id is filled in (else 0)
368 tools::Long
GetIndexForPoint( const Point
& rPoint
, sal_uInt16
& rItemID
) const;
369 // returns the bounding rectangle for an item at pos nItemPos
370 tools::Rectangle
GetBoundingRectangle( sal_uInt16 nItemPos
) const;
372 css::uno::Reference
<css::accessibility::XAccessible
> GetAccessible();
373 void SetAccessible(const css::uno::Reference
<css::accessibility::XAccessible
>& rxAccessible
);
375 // gets the activation key of the specified item
376 KeyEvent
GetActivationKey( sal_uInt16 nItemId
) const;
378 vcl::Window
* GetWindow() const { return pWindow
; }
380 void SetAccessibleName( sal_uInt16 nItemId
, const OUString
& rStr
);
381 OUString
GetAccessibleName( sal_uInt16 nItemId
) const;
383 void SetAccessibleDescription( sal_uInt16 nItemId
, const OUString
& rStr
);
384 OUString
GetAccessibleDescription( sal_uInt16 nItemId
) const;
386 // returns whether the item a position nItemPos is highlighted or not.
387 bool IsHighlighted( sal_uInt16 nItemPos
) const;
389 void HighlightItem( sal_uInt16 nItemPos
);
390 void DeHighlight() { HighlightItem( 0xFFFF ); } // MENUITEMPOS_INVALID
392 bool HandleMenuCommandEvent(Menu
*pMenu
, sal_uInt16 nEventId
) const;
393 bool HandleMenuActivateEvent(Menu
*pMenu
) const;
394 bool HandleMenuDeActivateEvent(Menu
*pMenu
) const;
399 void set_id(const OUString
& rID
) { maID
= rID
; }
402 * Get the ID of the window.
404 const OUString
& get_id() const { return maID
; }
407 struct MenuBarButtonCallbackArg
409 sal_uInt16 nId
; // Id of the button
410 bool bHighlight
; // highlight on/off
413 class VCL_DLLPUBLIC MenuBar final
: public Menu
415 Link
<void*,void> maCloseHdl
;
416 bool mbCloseBtnVisible
: 1;
417 bool mbFloatBtnVisible
: 1;
418 bool mbHideBtnVisible
: 1;
419 bool mbDisplayable
: 1;
421 friend class Application
;
423 friend class MenuBarWindow
;
424 friend class MenuFloatingWindow
;
425 friend class SystemWindow
;
427 SAL_DLLPRIVATE
static VclPtr
<vcl::Window
> ImplCreate(vcl::Window
* pParent
, vcl::Window
* pWindow
, MenuBar
* pMenu
);
428 SAL_DLLPRIVATE
static void ImplDestroy(MenuBar
* pMenu
, bool bDelete
);
429 SAL_DLLPRIVATE
bool ImplHandleKeyEvent(const KeyEvent
& rKEvent
);
431 /// Return the MenuBarWindow.
432 MenuBarWindow
* getMenuBarWindow();
436 MenuBar( const MenuBar
& rMenu
);
437 virtual ~MenuBar() override
;
438 virtual void dispose() override
;
440 MenuBar
& operator =( const MenuBar
& rMenu
);
442 virtual bool IsMenuBar() const override
{ return true; }
444 /// Close the 'pStartedFrom' menu window.
445 virtual void ClosePopup(Menu
* pMenu
) override
;
447 /// Forward the KeyInput call to the MenuBar.
448 virtual void MenuBarKeyInput(const KeyEvent
& rEvent
) override
;
450 void ShowCloseButton( bool bShow
);
451 bool HasCloseButton() const { return mbCloseBtnVisible
; }
452 bool HasFloatButton() const { return mbFloatBtnVisible
; }
453 bool HasHideButton() const { return mbHideBtnVisible
; }
454 void ShowButtons( bool bClose
, bool bFloat
, bool bHide
);
456 virtual void SelectItem(sal_uInt16 nId
) override
;
457 bool HandleMenuHighlightEvent(Menu
*pMenu
, sal_uInt16 nEventId
) const;
458 bool HandleMenuButtonEvent(sal_uInt16 nEventId
);
460 void SetCloseButtonClickHdl( const Link
<void*,void>& rLink
) { maCloseHdl
= rLink
; }
461 const Link
<void*,void>& GetCloseButtonClickHdl() const { return maCloseHdl
; }
463 // - by default a menubar is displayable
464 // - if a menubar is not displayable, its MenuBarWindow will never be shown
465 // and it will be hidden if it was visible before
466 // - note: if a menubar is displayable, this does not necessarily mean that it is currently visible
467 void SetDisplayable( bool bDisplayable
);
468 bool IsDisplayable() const { return mbDisplayable
; }
470 // add an arbitrary button to the menubar (will appear next to closer)
471 // passed link will be call with a MenuBarButtonCallbackArg on press
472 // passed string will be set as tooltip
473 sal_uInt16
AddMenuBarButton( const Image
&, const Link
<MenuBarButtonCallbackArg
&,bool>&, const OUString
& );
474 // set the highlight link for additional button with ID nId
475 // highlight link will be called with a MenuBarButtonHighlightArg
476 // the bHighlight member of that struct shall contain the new state
477 void SetMenuBarButtonHighlightHdl( sal_uInt16 nId
, const Link
<MenuBarButtonCallbackArg
&,bool>& );
478 // returns the rectangle occupied by the additional button named nId
479 // coordinates are relative to the systemwindow the menubar is attached to
480 // if the menubar is unattached an empty rectangle is returned
481 tools::Rectangle
GetMenuBarButtonRectPixel( sal_uInt16 nId
);
482 void RemoveMenuBarButton( sal_uInt16 nId
);
483 void LayoutChanged();
484 // get the height of the menubar, return the native menubar height if that is active or the vcl
486 int GetMenuBarHeight() const;
489 inline MenuBar
& MenuBar::operator=( const MenuBar
& rMenu
)
491 Menu::operator=(rMenu
);
495 class VCL_DLLPUBLIC PopupMenu final
: public Menu
498 friend class MenuFloatingWindow
;
499 friend class MenuBarWindow
;
500 friend struct MenuItemData
;
503 SAL_DLLPRIVATE MenuFloatingWindow
* ImplGetFloatingWindow() const;
504 SAL_DLLPRIVATE
bool PrepareRun(const VclPtr
<vcl::Window
>& pParentWin
, tools::Rectangle
& rRect
, FloatWinPopupFlags
& nPopupModeFlags
, Menu
* pSFrom
, bool& bRealExecute
, VclPtr
<MenuFloatingWindow
>&);
505 SAL_DLLPRIVATE
bool Run(const VclPtr
<MenuFloatingWindow
>&, bool bRealExecute
, bool bPreSelectFirst
, FloatWinPopupFlags nPopupModeFlags
, Menu
* pSFrom
, const tools::Rectangle
& rRect
);
506 SAL_DLLPRIVATE
void FinishRun(const VclPtr
<MenuFloatingWindow
>&, const VclPtr
<vcl::Window
>& pParentWin
, bool bRealExecute
, bool bIsNativeMenu
);
507 SAL_DLLPRIVATE sal_uInt16
ImplExecute(const VclPtr
<vcl::Window
>& pParentWin
, const tools::Rectangle
& rRect
, FloatWinPopupFlags nPopupModeFlags
, Menu
* pSFrom
, bool bPreSelectFirst
);
508 SAL_DLLPRIVATE
void ImplFlushPendingSelect();
509 SAL_DLLPRIVATE
tools::Long
ImplCalcHeight( sal_uInt16 nEntries
) const;
510 SAL_DLLPRIVATE sal_uInt16
ImplCalcVisEntries( tools::Long nMaxHeight
, sal_uInt16 nStartEntry
, sal_uInt16
* pLastVisible
= nullptr ) const;
514 PopupMenu( const PopupMenu
& rMenu
);
515 virtual ~PopupMenu() override
;
517 virtual bool IsMenuBar() const override
{ return false; }
519 /// Close the 'pStartedFrom' menu window.
520 virtual void ClosePopup(Menu
* pMenu
) override
;
522 void SetText( const OUString
& rTitle
)
527 sal_uInt16
Execute( vcl::Window
* pWindow
, const Point
& rPopupPos
);
528 sal_uInt16
Execute( vcl::Window
* pWindow
, const tools::Rectangle
& rRect
, PopupMenuFlags nFlags
= PopupMenuFlags::NONE
);
532 virtual void SelectItem(sal_uInt16 nId
) override
;
533 void SetSelectedEntry( sal_uInt16 nId
); // for use by native submenu only
535 css::uno::Reference
<css::awt::XPopupMenu
> CreateMenuInterface();
537 static PopupMenu
* GetActivePopupMenu();
539 PopupMenu
& operator=( const PopupMenu
& rMenu
);
542 inline PopupMenu
& PopupMenu::operator=( const PopupMenu
& rMenu
)
544 Menu::operator=( rMenu
);
548 #endif // INCLUDED_VCL_MENU_HXX
550 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */