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