/********************************************************************************
*                                                                               *
*                         I c o n   L i s t   W i d g e t                       *
*                                                                               *
*********************************************************************************
* Copyright (C) 1999,2025 by Jeroen van der Zijp.   All Rights Reserved.        *
*********************************************************************************
* This library 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.                                           *
*                                                                               *
* This library 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 <http://www.gnu.org/licenses/>          *
********************************************************************************/
#ifndef FXICONLIST_H
#define FXICONLIST_H

#ifndef FXSCROLLAREA_H
#include "FXScrollArea.h"
#endif

namespace FX {


/// Icon list styles
enum {
  ICONLIST_EXTENDEDSELECT = 0,                /// Extended selection mode
  ICONLIST_SINGLESELECT   = 0x00100000,       /// At most one selected item
  ICONLIST_BROWSESELECT   = 0x00200000,       /// Always exactly one selected item
  ICONLIST_MULTIPLESELECT = 0x00300000,       /// Multiple selection mode
  ICONLIST_AUTOSIZE       = 0x00400000,       /// Automatically size item spacing
  ICONLIST_DETAILED       = 0,                /// List mode
  ICONLIST_MINI_ICONS     = 0x00800000,       /// Mini Icon mode
  ICONLIST_BIG_ICONS      = 0x01000000,       /// Big Icon mode
  ICONLIST_ROWS           = 0,                /// Row-wise mode
  ICONLIST_COLUMNS        = 0x02000000,       /// Column-wise mode
  ICONLIST_NORMAL         = ICONLIST_EXTENDEDSELECT
  };


class FXIcon;
class FXHeader;
class FXFont;
class FXIconList;
class FXFileList;


/// Icon item
class FXAPI FXIconItem : public FXObject {
  FXDECLARE(FXIconItem)
  friend class FXIconList;
  friend class FXFileList;
protected:
  FXString  label;      // Text of item
  FXIcon   *bigIcon;    // Big icon shown in big icon mode
  FXIcon   *miniIcon;   // Mini icon shown in mini icon mode
  FXptr     data;       // User data pointer
  FXuint    state;      // State flags
private:
  FXIconItem(const FXIconItem&);
  FXIconItem& operator=(const FXIconItem&);
protected:
  FXIconItem():bigIcon(nullptr),miniIcon(nullptr),data(nullptr),state(0){}
  virtual void draw(const FXIconList* list,FXDC& dc,FXint x,FXint y,FXint w,FXint h) const;
  virtual FXint hitItem(const FXIconList* list,FXint rx,FXint ry,FXint rw=1,FXint rh=1) const;
protected:
  virtual void drawBigIcon(const FXIconList* list,FXDC& dc,FXint x,FXint y,FXint w,FXint h) const;
  virtual void drawMiniIcon(const FXIconList* list,FXDC& dc,FXint x,FXint y,FXint w,FXint h) const;
  virtual void drawDetails(const FXIconList* list,FXDC& dc,FXint x,FXint y,FXint w,FXint h) const;
public:
  enum {
    SELECTED      = 1,  /// Selected
    FOCUS         = 2,  /// Focus
    DISABLED      = 4,  /// Disabled
    DRAGGABLE     = 8,  /// Draggable
    BIGICONOWNED  = 16, /// Big icon owned by item
    MINIICONOWNED = 32  /// Mini icon owned by item
    };
public:

  /// Construct new item with given text, icons, and user-data
  FXIconItem(const FXString& text,FXIcon* bi=nullptr,FXIcon* mi=nullptr,FXptr ptr=nullptr):label(text),bigIcon(bi),miniIcon(mi),data(ptr),state(0){}

  /// Change item's text label
  virtual void setText(const FXString& txt);

  /// Return item's text label
  const FXString& getText() const { return label; }

  /// Change item's big icon, deleting the old icon if it was owned
  virtual void setBigIcon(FXIcon* icn,FXbool owned=false);

  /// Return item's big icon
  FXIcon* getBigIcon() const { return bigIcon; }

  /// Change item's mini icon, deleting the old icon if it was owned
  virtual void setMiniIcon(FXIcon* icn,FXbool owned=false);

  /// Return item's mini icon
  FXIcon* getMiniIcon() const { return miniIcon; }

  /// Change item's user data
  void setData(FXptr ptr){ data=ptr; }

  /// Get item's user data
  FXptr getData() const { return data; }

  /// Make item draw as focused
  virtual void setFocus(FXbool focus);

  /// Return true if item has focus
  FXbool hasFocus() const { return (state&FOCUS)!=0; }

  /// Select item
  virtual void setSelected(FXbool selected);

  /// Return true if this item is selected
  FXbool isSelected() const { return (state&SELECTED)!=0; }

  /// Enable or disable item
  virtual void setEnabled(FXbool enabled);

  /// Return true if this item is enabled
  FXbool isEnabled() const { return (state&DISABLED)==0; }

  /// Make item draggable
  virtual void setDraggable(FXbool draggable);

  /// Return true if this item is draggable
  FXbool isDraggable() const { return (state&DRAGGABLE)!=0; }

  /// Return tip text
  virtual FXString getTipText() const;

  /// Return width of item as drawn in list
  virtual FXint getWidth(const FXIconList* list) const;

  /// Return height of item as drawn in list
  virtual FXint getHeight(const FXIconList* list) const;

  /// Create server-side resources
  virtual void create();

  /// Detach server-side resources
  virtual void detach();

  /// Destroy server-side resources
  virtual void destroy();

  /// Save to stream
  virtual void save(FXStream& store) const;

  /// Load from stream
  virtual void load(FXStream& store);

  /// Destroy item and free icons if owned
  virtual ~FXIconItem();
  };


/// Icon item collate function
typedef FXint (*FXIconListSortFunc)(const FXIconItem*,const FXIconItem*);


/// List of FXIconItem's
typedef FXObjectListOf<FXIconItem> FXIconItemList;


/**
* A Icon List Widget displays a list of items, each with a text and
* optional icon.  Icon List can display its items in essentially three
* different ways; in big-icon mode, the bigger of the two icons is used
* for each item, and the text is placed underneath the icon. In mini-
* icon mode, the icons are listed in rows and columns, with the smaller
* icon preceding the text.  Finally, in detail mode the icons are listed
* in a single column, and all fields of the text are shown under a
* header control with one button for each subfield.
* When an item's selected state changes, the icon list sends
* a SEL_SELECTED or SEL_DESELECTED message.  A change of the current
* item is signified by the SEL_CHANGED message.
* The icon list sends SEL_COMMAND messages when the user clicks on an item,
* and SEL_CLICKED, SEL_DOUBLECLICKED, and SEL_TRIPLECLICKED when the user
* clicks once, twice, or thrice, respectively.
* When items are inserted or removed, the icon list sends messages
* of the type SEL_INSERTED or SEL_DELETED.
* In each of these cases, the index to the item, if any, is passed in the
* 3rd argument of the message.
* The text in each item is a string separated by tabs for each column;
* in mini- or big-icon mode, only the text before the first tab is shown.
* In detail-mode, the text before the first tab is shown in the first column,
* the text between the first and second tab is shown in the second column,
* and so on.
*/
class FXAPI FXIconList : public FXScrollArea {
  FXDECLARE(FXIconList)
protected:
  FXHeader          *header;            // Header control
  FXIconItemList     items;		// Item list
  FXint              nrows;             // Number of rows
  FXint              ncols;             // Number of columns
  FXint              anchor;            // Anchor item
  FXint              current;           // Current item
  FXint              extent;            // Extent item
  FXint              viewable;          // Visible item
  FXFont            *font;              // Font
  FXIconListSortFunc sortfunc;          // Item sort function
  FXColor            textColor;         // Text color
  FXColor            selbackColor;      // Selected back color
  FXColor            seltextColor;      // Selected text color
  FXint              itemSpace;         // Space for item label
  FXint              itemWidth;         // Item width
  FXint              itemHeight;        // Item height
  FXint              anchorx;           // Rectangular selection
  FXint              anchory;
  FXint              currentx;
  FXint              currenty;
  FXint              grabx;             // Grab point x
  FXint              graby;             // Grab point y
  FXString           lookup;            // Lookup string
  FXString           help;              // Help text
  FXbool             state;             // State of item
protected:
  FXIconList();
  void recompute();
  void startLasso(FXint ax,FXint ay);
  void updateLasso(FXint cx,FXint cy);
  void endLasso();
  void getrowscols(FXint& nr,FXint& nc,FXint w,FXint h) const;
  void lassoChanged(FXint ox,FXint oy,FXint ow,FXint oh,FXint nx,FXint ny,FXint nw,FXint nh,FXbool notify);
  virtual void moveContents(FXint x,FXint y);
  virtual FXIconItem *createItem(const FXString& text,FXIcon *big,FXIcon* mini,FXptr ptr);
  static FXint compareSection(const FXchar *p,const FXchar* q,FXint s);
  static FXint compareSectionCase(const FXchar *p,const FXchar* q,FXint s);
private:
  FXIconList(const FXIconList&);
  FXIconList &operator=(const FXIconList&);
public:
  long onPaint(FXObject*,FXSelector,void*);
  long onEnter(FXObject*,FXSelector,void*);
  long onLeave(FXObject*,FXSelector,void*);
  long onUngrabbed(FXObject*,FXSelector,void*);
  long onKeyPress(FXObject*,FXSelector,void*);
  long onKeyRelease(FXObject*,FXSelector,void*);
  long onLeftBtnPress(FXObject*,FXSelector,void*);
  long onLeftBtnRelease(FXObject*,FXSelector,void*);
  long onRightBtnPress(FXObject*,FXSelector,void*);
  long onRightBtnRelease(FXObject*,FXSelector,void*);
  long onMouseWheel(FXObject*,FXSelector,void*);
  long onMotion(FXObject*,FXSelector,void*);
  long onQueryTip(FXObject*,FXSelector,void*);
  long onQueryHelp(FXObject*,FXSelector,void*);
  long onTipTimer(FXObject*,FXSelector,void*);
  long onCmdSelectAll(FXObject*,FXSelector,void*);
  long onCmdDeselectAll(FXObject*,FXSelector,void*);
  long onCmdSelectInverse(FXObject*,FXSelector,void*);
  long onCmdArrangeByRows(FXObject*,FXSelector,void*);
  long onUpdArrangeByRows(FXObject*,FXSelector,void*);
  long onCmdArrangeByColumns(FXObject*,FXSelector,void*);
  long onUpdArrangeByColumns(FXObject*,FXSelector,void*);
  long onCmdShowDetails(FXObject*,FXSelector,void*);
  long onUpdShowDetails(FXObject*,FXSelector,void*);
  long onCmdShowBigIcons(FXObject*,FXSelector,void*);
  long onUpdShowBigIcons(FXObject*,FXSelector,void*);
  long onCmdShowMiniIcons(FXObject*,FXSelector,void*);
  long onUpdShowMiniIcons(FXObject*,FXSelector,void*);
  long onChgHeader(FXObject*,FXSelector,void*);
  long onClkHeader(FXObject*,FXSelector,void*);
  long onFocusIn(FXObject*,FXSelector,void*);
  long onFocusOut(FXObject*,FXSelector,void*);
  long onClicked(FXObject*,FXSelector,void*);
  long onDoubleClicked(FXObject*,FXSelector,void*);
  long onTripleClicked(FXObject*,FXSelector,void*);
  long onCommand(FXObject*,FXSelector,void*);
  long onAutoScroll(FXObject*,FXSelector,void*);
  long onLookupTimer(FXObject*,FXSelector,void*);
  long onCmdSetValue(FXObject*,FXSelector,void*);
  long onCmdGetIntValue(FXObject*,FXSelector,void*);
  long onCmdSetIntValue(FXObject*,FXSelector,void*);
public:
  static FXint ascending(const FXIconItem* a,const FXIconItem* b);
  static FXint descending(const FXIconItem* a,const FXIconItem* b);
  static FXint ascendingCase(const FXIconItem* a,const FXIconItem* b);
  static FXint descendingCase(const FXIconItem* a,const FXIconItem* b);
public:
  enum {
    ID_LOOKUPTIMER=FXScrollArea::ID_LAST,
    ID_HEADER,
    ID_SHOW_DETAILS,
    ID_SHOW_MINI_ICONS,
    ID_SHOW_BIG_ICONS,
    ID_ARRANGE_BY_ROWS,
    ID_ARRANGE_BY_COLUMNS,
    ID_SELECT_ALL,
    ID_DESELECT_ALL,
    ID_SELECT_INVERSE,
    ID_LAST
    };
public:

  /// Construct icon list with no items in it initially
  FXIconList(FXComposite *p,FXObject* tgt=nullptr,FXSelector sel=0,FXuint opts=ICONLIST_NORMAL,FXint x=0,FXint y=0,FXint w=0,FXint h=0);

  /// Create server-side resources
  virtual void create();

  /// Detach server-side resources
  virtual void detach();

  /// Recalculate layout
  virtual void recalc();

  /// Perform layout
  virtual void layout();

  /// Compute and return content width
  virtual FXint getContentWidth();

  /// Return content height
  virtual FXint getContentHeight();

  /// Return visible area y position
  virtual FXint getVisibleY() const;

  /// Return visible area height
  virtual FXint getVisibleHeight() const;

  /// Icon list can receive focus
  virtual FXbool canFocus() const;

  /// Move the focus to this window
  virtual void setFocus();

  /// Remove the focus from this window
  virtual void killFocus();

  /// Resize this window to the specified width and height
  virtual void resize(FXint w,FXint h);

  /// Move and resize this window in the parent's coordinates
  virtual void position(FXint x,FXint y,FXint w,FXint h);

  /// Return number of items
  FXint getNumItems() const { return (FXint)items.no(); }

  /// Return number of rows
  FXint getNumRows() const { return nrows; }

  /// Return number of columns
  FXint getNumCols() const { return ncols; }

  /// Return header control
  FXHeader* getHeader() const { return header; }

  /// Set headers from array of strings
  void setHeaders(const FXchar** strings,FXint size=1);

  /// Set headers from newline separated strings
  void setHeaders(const FXString& strings,FXint size=1);

  /// Append header with given text and optional icon
  void appendHeader(const FXString& text,FXIcon *icon=nullptr,FXint size=1);

  /// Remove header at index
  void removeHeader(FXint index);

  /// Change text of header at index
  void setHeaderText(FXint index,const FXString& text);

  /// Return text of header at index
  FXString getHeaderText(FXint index) const;

  /// Change icon of header at index
  void setHeaderIcon(FXint index,FXIcon *icon);

  /// Return icon of header at index
  FXIcon* getHeaderIcon(FXint index) const;

  /// Change size of header at index
  void setHeaderSize(FXint index,FXint size);

  /// Return width of header at index
  FXint getHeaderSize(FXint index) const;

  /// Return number of headers
  FXint getNumHeaders() const;

  /// Return the item at the given index
  FXIconItem *getItem(FXint index) const;

  /// Replace the item with a [possibly subclassed] item
  FXint setItem(FXint index,FXIconItem* item,FXbool notify=false);

  /// Replace items text, icons, and user-data pointer
  FXint setItem(FXint index,const FXString& text,FXIcon *big=nullptr,FXIcon* mini=nullptr,FXptr ptr=nullptr,FXbool notify=false);

  /// Fill list by appending items from array of strings
  FXint fillItems(const FXchar** strings,FXIcon *big=nullptr,FXIcon* mini=nullptr,FXptr ptr=nullptr,FXbool notify=false);

  /// Fill list by appending items from array of strings
  FXint fillItems(const FXString* strings,FXIcon *big=nullptr,FXIcon* mini=nullptr,FXptr ptr=nullptr,FXbool notify=false);

  /// Fill list by appending items from newline separated strings
  FXint fillItems(const FXString& strings,FXIcon *big=nullptr,FXIcon* mini=nullptr,FXptr ptr=nullptr,FXbool notify=false);

  /// Insert a new [possibly subclassed] item at the give index
  FXint insertItem(FXint index,FXIconItem* item,FXbool notify=false);

  /// Insert item at index with given text, icons, and user-data pointer
  FXint insertItem(FXint index,const FXString& text,FXIcon *big=nullptr,FXIcon* mini=nullptr,FXptr ptr=nullptr,FXbool notify=false);

  /// Append a [possibly subclassed] item to the end of the list
  FXint appendItem(FXIconItem* item,FXbool notify=false);

  /// Append new item with given text and optional icons, and user-data pointer
  FXint appendItem(const FXString& text,FXIcon *big=nullptr,FXIcon* mini=nullptr,FXptr ptr=nullptr,FXbool notify=false);

  /// Prepend a [possibly subclassed] item to the end of the list
  FXint prependItem(FXIconItem* item,FXbool notify=false);

  /// Prepend new item with given text and optional icons, and user-data pointer
  FXint prependItem(const FXString& text,FXIcon *big=nullptr,FXIcon* mini=nullptr,FXptr ptr=nullptr,FXbool notify=false);

  /// Move item from oldindex to newindex
  FXint moveItem(FXint newindex,FXint oldindex,FXbool notify=false);

  /// Extract item from list
  FXIconItem* extractItem(FXint index,FXbool notify=false);

  /// Remove item from list
  void removeItem(FXint index,FXbool notify=false);

  /// Remove all items from list
  void clearItems(FXbool notify=false);

  /// Return item width
  FXint getItemWidth() const { return itemWidth; }

  /// Return item height
  FXint getItemHeight() const { return itemHeight; }

  /// Return index of item at x,y, or -1 if none
  virtual FXint getItemAt(FXint x,FXint y) const;

  /**
  * Search items by name, beginning from item start.  If the start
  * item is -1 the search will start at the first item in the list.
  * Flags may be SEARCH_FORWARD or SEARCH_BACKWARD to control the
  * search direction; this can be combined with SEARCH_NOWRAP or SEARCH_WRAP
  * to control whether the search wraps at the start or end of the list.
  * The option SEARCH_IGNORECASE causes a case-insensitive match.  Finally,
  * passing SEARCH_PREFIX causes searching for a prefix of the item name.
  * Return -1 if no matching item is found.
  */
  FXint findItem(const FXString& string,FXint start=-1,FXuint flags=SEARCH_FORWARD|SEARCH_WRAP) const;

  /**
  * Search items by associated user data, beginning from item start. If the
  * start item is -1 the search will start at the first item in the list.
  * Flags may be SEARCH_FORWARD or SEARCH_BACKWARD to control the
  * search direction; this can be combined with SEARCH_NOWRAP or SEARCH_WRAP
  * to control whether the search wraps at the start or end of the list.
  */
  FXint findItemByData(FXptr ptr,FXint start=-1,FXuint flags=SEARCH_FORWARD|SEARCH_WRAP) const;

  /// Scroll to make item at index visible
  virtual void makeItemVisible(FXint index);

  /// Change item text
  void setItemText(FXint index,const FXString& text);

  /// Return item text
  FXString getItemText(FXint index) const;

  /// Change item big icon
  void setItemBigIcon(FXint index,FXIcon* icon,FXbool owned=false);

  /// Return big icon of item at index
  FXIcon* getItemBigIcon(FXint index) const;

  /// Change item mini icon
  void setItemMiniIcon(FXint index,FXIcon* icon,FXbool owned=false);

  /// Return mini icon of item at index
  FXIcon* getItemMiniIcon(FXint index) const;

  /// Change item user-data pointer
  void setItemData(FXint index,FXptr ptr);

  /// Return item user-data pointer
  FXptr getItemData(FXint index) const;

  /// Return true if item at index is selected
  FXbool isItemSelected(FXint index) const;

  /// Return true if item at index is current
  FXbool isItemCurrent(FXint index) const;

  /// Return true if item at index is visible
  FXbool isItemVisible(FXint index) const;

  /// Return true if item at index is enabled
  FXbool isItemEnabled(FXint index) const;

  /// Return item hit code: 0 outside, 1 icon, 2 text
  FXint hitItem(FXint index,FXint x,FXint y,FXint ww=1,FXint hh=1) const;

  /// Repaint item at index
  void updateItem(FXint index) const;

  /// Enable item at index
  virtual FXbool enableItem(FXint index);

  /// Disable item at index
  virtual FXbool disableItem(FXint index);

  /// Select item at index
  virtual FXbool selectItem(FXint index,FXbool notify=false);

  /// Deselect item at index
  virtual FXbool deselectItem(FXint index,FXbool notify=false);

  /// Toggle item at index
  virtual FXbool toggleItem(FXint index,FXbool notify=false);

  /// Select items in rectangle
  virtual FXbool selectInRectangle(FXint x,FXint y,FXint w,FXint h,FXbool notify=false);

  /// Extend selection from anchor index to index
  virtual FXbool extendSelection(FXint index,FXbool notify=false);

  /// Select all items
  virtual FXbool selectAll(FXbool notify=false);

  /// Deselect all items
  virtual FXbool killSelection(FXbool notify=false);

  /// Change current item index
  virtual void setCurrentItem(FXint index,FXbool notify=false);

  /// Return current item index, or -1 if none
  FXint getCurrentItem() const { return current; }

  /// Change anchor item index
  void setAnchorItem(FXint index);

  /// Return anchor item index, or -1 if none
  FXint getAnchorItem() const { return anchor; }

  /// Sort items
  void sortItems();

  /// Return sort function
  FXIconListSortFunc getSortFunc() const { return sortfunc; }

  /// Change sort function
  void setSortFunc(FXIconListSortFunc func){ sortfunc=func; }

  /// Change text font
  void setFont(FXFont* fnt);

  /// Return text font
  FXFont* getFont() const { return font; }

  /// Return normal text color
  FXColor getTextColor() const { return textColor; }

  /// Change normal text color
  void setTextColor(FXColor clr);

  /// Return selected text background
  FXColor getSelBackColor() const { return selbackColor; }

  /// Change selected text background
  void setSelBackColor(FXColor clr);

  /// Return selected text color
  FXColor getSelTextColor() const { return seltextColor; }

  /// Change selected text color
  void setSelTextColor(FXColor clr);

  /// Change maximum item space for each item
  void setItemSpace(FXint s);

  /// Return maximum item space
  FXint getItemSpace() const { return itemSpace; }

  /// Get the current icon list style
  FXuint getListStyle() const;

  /// Set the current icon list style.
  void setListStyle(FXuint style);

  /// Change selection mode
  void setSelectMode(FXuint mode);

  /// Return current selection mode
  FXuint getSelectMode() const;

  /// Set the status line help text for this widget
  void setHelpText(const FXString& text);

  /// Get the status line help text for this widget
  const FXString& getHelpText() const { return help; }

  /// Save list to a stream
  virtual void save(FXStream& store) const;

  /// Load list from a stream
  virtual void load(FXStream& store);

  /// Destructor
  virtual ~FXIconList();
  };

}

#endif
