    //------------------------------------------------------------------------------
    // emListBox.h
    //
    // Copyright (C) 2015-2016 Oliver Hamann.
    //
    // Homepage: http://eaglemode.sourceforge.net/
    //
    // This program is free software: you can redistribute it and/or modify it under
    // the terms of the GNU General Public License version 3 as published by the
    // Free Software Foundation.
    //
    // This program 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 General Public License version 3 for
    // more details.
    //
    // You should have received a copy of the GNU General Public License version 3
    // along with this program. If not, see <http://www.gnu.org/licenses/>.
    //------------------------------------------------------------------------------

    #ifndef emListBox_h
    #define emListBox_h

    #ifndef emAnything_h
    #include <emCore/emAnything.h>
    #endif

    #ifndef emRasterGroup_h
    #include <emCore/emRasterGroup.h>
    #endif

    //==============================================================================
    //================================= emListBox ==================================
    //==============================================================================

    class emListBox : public emRasterGroup {

    public:

            // Class for list box. It is an emRasterGroup which shows a group of
            // text items, from which the user can select one item. Optionally,
            // multi-selection can be enabled. Each item just consists of a text,
            // but it is possible to derive from emListBox in order to create custom
            // item panels, which show more than just a text.

            enum SelectionType {
                    // Type of selection a user can make in an emListBox.
                    READY_ONLY_SELECTION,
                    SINGLE_SELECTION,
                    MULTI_SELECTION,
                    TOGGLE_SELECTION
            };

            emListBox(
                    ParentArg parent, const emString & name,
                    const emString & caption=emString(),
                    const emString & description=emString(),
                    const emImage & icon=emImage(),
                    SelectionType selType=SINGLE_SELECTION
            );
                    // Constructor.
                    // Arguments:
                    //   parent      - Parent for this panel (emPanel or emView).
                    //   name        - The name for this panel.
                    //   caption     - The label's caption, or empty.
                    //   description - The label's description, or empty.
                    //   icon        - The label's icon, or empty.
                    //   selType     - Type of selection.

            virtual ~emListBox();
                    // Destructor.

            SelectionType GetSelectionType() const;
            void SetSelectionType(SelectionType selType);
                    // Get or set the type of selection, which the user can make in
                    // this list box.

            int GetItemCount() const;
                    // Get number of Items.

            void AddItem(
                    const emString & text,
                    const emAnything & data = emAnything()
            );
                    // Add an item to the end of the list.
                    // Arguments:
                    //   text - The text to be shown in the item.
                    //   data - Any custom data to be stored in the item.

            void InsertItem(
                    int index, const emString & text,
                    const emAnything & data = emAnything()
            );
                    // Add an item at any position in the list.
                    // Arguments:
                    //   index - Index of the new item.
                    //   text  - The text to be shown in the item.
                    //   data  - Any custom data to be stored in the item.

            void RemoveItem(int index);
                    // Remove an item from the list.
                    // Arguments:
                    //   index - Index of the item to be removed.

            void ClearItems();
                    // Remove all items.

            emString GetItemText(int index) const;
                    // Get the text of an item.
                    // Arguments:
                    //   index - Index of the item.
                    // Returns: The text of the item, or an empty string if the
                    // index is out of range.

            void SetItemText(int index, const emString & text);
                    // Set the text of an item.
                    // Arguments:
                    //   index - Index of the item.
                    //   text  - The text to be shown in the item.

            emAnything GetItemData(int index) const;
                    // Get the data of an item.
                    // Arguments:
                    //   index - Index of the item.
                    // Returns: The data of the item, or an invalid emAnything if
                    // the index is out of range.

            void SetItemData(int index, const emAnything & data);
                    // Set the data of an item.
                    // Arguments:
                    //   index - Index of the item.
                    //   data  - Any custom data to be stored in the item.

            int GetSelectionCount() const;
                    // Get number of selected items.

            const emArray<int> & GetSelectedIndices() const;
                    // Get the indices of the selected items. The returned array is
                    // always sorted.

            void SetSelectedIndices(const emArray<int> & itemIndices);
                    // Set the indices of the selected items.

            int GetSelectedIndex() const;
                    // Get the index of the first (or solely) selected item. If no
                    // item is selected, -1 is returned.

            void SetSelectedIndex(int index);
                    // Select a certain item solely.
                    // Arguments:
                    //   index - Index of the item.

            bool IsSelected(int index) const;
                    // Ask whether a certain item is selected.
                    // Arguments:
                    //   index - Index of the item.

            void Select(int index, bool solely=false);
                    // Select an item.
                    // Arguments:
                    //   index  - Index of the item.
                    //   solely - Whether all other items should be deselected.

            void Deselect(int index);
                    // Deselect an item.
                    // Arguments:
                    //   index - Index of the item.

            void ToggleSelection(int index);
                    // Invert the selection of an item.
                    // Arguments:
                    //   index - Index of the item.

            void SelectAll();
                    // Select all items.

            void ClearSelection();
                    // Deselect all items.

            const emSignal & GetSelectionSignal() const;
                    // This signal is signaled after each change of the selection.

            const emSignal & GetItemTriggerSignal() const;
                    // This signal is signaled when an item is triggered by a double
                    // click or by pressing the enter key. The triggered item index
                    // can be get with GetTriggeredItemIndex().

            int GetTriggeredItemIndex() const;
                    // Get the index of the item which was triggered by a double
                    // click or enter key press.

            void TriggerItem(int index);
                    // Trigger an item programmatically.

            class ItemPanelInterface {

            public:

                    // Class for an interface to an item panel. This must be derived
                    // by custom item panel classes. Also see
                    // emListBox::CreateItemPanel(...).

                    ItemPanelInterface(emListBox & listBox, int itemIndex);
                            // Constructor.
                            // Arguments:
                            //   listBox   - The list box.
                            //   itemIndex - The index of the item.

                    virtual ~ItemPanelInterface();
                            // Destructor.

                    emListBox & GetListBox() const;
                            // Get the list box.

                    int GetItemIndex() const;
                            // Get the item index.

                    emString GetItemText() const;
                            // The the text of the item.

                    emAnything GetItemData() const;
                            // The the data of the item.

                    bool IsItemSelected() const;
                            // Whether the item is selected.

            protected:

                    void ProcessItemInput(
                            emPanel * panel, emInputEvent & event,
                            const emInputState & state
                    );
                            // Process mouse an keyboard events which select,
                            // deselect, or trigger an item. This method must be
                            // called from the Input method of the item panel.

                    virtual void ItemTextChanged() = 0;
                            // Called when the text of the item has changed.

                    virtual void ItemDataChanged() = 0;
                            // Called when the data of the item has changed.

                    virtual void ItemSelectionChanged() = 0;
                            // Called when the selection of the item has changed.

            private:
                    friend class emListBox;
                    emListBox & ListBox;
                    int ItemIndex;
            };

            class DefaultItemPanel : public emPanel, public ItemPanelInterface {

            public:

                    // Default class for an item panel.

                    DefaultItemPanel(emListBox & listBox, const emString & name,
                                     int itemIndex);

                    virtual ~DefaultItemPanel();

            protected:

                    virtual void Input(emInputEvent & event,
                                       const emInputState & state,
                                       double mx, double my);

                    virtual bool IsOpaque() const;

                    virtual void Paint(const emPainter & painter,
                                       emColor canvasColor) const;

                    virtual void ItemTextChanged();

                    virtual void ItemDataChanged();

                    virtual void ItemSelectionChanged();
            };

    protected:

            virtual void CreateItemPanel(const emString & name, int itemIndex);
                    // Create the panel for an item. This can be overloaded in order
                    // to have custom item panels. The default implementation
                    // creates an instance of emListBox::DefaultItemPanel. A derived
                    // class may create a panel of an other class. It just has to be
                    // a derivative of emPanel and mListBox::ItemPanelInterface.

            virtual emString GetItemPanelName(int index) const;
                    // Get the name for an item panel. The default implementation
                    // simply converts the index to a decimal string.

            virtual emPanel * GetItemPanel(int index) const;
                    // Get an item panel. The default implementation calls
                    // GetChild(..) with the name of the item panel.

            virtual ItemPanelInterface * GetItemPanelInterface(int index) const;
                    // Get the ItemPanelInterface for an item panel. The default
                    // implementation calls GetItemPanel and does a dynamic cast.

            virtual void Notice(NoticeFlags flags);

            virtual void Input(emInputEvent & event, const emInputState & state,
                               double mx, double my);

            virtual void AutoExpand();

            // - - - - - - - - - - Depreciated methods - - - - - - - - - - - - - - -
            // The following virtual non-const methods have been replaced by const
            // methods (see above). The old versions still exist here with the
            // "final" keyword added, so that old overridings will fail to compile.
            // If you run into this, please adapt your overridings by adding "const".
            virtual emPanel * GetItemPanel(int index) final;
            virtual ItemPanelInterface * GetItemPanelInterface(int index) final;
            // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    private:

            friend class ItemPanelInterface;

            void ProcessItemInput(
                    int itemIndex, emPanel * panel, emInputEvent & event,
                    const emInputState & state
            );

            void SelectByInput(int itemIndex, bool shift, bool ctrl, bool trigger);

            void KeyWalk(emInputEvent & event, const emInputState & state);

            struct Item {
                    emString Text;
                    emAnything Data;
                    bool Selected;
            };

            SelectionType SelType;
            emArray<Item> Items;
            emArray<int> SelectedItemIndices;
            int TriggeredItemIndex;
            int PrevInputItemIndex;
            emSignal SelectionSignal;
            emSignal ItemTriggerSignal;
            emString KeyWalkChars;
            emUInt64 KeyWalkClock;
    };

    inline emListBox::SelectionType emListBox::GetSelectionType() const
    {
            return SelType;
    }

    inline int emListBox::GetItemCount() const
    {
            return Items.GetCount();
    }

    inline int emListBox::GetSelectionCount() const
    {
            return SelectedItemIndices.GetCount();
    }

    inline const emArray<int> & emListBox::GetSelectedIndices() const
    {
            return SelectedItemIndices;
    }

    inline const emSignal & emListBox::GetSelectionSignal() const
    {
            return SelectionSignal;
    }

    inline const emSignal & emListBox::GetItemTriggerSignal() const
    {
            return ItemTriggerSignal;
    }

    inline int emListBox::GetTriggeredItemIndex() const
    {
            return TriggeredItemIndex;
    }

    inline emListBox & emListBox::ItemPanelInterface::GetListBox() const
    {
            return ListBox;
    }

    inline int emListBox::ItemPanelInterface::GetItemIndex() const
    {
            return ItemIndex;
    }

    inline emString emListBox::ItemPanelInterface::GetItemText() const
    {
            return ListBox.GetItemText(ItemIndex);
    }

    inline emAnything emListBox::ItemPanelInterface::GetItemData() const
    {
            return ListBox.GetItemData(ItemIndex);
    }

    inline bool emListBox::ItemPanelInterface::IsItemSelected() const
    {
            return ListBox.IsSelected(ItemIndex);
    }

    #endif