A ScrolledMessageDialog with nice features

Due a popular demand, I rolled up my sleeves.
Any bug report is welcome.
Question. wx.YES_DEFAULT == 0, correct?

Jean-Michel Fauth, Switzerland

# This class represents a message dialog to display a long and/or
# multiline message. It uses a multiline text control, an icon and
# one or several buttons. All these components have their own
# style.
# This class keeps (as much a possible) the features of the standard
# wx.MessageDialog.
# It is pratically impossible to have a unified style for this widget,
# so every component has its own style.
# The attributes of the underlying TextCtrl, accessible via self.txt,
# can be modified. The text may be left or right justified or centered.
# The dialog window can be closed with an esc.

···

#
# jmScrolledMessageDialog(parent, id, title, pos, size, msg,
# ButtonStyle=wx.OK, IconStyle=wx.ICON_INFORMATION,
# TextStyle=wx.TE_LEFT)
#
# parent : parent
# id : id
# title : title of the dialog window
# pos : position
# size : size
# msg : text to be displayed
# ButtonStyle : wx.OK (default), wx.CANCEL, wx.YES_NO, wx.NO_DEFAULT,
# wx.YES_DEFAULT
# IconStyle : 0 (no icon), wx.ICON_INFORMATION (default), wx.ICON_ERROR,
# wx.ICON_EXCLAMATION, wx.ICON_QUESTION
# TextStyle : wx.TE_LEFT, wx.TE_CENTER, wx.TE_RIGHT

# The jmScrolledMessageDialog returns of these values : wx.ID_CANCEL,
wx.ID_OK
# wx.ID_YES, wx.ID_NO.
#
# Demo usage:
#
# def caller(self, ...):
# titel = 'A scrolled msgbox'
# msg = ''
# for i in xrange(20):
# msg += 'line number ' + str(i) + os.linesep
# msg.rstrip()
# IconStyle = wx.ICON_INFORMATION
# TextStyle = wx.TE_CENTER
# ButtonStyle = wx.YES_NO | wx.CANCEL
# dlg = jmScrolledMessageDialog(self, wx.NewId(), 'A scrolled msgbox', \
# (0, 0), (400, 200), msg, ButtonStyle, IconStyle, TextStyle)
# dlg.CenterOnScreen()
# dlg.txt.SetForegroundColour(wx.BLUE)
# dlg.txt.SetFont(wx.Font(10, wx.MODERN, wx.NORMAL, wx.NORMAL, False))
# r = dlg.ShowModal()
# if r == ... :
# dlg.Destroy()
#
# Development: win98, Python 2.3.4, wxPython 2.5.3.1
# Jean-Michel Fauth, 6 March 2005
#
class jmScrolledMessageDialog(wx.Dialog):

    def __init__(self, parent, id, title, pos, size, msg, \
                 ButtonStyle=wx.OK, IconStyle=wx.ICON_INFORMATION,
TextStyle=wx.TE_LEFT):
        wx.Dialog.__init__(self, parent, id, title, pos, size)

        AllowedIcons = [wx.ICON_INFORMATION, wx.ICON_ERROR,
wx.ICON_EXCLAMATION, wx.ICON_QUESTION]

        #set icons
        if IconStyle in AllowedIcons:
            if IconStyle == wx.ICON_INFORMATION:
                bmp = wx.ArtProvider_GetBitmap(wx.ART_INFORMATION)
            elif IconStyle == wx.ICON_ERROR:
                bmp = wx.ArtProvider_GetBitmap(wx.ART_ERROR)
            elif IconStyle == wx.ICON_EXCLAMATION:
                bmp = wx.ArtProvider_GetBitmap(wx.ART_WARNING)
            elif IconStyle == wx.ICON_QUESTION:
                bmp = wx.ArtProvider_GetBitmap(wx.ART_QUESTION)
            else:
                pass
            stabmp = wx.StaticBitmap(self, wx.NewId(), bmp, (-1, -1),
bmp.GetSize(), wx.NO_BORDER)

        #buttons sizers
        sizer3 = wx.BoxSizer(wx.HORIZONTAL)
        b = 10
        if ButtonStyle & wx.YES_NO == wx.YES_NO:
            butYES = wx.Button(self, wx.ID_YES)
            butNO = wx.Button(self, wx.ID_NO)
            sizer3.Add(butYES, 0, wx.RIGHT, b)
            sizer3.Add(butNO, 0, wx.RIGHT, b)
            butYES.Bind(wx.EVT_BUTTON, self.OnClickYES)
            butNO.Bind(wx.EVT_BUTTON, self.OnClickNO)

        elif ButtonStyle & wx.OK == wx.OK:
            butOK = wx.Button(self, wx.ID_OK)
            sizer3.Add(butOK, 0, wx.RIGHT, b)
        else:
            pass

        if ButtonStyle & wx.CANCEL == wx.CANCEL:
            butCANCEL = wx.Button(self, wx.ID_CANCEL)
            sizer3.Add(butCANCEL, 0, border=b)

        #set a default button
        #some problem with wx.YES_NO, wx.YES_DEFAULT = 0 !
        if ButtonStyle & wx.YES_NO == wx.YES_NO:
            if ButtonStyle & wx.NO_DEFAULT == wx.NO_DEFAULT:
                butNO.SetDefault()
                butNO.SetFocus()
            elif ButtonStyle & wx.YES_DEFAULT == wx.YES_DEFAULT:
                butYES.SetDefault()
                butYES.SetFocus()
            else:
                pass
        if ButtonStyle & wx.YES_NO != wx.YES_NO and ButtonStyle & wx.OK ==
wx.OK:
            butOK.SetDefault()
            butOK.SetFocus()
        if ButtonStyle & wx.CANCEL == wx.CANCEL:
            butCANCEL.SetDefault()
            butCANCEL.SetFocus()

        #the text control
        sty = wx.TE_READONLY | wx.TE_MULTILINE | TextStyle
        self.txt = wx.TextCtrl(self, wx.NewId(), msg, (-1, -1), (-1, -1),
sty)
        self.txt.SetBackgroundColour(self.GetBackgroundColour())

        #layout
        sizer2 = wx.BoxSizer(wx.VERTICAL)
        b = 10
        sizer2.Add(self.txt, 1, wx.BOTTOM | wx.GROW, b)
        sizer2.Add(sizer3, 0, wx.BOTTOM | wx.ALIGN_CENTER, b)

        sizer1 = wx.BoxSizer(wx.HORIZONTAL)
        b = 10
        if IconStyle in AllowedIcons:
            sizer1.Add(stabmp, 0, wx.LEFT | wx.TOP | wx.RIGHT, b)
        sizer1.Add(sizer2, 1, wx.GROW | wx.LEFT | wx.RIGHT | wx.TOP, b)

        self.SetSizer(sizer1)

        #for escape key
        self.Bind(wx.EVT_CHAR_HOOK, self.OnCharHook)

    def OnClickYES(self, event):
        self.EndModal(wx.ID_YES)

    def OnClickNO(self, event):
        self.EndModal(wx.ID_NO)

    def OnCharHook(self, event):
        if event.KeyCode() == wx.WXK_ESCAPE:
            self.EndModal(wx.ID_CANCEL)
        else:
            event.Skip()