# --------------------------------------------------------------------------- #
# ENHANCEDSTATUSBAR wxPython IMPLEMENTATION
# Python Code By:
#
# Andrea Gavana, @ 31 May 2005
# Nitro, @ 21 September 2005
# Latest Revision: 5 April 2025, 21.52.00 GMT (tested on Python 3.13, wxPython 4.2.2)
# Latest Revision: 21 September 2005, 19.57.20 GMT+2
# Latest Revision before Latest Revision: 21 September 2005, 18.29.35 GMT+2
# Latest Revision before Latest Revision before Latest Revision: 31 May 2005, 23.17 CET
#
#
# TODO List/Caveats
#
# 1. Some Requests/Features To Add?
#
#
# For All Kind Of Problems, Requests Of Enhancements And Bug Reports, Please
# Write To Me At:
#
# andrea.gavana@agip.it
# andrea_gavan@tin.it
#
# Or, Obviously, To The wxPython Mailing List!!!
#
#
# End Of Comments
# --------------------------------------------------------------------------- #

""" Description:

EnhancedStatusBar Is A Slight Modification (Actually A Subclassing) Of wx.StatusBar.
It Allows You To Add Almost Any Widget You Like To The wx.StatusBar Of Your Main
Frame Application And Also To Layout Them Properly.


What It Can Do:

1) Almost All The Functionalities Of wx.StatusBar Are Still Present;
2) You Can Add Different Kind Of Widgets Into Every Field Of The EnhancedStatusBar;
3) The AddWidget() Methods Accepts 2 Layout Inputs:
   - horizontalalignment: This Specify The Horizontal Alignment For Your Widget,
     And Can Be ESB_EXACT_FIT, ESB_ALIGN_CENTER_HORIZONTAL, ESB_ALIGN_LEFT And
     ESB_ALIGN_RIGHT;
   - varticalalignment: This Specify The Vertical Alignment For Your Widget,
     And Can Be ESB_EXACT_FIT, ESB_ALIGN_CENTER_VERTICAL, ESB_ALIGN_BOTTOM And
     ESB_ALIGN_LEFT;

EnhancedStatusBar Is Freeware And Distributed Under The wxPython License. 

Latest Revision: 5 April 2025, 21.52.00 GMT (tested on Python 3.13, wxPython 4.2.2)
Latest Revision: 21 September 2005, 19.57.20 GMT+2
Latest Revision before Latest Revision: 21 September 2005, 18.29.35 GMT+2
Latest Revision before Latest Revision before Latest Revision: 31 May 2005, 23.17 CET

"""

import wx

# Constants for alignment  
ESB_ALIGN_CENTER_HORIZONTAL = 0  
ESB_ALIGN_LEFT = 1  
ESB_ALIGN_RIGHT = 2  
ESB_ALIGN_CENTER_VERTICAL = 3  
ESB_ALIGN_TOP = 4  
ESB_ALIGN_BOTTOM = 5  
ESB_EXACT_FIT = 6

class EnhancedStatusBarItem:
    def __init__(self, widget, pos, horizontalalignment=ESB_ALIGN_CENTER_HORIZONTAL,
                 verticalalignment=ESB_ALIGN_CENTER_VERTICAL):
        self.widget = widget  
        self.pos = pos  
        self.horizontalalignment = horizontalalignment  
        self.verticalalignment = verticalalignment

class EnhancedStatusBar(wx.StatusBar):
    def __init__(self, parent, id=wx.ID_ANY, style=wx.STB_DEFAULT_STYLE, name="EnhancedStatusBar"):
        super().__init__(parent, id, style, name)
        
        self._items = {}
        self._curPos = 0  
        self._parent = parent
        
        self.Bind(wx.EVT_SIZE, self.OnSize)
        wx.CallAfter(self.OnSize)

    def SetSize(self, size):
        super().SetSize(size)
        
        if size[1] > 0:
            self.SetMinHeight(size[1])

    def OnSize(self, event=None):
        """Handles the wx.EVT_SIZE events for the status bar."""
        for pos, item in self._items.items():
            self._position_widget(item)

        if event is not None:
            event.Skip()

    def _position_widget(self, item):
        """Position a single widget based on its alignment settings."""
        widget, horizontalalignment, verticalalignment = item.widget, item.horizontalalignment, item.verticalalignment  
        rect = self.GetFieldRect(item.pos)
        widgetsize = widget.GetSize()

        if horizontalalignment == ESB_EXACT_FIT:
            self._fit_widget(widget, rect, widgetsize, verticalalignment)
        elif horizontalalignment in [ESB_ALIGN_LEFT, ESB_ALIGN_RIGHT]:
            self._position_horizontal_widget(widget, rect, widgetsize, horizontalalignment, verticalalignment)
        elif horizontalalignment == ESB_ALIGN_CENTER_HORIZONTAL:
            self._center_horizontal_widget(widget, rect, widgetsize, verticalalignment)

    def _fit_widget(self, widget, rect, widgetsize, verticalalignment):
        if verticalalignment == ESB_EXACT_FIT:
            widget.SetSize((rect.width - 4, rect.height - 4))
            widget.SetPosition((rect.x + 2, rect.y + 2))
        elif verticalalignment == ESB_ALIGN_CENTER_VERTICAL:
            widget.SetSize((rect.width - 4, widgetsize[1] - 4))
            widget.SetPosition((rect.x + 2, (rect.y + 2 + (rect.height - widgetsize[1])) // 2))
        elif verticalalignment == ESB_ALIGN_TOP:
            widget.SetSize((rect.width - 4, widgetsize[1] - 4))
            widget.SetPosition((rect.x + 2, rect.y + 2))
        elif verticalalignment == ESB_ALIGN_BOTTOM:
            widget.SetSize((rect.width - 4, widgetsize[1] - 4))
            widget.SetPosition((rect.x + 2, (rect.height - widgetsize[1] + 2)))

    def _position_horizontal_widget(self, widget, rect, widgetsize, horizontalalignment, verticalalignment):
        if horizontalalignment == ESB_ALIGN_LEFT:
            xpos = rect.x - 1  
        else:  # ESB_ALIGN_RIGHT  
            xpos = rect.x + rect.width - widgetsize[0] - 4
        
        if verticalalignment == ESB_EXACT_FIT:
            widget.SetSize((widgetsize[0] - 4, rect.height - 4))
            widget.SetPosition((xpos + 2, rect.y + 2))
        elif verticalalignment == ESB_ALIGN_CENTER_VERTICAL:
            widget.SetPosition((xpos + 2, (rect.y + 2 + (rect.height - widgetsize[1])) // 2))
        elif verticalalignment == ESB_ALIGN_TOP:
            widget.SetPosition((xpos + 2, rect.y + 2))
        elif verticalalignment == ESB_ALIGN_BOTTOM:
            widget.SetPosition((xpos + 2, (rect.height - widgetsize[1] + 2)))

    def _center_horizontal_widget(self, widget, rect, widgetsize, verticalalignment):
        widgetsize[0] = min(widgetsize[0], rect.width - 2)
        widget.SetSize((rect.width - 4, -1))
        xpos = rect.x + ((rect.width - 4) - widgetsize[0]) // 2
        
        if verticalalignment == ESB_EXACT_FIT:
            widget.SetSize((widgetsize[0] + 1, rect.height - 4))
            widget.SetPosition((xpos + 2, rect.y + 2))
        elif verticalalignment == ESB_ALIGN_CENTER_VERTICAL:
            widget.SetPosition((xpos + 2, (rect.y + 2 + (rect.height - widgetsize[1])) // 2))
        elif verticalalignment == ESB_ALIGN_TOP:
            widget.SetPosition((xpos + 2, rect.y + 2))
        elif verticalalignment == ESB_ALIGN_BOTTOM:
            widget.SetPosition((xpos + 2, (rect.height - widgetsize[1] + 2)))

    def AddWidget(self, widget, horizontalalignment=ESB_ALIGN_CENTER_HORIZONTAL,
                  verticalalignment=ESB_ALIGN_CENTER_VERTICAL, pos=-1):
        """Add a widget to the EnhancedStatusBar."""
        if pos == -1:
            pos = self._curPos  
            self._curPos += 1
        
        if self.GetFieldsCount() <= pos:
            raise Exception(f"\nERROR: EnhancedStatusBar has a max of {self.GetFieldsCount()} items, "
                            f"you tried to set item #{pos}")

        if horizontalalignment not in [ESB_ALIGN_CENTER_HORIZONTAL, ESB_EXACT_FIT, ESB_ALIGN_LEFT, ESB_ALIGN_RIGHT]:
            raise ValueError('Invalid horizontal alignment')

        if verticalalignment not in [ESB_ALIGN_CENTER_VERTICAL, ESB_EXACT_FIT, ESB_ALIGN_TOP, ESB_ALIGN_BOTTOM]:
            raise ValueError('Invalid vertical alignment')
        
        # Remove the previous widget if exists  
        if pos in self._items:
            self.RemoveChild(self._items[pos].widget)
            self._items[pos].widget.Destroy()
        
        self._items[pos] = EnhancedStatusBarItem(widget, pos, horizontalalignment, verticalalignment)
        wx.CallAfter(self.OnSize)
        
