from __future__ import print_function
#<pycode(py_kernwin_plgform)>
import sys

import ida_idaapi

class PluginForm(object):
    """
    PluginForm class.

    This form can be used to host additional controls. Please check the PyQt example.
    """

    WOPN_MDI      = 0x01 # no-op
    WOPN_TAB      = 0x02 # no-op
    WOPN_RESTORE  = _ida_kernwin.WOPN_RESTORE
    """
    if the widget is the only widget in a floating area when
    it is closed, remember that area's geometry. The next
    time that widget is created as floating (i.e., WOPN_DP_FLOATING)
    its geometry will be restored (e.g., "Execute script"
    """
    WOPN_ONTOP       = 0x08 # no-op
    WOPN_MENU        = 0x10 # no-op
    WOPN_CENTERED    = 0x20 # no-op
    WOPN_PERSIST     = _ida_kernwin.WOPN_PERSIST
    """form will persist until explicitly closed with Close()"""
    WOPN_DP_LEFT     = _ida_kernwin.WOPN_DP_LEFT
    """ Dock widget to the left of dest_ctrl"""
    WOPN_DP_TOP      = _ida_kernwin.WOPN_DP_TOP
    """ Dock widget above dest_ctrl"""
    WOPN_DP_RIGHT    = _ida_kernwin.WOPN_DP_RIGHT
    """ Dock widget to the right of dest_ctrl"""
    WOPN_DP_BOTTOM   = _ida_kernwin.WOPN_DP_BOTTOM
    """ Dock widget below dest_ctrl"""
    WOPN_DP_INSIDE   = _ida_kernwin.WOPN_DP_INSIDE
    """ Create a new tab bar with both widget and dest_ctrl"""
    WOPN_DP_TAB      = _ida_kernwin.WOPN_DP_TAB
    """
    Place widget into a tab next to dest_ctrl,
    if dest_ctrl is in a tab bar
    (otherwise the same as #WOPN_DP_INSIDE)
    """
    WOPN_DP_BEFORE   = _ida_kernwin.WOPN_DP_BEFORE
    """
    place widget before dst_form in the tab bar instead of after
    used with #WOPN_DP_INSIDE and #WOPN_DP_TAB
    """
    WOPN_DP_FLOATING = _ida_kernwin.WOPN_DP_FLOATING
    """
    When floating or in a splitter (i.e., not tabbed),
    use the widget's size hint to determine the best
    geometry (Qt only)
    """
    WOPN_DP_SZHINT   = _ida_kernwin.WOPN_DP_SZHINT
    """ Make widget floating"""
    WOPN_DP_INSIDE_BEFORE = _ida_kernwin.WOPN_DP_INSIDE_BEFORE
    WOPN_DP_TAB_BEFORE = _ida_kernwin.WOPN_DP_TAB_BEFORE

    WOPN_CREATE_ONLY = {}


    def __init__(self):
        """
        """
        self.__clink__ = _ida_kernwin.plgform_new()


    def Show(self, caption, options=0):
        """
        Creates the form if not was not created or brings to front if it was already created

        :param caption: The form caption
        :param options: One of PluginForm.WOPN_ constants
        """
        if options == self.WOPN_CREATE_ONLY:
            options = -1
        else:
            options |= PluginForm.WOPN_DP_TAB|PluginForm.WOPN_RESTORE
        return _ida_kernwin.plgform_show(self.__clink__, self, caption, options)


    @staticmethod
    def _ensure_widget_deps(ctx):
        for modname in ["shiboken6.Shiboken", "PySide6.QtWidgets"]:
            if not hasattr(ctx, modname):
                import importlib
                setattr(ctx, modname, importlib.import_module(modname))


    VALID_CAPSULE_NAME = b"$valid$"

    @staticmethod
    def TWidgetToQtPythonWidget(tw, ctx = sys.modules['__main__']):
        """
        Convert a TWidget* to a QWidget to be used by the Qt Python bindings
        """
        if type(tw).__name__ == 'SwigPyObject':
            ptr_l = int(tw)
        else:
            import ctypes
            ctypes.pythonapi.PyCapsule_GetPointer.restype = ctypes.c_void_p
            ctypes.pythonapi.PyCapsule_GetPointer.argtypes = [ctypes.py_object, ctypes.c_char_p]
            ptr_l = ctypes.pythonapi.PyCapsule_GetPointer(tw, PluginForm.VALID_CAPSULE_NAME)

        import shiboken6.Shiboken
        import PySide6.QtWidgets

        # We now need to look up the best possible type for the
        # object we're about to wrap (PySide6 won't grant look it up
        # for us.)

        # WARNING: Do _not_ hold a reference to wrapped instance here:
        # Shiboken keeps a "hard" internal mapping between raw pointers,
        # and object types. Keeping a reference to the as-QWidget-wrapped
        # object, would prevent the second wrap (below) to succeed.
        metaObject = shiboken6.Shiboken.wrapInstance(ptr_l, PySide6.QtWidgets.QWidget).metaObject()

        known_type = PySide6.QtWidgets.QWidget
        while metaObject:
            try:
                known_type = getattr(PySide6.QtWidgets, metaObject.className())
                break
            except AttributeError:
                metaObject = metaObject.superClass()

        return shiboken6.Shiboken.wrapInstance(ptr_l, known_type)

    TWidgetToPyQtWidget = TWidgetToQtPythonWidget
    FormToPyQtWidget = TWidgetToQtPythonWidget


    @staticmethod
    def QtWidgetToTWidget(w, ctx = sys.modules['__main__']):
        """
        Convert a QWidget to a TWidget* to be used by IDA

        :param ctx: Context. Reference to a module that already imported SIP and QtWidgets modules
        """
        PluginForm._ensure_widget_deps(ctx)
        import shiboken6.Shiboken
        result = shiboken6.Shiboken.getCppPointer(w)
        return TWidget__from_ptrval__(result[0])


    @staticmethod
    def TWidgetToPySideWidget(tw, ctx = sys.modules['__main__']):
        """
        Use this method to convert a TWidget* to a QWidget to be used by PySide

        :param ctx: Context. Reference to a module that already imported QtWidgets module
        """
        if tw is None:
            return None
        if type(tw).__name__ == "SwigPyObject":
            # Since 'tw' is a SwigPyObject, we first need to convert it to a PyCapsule.
            # However, there's no easy way of doing it, so we'll use a rather brutal approach:
            # converting the SwigPyObject to a 'long' (will go through 'SwigPyObject_long',
            # that will return the pointer's value as a long), and then convert that value
            # back to a pointer into a PyCapsule.
            ptr_l = ida_idaapi.long_type(tw)
            # Warning: this is untested
            import ctypes
            ctypes.pythonapi.PyCapsule_New.restype = ctypes.py_object
            ctypes.pythonapi.PyCapsule_New.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_void_p]
            tw = ctypes.pythonapi.PyCapsule_New(ptr_l, PluginForm.VALID_CAPSULE_NAME, 0)
        return ctx.QtGui.QWidget.FromCapsule(tw)
    FormToPySideWidget = TWidgetToPySideWidget

    def OnCreate(self, form):
        """
        This event is called when the plugin form is created.
        The programmer should populate the form when this event is triggered.

        :returns: None
        """
        pass


    def OnClose(self, form):
        """
        Called when the plugin form is closed

        :returns: None
        """
        pass


    def Close(self, options):
        """
        Closes the form.

        :param options: Close options (WCLS_SAVE, WCLS_NO_CONTEXT, ...)

        :returns: None
        """
        return _ida_kernwin.plgform_close(self.__clink__, options)


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

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


    WCLS_SAVE           = _ida_kernwin.WCLS_SAVE
    """Save state in desktop config"""

    WCLS_NO_CONTEXT     = _ida_kernwin.WCLS_NO_CONTEXT
    """Don't change the current context (useful for toolbars)"""

    WCLS_DONT_SAVE_SIZE = _ida_kernwin.WCLS_DONT_SAVE_SIZE
    """Don't save size of the window"""

    WCLS_DELETE_LATER   = _ida_kernwin.WCLS_DELETE_LATER
    """This flag should be used when Close() is called from an event handler"""

    WCLS_CLOSE_LATER  = WCLS_DELETE_LATER

#</pycode(py_kernwin_plgform)>
