#!/usr/bin/env python3
#
# GuiFrame.py
# Copyright (c) 2018, 2019 <NAME> <<EMAIL>>
#

import os, sys, wx, wx.lib.agw.aui

#
# Decorators
def GuiCommandDecorator(caption, label, icon, accel, initialState):
    def GuiCommandDecoratorOuter(targetObject):
        if callable(targetObject):
            if not hasattr(targetObject, "attrDict"):
                setattr(targetObject, "attrDict", [])
            targetObject.attrDict = {"caption": caption, "label": label, "icon": icon, "accel": accel, "initialState": initialState, "id": None}
            return targetObject
    return GuiCommandDecoratorOuter

def GuiCommandListDecorator(idx, caption, label, icon, accel, initialState):
    def GuiCommandListDecoratorOuter(targetObject):
        if callable(targetObject):
            if not hasattr(targetObject, "attrList"):
                setattr(targetObject, "attrList", [])
            targetObject.attrList.insert(0, {"caption": caption, "label": label, "icon": icon, "accel": accel, "initialState": initialState, "id": None, "idx": idx})
            return targetObject
    return GuiCommandListDecoratorOuter

def GuiSelectDecorator(idx, caption, label, icon, accel, initialState):
    def GuiSelectDecoratorOuter(targetObject):
        if callable(targetObject):
            if not hasattr(targetObject, "attrList"):
                setattr(targetObject, "attrList", [])
            setattr(targetObject, "isSelect", True)
            targetObject.attrList.insert(0, {"caption": caption, "label": label, "icon": icon, "accel": accel, "initialState": initialState, "id": None, "idx": idx})
            return targetObject
    return GuiSelectDecoratorOuter

def GuiSubMenuDecorator(caption, label, icon, accel, initialState):
    def GuiSubMenuDecoratorOuter(targetObject):
        if callable(targetObject):
            if not hasattr(targetObject, "attrDict"):
                setattr(targetObject, "attrDict", [])
            setattr(targetObject, "isSubMenu", True)
            targetObject.attrDict = {"caption": caption, "label": label, "icon": icon, "accel": accel, "initialState": initialState, "id": None, "menu":None}
            return targetObject
    return GuiSubMenuDecoratorOuter

class GuiToolBarArtProvider(wx.lib.agw.aui.AuiDefaultToolBarArt):
    def DrawBackground(self, dc, wnd, _rect, horizontal=True):
        dc.SetBrush(wx.Brush(wx.Colour(240, 240, 240, 0), wx.BRUSHSTYLE_SOLID)); dc.SetPen(wx.Pen(wx.Colour(240, 240, 240, 0), 1));
        dc.DrawRectangle(*_rect)
        dc.SetPen(wx.Pen(wx.Colour(180, 180, 180, 0), 1))
        dc.DrawLine(0, _rect[3]-1, _rect[2], _rect[3]-1); dc.DrawLine(_rect[2]-1, 0, _rect[2]-1, _rect[3]-1);
        dc.SetPen(wx.Pen(wx.Colour(255, 255, 255, 0), 1))
        dc.DrawLine(0, 0, _rect[2]-1, 0); dc.DrawLine(0, 0, 0, _rect[3]-1);

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

#
# Non-items (0xf000-0xffff)
NID_MENU_SEP        = 0xf000
NID_TOOLBAR_HSEP    = 0xf001

class GuiFrame(wx.Frame):
    def _initIcon(self, iconPathName):
        icon = wx.Icon()
        icon.CopyFromBitmap(wx.Bitmap(iconPathName, wx.BITMAP_TYPE_ANY))
        self.SetIcon(icon)

    def _initMenu(self, menuItem, menuWindow):
        if menuItem == NID_MENU_SEP:
            menuWindow.AppendSeparator()
        else:
            if menuItem.attrDict["id"] == None:
                menuItem.attrDict["id"] = wx.NewId()
            self.itemsById[menuItem.attrDict["id"]] = menuItem
            if hasattr(menuItem, "isSelect"):
                menuItemWindow = menuWindow.AppendRadioItem(menuItem.attrDict["id"], menuItem.attrDict["label"], menuItem.attrDict["caption"])
            elif hasattr(menuItem, "isSubMenu"):
                menuItem.attrDict["menu"] = wx.Menu()
                menuItemWindow = menuWindow.AppendSubMenu(menuItem.attrDict["menu"], menuItem.attrDict["label"], menuItem.attrDict["caption"])
            else:
                menuItemWindow = menuWindow.Append(menuItem.attrDict["id"], menuItem.attrDict["label"], menuItem.attrDict["caption"])
            if menuItem.attrDict["accel"] != None:
                menuItemWindow.SetAccel(menuItem.attrDict["accelEntry"])
            self.menuItemsById[menuItem.attrDict["id"]] = menuItemWindow
            self.Bind(wx.EVT_MENU, self.onMenu, menuItemWindow)
            if menuItem.attrDict["initialState"] != None:
                if hasattr(menuItem, "isSelect"):
                    menuItemWindow.Check(menuItem.attrDict["initialState"])
                else:
                    menuItemWindow.Enable(menuItem.attrDict["initialState"])

    def loadAccels(self, accelsIn, menus, toolBars):
        def loadAccels_(accels):
            nonlocal accelTableEntries
            accels_ = []
            for accel in accels:
                if type(accel) == tuple:
                    accels_ += accel[1:]
                else:
                    accels_ += [accel]
            for accel in accels_:
                if  (not accel in [NID_MENU_SEP, NID_TOOLBAR_HSEP]) \
                and (accel.attrDict["accel"] != None):
                    accelTableEntries += [wx.AcceleratorEntry()]
                    if accel.attrDict["id"] == None:
                        accel.attrDict["id"] = wx.NewId()
                    accelTableEntries[-1].Set(*accel.attrDict["accel"], accel.attrDict["id"])
                    accel.attrDict["accelEntry"] = accelTableEntries[-1]
                    self.itemsById[accel.attrDict["id"]] = accel
                    self.Bind(wx.EVT_MENU, self.onMenu, id=accel.attrDict["id"])
        accelTableEntries = []
        [loadAccels_(accel) for accel in accelsIn]; [loadAccels_(menu[1:]) for menu in menus]; [loadAccels_(toolBar) for toolBar in toolBars];
        self.SetAcceleratorTable(wx.AcceleratorTable(accelTableEntries))

    def loadBitmap(self, basePathName, descr, size=(16, 16)):
        if descr == None:
            descr = ["", None, wx.ArtProvider.GetBitmap(wx.ART_HELP, wx.ART_TOOLBAR, size)]
        elif (descr[0] == "") and (descr[1] != None):
            descr = ["", None, wx.ArtProvider.GetBitmap(descr[1], wx.ART_TOOLBAR, size)]
        elif descr[0] != "":
            bitmap, bitmapPathName = wx.Bitmap((16, 16)), os.path.join(basePathName, descr[0])
            bitmap.LoadFile(bitmapPathName, wx.BITMAP_TYPE_ANY)
            descr = ["", None, bitmap]
        elif len(descr) == 3:
            descr = ("", None, descr[2])
        return descr

    def loadMenus(self, menus):
        self.menuBar = wx.MenuBar()
        for menu in menus:
            menuWindow = wx.Menu()
            for menuItem in menu[1:]:
                if type(menuItem) == tuple:
                    menuSubWindow = wx.Menu()
                    for menuSubItem in menuItem[1:]:
                        self._initMenu(menuSubItem, menuSubWindow)
                    menuWindow.AppendSubMenu(menuSubWindow, menuItem[0], menuItem[0])
                else:
                    self._initMenu(menuItem, menuWindow)
            self.menuBar.Append(menuWindow, menu[0])
        self.SetMenuBar(self.menuBar)

    def loadToolBars(self, toolBars):
        for toolBar in toolBars:
            self.toolBars.append(wx.lib.agw.aui.AuiToolBar(self, -1))
            self.toolBars[-1].SetArtProvider(GuiToolBarArtProvider())
            self.toolBars[-1].SetToolBitmapSize((16, 16))
            for toolBarItem in toolBar:
                if toolBarItem == NID_TOOLBAR_HSEP:
                    self.toolBars[-1].AddSeparator()
                else:
                    if toolBarItem.attrDict["id"] == None:
                        toolBarItem.attrDict["id"] = wx.NewId()
                    self.itemsById[toolBarItem.attrDict["id"]] = toolBarItem
                    if hasattr(toolBarItem, "isSelect"):
                        toolBarItemWindow = self.toolBars[-1].AddRadioTool(toolBarItem.attrDict["id"], toolBarItem.attrDict["caption"], toolBarItem.attrDict["icon"][2], wx.NullBitmap, short_help_string=toolBarItem.attrDict["caption"])
                    else:
                        toolBarItemWindow = self.toolBars[-1].AddTool(toolBarItem.attrDict["id"], toolBarItem.attrDict["caption"], toolBarItem.attrDict["icon"][2], wx.NullBitmap, wx.ITEM_NORMAL, short_help_string=toolBarItem.attrDict["caption"])
                    self.toolBarItemsById[toolBarItem.attrDict["id"]] = (self.toolBars[-1], toolBarItemWindow,)
                    self.Bind(wx.EVT_TOOL, self.onMenu, toolBarItemWindow)
                    self.Bind(wx.EVT_TOOL_RCLICKED, self.onMenu, toolBarItemWindow)
                    if toolBarItem.attrDict["initialState"] != None:
                        if hasattr(toolBarItem, "isSelect"):
                            if toolBarItem.attrDict["initialState"]:
                                self.toolBars[-1].ToggleTool(toolBarItemWindow, True)
                        else:
                            self.toolBars[-1].EnableTool(toolBarItem.attrDict["id"], toolBarItem.attrDict["initialState"])
        self.toolBars[-1].Refresh()
        self.toolBarPanes, row = [], 0
        for toolBar in self.toolBars:
            toolBar.Realize(); toolBar.Fit();
            self.toolBarPanes += [wx.lib.agw.aui.AuiPaneInfo().ToolbarPane().CaptionVisible(False).CloseButton(False).Dockable(True).Floatable(True).Gripper(True).Row(row).Top()]
            self.auiManager.AddPane(toolBar, self.toolBarPanes[-1]); row += 1;
        self.auiManager.Update()

    def addWindow(self, window):
        self.auiManager.AddPane(window, wx.lib.agw.aui.AuiPaneInfo().CaptionVisible(False).Centre().CloseButton(False).Dockable(False).Floatable(False).Gripper(False))
        self.auiManager.Update()

    def onChar(self, event):
        event.Skip()

    def onMenu(self, event):
        eventId = event.GetId()
        if eventId in self.itemsById:
            self.itemsById[eventId](event)
        else:
            event.Skip()

    def onMouseWheel(self, event):
        event.Skip()

    def __init__(self, iconPathName, size, parent=None, title=""):
        super().__init__(parent, wx.ID_ANY, title, size=size)
        self.auiManager = wx.lib.agw.aui.AuiManager(); self.auiManager.SetManagedWindow(self);
        self.itemsById, self.menuItemsById, self.toolBarItemsById, self.toolBars = {}, {}, {}, []
        self._initIcon(iconPathName); self.statusBar = self.CreateStatusBar();
        self.SetFocus(); self.Show(True);
        for event, f in ((wx.EVT_CHAR, self.onChar), (wx.EVT_MENU, self.onMenu), (wx.EVT_MOUSEWHEEL, self.onMouseWheel)):
            self.Bind(event, f)

class GuiMiniFrame(wx.MiniFrame):
    def __init__(self, parent, size, title, pos=wx.DefaultPosition):
        super().__init__(parent, id=wx.ID_ANY, pos=pos, size=size, title=title)

# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120
