]>
Commit | Line | Data |
---|---|---|
00b6c4e3 RD |
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$ | |
1e4a197e | 9 | # Copyright: (c) 2001 - 2002 Riaan Booysen |
00b6c4e3 RD |
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 | ||
1114f46e | 19 | It can also maintain a Common definition dictionary of font names, colours and |
00b6c4e3 RD |
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 | ||
1114f46e | 45 | Currently the following languages are supported: |
00b6c4e3 RD |
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 * | |
1e4a197e | 56 | from wxPython.help import * |
00b6c4e3 RD |
57 | from wxPython.lib.anchors import LayoutAnchors |
58 | from wxPython.stc import * | |
59 | ||
60 | settingsIdNames = {-1: 'Selection', -2: 'Caret', -3: 'Edge'} | |
61 | ||
abd78a9f | 62 | commonPropDefs = {} |
00b6c4e3 RD |
63 | |
64 | styleCategoryDescriptions = { | |
1e4a197e RD |
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)) | |
00b6c4e3 RD |
95 | |
96 | class STCStyleEditDlg(wxDialog): | |
97 | """ Style editor for the wxStyledTextCtrl """ | |
98 | _custom_classes = {'wxWindow' : ['wxStyledTextCtrl']} | |
1114f46e | 99 | def _init_utils(self): |
1e4a197e | 100 | # generated method, don't edit |
00b6c4e3 RD |
101 | pass |
102 | ||
1114f46e | 103 | def _init_ctrls(self, prnt): |
1e4a197e RD |
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) | |
00b6c4e3 | 109 | self._init_utils() |
1e4a197e RD |
110 | self.SetClientSize(wxSize(451, 455)) |
111 | self.SetAutoLayout(True) | |
00b6c4e3 | 112 | self.SetSizeHints(425, 400, -1, -1) |
1e4a197e | 113 | self.Center(wxBOTH) |
00b6c4e3 RD |
114 | EVT_SIZE(self, self.OnStcstyleeditdlgSize) |
115 | ||
1e4a197e RD |
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) | |
00b6c4e3 | 141 | |
1e4a197e RD |
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) | |
00b6c4e3 | 208 | |
1e4a197e RD |
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)) | |
00b6c4e3 | 213 | |
1e4a197e RD |
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)) | |
00b6c4e3 RD |
219 | self.okBtn.SetToolTipString('Save changes to the config file') |
220 | EVT_BUTTON(self.okBtn, wxID_STCSTYLEEDITDLGOKBTN, self.OnOkbtnButton) | |
221 | ||
1e4a197e RD |
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)) | |
00b6c4e3 | 227 | self.cancelBtn.SetToolTipString('Close dialog without saving changes') |
1e4a197e RD |
228 | EVT_BUTTON(self.cancelBtn, wxID_STCSTYLEEDITDLGCANCELBTN, |
229 | self.OnCancelbtnButton) | |
00b6c4e3 | 230 | |
1e4a197e RD |
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) | |
00b6c4e3 | 234 | |
1e4a197e RD |
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) | |
00b6c4e3 | 238 | self.fixedWidthChk.SetToolTipString('Check this for Fixed Width fonts') |
1e4a197e RD |
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) | |
00b6c4e3 | 370 | |
1114f46e | 371 | def __init__(self, parent, langTitle, lang, configFile, STCsToUpdate=()): |
abd78a9f RD |
372 | global commonPropDefs |
373 | commonPropDefs = {'fore': '#888888', | |
374 | 'size': 8, | |
375 | 'face': wxSystemSettings_GetSystemFont(wxSYS_DEFAULT_GUI_FONT).GetFaceName()} | |
376 | ||
00b6c4e3 RD |
377 | self.stc_title = 'wxStyledTextCtrl Style Editor' |
378 | self.stc_title = 'wxStyledTextCtrl Style Editor - %s' % langTitle | |
1e4a197e RD |
379 | if wxPlatform == '__WXMSW__': |
380 | self.style_font_size = 8 | |
381 | else: | |
382 | self.style_font_size = 10 | |
00b6c4e3 | 383 | self._init_ctrls(parent) |
00b6c4e3 RD |
384 | self.lang = lang |
385 | self.configFile = configFile | |
386 | self.style = '' | |
1e4a197e | 387 | self.styleNum = 0 |
00b6c4e3 RD |
388 | self.names = [] |
389 | self.values = {} | |
390 | self.STCsToUpdate = STCsToUpdate | |
1e4a197e | 391 | self._blockUpdate = False |
1114f46e | 392 | |
1e4a197e RD |
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) | |
1114f46e RD |
400 | |
401 | (self.config, self.commonDefs, self.styleIdNames, self.styles, | |
402 | self.styleGroupNames, self.predefStyleGroups, | |
00b6c4e3 RD |
403 | self.otherLangStyleGroupNames, self.otherLangStyleGroups, |
404 | self.displaySrc, self.lexer, self.keywords, self.braceInfo) = \ | |
1114f46e RD |
405 | initFromConfig(configFile, lang) |
406 | ||
00b6c4e3 RD |
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) | |
1114f46e | 411 | |
00b6c4e3 RD |
412 | margin = 0 |
413 | self.stc.SetMarginType(margin, wxSTC_MARGIN_NUMBER) | |
414 | self.stc.SetMarginWidth(margin, 25) | |
1e4a197e | 415 | self.stc.SetMarginSensitive(margin, True) |
00b6c4e3 RD |
416 | EVT_STC_MARGINCLICK(self.stc, wxID_STCSTYLEEDITDLGSTC, self.OnMarginClick) |
417 | ||
1e4a197e | 418 | self.stc.SetUseTabs(False) |
00b6c4e3 | 419 | self.stc.SetTabWidth(4) |
1e4a197e | 420 | self.stc.SetIndentationGuides(True) |
00b6c4e3 RD |
421 | self.stc.SetEdgeMode(wxSTC_EDGE_BACKGROUND) |
422 | self.stc.SetEdgeColumn(44) | |
1114f46e | 423 | |
00b6c4e3 RD |
424 | self.setStyles() |
425 | ||
426 | self.populateStyleSelector() | |
427 | ||
428 | self.defNames, self.defValues = parseProp(\ | |
429 | self.styleDict.get(wxSTC_STYLE_DEFAULT, '')) | |
00b6c4e3 RD |
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 | |
1e4a197e | 438 | self.allCtrls = [((self.fgColBtn, self.fgColCb, self.fgColOkBtn), self.fgColDefCb, |
00b6c4e3 | 439 | 'fore', wxID_STCSTYLEEDITDLGFGCOLDEFCB), |
1e4a197e | 440 | ((self.bgColBtn, self.bgColCb, self.bgColOkBtn), self.bgColDefCb, |
00b6c4e3 | 441 | 'back', wxID_STCSTYLEEDITDLGBGCOLDEFCB), |
1114f46e | 442 | (self.taBoldCb, self.taBoldDefCb, |
00b6c4e3 | 443 | 'bold', wxID_STCSTYLEEDITDLGTABOLDDEFCB), |
1114f46e RD |
444 | (self.taItalicCb, self.taItalicDefCb, |
445 | 'italic', wxID_STCSTYLEEDITDLGTAITALICDEFCB), | |
446 | (self.taUnderlinedCb, self.taUnderlinedDefCb, | |
00b6c4e3 | 447 | 'underline', wxID_STCSTYLEEDITDLGTAUNDERLINEDDEFCB), |
1114f46e | 448 | (self.taEOLfilledCb, self.taEOLfilledDefCb, |
00b6c4e3 | 449 | 'eolfilled', wxID_STCSTYLEEDITDLGTAEOLFILLEDDEFCB), |
1e4a197e | 450 | ((self.sizeCb, self.sizeOkBtn), self.taSizeDefCb, |
00b6c4e3 | 451 | 'size', wxID_STCSTYLEEDITDLGTASIZEDEFCB), |
1e4a197e | 452 | ((self.faceCb, self.faceOkBtn, self.fixedWidthChk), self.faceDefCb, |
00b6c4e3 RD |
453 | 'face', wxID_STCSTYLEEDITDLGFACEDEFCB)] |
454 | ||
1e4a197e | 455 | self.clearCtrls(disableDefs=True) |
00b6c4e3 RD |
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') | |
1114f46e | 462 | |
00b6c4e3 | 463 | self.Center(wxBOTH) |
1114f46e | 464 | |
00b6c4e3 RD |
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) | |
1114f46e | 471 | |
00b6c4e3 RD |
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 | |
1114f46e | 483 | |
00b6c4e3 RD |
484 | try: |
485 | self.updateStyle() | |
1e4a197e | 486 | return True |
00b6c4e3 RD |
487 | except KeyError, errkey: |
488 | wxLogError('Name not found in Common definition, '\ | |
489 | 'please enter valid reference. (%s)'%errkey) | |
490 | self.restoreStyles(oldstyle) | |
1e4a197e | 491 | return False |
00b6c4e3 RD |
492 | |
493 | #---Control population methods-------------------------------------------------- | |
494 | def setStyles(self): | |
1e4a197e | 495 | if self._blockUpdate: return |
00b6c4e3 | 496 | self.styles, self.styleDict, self.styleNumIdxMap = \ |
1114f46e | 497 | setSTCStyles(self.stc, self.styles, self.styleIdNames, |
00b6c4e3 | 498 | self.commonDefs, self.lang, self.lexer, self.keywords) |
1114f46e | 499 | |
00b6c4e3 RD |
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) | |
1114f46e | 506 | |
00b6c4e3 RD |
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() | |
1114f46e | 515 | |
00b6c4e3 RD |
516 | def findInStyles(self, txt, styles): |
517 | for style in styles: | |
518 | if string.find(style, txt) != -1: | |
1e4a197e RD |
519 | return True |
520 | return False | |
00b6c4e3 RD |
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 | ||
1e4a197e RD |
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 | |
1114f46e | 599 | |
00b6c4e3 RD |
600 | def valIsCommonDef(self, val): |
601 | return len(val) >= 5 and val[:2] == '%(' | |
1114f46e | 602 | |
00b6c4e3 RD |
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: | |
1e4a197e | 609 | self.fgColDefCb.Enable(True) |
00b6c4e3 | 610 | if self.styleNum == -1: |
1e4a197e | 611 | self.bgColDefCb.Enable(True) |
1114f46e | 612 | |
00b6c4e3 | 613 | # populate with default style |
1e4a197e | 614 | self.populateProp(self.defValues.items(), True, |
00b6c4e3 RD |
615 | self.styleNum != wxSTC_STYLE_DEFAULT) |
616 | # override with current settings | |
1e4a197e | 617 | self.populateProp(self.values.items(), False) |
1114f46e | 618 | |
00b6c4e3 RD |
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 | ||
1e4a197e RD |
625 | def bindComboEvts(self, combo, btn, btnEvtMeth, comboEvtMeth, rdclickEvtMeth): |
626 | EVT_COMBOBOX(combo, combo.GetId(), comboEvtMeth) | |
627 | EVT_BUTTON(btn, btn.GetId(), btnEvtMeth) | |
00b6c4e3 | 628 | EVT_RIGHT_DCLICK(combo, rdclickEvtMeth) |
1e4a197e RD |
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') | |
00b6c4e3 RD |
632 | |
633 | def populateCombosWithCommonDefs(self, fixedWidthOnly=None): | |
1e4a197e RD |
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 | |
00b6c4e3 RD |
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: | |
1e4a197e RD |
684 | self.elementLb.InsertItems([name, '----Language----'], 0) |
685 | self.elementLb.Append('----Standard----') | |
1f443284 | 686 | stdStart = stdPos = self.elementLb.GetCount() |
00b6c4e3 RD |
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 | |
1114f46e | 693 | elif num >= 40: |
00b6c4e3 RD |
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 | |
1e4a197e | 702 | self.elementLb.Append('----Settings----') |
00b6c4e3 RD |
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 | |
1e4a197e | 710 | self.elementLb.Append('----Common----') |
1f443284 | 711 | self.commonDefsStartIdx = self.elementLb.GetCount() |
00b6c4e3 RD |
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 | |
1114f46e | 716 | |
00b6c4e3 RD |
717 | #---Colour methods-------------------------------------------------------------- |
718 | def getColourDlg(self, colour, title=''): | |
719 | data = wxColourData() | |
720 | data.SetColour(colour) | |
1e4a197e | 721 | data.SetChooseFull(True) |
00b6c4e3 RD |
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): | |
1114f46e | 734 | col = self.getColourDlg(colBtn.GetBackgroundColour(), |
00b6c4e3 | 735 | self.colDlgTitles[prop]+ ' colour') |
1114f46e | 736 | if col: |
00b6c4e3 RD |
737 | colBtn.SetForegroundColour(wxColour(0, 0, 0)) |
738 | colBtn.SetBackgroundColour(col) | |
739 | colStr = colToStr(col) | |
740 | colCb.SetValue(colStr) | |
1e4a197e | 741 | self.editProp(True, prop, colStr) |
00b6c4e3 RD |
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 | ||
1e4a197e RD |
749 | def editColTCProp(self, colCb, colBtn, prop, val=None): |
750 | if val is None: | |
751 | colStr = colCb.GetValue() | |
752 | else: | |
753 | colStr = val | |
1114f46e | 754 | if colStr: |
00b6c4e3 RD |
755 | col = strToCol(colStr%self.commonDefs) |
756 | if self.editProp(colStr!='', prop, colStr): | |
1114f46e | 757 | if colStr: |
00b6c4e3 RD |
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 | ||
1e4a197e RD |
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 | ||
00b6c4e3 RD |
774 | def OnbgColRet(self, event): |
775 | try: self.editColTCProp(self.bgColCb, self.bgColBtn, 'back') | |
776 | except AssertionError: wxLogError('Not a valid colour value') | |
777 | ||
1e4a197e RD |
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 | ||
00b6c4e3 RD |
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: | |
1e4a197e | 801 | self.elementLb.SetSelection(idx, True) |
00b6c4e3 RD |
802 | self.OnElementlbListbox(None) |
803 | ||
804 | def OnfaceRet(self, event): | |
1e4a197e RD |
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): | |
00b6c4e3 RD |
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): | |
1e4a197e RD |
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): | |
00b6c4e3 RD |
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) | |
1e4a197e | 839 | self.clearCtrls(disableDefs=True) |
00b6c4e3 | 840 | if prop == 'fore': |
1e4a197e RD |
841 | self.fgColBtn.Enable(True) |
842 | self.fgColCb.Enable(True) | |
843 | self.fgColOkBtn.Enable(True) | |
00b6c4e3 | 844 | elif prop == 'face': |
1e4a197e RD |
845 | self.faceCb.Enable(True) |
846 | self.fixedWidthChk.Enable(True) | |
847 | self.faceOkBtn.Enable(True) | |
00b6c4e3 | 848 | elif prop == 'size': |
1e4a197e RD |
849 | self.sizeCb.Enable(True) |
850 | self.sizeOkBtn.Enable(True) | |
00b6c4e3 RD |
851 | |
852 | commonDefVal = str(self.commonDefs[common]) | |
853 | self.styleDefST.SetLabel(commonDefVal) | |
1e4a197e | 854 | self.populateProp( [(prop, commonDefVal)], True) |
00b6c4e3 RD |
855 | |
856 | self.styleNum = 'common' | |
857 | self.style = [common, prop, commonDefVal] | |
858 | self.names, self.values = [prop], {prop: commonDefVal} | |
1114f46e | 859 | |
00b6c4e3 RD |
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) | |
00b6c4e3 RD |
865 | if self.styleNum == wxSTC_STYLE_DEFAULT: |
866 | self.defNames, self.defValues = \ | |
867 | self.names, self.values | |
868 | ||
869 | self.checkBraces(self.styleNum) | |
1114f46e | 870 | |
00b6c4e3 | 871 | self.styleDefST.SetLabel(self.style) |
1114f46e | 872 | |
00b6c4e3 RD |
873 | self.populateCtrls() |
874 | # separator selected | |
875 | else: | |
1e4a197e | 876 | self.clearCtrls(disableDefs=True) |
00b6c4e3 RD |
877 | if styleIdent: |
878 | self.styleDefST.SetLabel(styleCategoryDescriptions[styleIdent]) | |
879 | ||
880 | self.populateCombosWithCommonDefs() | |
1114f46e | 881 | |
00b6c4e3 | 882 | def OnDefaultCheckBox(self, event): |
1e4a197e RD |
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) | |
00b6c4e3 RD |
914 | |
915 | def OnOkbtnButton(self, event): | |
916 | # write styles and common defs to the config | |
1e4a197e RD |
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() | |
00b6c4e3 RD |
929 | self.EndModal(wxID_OK) |
930 | ||
931 | def OnCancelbtnButton(self, event): | |
932 | self.EndModal(wxID_CANCEL) | |
933 | ||
934 | def OnCommondefsbtnButton(self, event): | |
1114f46e | 935 | dlg = wxTextEntryDialog(self, 'Edit common definitions dictionary', |
00b6c4e3 RD |
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() | |
1114f46e | 952 | |
00b6c4e3 RD |
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')) | |
1f443284 | 981 | self.elementLb.SetSelection(self.elementLb.GetCount()-1, True) |
00b6c4e3 RD |
982 | self.populateCombosWithCommonDefs() |
983 | self.OnElementlbListbox(None) | |
984 | finally: | |
985 | dlg.Destroy() | |
986 | ||
987 | def OnRemovesharebtnButton(self, event): | |
988 | ownGroup = 'style.%s'%self.lang | |
1114f46e RD |
989 | comDef = self.elementLb.GetStringSelection() |
990 | ||
00b6c4e3 RD |
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) | |
1f443284 | 1011 | if selIdx == self.elementLb.GetCount(): |
00b6c4e3 | 1012 | selIdx = selIdx - 1 |
1e4a197e | 1013 | self.elementLb.SetSelection(selIdx, True) |
00b6c4e3 RD |
1014 | self.OnElementlbListbox(None) |
1015 | ||
1016 | #---STC events------------------------------------------------------------------ | |
1017 | def OnUpdateUI(self, event): | |
1e4a197e RD |
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) | |
00b6c4e3 RD |
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): | |
1e4a197e | 1050 | self.elementLb.SetStringSelection('Line numbers', True) |
00b6c4e3 RD |
1051 | self.OnElementlbListbox(None) |
1052 | ||
1114f46e | 1053 | |
00b6c4e3 RD |
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') | |
1e4a197e | 1061 | self.SetClientSize(wxSize(184, 200)) |
00b6c4e3 | 1062 | |
1e4a197e | 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) |
00b6c4e3 RD |
1064 | self.propTypeRBx.SetSelection(self._propTypeIdx) |
1065 | ||
1e4a197e | 1066 | self.staticBox1 = wxStaticBox(id = wxID_COMMONDEFDLGSTATICBOX1, label = 'Name', name = 'staticBox1', parent = self, pos = wxPoint(8, 108), size = wxSize(168, 46), style = 0) |
00b6c4e3 | 1067 | |
1e4a197e | 1068 | self.comDefNameTC = wxTextCtrl(id = wxID_COMMONDEFDLGCOMDEFNAMETC, name = 'comDefNameTC', parent = self, pos = wxPoint(16, 124), size = wxSize(152, 21), style = 0, value = '') |
00b6c4e3 RD |
1069 | self.comDefNameTC.SetLabel(self._comDefName) |
1070 | ||
1e4a197e | 1071 | self.okBtn = wxButton(id = wxID_COMMONDEFDLGOKBTN, label = 'OK', name = 'okBtn', parent = self, pos = wxPoint(8, 164), size = wxSize(80, 23), style = 0) |
00b6c4e3 RD |
1072 | EVT_BUTTON(self.okBtn, wxID_COMMONDEFDLGOKBTN, self.OnOkbtnButton) |
1073 | ||
1e4a197e | 1074 | self.cancelBtn = wxButton(id = wxID_COMMONDEFDLGCANCELBTN, label = 'Cancel', name = 'cancelBtn', parent = self, pos = wxPoint(96, 164), size = wxSize(80, 23), style = 0) |
00b6c4e3 RD |
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) | |
1114f46e RD |
1083 | |
1084 | self.propMap = {0: 'fore', 1: 'face', 2: 'size'} | |
00b6c4e3 RD |
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) | |
1114f46e | 1097 | |
00b6c4e3 | 1098 | #---Functions useful outside of the editor---------------------------------- |
1114f46e | 1099 | |
00b6c4e3 RD |
1100 | def setSelectionColour(stc, style): |
1101 | names, values = parseProp(style) | |
1102 | if 'fore' in names: | |
1e4a197e | 1103 | stc.SetSelForeground(True, strToCol(values['fore'])) |
00b6c4e3 | 1104 | if 'back' in names: |
1e4a197e | 1105 | stc.SetSelBackground(True, strToCol(values['back'])) |
00b6c4e3 RD |
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' | |
1114f46e RD |
1119 | return wxColour(string.atoi('0x'+strCol[1:3], 16), |
1120 | string.atoi('0x'+strCol[3:5], 16), | |
00b6c4e3 RD |
1121 | string.atoi('0x'+strCol[5:7], 16)) |
1122 | def colToStr(col): | |
1114f46e | 1123 | return '#%s%s%s' % (string.zfill(string.upper(hex(col.Red())[2:]), 2), |
00b6c4e3 RD |
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 | |
1114f46e | 1152 | |
00b6c4e3 RD |
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): | |
1e4a197e | 1158 | #wxLogMessage('Set style') |
00b6c4e3 RD |
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 | ||
1e4a197e RD |
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 | ||
00b6c4e3 | 1190 | # Set the styles on the wxSTC |
1e4a197e | 1191 | # stc.Show(False) |
00b6c4e3 RD |
1192 | stc.StyleResetDefault() |
1193 | stc.ClearDocumentStyle() | |
1194 | stc.SetLexer(lexer) | |
1195 | stc.SetKeyWords(0, keywords) | |
1114f46e | 1196 | stc.StyleSetSpec(wxSTC_STYLE_DEFAULT, |
00b6c4e3 RD |
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()) | |
1e4a197e | 1211 | # stc.Show(True) |
1114f46e | 1212 | |
00b6c4e3 RD |
1213 | return newStyles, styleDict, styleNumIdxMap |
1214 | ||
1215 | #---Config reading and writing ------------------------------------------------- | |
1216 | commonDefsFile = 'common.defs.%s'%(wxPlatform == '__WXMSW__' and 'msw' or 'gtk') | |
1217 | ||
1e4a197e RD |
1218 | def readPyValFromConfig(conf, name): |
1219 | return eval(string.replace(conf.Read(name), '\r\n', '\n')+'\n') | |
1220 | ||
00b6c4e3 RD |
1221 | def initFromConfig(configFile, lang): |
1222 | cfg = wxFileConfig(localFilename=configFile, style=wxCONFIG_USE_LOCAL_FILE) | |
1e4a197e | 1223 | cfg.SetExpandEnvVars(False) |
00b6c4e3 RD |
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) | |
1114f46e | 1236 | |
00b6c4e3 | 1237 | cont, val, idx = cfg.GetNextGroup(idx) |
1114f46e | 1238 | |
00b6c4e3 | 1239 | # read in common elements |
1e4a197e | 1240 | commonDefs = readPyValFromConfig(cfg, commonDefsFile) |
00b6c4e3 RD |
1241 | assert type(commonDefs) is type({}), \ |
1242 | 'Common definitions (%s) not a valid dict'%commonDefsFile | |
1243 | ||
1e4a197e | 1244 | commonStyleIdNames = readPyValFromConfig(cfg, 'common.styleidnames') |
00b6c4e3 RD |
1245 | assert type(commonStyleIdNames) is type({}), \ |
1246 | 'Common definitions (%s) not a valid dict'%'common.styleidnames' | |
1247 | ||
1248 | # Lang spesific settings | |
1114f46e | 1249 | cfg.SetPath(lang) |
1e4a197e | 1250 | styleIdNames = readPyValFromConfig(cfg, 'styleidnames') |
00b6c4e3 RD |
1251 | assert type(commonStyleIdNames) is type({}), \ |
1252 | 'Not a valid dict [%s] styleidnames)'%lang | |
1253 | styleIdNames.update(commonStyleIdNames) | |
1e4a197e | 1254 | braceInfo = readPyValFromConfig(cfg, 'braces') |
00b6c4e3 RD |
1255 | assert type(commonStyleIdNames) is type({}), \ |
1256 | 'Not a valid dict [%s] braces)'%lang | |
1114f46e | 1257 | |
00b6c4e3 | 1258 | displaySrc = cfg.Read('displaysrc') |
1e4a197e | 1259 | lexer = readPyValFromConfig(cfg, 'lexer') |
00b6c4e3 RD |
1260 | keywords = cfg.Read('keywords') |
1261 | ||
1262 | cfg.SetPath('') | |
1263 | ||
1264 | # read in current styles | |
1265 | styles = readStylesFromConfig(cfg, groupPrefix) | |
1266 | ||
1114f46e | 1267 | # read in predefined styles |
00b6c4e3 RD |
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) | |
1114f46e RD |
1276 | |
1277 | return (cfg, commonDefs, styleIdNames, styles, predefStyleGroupNames, | |
00b6c4e3 RD |
1278 | predefStyleGroups, otherLangStyleGroupNames, otherLangStyleGroups, |
1279 | displaySrc, lexer, keywords, braceInfo) | |
1280 | ||
1281 | def readStylesFromConfig(config, group): | |
1282 | config.SetPath('') | |
1114f46e | 1283 | config.SetPath(group) |
00b6c4e3 RD |
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.""" | |
1114f46e | 1307 | (cfg, commonDefs, styleIdNames, styles, predefStyleGroupNames, |
00b6c4e3 RD |
1308 | predefStyleGroups, otherLangStyleGroupNames, otherLangStyleGroups, |
1309 | displaySrc, lexer, keywords, braceInfo) = initFromConfig(config, lang) | |
1114f46e | 1310 | |
00b6c4e3 RD |
1311 | setSTCStyles(stc, styles, styleIdNames, commonDefs, lang, lexer, keywords) |
1312 | ||
1313 | #------------------------------------------------------------------------------- | |
1314 | if __name__ == '__main__': | |
1e4a197e RD |
1315 | from wxPython.help import * |
1316 | ||
00b6c4e3 | 1317 | app = wxPySimpleApp() |
1114f46e | 1318 | |
1e4a197e RD |
1319 | provider = wxSimpleHelpProvider() |
1320 | wxHelpProvider_Set(provider) | |
1321 | ||
1f443284 RD |
1322 | base = os.path.split(__file__)[0] |
1323 | config = os.path.abspath(os.path.join(base, 'stc-styles.rc.cfg')) | |
00b6c4e3 RD |
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') | |
1e4a197e | 1334 | f.Show(True) |
00b6c4e3 RD |
1335 | app.MainLoop() |
1336 | else: | |
1114f46e | 1337 | dlg = STCStyleEditDlg(None, |
00b6c4e3 RD |
1338 | 'Python', 'python', |
1339 | #'HTML', 'html', | |
1340 | #'XML', 'xml', | |
1114f46e RD |
1341 | #'C++', 'cpp', |
1342 | #'Text', 'text', | |
1343 | #'Properties', 'prop', | |
00b6c4e3 RD |
1344 | config) |
1345 | try: dlg.ShowModal() | |
1346 | finally: dlg.Destroy() |