// Aseprite UI Library
// Copyright (C) 2020-2022  Igara Studio S.A.
// Copyright (C) 2001-2017  David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.

#ifndef UI_LISTBOX_H_INCLUDED
#define UI_LISTBOX_H_INCLUDED
#pragma once

#include "obs/signal.h"
#include "ui/widget.h"

#include <vector>

namespace ui {

  class ListItem;

  class ListBox : public Widget {
  public:
    ListBox();

    bool isMultiselect() const { return m_multiselect; }
    void setMultiselect(const bool multiselect);

    Widget* getSelectedChild();
    int getSelectedIndex();

    void selectChild(Widget* item, Message* msg = nullptr);
    void selectIndex(int index, Message* msg = nullptr);

    int getItemsCount() const;

    void makeChildVisible(Widget* item);
    void centerScroll();
    void sortItems();
    void sortItems(bool (*cmp)(Widget* a, Widget* b));

    obs::signal<void()> Change;
    obs::signal<void()> DoubleClickItem;

  protected:
    virtual bool onProcessMessage(Message* msg) override;
    virtual void onPaint(PaintEvent& ev) override;
    virtual void onResize(ResizeEvent& ev) override;
    virtual void onSizeHint(SizeHintEvent& ev) override;
    virtual void onChange();
    virtual void onDoubleClickItem();

    int advanceIndexThroughVisibleItems(
      int startIndex, int delta, const bool loop);

    // True if this listbox accepts selecting multiple items at the
    // same time.
    bool m_multiselect;

    // Range of items selected when we click down/up. Used to specify
    // the range of selected items in a multiselect operation.
    int m_firstSelectedIndex;
    int m_lastSelectedIndex;

    // Initial state (isSelected()) of each list item when the
    // selection operation started. It's used to switch the state of
    // items in case that the user is Ctrl+clicking items several
    // items at the same time.
    std::vector<bool> m_states;

  private:
    // Finds the parent ListItem that contains the specified descendant.
    ListItem* findParentListItem(Widget* descendant);
  };

} // namespace ui

#endif
