wxWidgets/wxPython/samples/StyleEditor/STCStyleEditor.py

1359 lines
57 KiB
Python
Raw Normal View History

#-----------------------------------------------------------------------------
# Name: STCStyleEditor.py
# Purpose: Style editor for the wxStyledTextCtrl
#
# Author: Riaan Booysen
#
# Created: 2001/08/20
# RCS-ID: $Id$
# Copyright: (c) 2001 - 2005 Riaan Booysen
# Licence: wxWidgets license
#-----------------------------------------------------------------------------
#Boa:Dialog:STCStyleEditDlg
""" Style editor for the wxStyledTextCtrl.
Reads in property style definitions from a config file.
Modified styled can be saved (and optionally applied to a given list of STCs)
It can also maintain a Common definition dictionary of font names, colours and
sizes which can be shared across multiple language style definitions.
This is also used to store platform specific settings as fonts and sizes
vary with platform.
The following items are defined in the stc-styles.rc.cfg file.
common.defs.msw - Common definition dictionary used on wxMSW
common.defs.gtk - Common definition dictionary used on wxGTK
common.defs.mac - Common definition dictionary used on wxMAC
common.styleidnames - STC styles shared by all languages
Each supported language defines the following groups:
[<language>]
displaysrc - Example source to display in the editor
braces - Dictionary defining the (line, column) for showing 'good' and 'bad'
brace matching (both keys optional)
keywords - Space separated list of keywords
lexer - wxSTC constant for the language lexer
styleidnames - Dictionary of language specific style numbers and names
[style.<language>] - The users current style values
[style.<language>.default] - Default style values (can be reverted from)
0 or more predefined style groups or 'themes'
[style.<language>.<predefined name>]
Currently the following languages are supported:
python, html, xml, cpp, text, props
Other languages can be added by just defining the above settings for them in
the config file (if wxSTC implements them).
Use the initSTC function to initialise your wxSTC from a config file.
"""
import os, sys, string, pprint, copy
import wx
from wx.lib.anchors import LayoutAnchors
import wx.stc
import wxPython.stc # needed names from 2.4 for config files
settingsIdNames = {-1: 'Selection', -2: 'Caret', -3: 'Edge'}
commonPropDefs = {'fore': '#888888', 'size': 8,
'face': ''}
styleCategoryDescriptions = {
'----Language----': 'Styles specific to the language',
'----Standard----': 'Styles shared by all languages',
'----Settings----': 'Properties set by STC methods',
'----Common----': 'User definable values that can be shared between languages'}
platformSettings = {'__WXMSW__': ('msw', 8),
'__WXGTK__': ('gtk', 10),
'__WXMAC__': ('mac', 11)}
[wxID_STCSTYLEEDITDLG, wxID_STCSTYLEEDITDLGADDCOMMONITEMBTN,
wxID_STCSTYLEEDITDLGBGCOLBTN, wxID_STCSTYLEEDITDLGBGCOLCB,
wxID_STCSTYLEEDITDLGBGCOLDEFCB, wxID_STCSTYLEEDITDLGBGCOLOKBTN,
wxID_STCSTYLEEDITDLGCANCELBTN, wxID_STCSTYLEEDITDLGCONTEXTHELPBUTTON1,
wxID_STCSTYLEEDITDLGELEMENTLB, wxID_STCSTYLEEDITDLGFACECB,
wxID_STCSTYLEEDITDLGFACEDEFCB, wxID_STCSTYLEEDITDLGFACEOKBTN,
wxID_STCSTYLEEDITDLGFGCOLBTN, wxID_STCSTYLEEDITDLGFGCOLCB,
wxID_STCSTYLEEDITDLGFGCOLDEFCB, wxID_STCSTYLEEDITDLGFGCOLOKBTN,
wxID_STCSTYLEEDITDLGFIXEDWIDTHCHK, wxID_STCSTYLEEDITDLGOKBTN,
wxID_STCSTYLEEDITDLGPANEL1, wxID_STCSTYLEEDITDLGPANEL2,
wxID_STCSTYLEEDITDLGPANEL3, wxID_STCSTYLEEDITDLGPANEL4,
wxID_STCSTYLEEDITDLGREMOVECOMMONITEMBTN, wxID_STCSTYLEEDITDLGSIZECB,
wxID_STCSTYLEEDITDLGSIZEOKBTN, wxID_STCSTYLEEDITDLGSPEEDSETTINGCH,
wxID_STCSTYLEEDITDLGSTATICBOX1, wxID_STCSTYLEEDITDLGSTATICBOX2,
wxID_STCSTYLEEDITDLGSTATICLINE1, wxID_STCSTYLEEDITDLGSTATICTEXT2,
wxID_STCSTYLEEDITDLGSTATICTEXT3, wxID_STCSTYLEEDITDLGSTATICTEXT4,
wxID_STCSTYLEEDITDLGSTATICTEXT6, wxID_STCSTYLEEDITDLGSTATICTEXT7,
wxID_STCSTYLEEDITDLGSTATICTEXT8, wxID_STCSTYLEEDITDLGSTATICTEXT9,
wxID_STCSTYLEEDITDLGSTC, wxID_STCSTYLEEDITDLGSTYLEDEFST,
wxID_STCSTYLEEDITDLGTABOLDCB, wxID_STCSTYLEEDITDLGTABOLDDEFCB,
wxID_STCSTYLEEDITDLGTAEOLFILLEDCB, wxID_STCSTYLEEDITDLGTAEOLFILLEDDEFCB,
wxID_STCSTYLEEDITDLGTAITALICCB, wxID_STCSTYLEEDITDLGTAITALICDEFCB,
wxID_STCSTYLEEDITDLGTASIZEDEFCB, wxID_STCSTYLEEDITDLGTAUNDERLINEDCB,
wxID_STCSTYLEEDITDLGTAUNDERLINEDDEFCB,
] = [wx.NewId() for _init_ctrls in range(47)]
class STCStyleEditDlg(wx.Dialog):
""" Style editor for the wxStyledTextCtrl """
_custom_classes = {'wx.Window': ['wx.stc.StyledTextCtrl'],}
def _init_ctrls(self, prnt):
# generated method, don't edit
wx.Dialog.__init__(self, id=wxID_STCSTYLEEDITDLG,
name='STCStyleEditDlg', parent=prnt, pos=wx.Point(567, 292),
size=wx.Size(493, 482),
style=wx.WANTS_CHARS | wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER,
title=self.stc_title)
self.SetClientSize(wx.Size(485, 455))
self.SetAutoLayout(True)
self.SetSizeHints(425, 400, -1, -1)
self.Center(wx.BOTH)
self.Bind(wx.EVT_SIZE, self.OnStcstyleeditdlgSize)
self.speedsettingCh = wx.Choice(choices=[],
id=wxID_STCSTYLEEDITDLGSPEEDSETTINGCH, name='speedsettingCh',
parent=self, pos=wx.Point(96, 28), size=wx.Size(380, 21),
style=0)
self.speedsettingCh.SetConstraints(LayoutAnchors(self.speedsettingCh,
True, True, True, False))
self.speedsettingCh.SetHelpText('The speed setting allows you to revert to one of the predefined style sets. This will overwrite your current settings when tha dialog is posted.')
self.speedsettingCh.Bind(wx.EVT_CHOICE, self.OnSpeedsettingchChoice,
id=wxID_STCSTYLEEDITDLGSPEEDSETTINGCH)
self.elementLb = wx.ListBox(choices=[],
id=wxID_STCSTYLEEDITDLGELEMENTLB, name='elementLb', parent=self,
pos=wx.Point(8, 70), size=wx.Size(175, 128), style=0)
self.elementLb.SetConstraints(LayoutAnchors(self.elementLb, True, True,
True, False))
self.elementLb.SetHelpText('Select a style here to edit it. Common definitions can be added and maintained here. A common definition is a property that can be shared between styles and special cased per platform.')
self.elementLb.Bind(wx.EVT_LISTBOX, self.OnElementlbListbox,
id=wxID_STCSTYLEEDITDLGELEMENTLB)
self.addCommonItemBtn = wx.Button(id=wxID_STCSTYLEEDITDLGADDCOMMONITEMBTN,
label='Add', name='addCommonItemBtn', parent=self, pos=wx.Point(8,
200), size=wx.Size(88, 17), style=0)
self.addCommonItemBtn.SetToolTipString('Add new Common definition')
self.addCommonItemBtn.Bind(wx.EVT_BUTTON, self.OnAddsharebtnButton,
id=wxID_STCSTYLEEDITDLGADDCOMMONITEMBTN)
self.removeCommonItemBtn = wx.Button(id=wxID_STCSTYLEEDITDLGREMOVECOMMONITEMBTN,
label='Remove', name='removeCommonItemBtn', parent=self,
pos=wx.Point(96, 200), size=wx.Size(88, 17), style=0)
self.removeCommonItemBtn.SetToolTipString('Remove the selected Common definition')
self.removeCommonItemBtn.Bind(wx.EVT_BUTTON,
self.OnRemovesharebtnButton,
id=wxID_STCSTYLEEDITDLGREMOVECOMMONITEMBTN)
self.styleDefST = wx.StaticText(id=wxID_STCSTYLEEDITDLGSTYLEDEFST,
label='(nothing selected)', name='styleDefST', parent=self,
pos=wx.Point(96, 8), size=wx.Size(376, 16),
style=wx.ST_NO_AUTORESIZE)
self.styleDefST.SetFont(wx.Font(self.style_font_size, wx.SWISS,
wx.NORMAL, wx.BOLD, False, ''))
self.styleDefST.SetConstraints(LayoutAnchors(self.styleDefST, True,
True, True, False))
self.staticLine1 = wx.StaticLine(id=wxID_STCSTYLEEDITDLGSTATICLINE1,
name='staticLine1', parent=self, pos=wx.Point(48, 64),
size=wx.Size(135, 0), style=wx.LI_HORIZONTAL)
self.staticLine1.SetConstraints(LayoutAnchors(self.staticLine1, True,
True, True, False))
self.staticText6 = wx.StaticText(id=wxID_STCSTYLEEDITDLGSTATICTEXT6,
label='Style', name='staticText6', parent=self, pos=wx.Point(8,
56), size=wx.Size(40, 13), style=0)
self.staticText8 = wx.StaticText(id=wxID_STCSTYLEEDITDLGSTATICTEXT8,
label='Style def:', name='staticText8', parent=self,
pos=wx.Point(8, 8), size=wx.Size(88, 13), style=0)
self.staticText9 = wx.StaticText(id=wxID_STCSTYLEEDITDLGSTATICTEXT9,
label='SpeedSetting:', name='staticText9', parent=self,
pos=wx.Point(8, 32), size=wx.Size(88, 13), style=0)
self.panel3 = wx.Panel(id=wxID_STCSTYLEEDITDLGPANEL3, name='panel3',
parent=self, pos=wx.Point(199, 56), size=wx.Size(160, 120),
style=wx.TAB_TRAVERSAL)
self.panel3.SetConstraints(LayoutAnchors(self.panel3, False, True, True,
False))
self.panel4 = wx.Panel(id=wxID_STCSTYLEEDITDLGPANEL4, name='panel4',
parent=self, pos=wx.Point(364, 56), size=wx.Size(114, 120),
style=wx.TAB_TRAVERSAL)
self.panel4.SetConstraints(LayoutAnchors(self.panel4, False, True, True,
False))
self.panel1 = wx.Panel(id=wxID_STCSTYLEEDITDLGPANEL1, name='panel1',
parent=self, pos=wx.Point(202, 177), size=wx.Size(149, 40),
style=wx.TAB_TRAVERSAL)
self.panel1.SetConstraints(LayoutAnchors(self.panel1, False, True, True,
False))
self.panel2 = wx.Panel(id=wxID_STCSTYLEEDITDLGPANEL2, name='panel2',
parent=self, pos=wx.Point(364, 178), size=wx.Size(112, 40),
style=wx.TAB_TRAVERSAL)
self.panel2.SetConstraints(LayoutAnchors(self.panel2, False, True, True,
False))
self.stc = wx.stc.StyledTextCtrl(id=wxID_STCSTYLEEDITDLGSTC, name='stc',
parent=self, pos=wx.Point(8, 224), size=wx.Size(469, 191),
style=wx.SUNKEN_BORDER)
self.stc.SetConstraints(LayoutAnchors(self.stc, True, True, True, True))
self.stc.SetHelpText('The style preview window. Click or move the cursor over a specific style to select the style for editing in the editors above.')
self.stc.Bind(wx.EVT_LEFT_UP, self.OnUpdateUI)
self.stc.Bind(wx.EVT_KEY_UP, self.OnUpdateUI)
self.contextHelpButton1 = wx.ContextHelpButton(parent=self,
pos=wx.Point(8, 423), size=wx.Size(24, 24), style=wx.BU_AUTODRAW)
self.contextHelpButton1.SetConstraints(LayoutAnchors(self.contextHelpButton1,
True, False, False, True))
self.okBtn = wx.Button(id=wxID_STCSTYLEEDITDLGOKBTN, label='OK',
name='okBtn', parent=self, pos=wx.Point(316, 423),
size=wx.Size(75, 23), style=0)
self.okBtn.SetConstraints(LayoutAnchors(self.okBtn, False, False, True,
True))
self.okBtn.SetToolTipString('Save changes to the config file')
self.okBtn.Bind(wx.EVT_BUTTON, self.OnOkbtnButton,
id=wxID_STCSTYLEEDITDLGOKBTN)
self.cancelBtn = wx.Button(id=wxID_STCSTYLEEDITDLGCANCELBTN,
label='Cancel', name='cancelBtn', parent=self, pos=wx.Point(400,
423), size=wx.Size(75, 23), style=0)
self.cancelBtn.SetConstraints(LayoutAnchors(self.cancelBtn, False,
False, True, True))
self.cancelBtn.SetToolTipString('Close dialog without saving changes')
self.cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancelbtnButton,
id=wxID_STCSTYLEEDITDLGCANCELBTN)
self.staticText4 = wx.StaticText(id=wxID_STCSTYLEEDITDLGSTATICTEXT4,
label='Face:', name='staticText4', parent=self.panel1,
pos=wx.Point(0, 0), size=wx.Size(48, 13), style=0)
self.fixedWidthChk = wx.CheckBox(id=wxID_STCSTYLEEDITDLGFIXEDWIDTHCHK,
label='', name='fixedWidthChk', parent=self.panel1,
pos=wx.Point(0, 23), size=wx.Size(16, 19), style=0)
self.fixedWidthChk.SetToolTipString('Check this for Fixed Width fonts')
self.fixedWidthChk.Bind(wx.EVT_CHECKBOX, self.OnFixedwidthchkCheckbox,
id=wxID_STCSTYLEEDITDLGFIXEDWIDTHCHK)
self.faceCb = wx.ComboBox(choices=[], id=wxID_STCSTYLEEDITDLGFACECB,
name='faceCb', parent=self.panel1, pos=wx.Point(17, 18),
size=wx.Size(101, 21), style=0, value='')
self.staticText7 = wx.StaticText(id=wxID_STCSTYLEEDITDLGSTATICTEXT7,
label='Size:', name='staticText7', parent=self.panel2,
pos=wx.Point(0, 0), size=wx.Size(40, 13), style=0)
self.sizeCb = wx.ComboBox(choices=[], id=wxID_STCSTYLEEDITDLGSIZECB,
name='sizeCb', parent=self.panel2, pos=wx.Point(0, 17),
size=wx.Size(80, 21), style=0, value='')
self.sizeOkBtn = wx.Button(id=wxID_STCSTYLEEDITDLGSIZEOKBTN, label='ok',
name='sizeOkBtn', parent=self.panel2, pos=wx.Point(80, 17),
size=wx.Size(32, 21), style=0)
self.faceOkBtn = wx.Button(id=wxID_STCSTYLEEDITDLGFACEOKBTN, label='ok',
name='faceOkBtn', parent=self.panel1, pos=wx.Point(117, 18),
size=wx.Size(32, 21), style=0)
self.fgColBtn = wx.Button(id=wxID_STCSTYLEEDITDLGFGCOLBTN,
label='Foreground', name='fgColBtn', parent=self.panel3,
pos=wx.Point(8, 16), size=wx.Size(96, 16), style=0)
self.fgColBtn.Bind(wx.EVT_BUTTON, self.OnFgcolbtnButton,
id=wxID_STCSTYLEEDITDLGFGCOLBTN)
self.fgColCb = wx.ComboBox(choices=[], id=wxID_STCSTYLEEDITDLGFGCOLCB,
name='fgColCb', parent=self.panel3, pos=wx.Point(8, 32),
size=wx.Size(96, 21), style=0, value='')
self.fgColOkBtn = wx.Button(id=wxID_STCSTYLEEDITDLGFGCOLOKBTN,
label='ok', name='fgColOkBtn', parent=self.panel3,
pos=wx.Point(104, 32), size=wx.Size(32, 21), style=0)
self.staticText3 = wx.StaticText(id=wxID_STCSTYLEEDITDLGSTATICTEXT3,
label='default', name='staticText3', parent=self.panel3,
pos=wx.Point(112, 15), size=wx.Size(38, 16), style=0)
self.fgColDefCb = wx.CheckBox(id=wxID_STCSTYLEEDITDLGFGCOLDEFCB,
label='checkBox1', name='fgColDefCb', parent=self.panel3,
pos=wx.Point(136, 31), size=wx.Size(16, 16), style=0)
self.bgColBtn = wx.Button(id=wxID_STCSTYLEEDITDLGBGCOLBTN,
label='Background', name='bgColBtn', parent=self.panel3,
pos=wx.Point(8, 64), size=wx.Size(96, 16), style=0)
self.bgColBtn.Bind(wx.EVT_BUTTON, self.OnBgcolbtnButton,
id=wxID_STCSTYLEEDITDLGBGCOLBTN)
self.bgColCb = wx.ComboBox(choices=[], id=wxID_STCSTYLEEDITDLGBGCOLCB,
name='bgColCb', parent=self.panel3, pos=wx.Point(8, 80),
size=wx.Size(96, 21), style=0, value='')
self.bgColOkBtn = wx.Button(id=wxID_STCSTYLEEDITDLGBGCOLOKBTN,
label='ok', name='bgColOkBtn', parent=self.panel3,
pos=wx.Point(104, 80), size=wx.Size(32, 21), style=0)
self.staticBox2 = wx.StaticBox(id=wxID_STCSTYLEEDITDLGSTATICBOX2,
label='Text attributes', name='staticBox2', parent=self.panel4,
pos=wx.Point(0, 0), size=wx.Size(112, 112), style=0)
self.staticBox2.SetConstraints(LayoutAnchors(self.staticBox2, False,
True, True, False))
self.staticBox2.SetHelpText('Text attribute flags.')
self.staticText2 = wx.StaticText(id=wxID_STCSTYLEEDITDLGSTATICTEXT2,
label='default', name='staticText2', parent=self.panel4,
pos=wx.Point(64, 12), size=wx.Size(40, 16), style=0)
self.taBoldDefCb = wx.CheckBox(id=wxID_STCSTYLEEDITDLGTABOLDDEFCB,
label='checkBox1', name='taBoldDefCb', parent=self.panel4,
pos=wx.Point(88, 27), size=wx.Size(16, 16), style=0)
self.taItalicDefCb = wx.CheckBox(id=wxID_STCSTYLEEDITDLGTAITALICDEFCB,
label='checkBox1', name='taItalicDefCb', parent=self.panel4,
pos=wx.Point(88, 48), size=wx.Size(16, 16), style=0)
self.taUnderlinedDefCb = wx.CheckBox(id=wxID_STCSTYLEEDITDLGTAUNDERLINEDDEFCB,
label='checkBox1', name='taUnderlinedDefCb', parent=self.panel4,
pos=wx.Point(88, 70), size=wx.Size(16, 16), style=0)
self.taEOLfilledDefCb = wx.CheckBox(id=wxID_STCSTYLEEDITDLGTAEOLFILLEDDEFCB,
label='checkBox1', name='taEOLfilledDefCb', parent=self.panel4,
pos=wx.Point(88, 92), size=wx.Size(16, 16), style=0)
self.taEOLfilledCb = wx.CheckBox(id=wxID_STCSTYLEEDITDLGTAEOLFILLEDCB,
label='EOL filled', name='taEOLfilledCb', parent=self.panel4,
pos=wx.Point(8, 92), size=wx.Size(80, 16), style=0)
self.taEOLfilledCb.Bind(wx.EVT_CHECKBOX, self.OnTaeoffilledcbCheckbox,
id=wxID_STCSTYLEEDITDLGTAEOLFILLEDCB)
self.taUnderlinedCb = wx.CheckBox(id=wxID_STCSTYLEEDITDLGTAUNDERLINEDCB,
label='Underlined', name='taUnderlinedCb', parent=self.panel4,
pos=wx.Point(8, 70), size=wx.Size(80, 16), style=0)
self.taUnderlinedCb.Bind(wx.EVT_CHECKBOX, self.OnTaunderlinedcbCheckbox,
id=wxID_STCSTYLEEDITDLGTAUNDERLINEDCB)
self.taItalicCb = wx.CheckBox(id=wxID_STCSTYLEEDITDLGTAITALICCB,
label='Italic', name='taItalicCb', parent=self.panel4,
pos=wx.Point(8, 48), size=wx.Size(80, 16), style=0)
self.taItalicCb.Bind(wx.EVT_CHECKBOX, self.OnTaitaliccbCheckbox,
id=wxID_STCSTYLEEDITDLGTAITALICCB)
self.taBoldCb = wx.CheckBox(id=wxID_STCSTYLEEDITDLGTABOLDCB,
label='Bold', name='taBoldCb', parent=self.panel4, pos=wx.Point(8,
27), size=wx.Size(80, 16), style=0)
self.taBoldCb.Bind(wx.EVT_CHECKBOX, self.OnTaboldcbCheckbox,
id=wxID_STCSTYLEEDITDLGTABOLDCB)
self.bgColDefCb = wx.CheckBox(id=wxID_STCSTYLEEDITDLGBGCOLDEFCB,
label='checkBox1', name='bgColDefCb', parent=self.panel3,
pos=wx.Point(136, 79), size=wx.Size(16, 16), style=0)
self.staticBox1 = wx.StaticBox(id=wxID_STCSTYLEEDITDLGSTATICBOX1,
label='Colour', name='staticBox1', parent=self.panel3,
pos=wx.Point(0, 0), size=wx.Size(157, 112), style=0)
self.staticBox1.SetConstraints(LayoutAnchors(self.staticBox1, False,
True, True, False))
self.faceDefCb = wx.CheckBox(id=wxID_STCSTYLEEDITDLGFACEDEFCB,
label='checkBox1', name='faceDefCb', parent=self.panel1,
pos=wx.Point(117, 0), size=wx.Size(16, 16), style=0)
self.taSizeDefCb = wx.CheckBox(id=wxID_STCSTYLEEDITDLGTASIZEDEFCB,
label='checkBox1', name='taSizeDefCb', parent=self.panel2,
pos=wx.Point(80, 0), size=wx.Size(16, 16), style=0)
def __init__(self, parent, langTitle, lang, configFile, STCsToUpdate=()):
self.stc_title = 'wxStyledTextCtrl Style Editor'
self.stc_title = 'wxStyledTextCtrl Style Editor - %s' % langTitle
self.style_font_size = 8
self.style_font_size = platformSettings[wx.Platform][1]
self._init_ctrls(parent)
self.lang = lang
self.configFile = configFile
self.style = ''
self.styleNum = 0
self.names = []
self.values = {}
self.STCsToUpdate = STCsToUpdate
self._blockUpdate = False
global commonPropDefs
commonPropDefs = {'fore': '#888888', 'size': 8,
'face': wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT).GetFaceName()}
for combo, okBtn, evtRet, evtCB, evtRDC in (
(self.fgColCb, self.fgColOkBtn, self.OnfgColRet, self.OnfgColCombobox, self.OnGotoCommonDef),
(self.bgColCb, self.bgColOkBtn, self.OnbgColRet, self.OnbgColCombobox, self.OnGotoCommonDef),
(self.faceCb, self.faceOkBtn, self.OnfaceRet, self.OnfaceCombobox, self.OnGotoCommonDef),
(self.sizeCb, self.sizeOkBtn, self.OnsizeRet, self.OnsizeCombobox, self.OnGotoCommonDef)):
self.bindComboEvts(combo, okBtn, evtRet, evtCB, evtRDC)
(self.config, self.commonDefs, self.styleIdNames, self.styles,
self.styleGroupNames, self.predefStyleGroups,
self.otherLangStyleGroupNames, self.otherLangStyleGroups,
self.displaySrc, self.lexer, self.keywords, self.braceInfo) = \
initFromConfig(configFile, lang)
self.currSpeedSetting = 'style.%s'%self.lang
for grp in [self.currSpeedSetting]+self.styleGroupNames:
self.speedsettingCh.Append(grp)
self.speedsettingCh.SetSelection(0)
margin = 0
self.stc.SetMarginType(margin, wx.stc.STC_MARGIN_NUMBER)
self.stc.SetMarginWidth(margin, 25)
self.stc.SetMarginSensitive(margin, True)
self.stc.Bind(wx.stc.EVT_STC_MARGINCLICK, self.OnMarginClick, id=wxID_STCSTYLEEDITDLGSTC)
self.stc.SetUseTabs(False)
self.stc.SetTabWidth(4)
self.stc.SetIndentationGuides(True)
self.stc.SetEdgeMode(wx.stc.STC_EDGE_BACKGROUND)
self.stc.SetEdgeColumn(44)
self.setStyles()
self.populateStyleSelector()
self.defNames, self.defValues = parseProp(\
self.styleDict.get(wx.stc.STC_STYLE_DEFAULT, ''))
self.stc.SetText(self.displaySrc)
self.stc.EmptyUndoBuffer()
self.stc.SetCurrentPos(self.stc.GetTextLength())
self.stc.SetAnchor(self.stc.GetTextLength())
self.populateCombosWithCommonDefs()
# Logical grouping of controls and the property they edit
self.allCtrls = [((self.fgColBtn, self.fgColCb, self.fgColOkBtn), self.fgColDefCb,
'fore', wxID_STCSTYLEEDITDLGFGCOLDEFCB),
((self.bgColBtn, self.bgColCb, self.bgColOkBtn), self.bgColDefCb,
'back', wxID_STCSTYLEEDITDLGBGCOLDEFCB),
(self.taBoldCb, self.taBoldDefCb,
'bold', wxID_STCSTYLEEDITDLGTABOLDDEFCB),
(self.taItalicCb, self.taItalicDefCb,
'italic', wxID_STCSTYLEEDITDLGTAITALICDEFCB),
(self.taUnderlinedCb, self.taUnderlinedDefCb,
'underline', wxID_STCSTYLEEDITDLGTAUNDERLINEDDEFCB),
(self.taEOLfilledCb, self.taEOLfilledDefCb,
'eolfilled', wxID_STCSTYLEEDITDLGTAEOLFILLEDDEFCB),
((self.sizeCb, self.sizeOkBtn), self.taSizeDefCb,
'size', wxID_STCSTYLEEDITDLGTASIZEDEFCB),
((self.faceCb, self.faceOkBtn, self.fixedWidthChk), self.faceDefCb,
'face', wxID_STCSTYLEEDITDLGFACEDEFCB)]
self.clearCtrls(disableDefs=True)
# centralised default checkbox event handler
self.chbIdMap = {}
for ctrl, chb, prop, wid in self.allCtrls:
self.chbIdMap[wid] = ctrl, chb, prop, wid
chb.Bind(wx.EVT_CHECKBOX, self.OnDefaultCheckBox, id=wid)
chb.SetToolTipString('Toggle defaults')
self.Center(wx.BOTH)
#---Property methods------------------------------------------------------------
def getCtrlForProp(self, findprop):
for ctrl, chb, prop, wid in self.allCtrls:
if findprop == prop:
return ctrl, chb
raise Exception('PropNotFound', findprop)
def editProp(self, on, prop, val=''):
oldstyle = self.rememberStyles()
if on:
if not self.names.count(prop):
self.names.append(prop)
self.values[prop] = val
else:
try: self.names.remove(prop)
except ValueError: pass
try: del self.values[prop]
except KeyError: pass
try:
self.updateStyle()
return True
except KeyError, errkey:
wx.LogError('Name not found in Common definition, '\
'please enter valid reference. (%s)'%errkey)
self.restoreStyles(oldstyle)
return False
#---Control population methods--------------------------------------------------
def setStyles(self):
if self._blockUpdate: return
self.styles, self.styleDict, self.styleNumIdxMap = \
setSTCStyles(self.stc, self.styles, self.styleIdNames,
self.commonDefs, self.lang, self.lexer, self.keywords)
def updateStyle(self):
# called after a control edited self.names, self.values
# Special case for saving common defs settings
if self.styleNum == 'common':
#if not self.values:
# return
strVal = self.style[2] = self.values.values()[0]
if self.style[1] == 'size': self.style[2] = int(strVal)
self.commonDefs[self.style[0]] = self.style[2]
self.styleDefST.SetLabel(strVal)
else:
self.style = writePropVal(self.names, self.values)
styleDecl = writeProp(self.styleNum, self.style, self.lang)
self.styles[self.styleNumIdxMap[self.styleNum]] = styleDecl
self.styleDefST.SetLabel(self.style)
self.setStyles()
def findInStyles(self, txt, styles):
for style in styles:
if style.find(txt) != -1:
return True
return False
def rememberStyles(self):
return self.names[:], copy.copy(self.values)
def restoreStyles(self, style):
self.names, self.values = style
self.updateStyle()
def clearCtrls(self, isDefault=False, disableDefs=False):
self._blockUpdate = True
try:
for ctrl, chb, prop, wid in self.allCtrls:
if prop in ('fore', 'back'):
cbtn, txt, btn = ctrl
cbtn.SetBackgroundColour(\
wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE))
cbtn.SetForegroundColour(wx.Colour(255, 255, 255))
cbtn.Enable(isDefault)
txt.SetValue('')
txt.Enable(isDefault)
btn.Enable(isDefault)
elif prop == 'size':
cmb, btn = ctrl
cmb.SetValue('')
cmb.Enable(isDefault)
btn.Enable(isDefault)
elif prop == 'face':
cmb, btn, chk = ctrl
cmb.SetValue('')
cmb.Enable(isDefault)
btn.Enable(isDefault)
chk.Enable(isDefault)
chk.SetValue(False)
elif prop in ('bold', 'italic', 'underline', 'eolfilled'):
ctrl.SetValue(False)
ctrl.Enable(isDefault)
chb.Enable(not isDefault and not disableDefs)
chb.SetValue(True)
finally:
self._blockUpdate = False
def populateProp(self, items, default, forceDisable=False):
self._blockUpdate = True
try:
for name, val in items:
if name:
ctrl, chb = self.getCtrlForProp(name)
if name in ('fore', 'back'):
cbtn, txt, btn = ctrl
repval = val%self.commonDefs
cbtn.SetBackgroundColour(strToCol(repval))
cbtn.SetForegroundColour(wx.Colour(0, 0, 0))
cbtn.Enable(not forceDisable)
txt.SetValue(val)
txt.Enable(not forceDisable)
btn.Enable(not forceDisable)
chb.SetValue(default)
elif name == 'size':
cmb, btn = ctrl
cmb.SetValue(val)
cmb.Enable(not forceDisable)
btn.Enable(not forceDisable)
chb.SetValue(default)
elif name == 'face':
cmb, btn, chk = ctrl
cmb.SetValue(val)
cmb.Enable(not forceDisable)
btn.Enable(not forceDisable)
chk.Enable(not forceDisable)
chb.SetValue(default)
elif name in ('bold', 'italic', 'underline', 'eolfilled'):
ctrl.Enable(not forceDisable)
ctrl.SetValue(True)
chb.SetValue(default)
finally:
self._blockUpdate = False
def valIsCommonDef(self, val):
return len(val) >= 5 and val[:2] == '%('
def populateCtrls(self):
self.clearCtrls(self.styleNum == wx.stc.STC_STYLE_DEFAULT,
disableDefs=self.styleNum < 0)
# handle colour controls for settings
if self.styleNum < 0:
self.fgColDefCb.Enable(True)
if self.styleNum == -1:
self.bgColDefCb.Enable(True)
# populate with default style
self.populateProp(self.defValues.items(), True,
self.styleNum != wx.stc.STC_STYLE_DEFAULT)
# override with current settings
self.populateProp(self.values.items(), False)
def getCommonDefPropType(self, commonDefName):
val = self.commonDefs[commonDefName]
if type(val) == type(0): return 'size'
if len(val) == 7 and val[0] == '#': return 'fore'
return 'face'
def bindComboEvts(self, combo, btn, btnEvtMeth, comboEvtMeth, rdclickEvtMeth):
combo.Bind(wx.EVT_COMBOBOX, comboEvtMeth, id=combo.GetId())
btn.Bind(wx.EVT_BUTTON, btnEvtMeth, id=btn.GetId())
combo.Bind(wx.EVT_RIGHT_DCLICK, rdclickEvtMeth)
combo.SetToolTipString('Select from list or click "ok" button on the right to change a manual entry, right double-click \n'\
'the drop down button to select Common definition in the Style Editor (if applicable)')
btn.SetToolTipString('Accept value')
def populateCombosWithCommonDefs(self, fixedWidthOnly=None):
self._blockUpdate = True
try:
commonDefs = {'fore': [], 'face': [], 'size': []}
if self.elementLb.GetSelection() < self.commonDefsStartIdx:
for common in self.commonDefs.keys():
prop = self.getCommonDefPropType(common)
commonDefs[prop].append('%%(%s)%s'%(common,
prop=='size' and 'd' or 's'))
# Colours
currFg, currBg = self.fgColCb.GetValue(), self.bgColCb.GetValue()
self.fgColCb.Clear(); self.bgColCb.Clear()
for colCommonDef in commonDefs['fore']:
self.fgColCb.Append(colCommonDef)
self.bgColCb.Append(colCommonDef)
self.fgColCb.SetValue(currFg); self.bgColCb.SetValue(currBg)
# Font
if fixedWidthOnly is None:
fixedWidthOnly = self.fixedWidthChk.GetValue()
fontEnum = wx.FontEnumerator()
fontEnum.EnumerateFacenames(fixedWidthOnly=fixedWidthOnly)
fontNameList = fontEnum.GetFacenames()
fontNameList.sort()
currFace = self.faceCb.GetValue()
self.faceCb.Clear()
for colCommonDef in fontNameList+commonDefs['face']:
self.faceCb.Append(colCommonDef)
self.faceCb.SetValue(currFace)
# Size (XXX add std font sizes)
currSize = self.sizeCb.GetValue()
self.sizeCb.Clear()
for colCommonDef in commonDefs['size']:
self.sizeCb.Append(colCommonDef)
self.sizeCb.SetValue(currSize)
finally:
self._blockUpdate = False
def populateStyleSelector(self):
numStyles = self.styleIdNames.items()
numStyles.sort()
self.styleNumLookup = {}
stdStart = -1
stdOffset = 0
extrOffset = 0
# add styles
for num, name in numStyles:
if num == wx.stc.STC_STYLE_DEFAULT:
self.elementLb.InsertItems([name, '----Language----'], 0)
self.elementLb.Append('----Standard----')
stdStart = stdPos = self.elementLb.GetCount()
else:
# std styles
if num >= 33 and num < 40:
self.elementLb.InsertItems([name], stdStart + stdOffset)
stdOffset = stdOffset + 1
# extra styles
elif num >= 40:
self.elementLb.InsertItems([name], stdStart + extrOffset -1)
extrOffset = extrOffset + 1
# normal lang styles
else:
self.elementLb.Append(name)
self.styleNumLookup[name] = num
# add settings
self.elementLb.Append('----Settings----')
settings = settingsIdNames.items()
settings.sort();settings.reverse()
for num, name in settings:
self.elementLb.Append(name)
self.styleNumLookup[name] = num
# add definitions
self.elementLb.Append('----Common----')
self.commonDefsStartIdx = self.elementLb.GetCount()
for common in self.commonDefs.keys():
tpe = type(self.commonDefs[common])
self.elementLb.Append('%('+common+')'+(tpe is type('') and 's' or 'd'))
self.styleNumLookup[common] = num
#---Colour methods--------------------------------------------------------------
def getColourDlg(self, colour, title=''):
data = wx.ColourData()
data.SetColour(colour)
data.SetChooseFull(True)
dlg = wx.ColourDialog(self, data)
try:
dlg.SetTitle(title)
if dlg.ShowModal() == wx.ID_OK:
data = dlg.GetColourData()
return data.GetColour()
finally:
dlg.Destroy()
return None
colDlgTitles = {'fore': 'Foreground', 'back': 'Background'}
def editColProp(self, colBtn, colCb, prop):
col = self.getColourDlg(colBtn.GetBackgroundColour(),
self.colDlgTitles[prop]+ ' colour')
if col:
colBtn.SetForegroundColour(wx.Colour(0, 0, 0))
colBtn.SetBackgroundColour(col)
colStr = colToStr(col)
colCb.SetValue(colStr)
self.editProp(True, prop, colStr)
def OnFgcolbtnButton(self, event):
self.editColProp(self.fgColBtn, self.fgColCb, 'fore')
def OnBgcolbtnButton(self, event):
self.editColProp(self.bgColBtn, self.bgColCb, 'back')
def editColTCProp(self, colCb, colBtn, prop, val=None):
if val is None:
colStr = colCb.GetValue()
else:
colStr = val
if colStr:
col = strToCol(colStr%self.commonDefs)
if self.editProp(colStr!='', prop, colStr):
if colStr:
colBtn.SetForegroundColour(wx.Colour(0, 0, 0))
colBtn.SetBackgroundColour(col)
else:
colBtn.SetForegroundColour(wx.Colour(255, 255, 255))
colBtn.SetBackgroundColour(\
wxSystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE))
def OnfgColRet(self, event):
try: self.editColTCProp(self.fgColCb, self.fgColBtn, 'fore')
except AssertionError: wx.LogError('Not a valid colour value')
def OnfgColCombobox(self, event):
if self._blockUpdate: return
try: self.editColTCProp(self.fgColCb, self.fgColBtn, 'fore', event.GetString())
except AssertionError: wx.LogError('Not a valid colour value')
def OnbgColRet(self, event):
try: self.editColTCProp(self.bgColCb, self.bgColBtn, 'back')
except AssertionError: wx.LogError('Not a valid colour value')
def OnbgColCombobox(self, event):
if self._blockUpdate: return
try: self.editColTCProp(self.bgColCb, self.bgColBtn, 'back', event.GetString())
except AssertionError: wx.LogError('Not a valid colour value')
#---Text attribute events-------------------------------------------------------
def OnTaeoffilledcbCheckbox(self, event):
self.editProp(event.IsChecked(), 'eolfilled')
def OnTaitaliccbCheckbox(self, event):
self.editProp(event.IsChecked(), 'italic')
def OnTaboldcbCheckbox(self, event):
self.editProp(event.IsChecked(), 'bold')
def OnTaunderlinedcbCheckbox(self, event):
self.editProp(event.IsChecked(), 'underline')
def OnGotoCommonDef(self, event):
val = event.GetEventObject().GetValue()
if self.valIsCommonDef(val):
idx = self.elementLb.FindString(val)
if idx != -1:
self.elementLb.SetSelection(idx, True)
self.OnElementlbListbox(None)
def OnfaceRet(self, event):
self.setFace(self.faceCb.GetValue())
def OnfaceCombobox(self, event):
if self._blockUpdate: return
self.setFace(event.GetString())
def setFace(self, val):
try: val%self.commonDefs
except KeyError: wx.LogError('Invalid common definition')
else: self.editProp(val!='', 'face', val)
def OnsizeRet(self, event):
self.setSize(self.sizeCb.GetValue())
def OnsizeCombobox(self, event):
if self._blockUpdate: return
self.setSize(event.GetString())
def setSize(self, val):
try: int(val%self.commonDefs)
except ValueError: wx.LogError('Not a valid integer size value')
except KeyError: wx.LogError('Invalid common definition')
else: self.editProp(val!='', 'size', val)
#---Main GUI events-------------------------------------------------------------
def OnElementlbListbox(self, event):
isCommon = self.elementLb.GetSelection() >= self.commonDefsStartIdx
self.removeCommonItemBtn.Enable(isCommon)
styleIdent = self.elementLb.GetStringSelection()
# common definition selected
if isCommon:
common = styleIdent[2:-2]
prop = self.getCommonDefPropType(common)
self.clearCtrls(disableDefs=True)
if prop == 'fore':
self.fgColBtn.Enable(True)
self.fgColCb.Enable(True)
self.fgColOkBtn.Enable(True)
elif prop == 'face':
self.faceCb.Enable(True)
self.fixedWidthChk.Enable(True)
self.faceOkBtn.Enable(True)
elif prop == 'size':
self.sizeCb.Enable(True)
self.sizeOkBtn.Enable(True)
commonDefVal = str(self.commonDefs[common])
self.styleDefST.SetLabel(commonDefVal)
self.populateProp( [(prop, commonDefVal)], True)
self.styleNum = 'common'
self.style = [common, prop, commonDefVal]
self.names, self.values = [prop], {prop: commonDefVal}
# normal style element selected
elif len(styleIdent) >=2 and styleIdent[:2] != '--':
self.styleNum = self.styleNumLookup[styleIdent]
self.style = self.styleDict[self.styleNum]
self.names, self.values = parseProp(self.style)
if self.styleNum == wx.stc.STC_STYLE_DEFAULT:
self.defNames, self.defValues = \
self.names, self.values
self.checkBraces(self.styleNum)
self.styleDefST.SetLabel(self.style)
self.populateCtrls()
# separator selected
else:
self.clearCtrls(disableDefs=True)
if styleIdent:
self.styleDefST.SetLabel(styleCategoryDescriptions[styleIdent])
self.populateCombosWithCommonDefs()
def OnDefaultCheckBox(self, event):
if self.chbIdMap.has_key(event.GetId()):
ctrl, chb, prop, wid = self.chbIdMap[event.GetId()]
restore = not event.IsChecked()
if prop in ('fore', 'back'):
cbtn, cmb, btn = ctrl
cbtn.Enable(restore)
cmb.Enable(restore)
btn.Enable(restore)
if restore:
colStr = cmb.GetValue()
#if prop == 'fore': colStr = self.fgColCb.GetValue()
#else: colStr = self.bgColCb.GetValue()
if colStr: self.editProp(True, prop, colStr)
else:
self.editProp(False, prop)
elif prop == 'size':
cmb, btn = ctrl
val = cmb.GetValue()
if val: self.editProp(restore, prop, val)
cmb.Enable(restore)
btn.Enable(restore)
elif prop == 'face':
cmb, btn, chk = ctrl
val = cmb.GetStringSelection()
if val: self.editProp(restore, prop, val)
cmb.Enable(restore)
btn.Enable(restore)
chk.Enable(restore)
elif prop in ('bold', 'italic', 'underline', 'eolfilled'):
ctrl.Enable(restore)
if ctrl.GetValue(): self.editProp(restore, prop)
def OnOkbtnButton(self, event):
# write styles and common defs to the config
wx.BeginBusyCursor()
try:
writeStylesToConfig(self.config, 'style.%s'%self.lang, self.styles)
self.config.SetPath('')
self.config.Write(commonDefsFile, `self.commonDefs`)
self.config.Flush()
for stc in self.STCsToUpdate:
setSTCStyles(stc, self.styles, self.styleIdNames, self.commonDefs,
self.lang, self.lexer, self.keywords)
finally:
wx.EndBusyCursor()
self.EndModal(wx.ID_OK)
def OnCancelbtnButton(self, event):
self.EndModal(wx.ID_CANCEL)
def OnCommondefsbtnButton(self, event):
dlg = wx.TextEntryDialog(self, 'Edit common definitions dictionary',
'Common definitions', pprint.pformat(self.commonDefs),
style=wx.TE_MULTILINE | wx.OK | wx.CANCEL | wx.CENTRE)
try:
if dlg.ShowModal() == wx.ID_OK:
answer = eval(dlg.GetValue(), stc.__dict__)
assert type(answer) is type({}), 'Not a valid dictionary'
oldDefs = self.commonDefs
self.commonDefs = answer
try:
self.setStyles()
except KeyError, badkey:
wx.LogError(str(badkey)+' not defined but required, \n'\
'reverting to previous common definition')
self.commonDefs = oldDefs
self.setStyles()
self.populateCombosWithCommonDefs()
finally:
dlg.Destroy()
def OnSpeedsettingchChoice(self, event):
group = event.GetString()
if group:
userStyles = 'style.%s'%self.lang
if self.currSpeedSetting == userStyles:
self.predefStyleGroups[userStyles] = self.styles
self.styles = self.predefStyleGroups[group]
self.setStyles()
self.defNames, self.defValues = parseProp(\
self.styleDict.get(wx.stc.STC_STYLE_DEFAULT, ''))
self.OnElementlbListbox(None)
self.currSpeedSetting = group
def OnFixedwidthchkCheckbox(self, event):
self.populateCombosWithCommonDefs(event.IsChecked())
def OnAddsharebtnButton(self, event):
dlg = CommonDefDlg(self)
try:
if dlg.ShowModal() == wx.ID_OK:
prop, name = dlg.result
if not self.commonDefs.has_key(name):
self.commonDefs[name] = commonPropDefs[prop]
self.elementLb.Append('%('+name+')'+\
(type(commonPropDefs[prop]) is type('') and 's' or 'd'))
self.elementLb.SetSelection(self.elementLb.GetCount()-1, True)
self.populateCombosWithCommonDefs()
self.OnElementlbListbox(None)
finally:
dlg.Destroy()
def OnRemovesharebtnButton(self, event):
ownGroup = 'style.%s'%self.lang
comDef = self.elementLb.GetStringSelection()
# Search ALL styles before removing
srchDct = {ownGroup: self.styles}
srchDct.update(self.predefStyleGroups)
srchDct.update(self.otherLangStyleGroups)
matchList = []
for grpName, styles in srchDct.items():
if self.findInStyles(comDef, styles):
matchList.append(grpName)
if matchList:
wx.LogError('Aborted: '+comDef+' is still used in the styles of the \n'\
'following groups in the config file (stc-styles.rc.cfg):\n'+ \
'\n'.join(matchList))
else:
del self.commonDefs[comDef[2:-2]]
self.setStyles()
self.populateCombosWithCommonDefs()
selIdx = self.elementLb.GetSelection()
self.elementLb.Delete(selIdx)
if selIdx == self.elementLb.GetCount():
selIdx = selIdx - 1
self.elementLb.SetSelection(selIdx, True)
self.OnElementlbListbox(None)
#---STC events------------------------------------------------------------------
def OnUpdateUI(self, event):
styleBefore = self.stc.GetStyleAt(self.stc.GetCurrentPos())
if self.styleIdNames.has_key(styleBefore):
self.elementLb.SetStringSelection(self.styleIdNames[styleBefore],
True)
else:
self.elementLb.SetSelection(0, False)
self.styleDefST.SetLabel('Style %d not defined, sorry.'%styleBefore)
self.OnElementlbListbox(None)
event.Skip()
def checkBraces(self, style):
if style == wx.stc.STC_STYLE_BRACELIGHT and self.braceInfo.has_key('good'):
line, col = self.braceInfo['good']
pos = self.stc.PositionFromLine(line-1) + col
braceOpposite = self.stc.BraceMatch(pos)
if braceOpposite != -1:
self.stc.BraceHighlight(pos, braceOpposite)
elif style == wx.stc.STC_STYLE_BRACEBAD and self.braceInfo.has_key('bad'):
line, col = self.braceInfo['bad']
pos = self.stc.PositionFromLine(line-1) + col
self.stc.BraceBadLight(pos)
else:
self.stc.BraceBadLight(-1)
return
def OnStcstyleeditdlgSize(self, event):
self.Layout()
# Without this refresh, resizing leaves artifacts
self.Refresh(1)
event.Skip()
def OnMarginClick(self, event):
self.elementLb.SetStringSelection('Line numbers', True)
self.OnElementlbListbox(None)
#---Common definition dialog----------------------------------------------------
[wxID_COMMONDEFDLG, wxID_COMMONDEFDLGCANCELBTN, wxID_COMMONDEFDLGCOMDEFNAMETC, wxID_COMMONDEFDLGOKBTN, wxID_COMMONDEFDLGPROPTYPERBX, wxID_COMMONDEFDLGSTATICBOX1] = [wx.NewId() for _init_ctrls in range(6)]
class CommonDefDlg(wx.Dialog):
def _init_ctrls(self, prnt):
wx.Dialog.__init__(self, id = wxID_COMMONDEFDLG, name = 'CommonDefDlg', parent = prnt, pos = wx.Point(398, 249), size = wx.Size(192, 220), style= wx.DEFAULT_DIALOG_STYLE, title = 'Common definition')
self.SetClientSize(wx.Size(184, 200))
self.propTypeRBx = wx.RadioBox(choices = ['Colour value', 'Font face', 'Size value'], id = wxID_COMMONDEFDLGPROPTYPERBX, label = 'Property type', majorDimension = 1, name = 'propTypeRBx', parent = self, point = wx.Point(8, 8), size = wx.Size(168, 92), style= wx.RA_SPECIFY_COLS)
self.propTypeRBx.SetSelection(self._propTypeIdx)
self.staticBox1 = wx.StaticBox(id = wxID_COMMONDEFDLGSTATICBOX1, label = 'Name', name = 'staticBox1', parent = self, pos = wx.Point(8, 108), size = wx.Size(168, 46), style = 0)
self.comDefNameTC = wx.TextCtrl(id = wxID_COMMONDEFDLGCOMDEFNAMETC, name = 'comDefNameTC', parent = self, pos = wx.Point(16, 124), size = wx.Size(152, 21), style = 0, value = '')
self.comDefNameTC.SetLabel(self._comDefName)
self.okBtn = wx.Button(id = wxID_COMMONDEFDLGOKBTN, label = 'OK', name = 'okBtn', parent = self, pos = wx.Point(8, 164), size = wx.Size(80, 23), style = 0)
self.okBtn.Bind(wx.EVT_BUTTON, self.OnOkbtnButton, id=wxID_COMMONDEFDLGOKBTN)
self.cancelBtn = wx.Button(id = wxID_COMMONDEFDLGCANCELBTN, label = 'Cancel', name = 'cancelBtn', parent = self, pos = wx.Point(96, 164), size = wx.Size(80, 23), style = 0)
self.cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancelbtnButton, id=wxID_COMMONDEFDLGCANCELBTN)
def __init__(self, parent, name='', propIdx=0):
self._comDefName = ''
self._comDefName = name
self._propTypeIdx = 0
self._propTypeIdx = propIdx
self._init_ctrls(parent)
self.propMap = {0: 'fore', 1: 'face', 2: 'size'}
self.result = ( '', '' )
self.Center(wx.BOTH)
def OnOkbtnButton(self, event):
self.result = ( self.propMap[self.propTypeRBx.GetSelection()],
self.comDefNameTC.GetValue() )
self.EndModal(wx.ID_OK)
def OnCancelbtnButton(self, event):
self.result = ( '', '' )
self.EndModal(wx.ID_CANCEL)
#---Functions useful outside of the editor----------------------------------
def setSelectionColour(stc, style):
names, values = parseProp(style)
if 'fore' in names:
stc.SetSelForeground(True, strToCol(values['fore']))
if 'back' in names:
stc.SetSelBackground(True, strToCol(values['back']))
def setCursorColour(stc, style):
names, values = parseProp(style)
if 'fore' in names:
stc.SetCaretForeground(strToCol(values['fore']))
def setEdgeColour(stc, style):
names, values = parseProp(style)
if 'fore' in names:
stc.SetEdgeColour(strToCol(values['fore']))
def strToCol(strCol):
assert len(strCol) == 7 and strCol[0] == '#', 'Not a valid colour string: '+strCol
return wx.Colour(string.atoi('0x'+strCol[1:3], 16),
string.atoi('0x'+strCol[3:5], 16),
string.atoi('0x'+strCol[5:7], 16))
def colToStr(col):
return '#%s%s%s' % (string.zfill(string.upper(hex(col.Red())[2:]), 2),
string.zfill(string.upper(hex(col.Green())[2:]), 2),
string.zfill(string.upper(hex(col.Blue())[2:]), 2))
def writeProp(num, style, lang):
if num >= 0:
return 'style.%s.%s='%(lang, string.zfill(`num`, 3)) + style
else:
return 'setting.%s.%d='%(lang, num) + style
def writePropVal(names, values):
res = []
for name in names:
if name:
res.append(values[name] and name+':'+values[name] or name)
return ','.join(res)
def parseProp(prop):
items = prop.split(',')
names = []
values = {}
for item in items:
nameVal = item.split(':')
names.append(nameVal[0].strip())
if len(nameVal) == 1:
values[nameVal[0]] = ''
else:
values[nameVal[0]] = nameVal[1].strip()
return names, values
def parsePropLine(prop):
name, value = prop.split('=')
return int(name.split('.')[-1]), value
def setSTCStyles(stc, styles, styleIdNames, commonDefs, lang, lexer, keywords):
styleDict = {}
styleNumIdxMap = {}
# build style dict based on given styles
for numStyle in styles:
num, style = parsePropLine(numStyle)
styleDict[num] = style
# Add blank style entries for undefined styles
newStyles = []
styleItems = styleIdNames.items() + settingsIdNames.items()
styleItems.sort()
idx = 0
for num, name in styleItems:
styleNumIdxMap[num] = idx
if not styleDict.has_key(num):
styleDict[num] = ''
newStyles.append(writeProp(num, styleDict[num], lang))
idx = idx + 1
# Set background colour to reduce flashing effect on refresh or page switch
bkCol = None
if styleDict.has_key(0): prop = styleDict[0]
else: prop = styleDict[wx.stc.STC_STYLE_DEFAULT]
names, vals = parseProp(prop)
if 'back' in names:
bkCol = strToCol(vals['back']%commonDefs)
if bkCol is None:
bkCol = wx.WHITE
stc.SetBackgroundColour(bkCol)
# Set the styles on the wxSTC
stc.StyleResetDefault()
stc.ClearDocumentStyle()
stc.SetLexer(lexer)
stc.SetKeyWords(0, keywords)
stc.StyleSetSpec(wx.stc.STC_STYLE_DEFAULT,
styleDict[wx.stc.STC_STYLE_DEFAULT] % commonDefs)
stc.StyleClearAll()
for num, style in styleDict.items():
if num >= 0:
stc.StyleSetSpec(num, style % commonDefs)
elif num == -1:
setSelectionColour(stc, style % commonDefs)
elif num == -2:
setCursorColour(stc, style % commonDefs)
elif num == -3:
setEdgeColour(stc, style % commonDefs)
stc.Colourise(0, stc.GetTextLength())
return newStyles, styleDict, styleNumIdxMap
#---Config reading and writing -------------------------------------------------
commonDefsFile = 'common.defs.%s'%(platformSettings[wx.Platform][0])
def readPyValFromConfig(conf, name):
ns = {}
#ns.update(wx.stc.__dict__)
ns.update(wxPython.stc.__dict__)
ns['wx'] = wx
value = conf.Read(name).replace('\r\n', '\n')+'\n'
try:
return eval(value, ns)
except:
print value
raise
def initFromConfig(configFile, lang):
if not os.path.exists(configFile):
raise Exception, 'Config file %s not found'%configFile
cfg = wx.FileConfig(localFilename=configFile, style= wx.CONFIG_USE_LOCAL_FILE)
cfg.SetExpandEnvVars(False)
# read in all group names for this language
groupPrefix = 'style.%s'%lang
gpLen = len(groupPrefix)
predefStyleGroupNames, otherLangStyleGroupNames = [], []
cont, val, idx = cfg.GetFirstGroup()
while cont:
if val != groupPrefix and len(val) >= 5 and val[:5] == 'style':
if len(val) > gpLen and val[:gpLen] == groupPrefix:
predefStyleGroupNames.append(val)
else:
otherLangStyleGroupNames.append(val)
cont, val, idx = cfg.GetNextGroup(idx)
# read in common elements
commonDefs = readPyValFromConfig(cfg, commonDefsFile)
assert type(commonDefs) is type({}), \
'Common definitions (%s) not a valid dict'%commonDefsFile
commonStyleIdNames = readPyValFromConfig(cfg, 'common.styleidnames')
assert type(commonStyleIdNames) is type({}), \
'Common definitions (%s) not a valid dict'%'common.styleidnames'
# Lang specific settings
cfg.SetPath(lang)
styleIdNames = readPyValFromConfig(cfg, 'styleidnames')
assert type(commonStyleIdNames) is type({}), \
'Not a valid dict [%s] styleidnames)'%lang
styleIdNames.update(commonStyleIdNames)
braceInfo = readPyValFromConfig(cfg, 'braces')
assert type(commonStyleIdNames) is type({}), \
'Not a valid dict [%s] braces)'%lang
displaySrc = cfg.Read('displaysrc')
lexer = readPyValFromConfig(cfg, 'lexer')
keywords = cfg.Read('keywords')
cfg.SetPath('')
# read in current styles
styles = readStylesFromConfig(cfg, groupPrefix)
# read in predefined styles
predefStyleGroups = {}
for group in predefStyleGroupNames:
predefStyleGroups[group] = readStylesFromConfig(cfg, group)
# read in all other style sections
otherLangStyleGroups = {}
for group in otherLangStyleGroupNames:
otherLangStyleGroups[group] = readStylesFromConfig(cfg, group)
return (cfg, commonDefs, styleIdNames, styles, predefStyleGroupNames,
predefStyleGroups, otherLangStyleGroupNames, otherLangStyleGroups,
displaySrc, lexer, keywords, braceInfo)
def readStylesFromConfig(config, group):
config.SetPath('')
config.SetPath(group)
styles = []
cont, val, idx = config.GetFirstEntry()
while cont:
styles.append(val+'='+config.Read(val))
cont, val, idx = config.GetNextEntry(idx)
config.SetPath('')
return styles
def writeStylesToConfig(config, group, styles):
config.SetPath('')
config.DeleteGroup(group)
config.SetPath(group)
for style in styles:
name, value = style.split('=')
config.Write(name, value.strip())
config.SetPath('')
#-------------------------------------------------------------------------------
def initSTC(stc, config, lang):
""" Main module entry point. Initialise a wxSTC from given config file."""
(cfg, commonDefs, styleIdNames, styles, predefStyleGroupNames,
predefStyleGroups, otherLangStyleGroupNames, otherLangStyleGroups,
displaySrc, lexer, keywords, braceInfo) = initFromConfig(config, lang)
setSTCStyles(stc, styles, styleIdNames, commonDefs, lang, lexer, keywords)
#-------------------------------------------------------------------------------
if __name__ == '__main__':
app = wx.PySimpleApp()
provider = wx.SimpleHelpProvider()
wx.HelpProvider.Set(provider)
home = os.environ.get('HOME')
if home:
home = os.path.join(home, '.boa-constructor')
if not os.path.exists(home):
home = '.'
else:
home = '.'
config = os.path.abspath(os.path.join(home, 'stc-styles.rc.cfg'))
if 0:
f = wx.Frame(None, -1, 'Test frame (double click for editor)')
stc = wx.stc.StyledTextCtrl(f, -1)
def OnDblClick(evt, stc=stc):
dlg = STCStyleEditDlg(None, 'Python', 'python', config, (stc,))
try: dlg.ShowModal()
finally: dlg.Destroy()
stc.SetText(open('STCStyleEditor.py').read())
stc.Bind(wx.EVT_LEFT_DCLICK, OnDblClick)
initSTC(stc, config, 'python')
f.Show(True)
app.MainLoop()
else:
dlg = STCStyleEditDlg(None,
'Python', 'python',
#'HTML', 'html',
#'XML', 'xml',
#'C++', 'cpp',
#'Text', 'text',
#'Properties', 'prop',
config)
try: dlg.ShowModal()
finally: dlg.Destroy()