#--------------------------------------------------------------------------
#<pycode(py_kernwin_choose)>
import _ida_kernwin

class Choose(object):
    """
    Chooser wrapper class.

    Some constants are defined in this class.
    Please refer to kernwin.hpp for more information.
    """

    CH_MODAL        = _ida_kernwin.CH_MODAL
    """Modal chooser"""

    CH_MULTI        = _ida_kernwin.CH_MULTI
    """
    Allow multi selection.
    Refer the description of the OnInsertLine(), OnDeleteLine(),
    OnEditLine(), OnSelectLine(), OnRefresh(), OnSelectionChange() to
    see a difference between single and multi selection callbacks.
    """

    CH_NOBTNS       = _ida_kernwin.CH_NOBTNS

    CH_ATTRS        = _ida_kernwin.CH_ATTRS

    CH_NOIDB        = _ida_kernwin.CH_NOIDB
    """use the chooser even without an open database, same as x0=-2"""

    CH_FORCE_DEFAULT = _ida_kernwin.CH_FORCE_DEFAULT
    """
    If a non-modal chooser was already open, change selection to the given
    default one
    """

    CH_CAN_INS      = _ida_kernwin.CH_CAN_INS
    """allow to insert new items"""

    CH_CAN_DEL      = _ida_kernwin.CH_CAN_DEL
    """allow to delete existing item(s)"""

    CH_CAN_EDIT     = _ida_kernwin.CH_CAN_EDIT
    """allow to edit existing item(s)"""

    CH_CAN_REFRESH  = _ida_kernwin.CH_CAN_REFRESH
    """allow to refresh chooser"""

    CH_QFLT         =  _ida_kernwin.CH_QFLT
    """open with quick filter enabled and focused"""

    CH_QFTYP_SHIFT  = _ida_kernwin.CH_QFTYP_SHIFT
    CH_QFTYP_DEFAULT     = _ida_kernwin.CH_QFTYP_DEFAULT
    CH_QFTYP_NORMAL      = _ida_kernwin.CH_QFTYP_NORMAL
    CH_QFTYP_WHOLE_WORDS = _ida_kernwin.CH_QFTYP_WHOLE_WORDS
    CH_QFTYP_REGEX       = _ida_kernwin.CH_QFTYP_REGEX
    CH_QFTYP_FUZZY       = _ida_kernwin.CH_QFTYP_FUZZY
    CH_QFTYP_MASK        = _ida_kernwin.CH_QFTYP_MASK

    CH_NO_STATUS_BAR = _ida_kernwin.CH_NO_STATUS_BAR
    """don't show a status bar"""
    CH_RESTORE       = _ida_kernwin.CH_RESTORE
    """restore floating position if present (equivalent of WOPN_RESTORE) (GUI version only)"""

    CH_RENAME_IS_EDIT = _ida_kernwin.CH_RENAME_IS_EDIT
    """triggering a 'edit/rename' (i.e., F2 shortcut) on a cell,
       should call the edit() callback for the corresponding row."""

    CH_BUILTIN_SHIFT = _ida_kernwin.CH_BUILTIN_SHIFT
    CH_BUILTIN_MASK = _ida_kernwin.CH_BUILTIN_MASK

    """The chooser can provide a dirtree_t, meaning a tree-like structure
       can be provided to the user (instead of a flat table)"""
    CH_HAS_DIRTREE = _ida_kernwin.CH_HAS_DIRTREE

    """The chooser can be used in a diffing/merging workflow"""
    CH_HAS_DIFF = _ida_kernwin.CH_HAS_DIFF

    # column flags (are specified in the widths array)
    CHCOL_PLAIN     = _ida_kernwin.CHCOL_PLAIN
    CHCOL_PATH      = _ida_kernwin.CHCOL_PATH
    CHCOL_HEX       = _ida_kernwin.CHCOL_HEX
    CHCOL_DEC       = _ida_kernwin.CHCOL_DEC
    CHCOL_EA        = _ida_kernwin.CHCOL_EA
    CHCOL_FNAME     = _ida_kernwin.CHCOL_FNAME
    CHCOL_FORMAT    = _ida_kernwin.CHCOL_FORMAT
    CHCOL_DEFHIDDEN = _ida_kernwin.CHCOL_DEFHIDDEN
    CHCOL_DRAGHINT  = _ida_kernwin.CHCOL_DRAGHINT
    CHCOL_INODENAME = _ida_kernwin.CHCOL_INODENAME

    # special values of the chooser index
    NO_SELECTION   = -1
    """there is no selected item"""
    EMPTY_CHOOSER  = -2
    """the chooser is initialized"""
    ALREADY_EXISTS = -3
    """the non-modal chooser with the same data is already open"""
    NO_ATTR        = -4
    """some mandatory attribute is missing"""

    # return value of ins(), del(), edit(), enter(), refresh() callbacks
    NOTHING_CHANGED   = 0
    ALL_CHANGED       = 1
    SELECTION_CHANGED = 2

    class UI_Hooks_Trampoline(UI_Hooks):
        def __init__(self, v):
            UI_Hooks.__init__(self)
            self.hook()
            import weakref
            self.v = weakref.ref(v)

        def populating_widget_popup(self, widget, popup_handle):
            chooser = self.v()
            if widget == chooser.GetWidget() and \
               hasattr(chooser, "OnPopup") and \
               callable(getattr(chooser, "OnPopup")):
                chooser.OnPopup(widget, popup_handle)

    def __init__(self, title, cols, flags = 0, popup_names = None,
                 icon=-1, x1=-1, y1=-1, x2=-1, y2=-1,
                 deflt = None,
                 embedded = False, width = None, height = None,
                 forbidden_cb = 0, flags2 = 0):
        """
        Constructs a chooser window.
        :param title: The chooser title
        :param cols: a list of colums; each list item is a list of two items
            example: [ ["Address", 10 | Choose.CHCOL_HEX],
                       ["Name",    30 | Choose.CHCOL_PLAIN] ]
        :param flags: One of CH_XXXX constants
        :param flags2: One of CH2_XXXX constants
        :param deflt: The index of the default item (0-based) for single
            selection choosers or the list of indexes for multi selection
            chooser
        :param popup_names: List of new captions to replace this list
            ["Insert", "Delete", "Edit", "Refresh"]
        :param icon: Icon index (the icon should exist in ida resources or
            an index to a custom loaded icon)
        :param x1: The default location (for txt-version)
        :param y1: The default location (for txt-version)
        :param x2: The default location (for txt-version)
        :param y2: The default location (for txt-version)
        :param embedded: Create as embedded chooser
        :param width: Embedded chooser width
        :param height: Embedded chooser height
        :param forbidden_cb: Explicitly forbidden callbacks
        """
        self.title = title
        self.flags = flags
        self.flags2 = flags2
        self.cols = cols
        if deflt == None:
          deflt = 0 if (flags & Choose.CH_MULTI) == 0 else [0]
        self.deflt = deflt
        self.popup_names = popup_names
        self.icon = icon
        self.x1 = x1
        self.y1 = y1
        self.x2 = x2
        self.y2 = y2
        self.embedded = embedded
        self.width = width
        self.height = height
        self.forbidden_cb = forbidden_cb
        self.ui_hooks_trampoline = None # set on Show
        def _qccb(ctx, cmd_id):
            for idx in ctx.chooser_selection:
                self.OnCommand(idx, cmd_id)
        self._quick_commands = quick_widget_commands_t(_qccb)


    def Embedded(self, create_chobj=False):
        """
        Creates an embedded chooser (as opposed to Show())
        :returns: Returns 0 on success or NO_ATTR
        """
        if not self.embedded:
          return Choose.NO_ATTR
        if create_chobj:
            return _ida_kernwin.choose_create_embedded_chobj(self)
        else:
            return _ida_kernwin.choose_choose(self)


    def GetEmbSelection(self):
        """
        Deprecated. For embedded choosers, the selection is
        available through 'Form.EmbeddedChooserControl.selection'
        """
        return None


    def Show(self, modal=False):
        """
        Activates or creates a chooser window
        :param modal: Display as modal dialog
        :returns: For all choosers it will return NO_ATTR if some mandatory
                 attribute is missing. The mandatory attributes are: flags,
                 title, cols, OnGetSize(), OnGetLine();
                 For modal choosers it will return the selected item index (0-based),
                 or NO_SELECTION if no selection,
                 or EMPTY_CHOOSER if the OnRefresh() callback returns EMPTY_CHOOSER;
                 For non-modal choosers it will return 0
                 or ALREADY_EXISTS if the chooser was already open and is active now;
        """
        if self.embedded:
          return Choose.NO_ATTR
        # it will be deleted and unhooked in py_choose_t::closed()
        self.ui_hooks_trampoline = self.UI_Hooks_Trampoline(self)
        if modal:
            self.flags |= Choose.CH_MODAL

            # Disable the timeout
            with disabled_script_timeout_t():
                n = _ida_kernwin.choose_choose(self)

            # Delete the modal chooser instance
            self.Close()

            return n
        else:
            self.flags &= ~Choose.CH_MODAL
            return _ida_kernwin.choose_choose(self)


    def Activate(self):
        """Activates a visible chooser"""
        return _ida_kernwin.choose_activate(self)


    def Refresh(self):
        """Causes the refresh callback to trigger"""
        return _ida_kernwin.choose_refresh(self)


    def Close(self):
        """Closes the chooser"""
        if not self.embedded:
            _ida_kernwin.choose_close(self)

    def GetWidget(self):
        """
        Return the TWidget underlying this view.

        :returns: The TWidget underlying this view, or None.
        """
        return _ida_kernwin.choose_get_widget(self)

    def adjust_last_item(self, n):
        """
        Helper for OnDeleteLine() and OnRefresh() callbacks.
        They can be finished by the following line:
        return [Choose.ALL_CHANGED] + self.adjust_last_item(n)
        :param n: line number of the remaining select item
        :returns: list of selected lines numbers (one element or empty)
        """
        cnt = self.OnGetSize()
        if cnt == 0:
            return []
        # take in account deleting of the last item(s)
        if n >= cnt:
            n = cnt - 1
        return [n]

    def AddCommand(self,
                   caption,
                   flags = _ida_kernwin.CHOOSER_POPUP_MENU,
                   menu_index = -1,
                   icon = -1,
                   emb=None,
                   shortcut=None):
        return self._quick_commands.add(
            caption=caption,
            flags=flags,
            menu_index=menu_index,
            icon=icon,
            emb=emb,
            shortcut=shortcut)

    def OnPopup(self, widget, popup_handle):
        self._quick_commands.populate_popup(widget, popup_handle)

    def OnInit(self):
        """
        Initialize the chooser and populate it.

        This callback is optional
        """
        pass

    def OnGetSize(self):
        """
        Get the number of elements in the chooser.

        This callback is mandatory

        :returns: the number of elements
        """
        pass

    def OnGetLine(self, n):
        """
        Get data for an element

        This callback is mandatory

        :param n: the index to fetch data for
        :returns: a list of strings
        """
        pass

    def OnGetIcon(self, n):
        """
        Get an icon to associate with the first cell of an element

        :param n: index of the element
        :returns: an icon ID
        """
        pass

    def OnGetLineAttr(self, n):
        """
        Get attributes for an element

        :param n: index of the element
        :returns: a tuple (color, flags)
        """
        pass

    def OnInsertLine(self, sel):
        """
        User asked to insert an element

        :param sel: the current selection
        :returns: a tuple (changed, selection)
        """
        pass

    def OnDeleteLine(self, sel):
        """
        User deleted an element

        :param sel: the current selection
        :returns: a tuple (changed, selection)
        """
        pass

    def OnEditLine(self, sel):
        """
        User asked to edit an element.

        :param sel: the current selection
        :returns: a tuple (changed, selection)
        """
        pass

    def OnSelectLine(self, sel):
        """
        User pressed the enter key, or double-clicked a selection

        :param sel: the current selection
        :returns: a tuple (changed, selection)
        """
        pass

    def OnSelectionChange(self, sel):
        """
        Selection changed

        :param sel: the new selection
        """
        pass

    def OnRefresh(self, sel):
        """
        The chooser needs to be refreshed.
        It returns the new positions of the selected items.

        :param sel: the current selection
        :returns: a tuple (changed, selection)
        """
        pass

    def OnClose(self):
        """
        The chooser window is closed.
        """
        pass

    def OnGetEA(self, n):
        """
        Get the address of an element

        When this function returns valid addresses:
          * If any column has the `CHCOL_FNAME` flag, rows will
            be colored according to the attributes of the functions
            who own those addresses (extern, library function,
            Lumina, ... - similar to what the "Functions" widget does)
          * When a selection is present and the user presses `<Enter>`
            (`<Shift+Enter>` if the chooser is modal), IDA will jump
            to that address (through jumpto())
        :param n: element number (0-based)
        :returns: the effective address, ida_idaapi.BADADDR if the element has no address
        """
        pass

    def OnGetDirTree(self):
        """
        Get the dirtree_t that will be used to present a tree-like
        structure to the user (see CH_HAS_DIRTREE)

        :returns: the dirtree_t, or None
        """
        pass

    def OnIndexToInode(self, n):
        """
        Map an element index to a dirtree_t inode

        This callback is mandatory if CH_HAS_DIRTREE is specified

        :param n: index of the element
        :returns: the inode number
        """
        pass

    def OnIndexToDiffpos(self, n):
        """
        Map an element index to a diffpos_t

        This callback is mandatory if CH_HAS_DIFF is specified

        :param n: index of the element
        :returns: the diffpos
        """
        pass

    def OnLazyLoadDir(self, path):
        """
        Callback for lazy-loaded, dirtree-based choosers;
        the function will be called when a folder is expanded and it has
        not been loaded before. The implementation should use the
        given dirtree's link() or mkdir() methods to add the folder contents.

        :param path: an absolute dirtree path to the directory that is being expanded
        :returns: success
        """
        pass

#</pycode(py_kernwin_choose)>
