]> git.saurik.com Git - wxWidgets.git/blob - wxPython/samples/StyleEditor/STCStyleEditor.py
mentioned that the handlers should be allocated on the heap also in ClearHandlers...
[wxWidgets.git] / wxPython / samples / StyleEditor / STCStyleEditor.py
1 #-----------------------------------------------------------------------------
2 # Name: STCStyleEditor.py
3 # Purpose: Style editor for the wxStyledTextCtrl
4 #
5 # Author: Riaan Booysen
6 #
7 # Created: 2001/08/20
8 # RCS-ID: $Id$
9 # Copyright: (c) 2001 - 2005 Riaan Booysen
10 # Licence: wxWidgets license
11 #-----------------------------------------------------------------------------
12 #Boa:Dialog:STCStyleEditDlg
13
14 """ Style editor for the wxStyledTextCtrl.
15
16 Reads in property style definitions from a config file.
17 Modified styled can be saved (and optionally applied to a given list of STCs)
18
19 It can also maintain a Common definition dictionary of font names, colours and
20 sizes which can be shared across multiple language style definitions.
21 This is also used to store platform specific settings as fonts and sizes
22 vary with platform.
23
24 The following items are defined in the stc-styles.rc.cfg file.
25
26 common.defs.msw - Common definition dictionary used on wxMSW
27 common.defs.gtk - Common definition dictionary used on wxGTK
28 common.defs.mac - Common definition dictionary used on wxMAC
29 common.styleidnames - STC styles shared by all languages
30
31 Each supported language defines the following groups:
32 [<language>]
33 displaysrc - Example source to display in the editor
34 braces - Dictionary defining the (line, column) for showing 'good' and 'bad'
35 brace matching (both keys optional)
36 keywords - Space separated list of keywords
37 lexer - wxSTC constant for the language lexer
38 styleidnames - Dictionary of language specific style numbers and names
39
40 [style.<language>] - The users current style values
41 [style.<language>.default] - Default style values (can be reverted from)
42
43 0 or more predefined style groups or 'themes'
44 [style.<language>.<predefined name>]
45
46 Currently the following languages are supported:
47 python, html, xml, cpp, text, props
48 Other languages can be added by just defining the above settings for them in
49 the config file (if wxSTC implements them).
50
51 Use the initSTC function to initialise your wxSTC from a config file.
52 """
53
54 import os, sys, string, pprint, copy
55
56 import wx
57 from wx.lib.anchors import LayoutAnchors
58 import wx.stc
59 import wxPython.stc # needed names from 2.4 for config files
60
61 settingsIdNames = {-1: 'Selection', -2: 'Caret', -3: 'Edge'}
62
63 commonPropDefs = {'fore': '#888888', 'size': 8,
64 'face': ''}
65
66 styleCategoryDescriptions = {
67 '----Language----': 'Styles specific to the language',
68 '----Standard----': 'Styles shared by all languages',
69 '----Settings----': 'Properties set by STC methods',
70 '----Common----': 'User definable values that can be shared between languages'}
71
72 platformSettings = {'__WXMSW__': ('msw', 8),
73 '__WXGTK__': ('gtk', 10),
74 '__WXMAC__': ('mac', 11)}
75
76 [wxID_STCSTYLEEDITDLG, wxID_STCSTYLEEDITDLGADDCOMMONITEMBTN,
77 wxID_STCSTYLEEDITDLGBGCOLBTN, wxID_STCSTYLEEDITDLGBGCOLCB,
78 wxID_STCSTYLEEDITDLGBGCOLDEFCB, wxID_STCSTYLEEDITDLGBGCOLOKBTN,
79 wxID_STCSTYLEEDITDLGCANCELBTN, wxID_STCSTYLEEDITDLGCONTEXTHELPBUTTON1,
80 wxID_STCSTYLEEDITDLGELEMENTLB, wxID_STCSTYLEEDITDLGFACECB,
81 wxID_STCSTYLEEDITDLGFACEDEFCB, wxID_STCSTYLEEDITDLGFACEOKBTN,
82 wxID_STCSTYLEEDITDLGFGCOLBTN, wxID_STCSTYLEEDITDLGFGCOLCB,
83 wxID_STCSTYLEEDITDLGFGCOLDEFCB, wxID_STCSTYLEEDITDLGFGCOLOKBTN,
84 wxID_STCSTYLEEDITDLGFIXEDWIDTHCHK, wxID_STCSTYLEEDITDLGOKBTN,
85 wxID_STCSTYLEEDITDLGPANEL1, wxID_STCSTYLEEDITDLGPANEL2,
86 wxID_STCSTYLEEDITDLGPANEL3, wxID_STCSTYLEEDITDLGPANEL4,
87 wxID_STCSTYLEEDITDLGREMOVECOMMONITEMBTN, wxID_STCSTYLEEDITDLGSIZECB,
88 wxID_STCSTYLEEDITDLGSIZEOKBTN, wxID_STCSTYLEEDITDLGSPEEDSETTINGCH,
89 wxID_STCSTYLEEDITDLGSTATICBOX1, wxID_STCSTYLEEDITDLGSTATICBOX2,
90 wxID_STCSTYLEEDITDLGSTATICLINE1, wxID_STCSTYLEEDITDLGSTATICTEXT2,
91 wxID_STCSTYLEEDITDLGSTATICTEXT3, wxID_STCSTYLEEDITDLGSTATICTEXT4,
92 wxID_STCSTYLEEDITDLGSTATICTEXT6, wxID_STCSTYLEEDITDLGSTATICTEXT7,
93 wxID_STCSTYLEEDITDLGSTATICTEXT8, wxID_STCSTYLEEDITDLGSTATICTEXT9,
94 wxID_STCSTYLEEDITDLGSTC, wxID_STCSTYLEEDITDLGSTYLEDEFST,
95 wxID_STCSTYLEEDITDLGTABOLDCB, wxID_STCSTYLEEDITDLGTABOLDDEFCB,
96 wxID_STCSTYLEEDITDLGTAEOLFILLEDCB, wxID_STCSTYLEEDITDLGTAEOLFILLEDDEFCB,
97 wxID_STCSTYLEEDITDLGTAITALICCB, wxID_STCSTYLEEDITDLGTAITALICDEFCB,
98 wxID_STCSTYLEEDITDLGTASIZEDEFCB, wxID_STCSTYLEEDITDLGTAUNDERLINEDCB,
99 wxID_STCSTYLEEDITDLGTAUNDERLINEDDEFCB,
100 ] = [wx.NewId() for _init_ctrls in range(47)]
101
102 class STCStyleEditDlg(wx.Dialog):
103 """ Style editor for the wxStyledTextCtrl """
104 _custom_classes = {'wx.Window': ['wx.stc.StyledTextCtrl'],}
105 def _init_ctrls(self, prnt):
106 # generated method, don't edit
107 wx.Dialog.__init__(self, id=wxID_STCSTYLEEDITDLG,
108 name='STCStyleEditDlg', parent=prnt, pos=wx.Point(567, 292),
109 size=wx.Size(493, 482),
110 style=wx.WANTS_CHARS | wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER,
111 title=self.stc_title)
112 self.SetClientSize(wx.Size(485, 455))
113 self.SetAutoLayout(True)
114 self.SetSizeHints(425, 400, -1, -1)
115 self.Center(wx.BOTH)
116 self.Bind(wx.EVT_SIZE, self.OnStcstyleeditdlgSize)
117
118 self.speedsettingCh = wx.Choice(choices=[],
119 id=wxID_STCSTYLEEDITDLGSPEEDSETTINGCH, name='speedsettingCh',
120 parent=self, pos=wx.Point(96, 28), size=wx.Size(380, 21),
121 style=0)
122 self.speedsettingCh.SetConstraints(LayoutAnchors(self.speedsettingCh,
123 True, True, True, False))
124 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.')
125 self.speedsettingCh.Bind(wx.EVT_CHOICE, self.OnSpeedsettingchChoice,
126 id=wxID_STCSTYLEEDITDLGSPEEDSETTINGCH)
127
128 self.elementLb = wx.ListBox(choices=[],
129 id=wxID_STCSTYLEEDITDLGELEMENTLB, name='elementLb', parent=self,
130 pos=wx.Point(8, 70), size=wx.Size(175, 128), style=0)
131 self.elementLb.SetConstraints(LayoutAnchors(self.elementLb, True, True,
132 True, False))
133 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.')
134 self.elementLb.Bind(wx.EVT_LISTBOX, self.OnElementlbListbox,
135 id=wxID_STCSTYLEEDITDLGELEMENTLB)
136
137 self.addCommonItemBtn = wx.Button(id=wxID_STCSTYLEEDITDLGADDCOMMONITEMBTN,
138 label='Add', name='addCommonItemBtn', parent=self, pos=wx.Point(8,
139 200), size=wx.Size(88, 17), style=0)
140 self.addCommonItemBtn.SetToolTipString('Add new Common definition')
141 self.addCommonItemBtn.Bind(wx.EVT_BUTTON, self.OnAddsharebtnButton,
142 id=wxID_STCSTYLEEDITDLGADDCOMMONITEMBTN)
143
144 self.removeCommonItemBtn = wx.Button(id=wxID_STCSTYLEEDITDLGREMOVECOMMONITEMBTN,
145 label='Remove', name='removeCommonItemBtn', parent=self,
146 pos=wx.Point(96, 200), size=wx.Size(88, 17), style=0)
147 self.removeCommonItemBtn.SetToolTipString('Remove the selected Common definition')
148 self.removeCommonItemBtn.Bind(wx.EVT_BUTTON,
149 self.OnRemovesharebtnButton,
150 id=wxID_STCSTYLEEDITDLGREMOVECOMMONITEMBTN)
151
152 self.styleDefST = wx.StaticText(id=wxID_STCSTYLEEDITDLGSTYLEDEFST,
153 label='(nothing selected)', name='styleDefST', parent=self,
154 pos=wx.Point(96, 8), size=wx.Size(376, 16),
155 style=wx.ST_NO_AUTORESIZE)
156 self.styleDefST.SetFont(wx.Font(self.style_font_size, wx.SWISS,
157 wx.NORMAL, wx.BOLD, False, ''))
158 self.styleDefST.SetConstraints(LayoutAnchors(self.styleDefST, True,
159 True, True, False))
160
161 self.staticLine1 = wx.StaticLine(id=wxID_STCSTYLEEDITDLGSTATICLINE1,
162 name='staticLine1', parent=self, pos=wx.Point(48, 64),
163 size=wx.Size(135, 0), style=wx.LI_HORIZONTAL)
164 self.staticLine1.SetConstraints(LayoutAnchors(self.staticLine1, True,
165 True, True, False))
166
167 self.staticText6 = wx.StaticText(id=wxID_STCSTYLEEDITDLGSTATICTEXT6,
168 label='Style', name='staticText6', parent=self, pos=wx.Point(8,
169 56), size=wx.Size(40, 13), style=0)
170
171 self.staticText8 = wx.StaticText(id=wxID_STCSTYLEEDITDLGSTATICTEXT8,
172 label='Style def:', name='staticText8', parent=self,
173 pos=wx.Point(8, 8), size=wx.Size(88, 13), style=0)
174
175 self.staticText9 = wx.StaticText(id=wxID_STCSTYLEEDITDLGSTATICTEXT9,
176 label='SpeedSetting:', name='staticText9', parent=self,
177 pos=wx.Point(8, 32), size=wx.Size(88, 13), style=0)
178
179 self.panel3 = wx.Panel(id=wxID_STCSTYLEEDITDLGPANEL3, name='panel3',
180 parent=self, pos=wx.Point(199, 56), size=wx.Size(160, 120),
181 style=wx.TAB_TRAVERSAL)
182 self.panel3.SetConstraints(LayoutAnchors(self.panel3, False, True, True,
183 False))
184
185 self.panel4 = wx.Panel(id=wxID_STCSTYLEEDITDLGPANEL4, name='panel4',
186 parent=self, pos=wx.Point(364, 56), size=wx.Size(114, 120),
187 style=wx.TAB_TRAVERSAL)
188 self.panel4.SetConstraints(LayoutAnchors(self.panel4, False, True, True,
189 False))
190
191 self.panel1 = wx.Panel(id=wxID_STCSTYLEEDITDLGPANEL1, name='panel1',
192 parent=self, pos=wx.Point(202, 177), size=wx.Size(149, 40),
193 style=wx.TAB_TRAVERSAL)
194 self.panel1.SetConstraints(LayoutAnchors(self.panel1, False, True, True,
195 False))
196
197 self.panel2 = wx.Panel(id=wxID_STCSTYLEEDITDLGPANEL2, name='panel2',
198 parent=self, pos=wx.Point(364, 178), size=wx.Size(112, 40),
199 style=wx.TAB_TRAVERSAL)
200 self.panel2.SetConstraints(LayoutAnchors(self.panel2, False, True, True,
201 False))
202
203 self.stc = wx.stc.StyledTextCtrl(id=wxID_STCSTYLEEDITDLGSTC, name='stc',
204 parent=self, pos=wx.Point(8, 224), size=wx.Size(469, 191),
205 style=wx.SUNKEN_BORDER)
206 self.stc.SetConstraints(LayoutAnchors(self.stc, True, True, True, True))
207 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.')
208 self.stc.Bind(wx.EVT_LEFT_UP, self.OnUpdateUI)
209 self.stc.Bind(wx.EVT_KEY_UP, self.OnUpdateUI)
210
211 self.contextHelpButton1 = wx.ContextHelpButton(parent=self,
212 pos=wx.Point(8, 423), size=wx.Size(24, 24), style=wx.BU_AUTODRAW)
213 self.contextHelpButton1.SetConstraints(LayoutAnchors(self.contextHelpButton1,
214 True, False, False, True))
215
216 self.okBtn = wx.Button(id=wxID_STCSTYLEEDITDLGOKBTN, label='OK',
217 name='okBtn', parent=self, pos=wx.Point(316, 423),
218 size=wx.Size(75, 23), style=0)
219 self.okBtn.SetConstraints(LayoutAnchors(self.okBtn, False, False, True,
220 True))
221 self.okBtn.SetToolTipString('Save changes to the config file')
222 self.okBtn.Bind(wx.EVT_BUTTON, self.OnOkbtnButton,
223 id=wxID_STCSTYLEEDITDLGOKBTN)
224
225 self.cancelBtn = wx.Button(id=wxID_STCSTYLEEDITDLGCANCELBTN,
226 label='Cancel', name='cancelBtn', parent=self, pos=wx.Point(400,
227 423), size=wx.Size(75, 23), style=0)
228 self.cancelBtn.SetConstraints(LayoutAnchors(self.cancelBtn, False,
229 False, True, True))
230 self.cancelBtn.SetToolTipString('Close dialog without saving changes')
231 self.cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancelbtnButton,
232 id=wxID_STCSTYLEEDITDLGCANCELBTN)
233
234 self.staticText4 = wx.StaticText(id=wxID_STCSTYLEEDITDLGSTATICTEXT4,
235 label='Face:', name='staticText4', parent=self.panel1,
236 pos=wx.Point(0, 0), size=wx.Size(48, 13), style=0)
237
238 self.fixedWidthChk = wx.CheckBox(id=wxID_STCSTYLEEDITDLGFIXEDWIDTHCHK,
239 label='', name='fixedWidthChk', parent=self.panel1,
240 pos=wx.Point(0, 23), size=wx.Size(16, 19), style=0)
241 self.fixedWidthChk.SetToolTipString('Check this for Fixed Width fonts')
242 self.fixedWidthChk.Bind(wx.EVT_CHECKBOX, self.OnFixedwidthchkCheckbox,
243 id=wxID_STCSTYLEEDITDLGFIXEDWIDTHCHK)
244
245 self.faceCb = wx.ComboBox(choices=[], id=wxID_STCSTYLEEDITDLGFACECB,
246 name='faceCb', parent=self.panel1, pos=wx.Point(17, 18),
247 size=wx.Size(101, 21), style=0, value='')
248
249 self.staticText7 = wx.StaticText(id=wxID_STCSTYLEEDITDLGSTATICTEXT7,
250 label='Size:', name='staticText7', parent=self.panel2,
251 pos=wx.Point(0, 0), size=wx.Size(40, 13), style=0)
252
253 self.sizeCb = wx.ComboBox(choices=[], id=wxID_STCSTYLEEDITDLGSIZECB,
254 name='sizeCb', parent=self.panel2, pos=wx.Point(0, 17),
255 size=wx.Size(80, 21), style=0, value='')
256
257 self.sizeOkBtn = wx.Button(id=wxID_STCSTYLEEDITDLGSIZEOKBTN, label='ok',
258 name='sizeOkBtn', parent=self.panel2, pos=wx.Point(80, 17),
259 size=wx.Size(32, 21), style=0)
260
261 self.faceOkBtn = wx.Button(id=wxID_STCSTYLEEDITDLGFACEOKBTN, label='ok',
262 name='faceOkBtn', parent=self.panel1, pos=wx.Point(117, 18),
263 size=wx.Size(32, 21), style=0)
264
265 self.fgColBtn = wx.Button(id=wxID_STCSTYLEEDITDLGFGCOLBTN,
266 label='Foreground', name='fgColBtn', parent=self.panel3,
267 pos=wx.Point(8, 16), size=wx.Size(96, 16), style=0)
268 self.fgColBtn.Bind(wx.EVT_BUTTON, self.OnFgcolbtnButton,
269 id=wxID_STCSTYLEEDITDLGFGCOLBTN)
270
271 self.fgColCb = wx.ComboBox(choices=[], id=wxID_STCSTYLEEDITDLGFGCOLCB,
272 name='fgColCb', parent=self.panel3, pos=wx.Point(8, 32),
273 size=wx.Size(96, 21), style=0, value='')
274
275 self.fgColOkBtn = wx.Button(id=wxID_STCSTYLEEDITDLGFGCOLOKBTN,
276 label='ok', name='fgColOkBtn', parent=self.panel3,
277 pos=wx.Point(104, 32), size=wx.Size(32, 21), style=0)
278
279 self.staticText3 = wx.StaticText(id=wxID_STCSTYLEEDITDLGSTATICTEXT3,
280 label='default', name='staticText3', parent=self.panel3,
281 pos=wx.Point(112, 15), size=wx.Size(38, 16), style=0)
282
283 self.fgColDefCb = wx.CheckBox(id=wxID_STCSTYLEEDITDLGFGCOLDEFCB,
284 label='checkBox1', name='fgColDefCb', parent=self.panel3,
285 pos=wx.Point(136, 31), size=wx.Size(16, 16), style=0)
286
287 self.bgColBtn = wx.Button(id=wxID_STCSTYLEEDITDLGBGCOLBTN,
288 label='Background', name='bgColBtn', parent=self.panel3,
289 pos=wx.Point(8, 64), size=wx.Size(96, 16), style=0)
290 self.bgColBtn.Bind(wx.EVT_BUTTON, self.OnBgcolbtnButton,
291 id=wxID_STCSTYLEEDITDLGBGCOLBTN)
292
293 self.bgColCb = wx.ComboBox(choices=[], id=wxID_STCSTYLEEDITDLGBGCOLCB,
294 name='bgColCb', parent=self.panel3, pos=wx.Point(8, 80),
295 size=wx.Size(96, 21), style=0, value='')
296
297 self.bgColOkBtn = wx.Button(id=wxID_STCSTYLEEDITDLGBGCOLOKBTN,
298 label='ok', name='bgColOkBtn', parent=self.panel3,
299 pos=wx.Point(104, 80), size=wx.Size(32, 21), style=0)
300
301 self.staticBox2 = wx.StaticBox(id=wxID_STCSTYLEEDITDLGSTATICBOX2,
302 label='Text attributes', name='staticBox2', parent=self.panel4,
303 pos=wx.Point(0, 0), size=wx.Size(112, 112), style=0)
304 self.staticBox2.SetConstraints(LayoutAnchors(self.staticBox2, False,
305 True, True, False))
306 self.staticBox2.SetHelpText('Text attribute flags.')
307
308 self.staticText2 = wx.StaticText(id=wxID_STCSTYLEEDITDLGSTATICTEXT2,
309 label='default', name='staticText2', parent=self.panel4,
310 pos=wx.Point(64, 12), size=wx.Size(40, 16), style=0)
311
312 self.taBoldDefCb = wx.CheckBox(id=wxID_STCSTYLEEDITDLGTABOLDDEFCB,
313 label='checkBox1', name='taBoldDefCb', parent=self.panel4,
314 pos=wx.Point(88, 27), size=wx.Size(16, 16), style=0)
315
316 self.taItalicDefCb = wx.CheckBox(id=wxID_STCSTYLEEDITDLGTAITALICDEFCB,
317 label='checkBox1', name='taItalicDefCb', parent=self.panel4,
318 pos=wx.Point(88, 48), size=wx.Size(16, 16), style=0)
319
320 self.taUnderlinedDefCb = wx.CheckBox(id=wxID_STCSTYLEEDITDLGTAUNDERLINEDDEFCB,
321 label='checkBox1', name='taUnderlinedDefCb', parent=self.panel4,
322 pos=wx.Point(88, 70), size=wx.Size(16, 16), style=0)
323
324 self.taEOLfilledDefCb = wx.CheckBox(id=wxID_STCSTYLEEDITDLGTAEOLFILLEDDEFCB,
325 label='checkBox1', name='taEOLfilledDefCb', parent=self.panel4,
326 pos=wx.Point(88, 92), size=wx.Size(16, 16), style=0)
327
328 self.taEOLfilledCb = wx.CheckBox(id=wxID_STCSTYLEEDITDLGTAEOLFILLEDCB,
329 label='EOL filled', name='taEOLfilledCb', parent=self.panel4,
330 pos=wx.Point(8, 92), size=wx.Size(80, 16), style=0)
331 self.taEOLfilledCb.Bind(wx.EVT_CHECKBOX, self.OnTaeoffilledcbCheckbox,
332 id=wxID_STCSTYLEEDITDLGTAEOLFILLEDCB)
333
334 self.taUnderlinedCb = wx.CheckBox(id=wxID_STCSTYLEEDITDLGTAUNDERLINEDCB,
335 label='Underlined', name='taUnderlinedCb', parent=self.panel4,
336 pos=wx.Point(8, 70), size=wx.Size(80, 16), style=0)
337 self.taUnderlinedCb.Bind(wx.EVT_CHECKBOX, self.OnTaunderlinedcbCheckbox,
338 id=wxID_STCSTYLEEDITDLGTAUNDERLINEDCB)
339
340 self.taItalicCb = wx.CheckBox(id=wxID_STCSTYLEEDITDLGTAITALICCB,
341 label='Italic', name='taItalicCb', parent=self.panel4,
342 pos=wx.Point(8, 48), size=wx.Size(80, 16), style=0)
343 self.taItalicCb.Bind(wx.EVT_CHECKBOX, self.OnTaitaliccbCheckbox,
344 id=wxID_STCSTYLEEDITDLGTAITALICCB)
345
346 self.taBoldCb = wx.CheckBox(id=wxID_STCSTYLEEDITDLGTABOLDCB,
347 label='Bold', name='taBoldCb', parent=self.panel4, pos=wx.Point(8,
348 27), size=wx.Size(80, 16), style=0)
349 self.taBoldCb.Bind(wx.EVT_CHECKBOX, self.OnTaboldcbCheckbox,
350 id=wxID_STCSTYLEEDITDLGTABOLDCB)
351
352 self.bgColDefCb = wx.CheckBox(id=wxID_STCSTYLEEDITDLGBGCOLDEFCB,
353 label='checkBox1', name='bgColDefCb', parent=self.panel3,
354 pos=wx.Point(136, 79), size=wx.Size(16, 16), style=0)
355
356 self.staticBox1 = wx.StaticBox(id=wxID_STCSTYLEEDITDLGSTATICBOX1,
357 label='Colour', name='staticBox1', parent=self.panel3,
358 pos=wx.Point(0, 0), size=wx.Size(157, 112), style=0)
359 self.staticBox1.SetConstraints(LayoutAnchors(self.staticBox1, False,
360 True, True, False))
361
362 self.faceDefCb = wx.CheckBox(id=wxID_STCSTYLEEDITDLGFACEDEFCB,
363 label='checkBox1', name='faceDefCb', parent=self.panel1,
364 pos=wx.Point(117, 0), size=wx.Size(16, 16), style=0)
365
366 self.taSizeDefCb = wx.CheckBox(id=wxID_STCSTYLEEDITDLGTASIZEDEFCB,
367 label='checkBox1', name='taSizeDefCb', parent=self.panel2,
368 pos=wx.Point(80, 0), size=wx.Size(16, 16), style=0)
369
370 def __init__(self, parent, langTitle, lang, configFile, STCsToUpdate=()):
371 self.stc_title = 'wxStyledTextCtrl Style Editor'
372 self.stc_title = 'wxStyledTextCtrl Style Editor - %s' % langTitle
373 self.style_font_size = 8
374 self.style_font_size = platformSettings[wx.Platform][1]
375 self._init_ctrls(parent)
376 self.lang = lang
377 self.configFile = configFile
378 self.style = ''
379 self.styleNum = 0
380 self.names = []
381 self.values = {}
382 self.STCsToUpdate = STCsToUpdate
383 self._blockUpdate = False
384
385 global commonPropDefs
386 commonPropDefs = {'fore': '#888888', 'size': 8,
387 'face': wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT).GetFaceName()}
388
389 for combo, okBtn, evtRet, evtCB, evtRDC in (
390 (self.fgColCb, self.fgColOkBtn, self.OnfgColRet, self.OnfgColCombobox, self.OnGotoCommonDef),
391 (self.bgColCb, self.bgColOkBtn, self.OnbgColRet, self.OnbgColCombobox, self.OnGotoCommonDef),
392 (self.faceCb, self.faceOkBtn, self.OnfaceRet, self.OnfaceCombobox, self.OnGotoCommonDef),
393 (self.sizeCb, self.sizeOkBtn, self.OnsizeRet, self.OnsizeCombobox, self.OnGotoCommonDef)):
394 self.bindComboEvts(combo, okBtn, evtRet, evtCB, evtRDC)
395
396 (self.config, self.commonDefs, self.styleIdNames, self.styles,
397 self.styleGroupNames, self.predefStyleGroups,
398 self.otherLangStyleGroupNames, self.otherLangStyleGroups,
399 self.displaySrc, self.lexer, self.keywords, self.braceInfo) = \
400 initFromConfig(configFile, lang)
401
402 self.currSpeedSetting = 'style.%s'%self.lang
403 for grp in [self.currSpeedSetting]+self.styleGroupNames:
404 self.speedsettingCh.Append(grp)
405 self.speedsettingCh.SetSelection(0)
406
407 margin = 0
408 self.stc.SetMarginType(margin, wx.stc.STC_MARGIN_NUMBER)
409 self.stc.SetMarginWidth(margin, 25)
410 self.stc.SetMarginSensitive(margin, True)
411 self.stc.Bind(wx.stc.EVT_STC_MARGINCLICK, self.OnMarginClick, id=wxID_STCSTYLEEDITDLGSTC)
412
413 self.stc.SetUseTabs(False)
414 self.stc.SetTabWidth(4)
415 self.stc.SetIndentationGuides(True)
416 self.stc.SetEdgeMode(wx.stc.STC_EDGE_BACKGROUND)
417 self.stc.SetEdgeColumn(44)
418
419 self.setStyles()
420
421 self.populateStyleSelector()
422
423 self.defNames, self.defValues = parseProp(\
424 self.styleDict.get(wx.stc.STC_STYLE_DEFAULT, ''))
425 self.stc.SetText(self.displaySrc)
426 self.stc.EmptyUndoBuffer()
427 self.stc.SetCurrentPos(self.stc.GetTextLength())
428 self.stc.SetAnchor(self.stc.GetTextLength())
429
430 self.populateCombosWithCommonDefs()
431
432 # Logical grouping of controls and the property they edit
433 self.allCtrls = [((self.fgColBtn, self.fgColCb, self.fgColOkBtn), self.fgColDefCb,
434 'fore', wxID_STCSTYLEEDITDLGFGCOLDEFCB),
435 ((self.bgColBtn, self.bgColCb, self.bgColOkBtn), self.bgColDefCb,
436 'back', wxID_STCSTYLEEDITDLGBGCOLDEFCB),
437 (self.taBoldCb, self.taBoldDefCb,
438 'bold', wxID_STCSTYLEEDITDLGTABOLDDEFCB),
439 (self.taItalicCb, self.taItalicDefCb,
440 'italic', wxID_STCSTYLEEDITDLGTAITALICDEFCB),
441 (self.taUnderlinedCb, self.taUnderlinedDefCb,
442 'underline', wxID_STCSTYLEEDITDLGTAUNDERLINEDDEFCB),
443 (self.taEOLfilledCb, self.taEOLfilledDefCb,
444 'eolfilled', wxID_STCSTYLEEDITDLGTAEOLFILLEDDEFCB),
445 ((self.sizeCb, self.sizeOkBtn), self.taSizeDefCb,
446 'size', wxID_STCSTYLEEDITDLGTASIZEDEFCB),
447 ((self.faceCb, self.faceOkBtn, self.fixedWidthChk), self.faceDefCb,
448 'face', wxID_STCSTYLEEDITDLGFACEDEFCB)]
449
450 self.clearCtrls(disableDefs=True)
451 # centralised default checkbox event handler
452 self.chbIdMap = {}
453 for ctrl, chb, prop, wid in self.allCtrls:
454 self.chbIdMap[wid] = ctrl, chb, prop, wid
455 chb.Bind(wx.EVT_CHECKBOX, self.OnDefaultCheckBox, id=wid)
456 chb.SetToolTipString('Toggle defaults')
457
458 self.Center(wx.BOTH)
459
460 #---Property methods------------------------------------------------------------
461 def getCtrlForProp(self, findprop):
462 for ctrl, chb, prop, wid in self.allCtrls:
463 if findprop == prop:
464 return ctrl, chb
465 raise Exception('PropNotFound', findprop)
466
467 def editProp(self, on, prop, val=''):
468 oldstyle = self.rememberStyles()
469 if on:
470 if not self.names.count(prop):
471 self.names.append(prop)
472 self.values[prop] = val
473 else:
474 try: self.names.remove(prop)
475 except ValueError: pass
476 try: del self.values[prop]
477 except KeyError: pass
478
479 try:
480 self.updateStyle()
481 return True
482 except KeyError, errkey:
483 wx.LogError('Name not found in Common definition, '\
484 'please enter valid reference. (%s)'%errkey)
485 self.restoreStyles(oldstyle)
486 return False
487
488 #---Control population methods--------------------------------------------------
489 def setStyles(self):
490 if self._blockUpdate: return
491 self.styles, self.styleDict, self.styleNumIdxMap = \
492 setSTCStyles(self.stc, self.styles, self.styleIdNames,
493 self.commonDefs, self.lang, self.lexer, self.keywords)
494
495 def updateStyle(self):
496 # called after a control edited self.names, self.values
497 # Special case for saving common defs settings
498 if self.styleNum == 'common':
499 #if not self.values:
500 # return
501
502 strVal = self.style[2] = self.values.values()[0]
503 if self.style[1] == 'size': self.style[2] = int(strVal)
504
505 self.commonDefs[self.style[0]] = self.style[2]
506 self.styleDefST.SetLabel(strVal)
507 else:
508 self.style = writePropVal(self.names, self.values)
509 styleDecl = writeProp(self.styleNum, self.style, self.lang)
510 self.styles[self.styleNumIdxMap[self.styleNum]] = styleDecl
511 self.styleDefST.SetLabel(self.style)
512 self.setStyles()
513
514 def findInStyles(self, txt, styles):
515 for style in styles:
516 if style.find(txt) != -1:
517 return True
518 return False
519
520 def rememberStyles(self):
521 return self.names[:], copy.copy(self.values)
522
523 def restoreStyles(self, style):
524 self.names, self.values = style
525 self.updateStyle()
526
527 def clearCtrls(self, isDefault=False, disableDefs=False):
528 self._blockUpdate = True
529 try:
530 for ctrl, chb, prop, wid in self.allCtrls:
531 if prop in ('fore', 'back'):
532 cbtn, txt, btn = ctrl
533 cbtn.SetBackgroundColour(\
534 wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE))
535 cbtn.SetForegroundColour(wx.Colour(255, 255, 255))
536 cbtn.Enable(isDefault)
537 txt.SetValue('')
538 txt.Enable(isDefault)
539 btn.Enable(isDefault)
540 elif prop == 'size':
541 cmb, btn = ctrl
542 cmb.SetValue('')
543 cmb.Enable(isDefault)
544 btn.Enable(isDefault)
545 elif prop == 'face':
546 cmb, btn, chk = ctrl
547 cmb.SetValue('')
548 cmb.Enable(isDefault)
549 btn.Enable(isDefault)
550 chk.Enable(isDefault)
551 chk.SetValue(False)
552 elif prop in ('bold', 'italic', 'underline', 'eolfilled'):
553 ctrl.SetValue(False)
554 ctrl.Enable(isDefault)
555
556 chb.Enable(not isDefault and not disableDefs)
557 chb.SetValue(True)
558 finally:
559 self._blockUpdate = False
560
561 def populateProp(self, items, default, forceDisable=False):
562 self._blockUpdate = True
563 try:
564 for name, val in items:
565 if name:
566 ctrl, chb = self.getCtrlForProp(name)
567
568 if name in ('fore', 'back'):
569 cbtn, txt, btn = ctrl
570 repval = val%self.commonDefs
571 cbtn.SetBackgroundColour(strToCol(repval))
572 cbtn.SetForegroundColour(wx.Colour(0, 0, 0))
573 cbtn.Enable(not forceDisable)
574 txt.SetValue(val)
575 txt.Enable(not forceDisable)
576 btn.Enable(not forceDisable)
577 chb.SetValue(default)
578 elif name == 'size':
579 cmb, btn = ctrl
580 cmb.SetValue(val)
581 cmb.Enable(not forceDisable)
582 btn.Enable(not forceDisable)
583 chb.SetValue(default)
584 elif name == 'face':
585 cmb, btn, chk = ctrl
586 cmb.SetValue(val)
587 cmb.Enable(not forceDisable)
588 btn.Enable(not forceDisable)
589 chk.Enable(not forceDisable)
590 chb.SetValue(default)
591 elif name in ('bold', 'italic', 'underline', 'eolfilled'):
592 ctrl.Enable(not forceDisable)
593 ctrl.SetValue(True)
594 chb.SetValue(default)
595 finally:
596 self._blockUpdate = False
597
598 def valIsCommonDef(self, val):
599 return len(val) >= 5 and val[:2] == '%('
600
601 def populateCtrls(self):
602 self.clearCtrls(self.styleNum == wx.stc.STC_STYLE_DEFAULT,
603 disableDefs=self.styleNum < 0)
604
605 # handle colour controls for settings
606 if self.styleNum < 0:
607 self.fgColDefCb.Enable(True)
608 if self.styleNum == -1:
609 self.bgColDefCb.Enable(True)
610
611 # populate with default style
612 self.populateProp(self.defValues.items(), True,
613 self.styleNum != wx.stc.STC_STYLE_DEFAULT)
614 # override with current settings
615 self.populateProp(self.values.items(), False)
616
617 def getCommonDefPropType(self, commonDefName):
618 val = self.commonDefs[commonDefName]
619 if type(val) == type(0): return 'size'
620 if len(val) == 7 and val[0] == '#': return 'fore'
621 return 'face'
622
623 def bindComboEvts(self, combo, btn, btnEvtMeth, comboEvtMeth, rdclickEvtMeth):
624 combo.Bind(wx.EVT_COMBOBOX, comboEvtMeth, id=combo.GetId())
625 btn.Bind(wx.EVT_BUTTON, btnEvtMeth, id=btn.GetId())
626 combo.Bind(wx.EVT_RIGHT_DCLICK, rdclickEvtMeth)
627 combo.SetToolTipString('Select from list or click "ok" button on the right to change a manual entry, right double-click \n'\
628 'the drop down button to select Common definition in the Style Editor (if applicable)')
629 btn.SetToolTipString('Accept value')
630
631 def populateCombosWithCommonDefs(self, fixedWidthOnly=None):
632 self._blockUpdate = True
633 try:
634 commonDefs = {'fore': [], 'face': [], 'size': []}
635
636 if self.elementLb.GetSelection() < self.commonDefsStartIdx:
637 for common in self.commonDefs.keys():
638 prop = self.getCommonDefPropType(common)
639 commonDefs[prop].append('%%(%s)%s'%(common,
640 prop=='size' and 'd' or 's'))
641
642 # Colours
643 currFg, currBg = self.fgColCb.GetValue(), self.bgColCb.GetValue()
644 self.fgColCb.Clear(); self.bgColCb.Clear()
645 for colCommonDef in commonDefs['fore']:
646 self.fgColCb.Append(colCommonDef)
647 self.bgColCb.Append(colCommonDef)
648 self.fgColCb.SetValue(currFg); self.bgColCb.SetValue(currBg)
649
650 # Font
651 if fixedWidthOnly is None:
652 fixedWidthOnly = self.fixedWidthChk.GetValue()
653 fontEnum = wx.FontEnumerator()
654 fontEnum.EnumerateFacenames(fixedWidthOnly=fixedWidthOnly)
655 fontNameList = fontEnum.GetFacenames()
656 fontNameList.sort()
657
658 currFace = self.faceCb.GetValue()
659 self.faceCb.Clear()
660 for colCommonDef in fontNameList+commonDefs['face']:
661 self.faceCb.Append(colCommonDef)
662 self.faceCb.SetValue(currFace)
663
664 # Size (XXX add std font sizes)
665 currSize = self.sizeCb.GetValue()
666 self.sizeCb.Clear()
667 for colCommonDef in commonDefs['size']:
668 self.sizeCb.Append(colCommonDef)
669 self.sizeCb.SetValue(currSize)
670 finally:
671 self._blockUpdate = False
672
673 def populateStyleSelector(self):
674 numStyles = self.styleIdNames.items()
675 numStyles.sort()
676 self.styleNumLookup = {}
677 stdStart = -1
678 stdOffset = 0
679 extrOffset = 0
680 # add styles
681 for num, name in numStyles:
682 if num == wx.stc.STC_STYLE_DEFAULT:
683 self.elementLb.InsertItems([name, '----Language----'], 0)
684 self.elementLb.Append('----Standard----')
685 stdStart = stdPos = self.elementLb.GetCount()
686 else:
687 # std styles
688 if num >= 33 and num < 40:
689 self.elementLb.InsertItems([name], stdStart + stdOffset)
690 stdOffset = stdOffset + 1
691 # extra styles
692 elif num >= 40:
693 self.elementLb.InsertItems([name], stdStart + extrOffset -1)
694 extrOffset = extrOffset + 1
695 # normal lang styles
696 else:
697 self.elementLb.Append(name)
698 self.styleNumLookup[name] = num
699
700 # add settings
701 self.elementLb.Append('----Settings----')
702 settings = settingsIdNames.items()
703 settings.sort();settings.reverse()
704 for num, name in settings:
705 self.elementLb.Append(name)
706 self.styleNumLookup[name] = num
707
708 # add definitions
709 self.elementLb.Append('----Common----')
710 self.commonDefsStartIdx = self.elementLb.GetCount()
711 for common in self.commonDefs.keys():
712 tpe = type(self.commonDefs[common])
713 self.elementLb.Append('%('+common+')'+(tpe is type('') and 's' or 'd'))
714 self.styleNumLookup[common] = num
715
716 #---Colour methods--------------------------------------------------------------
717 def getColourDlg(self, colour, title=''):
718 data = wx.ColourData()
719 data.SetColour(colour)
720 data.SetChooseFull(True)
721 dlg = wx.ColourDialog(self, data)
722 try:
723 dlg.SetTitle(title)
724 if dlg.ShowModal() == wx.ID_OK:
725 data = dlg.GetColourData()
726 return data.GetColour()
727 finally:
728 dlg.Destroy()
729 return None
730
731 colDlgTitles = {'fore': 'Foreground', 'back': 'Background'}
732 def editColProp(self, colBtn, colCb, prop):
733 col = self.getColourDlg(colBtn.GetBackgroundColour(),
734 self.colDlgTitles[prop]+ ' colour')
735 if col:
736 colBtn.SetForegroundColour(wx.Colour(0, 0, 0))
737 colBtn.SetBackgroundColour(col)
738 colStr = colToStr(col)
739 colCb.SetValue(colStr)
740 self.editProp(True, prop, colStr)
741
742 def OnFgcolbtnButton(self, event):
743 self.editColProp(self.fgColBtn, self.fgColCb, 'fore')
744
745 def OnBgcolbtnButton(self, event):
746 self.editColProp(self.bgColBtn, self.bgColCb, 'back')
747
748 def editColTCProp(self, colCb, colBtn, prop, val=None):
749 if val is None:
750 colStr = colCb.GetValue()
751 else:
752 colStr = val
753 if colStr:
754 col = strToCol(colStr%self.commonDefs)
755 if self.editProp(colStr!='', prop, colStr):
756 if colStr:
757 colBtn.SetForegroundColour(wx.Colour(0, 0, 0))
758 colBtn.SetBackgroundColour(col)
759 else:
760 colBtn.SetForegroundColour(wx.Colour(255, 255, 255))
761 colBtn.SetBackgroundColour(\
762 wxSystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE))
763
764 def OnfgColRet(self, event):
765 try: self.editColTCProp(self.fgColCb, self.fgColBtn, 'fore')
766 except AssertionError: wx.LogError('Not a valid colour value')
767
768 def OnfgColCombobox(self, event):
769 if self._blockUpdate: return
770 try: self.editColTCProp(self.fgColCb, self.fgColBtn, 'fore', event.GetString())
771 except AssertionError: wx.LogError('Not a valid colour value')
772
773 def OnbgColRet(self, event):
774 try: self.editColTCProp(self.bgColCb, self.bgColBtn, 'back')
775 except AssertionError: wx.LogError('Not a valid colour value')
776
777 def OnbgColCombobox(self, event):
778 if self._blockUpdate: return
779 try: self.editColTCProp(self.bgColCb, self.bgColBtn, 'back', event.GetString())
780 except AssertionError: wx.LogError('Not a valid colour value')
781
782 #---Text attribute events-------------------------------------------------------
783 def OnTaeoffilledcbCheckbox(self, event):
784 self.editProp(event.IsChecked(), 'eolfilled')
785
786 def OnTaitaliccbCheckbox(self, event):
787 self.editProp(event.IsChecked(), 'italic')
788
789 def OnTaboldcbCheckbox(self, event):
790 self.editProp(event.IsChecked(), 'bold')
791
792 def OnTaunderlinedcbCheckbox(self, event):
793 self.editProp(event.IsChecked(), 'underline')
794
795 def OnGotoCommonDef(self, event):
796 val = event.GetEventObject().GetValue()
797 if self.valIsCommonDef(val):
798 idx = self.elementLb.FindString(val)
799 if idx != -1:
800 self.elementLb.SetSelection(idx, True)
801 self.OnElementlbListbox(None)
802
803 def OnfaceRet(self, event):
804 self.setFace(self.faceCb.GetValue())
805
806 def OnfaceCombobox(self, event):
807 if self._blockUpdate: return
808 self.setFace(event.GetString())
809
810 def setFace(self, val):
811 try: val%self.commonDefs
812 except KeyError: wx.LogError('Invalid common definition')
813 else: self.editProp(val!='', 'face', val)
814
815 def OnsizeRet(self, event):
816 self.setSize(self.sizeCb.GetValue())
817
818 def OnsizeCombobox(self, event):
819 if self._blockUpdate: return
820 self.setSize(event.GetString())
821
822 def setSize(self, val):
823 try: int(val%self.commonDefs)
824 except ValueError: wx.LogError('Not a valid integer size value')
825 except KeyError: wx.LogError('Invalid common definition')
826 else: self.editProp(val!='', 'size', val)
827
828 #---Main GUI events-------------------------------------------------------------
829 def OnElementlbListbox(self, event):
830 isCommon = self.elementLb.GetSelection() >= self.commonDefsStartIdx
831 self.removeCommonItemBtn.Enable(isCommon)
832
833 styleIdent = self.elementLb.GetStringSelection()
834 # common definition selected
835 if isCommon:
836 common = styleIdent[2:-2]
837 prop = self.getCommonDefPropType(common)
838 self.clearCtrls(disableDefs=True)
839 if prop == 'fore':
840 self.fgColBtn.Enable(True)
841 self.fgColCb.Enable(True)
842 self.fgColOkBtn.Enable(True)
843 elif prop == 'face':
844 self.faceCb.Enable(True)
845 self.fixedWidthChk.Enable(True)
846 self.faceOkBtn.Enable(True)
847 elif prop == 'size':
848 self.sizeCb.Enable(True)
849 self.sizeOkBtn.Enable(True)
850
851 commonDefVal = str(self.commonDefs[common])
852 self.styleDefST.SetLabel(commonDefVal)
853 self.populateProp( [(prop, commonDefVal)], True)
854
855 self.styleNum = 'common'
856 self.style = [common, prop, commonDefVal]
857 self.names, self.values = [prop], {prop: commonDefVal}
858
859 # normal style element selected
860 elif len(styleIdent) >=2 and styleIdent[:2] != '--':
861 self.styleNum = self.styleNumLookup[styleIdent]
862 self.style = self.styleDict[self.styleNum]
863 self.names, self.values = parseProp(self.style)
864 if self.styleNum == wx.stc.STC_STYLE_DEFAULT:
865 self.defNames, self.defValues = \
866 self.names, self.values
867
868 self.checkBraces(self.styleNum)
869
870 self.styleDefST.SetLabel(self.style)
871
872 self.populateCtrls()
873 # separator selected
874 else:
875 self.clearCtrls(disableDefs=True)
876 if styleIdent:
877 self.styleDefST.SetLabel(styleCategoryDescriptions[styleIdent])
878
879 self.populateCombosWithCommonDefs()
880
881 def OnDefaultCheckBox(self, event):
882 if self.chbIdMap.has_key(event.GetId()):
883 ctrl, chb, prop, wid = self.chbIdMap[event.GetId()]
884 restore = not event.IsChecked()
885 if prop in ('fore', 'back'):
886 cbtn, cmb, btn = ctrl
887 cbtn.Enable(restore)
888 cmb.Enable(restore)
889 btn.Enable(restore)
890 if restore:
891 colStr = cmb.GetValue()
892 #if prop == 'fore': colStr = self.fgColCb.GetValue()
893 #else: colStr = self.bgColCb.GetValue()
894 if colStr: self.editProp(True, prop, colStr)
895 else:
896 self.editProp(False, prop)
897 elif prop == 'size':
898 cmb, btn = ctrl
899 val = cmb.GetValue()
900 if val: self.editProp(restore, prop, val)
901 cmb.Enable(restore)
902 btn.Enable(restore)
903 elif prop == 'face':
904 cmb, btn, chk = ctrl
905 val = cmb.GetStringSelection()
906 if val: self.editProp(restore, prop, val)
907 cmb.Enable(restore)
908 btn.Enable(restore)
909 chk.Enable(restore)
910 elif prop in ('bold', 'italic', 'underline', 'eolfilled'):
911 ctrl.Enable(restore)
912 if ctrl.GetValue(): self.editProp(restore, prop)
913
914 def OnOkbtnButton(self, event):
915 # write styles and common defs to the config
916 wx.BeginBusyCursor()
917 try:
918 writeStylesToConfig(self.config, 'style.%s'%self.lang, self.styles)
919 self.config.SetPath('')
920 self.config.Write(commonDefsFile, `self.commonDefs`)
921 self.config.Flush()
922
923 for stc in self.STCsToUpdate:
924 setSTCStyles(stc, self.styles, self.styleIdNames, self.commonDefs,
925 self.lang, self.lexer, self.keywords)
926 finally:
927 wx.EndBusyCursor()
928 self.EndModal(wx.ID_OK)
929
930 def OnCancelbtnButton(self, event):
931 self.EndModal(wx.ID_CANCEL)
932
933 def OnCommondefsbtnButton(self, event):
934 dlg = wx.TextEntryDialog(self, 'Edit common definitions dictionary',
935 'Common definitions', pprint.pformat(self.commonDefs),
936 style=wx.TE_MULTILINE | wx.OK | wx.CANCEL | wx.CENTRE)
937 try:
938 if dlg.ShowModal() == wx.ID_OK:
939 answer = eval(dlg.GetValue(), stc.__dict__)
940 assert type(answer) is type({}), 'Not a valid dictionary'
941 oldDefs = self.commonDefs
942 self.commonDefs = answer
943 try:
944 self.setStyles()
945 except KeyError, badkey:
946 wx.LogError(str(badkey)+' not defined but required, \n'\
947 'reverting to previous common definition')
948 self.commonDefs = oldDefs
949 self.setStyles()
950 self.populateCombosWithCommonDefs()
951
952 finally:
953 dlg.Destroy()
954
955 def OnSpeedsettingchChoice(self, event):
956 group = event.GetString()
957 if group:
958 userStyles = 'style.%s'%self.lang
959 if self.currSpeedSetting == userStyles:
960 self.predefStyleGroups[userStyles] = self.styles
961 self.styles = self.predefStyleGroups[group]
962 self.setStyles()
963 self.defNames, self.defValues = parseProp(\
964 self.styleDict.get(wx.stc.STC_STYLE_DEFAULT, ''))
965 self.OnElementlbListbox(None)
966 self.currSpeedSetting = group
967
968 def OnFixedwidthchkCheckbox(self, event):
969 self.populateCombosWithCommonDefs(event.IsChecked())
970
971 def OnAddsharebtnButton(self, event):
972 dlg = CommonDefDlg(self)
973 try:
974 if dlg.ShowModal() == wx.ID_OK:
975 prop, name = dlg.result
976 if not self.commonDefs.has_key(name):
977 self.commonDefs[name] = commonPropDefs[prop]
978 self.elementLb.Append('%('+name+')'+\
979 (type(commonPropDefs[prop]) is type('') and 's' or 'd'))
980 self.elementLb.SetSelection(self.elementLb.GetCount()-1, True)
981 self.populateCombosWithCommonDefs()
982 self.OnElementlbListbox(None)
983 finally:
984 dlg.Destroy()
985
986 def OnRemovesharebtnButton(self, event):
987 ownGroup = 'style.%s'%self.lang
988 comDef = self.elementLb.GetStringSelection()
989
990 # Search ALL styles before removing
991 srchDct = {ownGroup: self.styles}
992 srchDct.update(self.predefStyleGroups)
993 srchDct.update(self.otherLangStyleGroups)
994
995 matchList = []
996 for grpName, styles in srchDct.items():
997 if self.findInStyles(comDef, styles):
998 matchList.append(grpName)
999
1000 if matchList:
1001 wx.LogError('Aborted: '+comDef+' is still used in the styles of the \n'\
1002 'following groups in the config file (stc-styles.rc.cfg):\n'+ \
1003 '\n'.join(matchList))
1004 else:
1005 del self.commonDefs[comDef[2:-2]]
1006 self.setStyles()
1007 self.populateCombosWithCommonDefs()
1008 selIdx = self.elementLb.GetSelection()
1009 self.elementLb.Delete(selIdx)
1010 if selIdx == self.elementLb.GetCount():
1011 selIdx = selIdx - 1
1012 self.elementLb.SetSelection(selIdx, True)
1013 self.OnElementlbListbox(None)
1014
1015 #---STC events------------------------------------------------------------------
1016 def OnUpdateUI(self, event):
1017 styleBefore = self.stc.GetStyleAt(self.stc.GetCurrentPos())
1018 if self.styleIdNames.has_key(styleBefore):
1019 self.elementLb.SetStringSelection(self.styleIdNames[styleBefore],
1020 True)
1021 else:
1022 self.elementLb.SetSelection(0, False)
1023 self.styleDefST.SetLabel('Style %d not defined, sorry.'%styleBefore)
1024 self.OnElementlbListbox(None)
1025 event.Skip()
1026
1027 def checkBraces(self, style):
1028 if style == wx.stc.STC_STYLE_BRACELIGHT and self.braceInfo.has_key('good'):
1029 line, col = self.braceInfo['good']
1030 pos = self.stc.PositionFromLine(line-1) + col
1031 braceOpposite = self.stc.BraceMatch(pos)
1032 if braceOpposite != -1:
1033 self.stc.BraceHighlight(pos, braceOpposite)
1034 elif style == wx.stc.STC_STYLE_BRACEBAD and self.braceInfo.has_key('bad'):
1035 line, col = self.braceInfo['bad']
1036 pos = self.stc.PositionFromLine(line-1) + col
1037 self.stc.BraceBadLight(pos)
1038 else:
1039 self.stc.BraceBadLight(-1)
1040 return
1041
1042 def OnStcstyleeditdlgSize(self, event):
1043 self.Layout()
1044 # Without this refresh, resizing leaves artifacts
1045 self.Refresh(1)
1046 event.Skip()
1047
1048 def OnMarginClick(self, event):
1049 self.elementLb.SetStringSelection('Line numbers', True)
1050 self.OnElementlbListbox(None)
1051
1052
1053 #---Common definition dialog----------------------------------------------------
1054
1055 [wxID_COMMONDEFDLG, wxID_COMMONDEFDLGCANCELBTN, wxID_COMMONDEFDLGCOMDEFNAMETC, wxID_COMMONDEFDLGOKBTN, wxID_COMMONDEFDLGPROPTYPERBX, wxID_COMMONDEFDLGSTATICBOX1] = [wx.NewId() for _init_ctrls in range(6)]
1056
1057 class CommonDefDlg(wx.Dialog):
1058 def _init_ctrls(self, prnt):
1059 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')
1060 self.SetClientSize(wx.Size(184, 200))
1061
1062 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)
1063 self.propTypeRBx.SetSelection(self._propTypeIdx)
1064
1065 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)
1066
1067 self.comDefNameTC = wx.TextCtrl(id = wxID_COMMONDEFDLGCOMDEFNAMETC, name = 'comDefNameTC', parent = self, pos = wx.Point(16, 124), size = wx.Size(152, 21), style = 0, value = '')
1068 self.comDefNameTC.SetLabel(self._comDefName)
1069
1070 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)
1071 self.okBtn.Bind(wx.EVT_BUTTON, self.OnOkbtnButton, id=wxID_COMMONDEFDLGOKBTN)
1072
1073 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)
1074 self.cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancelbtnButton, id=wxID_COMMONDEFDLGCANCELBTN)
1075
1076 def __init__(self, parent, name='', propIdx=0):
1077 self._comDefName = ''
1078 self._comDefName = name
1079 self._propTypeIdx = 0
1080 self._propTypeIdx = propIdx
1081 self._init_ctrls(parent)
1082
1083 self.propMap = {0: 'fore', 1: 'face', 2: 'size'}
1084 self.result = ( '', '' )
1085
1086 self.Center(wx.BOTH)
1087
1088 def OnOkbtnButton(self, event):
1089 self.result = ( self.propMap[self.propTypeRBx.GetSelection()],
1090 self.comDefNameTC.GetValue() )
1091 self.EndModal(wx.ID_OK)
1092
1093 def OnCancelbtnButton(self, event):
1094 self.result = ( '', '' )
1095 self.EndModal(wx.ID_CANCEL)
1096
1097 #---Functions useful outside of the editor----------------------------------
1098
1099 def setSelectionColour(stc, style):
1100 names, values = parseProp(style)
1101 if 'fore' in names:
1102 stc.SetSelForeground(True, strToCol(values['fore']))
1103 if 'back' in names:
1104 stc.SetSelBackground(True, strToCol(values['back']))
1105
1106 def setCursorColour(stc, style):
1107 names, values = parseProp(style)
1108 if 'fore' in names:
1109 stc.SetCaretForeground(strToCol(values['fore']))
1110
1111 def setEdgeColour(stc, style):
1112 names, values = parseProp(style)
1113 if 'fore' in names:
1114 stc.SetEdgeColour(strToCol(values['fore']))
1115
1116 def strToCol(strCol):
1117 assert len(strCol) == 7 and strCol[0] == '#', 'Not a valid colour string: '+strCol
1118 return wx.Colour(string.atoi('0x'+strCol[1:3], 16),
1119 string.atoi('0x'+strCol[3:5], 16),
1120 string.atoi('0x'+strCol[5:7], 16))
1121 def colToStr(col):
1122 return '#%s%s%s' % (string.zfill(string.upper(hex(col.Red())[2:]), 2),
1123 string.zfill(string.upper(hex(col.Green())[2:]), 2),
1124 string.zfill(string.upper(hex(col.Blue())[2:]), 2))
1125
1126 def writeProp(num, style, lang):
1127 if num >= 0:
1128 return 'style.%s.%s='%(lang, string.zfill(`num`, 3)) + style
1129 else:
1130 return 'setting.%s.%d='%(lang, num) + style
1131
1132 def writePropVal(names, values):
1133 res = []
1134 for name in names:
1135 if name:
1136 res.append(values[name] and name+':'+values[name] or name)
1137 return ','.join(res)
1138
1139 def parseProp(prop):
1140 items = prop.split(',')
1141 names = []
1142 values = {}
1143 for item in items:
1144 nameVal = item.split(':')
1145 names.append(nameVal[0].strip())
1146 if len(nameVal) == 1:
1147 values[nameVal[0]] = ''
1148 else:
1149 values[nameVal[0]] = nameVal[1].strip()
1150 return names, values
1151
1152 def parsePropLine(prop):
1153 name, value = prop.split('=')
1154 return int(name.split('.')[-1]), value
1155
1156 def setSTCStyles(stc, styles, styleIdNames, commonDefs, lang, lexer, keywords):
1157 styleDict = {}
1158 styleNumIdxMap = {}
1159
1160 # build style dict based on given styles
1161 for numStyle in styles:
1162 num, style = parsePropLine(numStyle)
1163 styleDict[num] = style
1164
1165 # Add blank style entries for undefined styles
1166 newStyles = []
1167 styleItems = styleIdNames.items() + settingsIdNames.items()
1168 styleItems.sort()
1169 idx = 0
1170 for num, name in styleItems:
1171 styleNumIdxMap[num] = idx
1172 if not styleDict.has_key(num):
1173 styleDict[num] = ''
1174 newStyles.append(writeProp(num, styleDict[num], lang))
1175 idx = idx + 1
1176
1177 # Set background colour to reduce flashing effect on refresh or page switch
1178 bkCol = None
1179 if styleDict.has_key(0): prop = styleDict[0]
1180 else: prop = styleDict[wx.stc.STC_STYLE_DEFAULT]
1181 names, vals = parseProp(prop)
1182 if 'back' in names:
1183 bkCol = strToCol(vals['back']%commonDefs)
1184 if bkCol is None:
1185 bkCol = wx.WHITE
1186 stc.SetBackgroundColour(bkCol)
1187
1188 # Set the styles on the wxSTC
1189 stc.StyleResetDefault()
1190 stc.ClearDocumentStyle()
1191 stc.SetLexer(lexer)
1192 stc.SetKeyWords(0, keywords)
1193 stc.StyleSetSpec(wx.stc.STC_STYLE_DEFAULT,
1194 styleDict[wx.stc.STC_STYLE_DEFAULT] % commonDefs)
1195 stc.StyleClearAll()
1196
1197 for num, style in styleDict.items():
1198 if num >= 0:
1199 stc.StyleSetSpec(num, style % commonDefs)
1200 elif num == -1:
1201 setSelectionColour(stc, style % commonDefs)
1202 elif num == -2:
1203 setCursorColour(stc, style % commonDefs)
1204 elif num == -3:
1205 setEdgeColour(stc, style % commonDefs)
1206
1207 stc.Colourise(0, stc.GetTextLength())
1208
1209 return newStyles, styleDict, styleNumIdxMap
1210
1211 #---Config reading and writing -------------------------------------------------
1212 commonDefsFile = 'common.defs.%s'%(platformSettings[wx.Platform][0])
1213
1214 def readPyValFromConfig(conf, name):
1215 ns = {}
1216 #ns.update(wx.stc.__dict__)
1217 ns.update(wxPython.stc.__dict__)
1218 ns['wx'] = wx
1219 value = conf.Read(name).replace('\r\n', '\n')+'\n'
1220 try:
1221 return eval(value, ns)
1222 except:
1223 print value
1224 raise
1225
1226 def initFromConfig(configFile, lang):
1227 if not os.path.exists(configFile):
1228 raise Exception, 'Config file %s not found'%configFile
1229 cfg = wx.FileConfig(localFilename=configFile, style= wx.CONFIG_USE_LOCAL_FILE)
1230 cfg.SetExpandEnvVars(False)
1231
1232 # read in all group names for this language
1233 groupPrefix = 'style.%s'%lang
1234 gpLen = len(groupPrefix)
1235 predefStyleGroupNames, otherLangStyleGroupNames = [], []
1236 cont, val, idx = cfg.GetFirstGroup()
1237 while cont:
1238 if val != groupPrefix and len(val) >= 5 and val[:5] == 'style':
1239 if len(val) > gpLen and val[:gpLen] == groupPrefix:
1240 predefStyleGroupNames.append(val)
1241 else:
1242 otherLangStyleGroupNames.append(val)
1243
1244 cont, val, idx = cfg.GetNextGroup(idx)
1245
1246 # read in common elements
1247 commonDefs = readPyValFromConfig(cfg, commonDefsFile)
1248 assert type(commonDefs) is type({}), \
1249 'Common definitions (%s) not a valid dict'%commonDefsFile
1250
1251 commonStyleIdNames = readPyValFromConfig(cfg, 'common.styleidnames')
1252 assert type(commonStyleIdNames) is type({}), \
1253 'Common definitions (%s) not a valid dict'%'common.styleidnames'
1254
1255 # Lang specific settings
1256 cfg.SetPath(lang)
1257 styleIdNames = readPyValFromConfig(cfg, 'styleidnames')
1258 assert type(commonStyleIdNames) is type({}), \
1259 'Not a valid dict [%s] styleidnames)'%lang
1260 styleIdNames.update(commonStyleIdNames)
1261 braceInfo = readPyValFromConfig(cfg, 'braces')
1262 assert type(commonStyleIdNames) is type({}), \
1263 'Not a valid dict [%s] braces)'%lang
1264
1265 displaySrc = cfg.Read('displaysrc')
1266 lexer = readPyValFromConfig(cfg, 'lexer')
1267 keywords = cfg.Read('keywords')
1268
1269 cfg.SetPath('')
1270
1271 # read in current styles
1272 styles = readStylesFromConfig(cfg, groupPrefix)
1273
1274 # read in predefined styles
1275 predefStyleGroups = {}
1276 for group in predefStyleGroupNames:
1277 predefStyleGroups[group] = readStylesFromConfig(cfg, group)
1278
1279 # read in all other style sections
1280 otherLangStyleGroups = {}
1281 for group in otherLangStyleGroupNames:
1282 otherLangStyleGroups[group] = readStylesFromConfig(cfg, group)
1283
1284 return (cfg, commonDefs, styleIdNames, styles, predefStyleGroupNames,
1285 predefStyleGroups, otherLangStyleGroupNames, otherLangStyleGroups,
1286 displaySrc, lexer, keywords, braceInfo)
1287
1288 def readStylesFromConfig(config, group):
1289 config.SetPath('')
1290 config.SetPath(group)
1291 styles = []
1292 cont, val, idx = config.GetFirstEntry()
1293 while cont:
1294 styles.append(val+'='+config.Read(val))
1295 cont, val, idx = config.GetNextEntry(idx)
1296 config.SetPath('')
1297
1298 return styles
1299
1300 def writeStylesToConfig(config, group, styles):
1301 config.SetPath('')
1302 config.DeleteGroup(group)
1303 config.SetPath(group)
1304
1305 for style in styles:
1306 name, value = style.split('=')
1307 config.Write(name, value.strip())
1308
1309 config.SetPath('')
1310
1311 #-------------------------------------------------------------------------------
1312 def initSTC(stc, config, lang):
1313 """ Main module entry point. Initialise a wxSTC from given config file."""
1314 (cfg, commonDefs, styleIdNames, styles, predefStyleGroupNames,
1315 predefStyleGroups, otherLangStyleGroupNames, otherLangStyleGroups,
1316 displaySrc, lexer, keywords, braceInfo) = initFromConfig(config, lang)
1317
1318 setSTCStyles(stc, styles, styleIdNames, commonDefs, lang, lexer, keywords)
1319
1320 #-------------------------------------------------------------------------------
1321 if __name__ == '__main__':
1322 app = wx.PySimpleApp()
1323
1324 provider = wx.SimpleHelpProvider()
1325 wx.HelpProvider.Set(provider)
1326
1327 home = os.environ.get('HOME')
1328 if home:
1329 home = os.path.join(home, '.boa-constructor')
1330 if not os.path.exists(home):
1331 home = '.'
1332 else:
1333 home = '.'
1334
1335 config = os.path.abspath(os.path.join(home, 'stc-styles.rc.cfg'))
1336 if 0:
1337 f = wx.Frame(None, -1, 'Test frame (double click for editor)')
1338 stc = wx.stc.StyledTextCtrl(f, -1)
1339 def OnDblClick(evt, stc=stc):
1340 dlg = STCStyleEditDlg(None, 'Python', 'python', config, (stc,))
1341 try: dlg.ShowModal()
1342 finally: dlg.Destroy()
1343 stc.SetText(open('STCStyleEditor.py').read())
1344 stc.Bind(wx.EVT_LEFT_DCLICK, OnDblClick)
1345 initSTC(stc, config, 'python')
1346 f.Show(True)
1347 app.MainLoop()
1348 else:
1349 dlg = STCStyleEditDlg(None,
1350 'Python', 'python',
1351 #'HTML', 'html',
1352 #'XML', 'xml',
1353 #'C++', 'cpp',
1354 #'Text', 'text',
1355 #'Properties', 'prop',
1356 config)
1357 try: dlg.ShowModal()
1358 finally: dlg.Destroy()