root/headers/os/interface/Menu.h
/*
 * Copyright 2007-2013 Haiku, Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 */
#ifndef _MENU_H
#define _MENU_H


#include <InterfaceDefs.h>
#include <List.h>
#include <View.h>


class BMenu;
class BMenuBar;
class BMenuItem;


namespace BPrivate {
        class BMenuWindow;
        class ExtraMenuData;
        class TriggerList;
        class MenuPrivate;
}

enum menu_layout {
        B_ITEMS_IN_ROW = 0,
        B_ITEMS_IN_COLUMN,
        B_ITEMS_IN_MATRIX
};

struct menu_info {
        float           font_size;
        font_family     f_family;
        font_style      f_style;
        rgb_color       background_color;
        int32           separator;
        bool            click_to_open;
        bool            triggers_always_shown;
};

status_t get_menu_info(menu_info* info);
status_t set_menu_info(menu_info* info);

typedef bool (*menu_tracking_hook)(BMenu* menu, void* state);


class BMenu : public BView {
public:
                                                                BMenu(const char* name,
                                                                        menu_layout layout = B_ITEMS_IN_COLUMN);
                                                                BMenu(const char* name, float width,
                                                                        float height);
                                                                BMenu(BMessage* archive);

        virtual                                         ~BMenu();

        static  BArchivable*            Instantiate(BMessage* archive);
        virtual status_t                        Archive(BMessage* archive,
                                                                        bool deep = true) const;

        virtual void                            AttachedToWindow();
        virtual void                            DetachedFromWindow();
        virtual void                            AllAttached();
        virtual void                            AllDetached();

        virtual void                            Draw(BRect updateRect);

        virtual void                            MessageReceived(BMessage* message);
        virtual void                            KeyDown(const char* bytes, int32 numBytes);

        virtual BSize                           MinSize();
        virtual BSize                           MaxSize();
        virtual BSize                           PreferredSize();
        virtual void                            GetPreferredSize(float* _width,
                                                                        float* _height);
        virtual void                            ResizeToPreferred();
        virtual void                            DoLayout();
        virtual void                            FrameMoved(BPoint where);
        virtual void                            FrameResized(float width, float height);

                        void                            InvalidateLayout();

        virtual void                            MakeFocus(bool focus = true);

                        bool                            AddItem(BMenuItem* item);
                        bool                            AddItem(BMenuItem* item, int32 index);
                        bool                            AddItem(BMenuItem* item, BRect frame);
                        bool                            AddItem(BMenu* menu);
                        bool                            AddItem(BMenu* menu, int32 index);
                        bool                            AddItem(BMenu* menu, BRect frame);
                        bool                            AddList(BList* list, int32 index);

                        bool                            AddSeparatorItem();

                        bool                            RemoveItem(BMenuItem* item);
                        BMenuItem*                      RemoveItem(int32 index);
                        bool                            RemoveItems(int32 index, int32 count,
                                                                        bool deleteItems = false);
                        bool                            RemoveItem(BMenu* menu);

                        BMenuItem*                      ItemAt(int32 index) const;
                        BMenu*                          SubmenuAt(int32 index) const;
                        int32                           CountItems() const;
                        int32                           IndexOf(BMenuItem* item) const;
                        int32                           IndexOf(BMenu* menu) const;
                        BMenuItem*                      FindItem(uint32 command) const;
                        BMenuItem*                      FindItem(const char* name) const;

        virtual status_t                        SetTargetForItems(BHandler* target);
        virtual status_t                        SetTargetForItems(BMessenger messenger);
        virtual void                            SetEnabled(bool enable);
        virtual void                            SetRadioMode(bool on);
        virtual void                            SetTriggersEnabled(bool enable);
        virtual void                            SetMaxContentWidth(float maxWidth);

                        void                            SetLabelFromMarked(bool on);
                        bool                            IsLabelFromMarked();
                        bool                            IsEnabled() const;
                        bool                            IsRadioMode() const;
                        bool                            AreTriggersEnabled() const;
                        bool                            IsRedrawAfterSticky() const;
                        float                           MaxContentWidth() const;

                        BMenuItem*                      FindMarked();
                        int32                           FindMarkedIndex();

                        BMenu*                          Supermenu() const;
                        BMenuItem*                      Superitem() const;


        virtual BHandler*                       ResolveSpecifier(BMessage* message,
                                                                        int32 index, BMessage* specifier,
                                                                        int32 form, const char* property);
        virtual status_t                        GetSupportedSuites(BMessage* data);

        virtual status_t                        Perform(perform_code d, void* arg);

protected:
                                                                BMenu(BRect frame, const char* name,
                                                                        uint32 resizeMask, uint32 flags,
                                                                        menu_layout layout, bool resizeToFit);

        virtual void                            LayoutInvalidated(bool descendants);

        virtual BPoint                          ScreenLocation();

                        void                            SetItemMargins(float left, float top,
                                                                        float right, float bottom);
                        void                            GetItemMargins(float* _left, float* _top,
                                                                        float* _right, float* _bottom) const;

                        menu_layout                     Layout() const;

        virtual void                            Show();
                        void                            Show(bool selectFirstItem);
                        void                            Hide();
                        BMenuItem*                      Track(bool startOpened = false,
                                                                        BRect* specialRect = NULL);

public:
        enum add_state {
                B_INITIAL_ADD,
                B_PROCESSING,
                B_ABORT
        };
        virtual bool                            AddDynamicItem(add_state state);
        virtual void                            DrawBackground(BRect updateRect);

                        void                            SetTrackingHook(menu_tracking_hook hook,
                                                                        void* state);

        // Reorder items
                        void                            SortItems(int (*compare)(const BMenuItem*,
                                                                        const BMenuItem*));
                        bool                            SwapItems(int32 indexA, int32 indexB);
                        bool                            MoveItem(int32 indexFrom, int32 indexTo);

private:
        friend class BMenuBar;
        friend class BSeparatorItem;
        friend class BPrivate::MenuPrivate;
        friend status_t _init_interface_kit_();
        friend status_t set_menu_info(menu_info* info);
        friend status_t get_menu_info(menu_info* info);

        struct LayoutData;

        virtual void                            _ReservedMenu3();
        virtual void                            _ReservedMenu4();
        virtual void                            _ReservedMenu5();
        virtual void                            _ReservedMenu6();

                        BMenu&                          operator=(const BMenu& other);

                        void                            _InitData(BMessage* archive);
                        bool                            _Show(bool selectFirstItem = false,
                                                                        bool keyDown = false);
                        void                            _Hide();
                        BMenuItem*                      _Track(int* action, long start = -1);
                        void                            _ScriptReceived(BMessage* message);
                        void                            _ItemScriptReceived(BMessage* message,
                                                                        BMenuItem* item);
                        status_t                        _ResolveItemSpecifier(const BMessage& specifier,
                                                                        int32 what, BMenuItem*& item,
                                                                        int32 *index = NULL);
                        status_t                        _InsertItemAtSpecifier(
                                                                        const BMessage& specifier, int32 what,
                                                                        BMenuItem* item);

                        void                            _UpdateNavigationArea(BPoint position,
                                                                        BRect& navAreaRectAbove,
                                                                        BRect& navAreaBelow);

                        void                            _UpdateStateOpenSelect(BMenuItem* item,
                                                                        BPoint position, BRect& navAreaRectAbove,
                                                                        BRect& navAreaBelow,
                                                                        bigtime_t& selectedTime,
                                                                        bigtime_t& navigationAreaTime);
                        void                            _UpdateStateClose(BMenuItem* item,
                                                                        const BPoint& where,
                                                                        const uint32& buttons);

                        bool                            _AddItem(BMenuItem* item, int32 index);
                        bool                            _RemoveItems(int32 index, int32 count,
                                                                        BMenuItem* item, bool deleteItems = false);
                        bool                            _RelayoutIfNeeded();
                        void                            _LayoutItems(int32 index);
                        BSize                           _ValidatePreferredSize();
                        void                            _ComputeLayout(int32 index, bool bestFit,
                                                                        bool moveItems, float* width,
                                                                        float* height);
                        void                            _ComputeColumnLayout(int32 index, bool bestFit,
                                                                        bool moveItems, BRect* override, BRect& outRect);
                        void                            _ComputeRowLayout(int32 index, bool bestFit,
                                                                        bool moveItems, BRect& outRect);
                        void                            _ComputeMatrixLayout(BRect& outRect);

                        BRect                           _CalcFrame(BPoint where, bool* scrollOn);

protected:
                        void                            DrawItems(BRect updateRect);

private:
                        bool                            _OverSuper(BPoint loc);
                        bool                            _OverSubmenu(BMenuItem* item, BPoint loc);
                        BPrivate::BMenuWindow* _MenuWindow();
                        void                            _DeleteMenuWindow();
                        BMenuItem*                      _HitTestItems(BPoint where,
                                                                        BPoint slop = B_ORIGIN) const;
                        BRect                           _Superbounds() const;
                        void                            _CacheFontInfo();

                        void                            _ItemMarked(BMenuItem* item);
                        void                            _Install(BWindow* target);
                        void                            _Uninstall();
                        void                            _SelectItem(BMenuItem* item,
                                                                        bool showSubmenu = true,
                                                                        bool selectFirstItem = false,
                                                                        bool keyDown = false);
                        bool                            _SelectNextItem(BMenuItem* item, bool forward);
                        BMenuItem*                      _NextItem(BMenuItem* item, bool forward) const;
                        void                            _SetIgnoreHidden(bool ignoreHidden)
                                                                        { fIgnoreHidden = ignoreHidden; }
                        void                            _SetStickyMode(bool on);
                        bool                            _IsStickyMode() const;

                        // Methods to get the current modifier keycode
                        void                            _GetShiftKey(uint32 &value) const;
                        void                            _GetControlKey(uint32 &value) const;
                        void                            _GetCommandKey(uint32 &value) const;
                        void                            _GetOptionKey(uint32 &value) const;
                        void                            _GetMenuKey(uint32 &value) const;

                        void                            _CalcTriggers();
                        bool                            _ChooseTrigger(const char* title, int32& index,
                                                                        uint32& trigger,
                                                                        BPrivate::TriggerList& triggers);
                        void                            _UpdateWindowViewSize(const bool &updatePosition);
                        bool                            _AddDynamicItems(bool keyDown = false);
                        bool                            _OkToProceed(BMenuItem* item,
                                                                        bool keyDown = false);

                        bool                            _CustomTrackingWantsToQuit();

                        int                                     _State(BMenuItem** _item = NULL) const;
                        void                            _InvokeItem(BMenuItem* item, bool now = false);
                        void                            _QuitTracking(bool onlyThis = true);

        static  menu_info                       sMenuInfo;

                        // Variables to keep track of what code is currently assigned to
                        // each modifier key
        static  uint32                          sShiftKey;
        static  uint32                          sControlKey;
        static  uint32                          sOptionKey;
        static  uint32                          sCommandKey;
        static  uint32                          sMenuKey;

                        BMenuItem*                      fChosenItem;
                        BList                           fItems;
                        BRect                           fPad;
                        BMenuItem*                      fSelected;
                        BPrivate::BMenuWindow* fCachedMenuWindow;
                        BMenu*                          fSuper;
                        BMenuItem*                      fSuperitem;
                        BRect                           fSuperbounds;
                        float                           fAscent;
                        float                           fDescent;
                        float                           fFontHeight;
                        uint32                          fState;
                        menu_layout                     fLayout;
                        BRect*                          fExtraRect;
                        float                           fMaxContentWidth;
                        BPoint*                         fInitMatrixSize;
                        BPrivate::ExtraMenuData* fExtraMenuData;

                        LayoutData*                     fLayoutData;

                        int32                           _reserved;

                        char                            fTrigger;
                        bool                            fResizeToFit;
                        bool                            fUseCachedMenuLayout;
                        bool                            fEnabled;
                        bool                            fDynamicName;
                        bool                            fRadioMode;
                        bool                            fTrackNewBounds;
                        bool                            fStickyMode;
                        bool                            fIgnoreHidden;
                        bool                            fTriggerEnabled;
                        bool                            fHasSubmenus;
                        bool                            fAttachAborted;
};

#endif // _MENU_H