# radio_box.py: wxRadioBox objects
# $Id: radio_box.py,v 1.14 2005/05/06 21:48:19 agriggio Exp $
#
# Copyright (c) 2002-2005 Alberto Griggio <agriggio@users.sourceforge.net>
# License: MIT (see license.txt)
# THIS PROGRAM COMES WITH NO WARRANTY

from wxPython.wx import *
import common, misc
from edit_windows import ManagedBase
from tree import Tree
from widget_properties import *
from misc import wxGladeRadioButton

from ChoicesProperty import *


class EditRadioBox(ManagedBase):

    events = ['EVT_RADIOBOX']
    
    def __init__(self, name, parent, id, label, choices, major_dim, style,
                 sizer, pos, property_window, show=True):
        """\
        Class to handle wxRadioBox objects
        """
        ManagedBase.__init__(self, name, 'wxRadioBox', parent, id, sizer,
                             pos, property_window, show=show)
        self.static_box = None 
        self.selection = 0
        self.choices = choices
        self.buttons = None 
        self.major_dim = major_dim

        if not style: self.style = wxRA_SPECIFY_ROWS
        else: self.style = style
        self.label = label
        # properties
        self.access_functions['label'] = (self.get_label, self.set_label)
        self.access_functions['choices'] = (self.get_choices, self.set_choices)
        self.access_functions['style'] = (self.get_style, self.set_style)
        self.access_functions['dimension'] = (self.get_major_dimension,
                                              self.set_major_dimension)
        self.access_functions['selection'] = (self.get_selection,
                                              self.set_selection)
        self.properties['label'] = TextProperty(self, 'label', None)
        self.properties['selection'] = SpinProperty(self, 'selection', None,
                                                    r=(0, len(choices)-1))
        self.properties['choices'] = ChoicesProperty(self, 'choices', None,
                                                     [('Label',
                                                       GridProperty.STRING)],
                                                     len(choices))
        self.style_pos = [wxRA_SPECIFY_ROWS, wxRA_SPECIFY_COLS]
        self.properties['style'] = RadioProperty(self, 'style', None,
                                                 ['wxRA_SPECIFY_ROWS',
                                                  'wxRA_SPECIFY_COLS'])
        self.properties['dimension'] = SpinProperty(self, 'dimension', None)

    def create_widget(self):
        self.widget = wxPanel(self.parent.widget, self.id)
        self.static_box = wxStaticBox(self.widget, -1, self.label)        
        self.buttons = [ self.create_button(c) for c in self.choices ]
        if self.buttons: self.buttons[0].SetValue(True)
        EVT_LEFT_DOWN(self.static_box, self.on_set_focus)
        EVT_RIGHT_DOWN(self.static_box, self.popup_menu)
        self.widget.GetBestSize = self.GetBestSize
        self.widget.SetForegroundColour = self.SetForegroundColour
        self.widget.SetBackgroundColour = self.SetBackgroundColour
        self.widget.SetFont = self.SetFont
        self.set_selection(self.selection)
        self.do_layout()
        
    def create_properties(self):
        ManagedBase.create_properties(self)
        panel = wxPanel(self.notebook, -1)
        szr = wxBoxSizer(wxVERTICAL)
        self.properties['label'].display(panel)
        self.properties['style'].display(panel)
        self.properties['dimension'].display(panel)
        self.properties['selection'].display(panel)
        self.properties['choices'].display(panel)

        self.properties['style'].set_value(self.get_style())

        szr.Add(self.properties['label'].panel, 0, wxEXPAND)
        szr.Add(self.properties['style'].panel, 0, wxALL|wxEXPAND, 3)
        szr.Add(self.properties['dimension'].panel, 0, wxEXPAND)
        szr.Add(self.properties['selection'].panel, 0, wxEXPAND)
        szr.Add(self.properties['choices'].panel, 1, wxALL|wxEXPAND, 3)
        panel.SetAutoLayout(True)
        panel.SetSizer(szr)
        szr.Fit(panel)
        self.notebook.AddPage(panel, 'Widget')
        self.properties['choices'].set_col_sizes([-1])

    def create_button(self, label):
        r = wxGladeRadioButton(self.widget, -1, label)
        EVT_LEFT_DOWN(r, self.on_set_focus)
        EVT_RIGHT_DOWN(r, self.popup_menu)
        return r

    def do_layout(self):
        """\
        Lays out the radio buttons according to the values of self.style and
        self.major_dim
        """
        if not self.widget: return
        buttons_layout = self.buttons
        if self.major_dim:
            if self.style & wxRA_SPECIFY_COLS: cols = self.major_dim; rows = 0
            else: cols = 0; rows = self.major_dim
            sizer = wxGridSizer(rows, cols)
            if wxPlatform == '__WXGTK__':
                # we need to reorder self.buttons 'cos wxRadioBox lays out its
                # elements by colums, while wxGridSizer by rows
                import math
                if not rows: step = int(math.ceil(1.0*len(self.buttons)/cols))
                else: step = rows
                start = 0
                tmp = [ [] for i in range(step) ]
                for i in range(len(self.buttons)):
                    tmp[i%step].append(self.buttons[i])
                buttons_layout = []
                for t in tmp: buttons_layout.extend(t)
        else:
            sizer = wxBoxSizer(wxVERTICAL)
        for button in buttons_layout:
            w, h = button.GetBestSize()
            sizer.Add(button, 0, wxEXPAND)
            sizer.SetItemMinSize(button, w, h)
        self.widget.SetAutoLayout(True)
        sb_sizer = wxStaticBoxSizer(self.static_box, wxVERTICAL)
        self.widget.SetSizer(sb_sizer)
        sb_sizer.Add(sizer, 1, wxEXPAND)
        sb_sizer.SetMinSize(sizer.GetMinSize())
        sb_sizer.Fit(self.widget)
        sp = self.sizer_properties
        self.sizer.set_item(self.pos, size=self.widget.GetBestSize())

    def get_label(self):
        return self.label
    
    def set_label(self, value):
        value = misc.wxstr(value)
        if not misc.streq(value, self.label):
            self.label = value
            if self.static_box:
                self.static_box.SetLabel(value)
                if not self.properties['size'].is_active():
                    self.sizer.set_item(self.pos,
                                        size=self.widget.GetBestSize())

    def get_style(self):
        if self.style == wxRA_SPECIFY_ROWS: return 0
        else: return 1

    def set_style(self, value):
        if value == 0 or value == 'wxRA_SPECIFY_ROWS':
            self.style = wxRA_SPECIFY_ROWS
        else: self.style = wxRA_SPECIFY_COLS
        self.do_layout()

    def get_major_dimension(self):
        return self.major_dim

    def set_major_dimension(self, value):
        self.major_dim = int(value)
        self.do_layout()

    def get_choices(self):
        return zip(self.choices)

    def set_choices(self, values):
        self.choices = [ misc.wxstr(v[0]) for v in values ]
        self.properties['selection'].set_range(0, len(self.choices)-1)
        if not self.widget: return
        
        delta = len(values) - len(self.buttons)
        if delta > 0:
            self.buttons.extend([ self.create_button("")
                                  for i in range(delta) ])
        elif delta < 0:
            to_remove = self.buttons[delta:]
            self.buttons = self.buttons[:delta]
            for b in to_remove: b.Hide(); b.Destroy()
        for i in range(len(values)):
            self.buttons[i].SetLabel(values[i][0])
        self.do_layout()

    def get_selection(self): return self.selection

    def set_selection(self, index):
        self.selection = int(index)
        if self.widget:
            for b in self.buttons: b.SetValue(False)
            try: self.buttons[self.selection].SetValue(True)
            except IndexError: pass

    def get_property_handler(self, prop_name):
        if prop_name == 'choices':
            return ChoicesHandler(self)
        return ManagedBase.get_property_handler(self, prop_name)

    def GetBestSize(self):
        w, h = self.widget.GetSizer().GetMinSize()
        w2, h2 = self.static_box.GetBestSize()
        return max(w, w2), h

    def SetBackgroundColour(self, colour):
        wxPanel.SetBackgroundColour(self.widget, colour)
        self.static_box.SetBackgroundColour(colour)
        for b in self.buttons: b.SetBackgroundColour(colour)
        self.widget.Refresh()
        
    def SetForegroundColour(self, colour):
        wxPanel.SetForegroundColour(self.widget, colour)
        self.static_box.SetForegroundColour(colour)
        for b in self.buttons: b.SetForegroundColour(colour)
        self.widget.Refresh()

    def SetFont(self, font):
        wxPanel.SetFont(self.widget, font)
        self.static_box.SetFont(font)
        for b in self.buttons: b.SetFont(font)
        self.widget.Refresh()

# end of class EditRadioBox

        
def builder(parent, sizer, pos, number=[1]):
    """\
    factory function for EditRadioBox objects.
    """
    label = 'radio_box_%d' % number[0]
    while common.app_tree.has_name(label):
        number[0] += 1
        label = 'radio_box_%d' % number[0]
    radio_box = EditRadioBox(label, parent, wxNewId(), label,
                             [misc._encode('choice 1')],
                             0, 0, sizer, pos, common.property_panel)
    #sizer.set_item(pos, 0, 0, size=radio_box.GetSize())
    node = Tree.Node(radio_box)
    radio_box.node = node
    radio_box.show_widget(True)
    common.app_tree.insert(node, sizer.node, pos-1)

def xml_builder(attrs, parent, sizer, sizeritem, pos=None):
    """\
    factory to build EditRadioBox objects from an xml file
    """
    from xml_parse import XmlParsingError
    try: label = attrs['name']
    except KeyError: raise XmlParsingError, "'name' attribute missing"
    if sizer is None or sizeritem is None:
        raise XmlParsingError, "sizer or sizeritem object cannot be None"
    radio_box = EditRadioBox(label, parent, wxNewId(), '', [], 0, 0,
                             sizer, pos, common.property_panel) 
    sizer.set_item(radio_box.pos, option=sizeritem.option,
                   flag=sizeritem.flag, border=sizeritem.border)
##                    size=radio_box.GetBestSize())
    node = Tree.Node(radio_box)
    radio_box.node = node
    if pos is None: common.app_tree.add(node, sizer.node)
    else: common.app_tree.insert(node, sizer.node, pos-1)
    return radio_box

    
def initialize():
    """\
    initialization function for the module: returns a wxBitmapButton to be
    added to the main palette.
    """
    common.widgets['EditRadioBox'] = builder
    common.widgets_from_xml['EditRadioBox'] = xml_builder
        
    return common.make_object_button('EditRadioBox', 'icons/radio_box.xpm')
