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