]>
Commit | Line | Data |
---|---|---|
d14a1e28 | 1 | #---------------------------------------------------------------------- |
a5deb2fb RD |
2 | # Name: wx.lib.dialogs |
3 | # Purpose: ScrolledMessageDialog, MultipleChoiceDialog and | |
d14a1e28 RD |
4 | # function wrappers for the common dialogs by Kevin Altis. |
5 | # | |
6 | # Author: Various | |
7 | # | |
8 | # Created: 3-January-2002 | |
9 | # RCS-ID: $Id$ | |
10 | # Copyright: (c) 2002 by Total Control Software | |
11 | # Licence: wxWindows license | |
12 | #---------------------------------------------------------------------- | |
b881fc78 RD |
13 | # 12/01/2003 - Jeff Grimmett (grimmtooth@softhome.net) |
14 | # | |
15 | # o Updated for 2.5 compatability. | |
16 | # | |
33785d9f RD |
17 | # 12/18/2003 - Jeff Grimmett (grimmtooth@softhome.net) |
18 | # | |
19 | # o wxScrolledMessageDialog -> ScrolledMessageDialog | |
20 | # o wxMultipleChoiceDialog -> MultipleChoiceDialog | |
21 | # | |
1fded56b | 22 | |
b881fc78 RD |
23 | import wx |
24 | import layoutf | |
1fded56b | 25 | |
d14a1e28 RD |
26 | #---------------------------------------------------------------------- |
27 | ||
33785d9f | 28 | class ScrolledMessageDialog(wx.Dialog): |
f50544d8 RD |
29 | def __init__(self, parent, msg, caption, |
30 | pos=wx.DefaultPosition, size=(500,300), | |
31 | style=wx.DEFAULT_DIALOG_STYLE): | |
32 | wx.Dialog.__init__(self, parent, -1, caption, pos, size, style) | |
d14a1e28 RD |
33 | x, y = pos |
34 | if x == -1 and y == -1: | |
b881fc78 RD |
35 | self.CenterOnScreen(wx.BOTH) |
36 | ||
f50544d8 RD |
37 | text = wx.TextCtrl(self, -1, msg, |
38 | style=wx.TE_MULTILINE | wx.TE_READONLY) | |
b881fc78 RD |
39 | |
40 | ok = wx.Button(self, wx.ID_OK, "OK") | |
678666f2 | 41 | ok.SetDefault() |
b881fc78 RD |
42 | lc = layoutf.Layoutf('t=t5#1;b=t5#2;l=l5#1;r=r5#1', (self,ok)) |
43 | text.SetConstraints(lc) | |
44 | ||
678666f2 | 45 | lc = layoutf.Layoutf('b=b5#1;x%w50#1;w!80;h*', (self,)) |
b881fc78 | 46 | ok.SetConstraints(lc) |
d14a1e28 RD |
47 | self.SetAutoLayout(1) |
48 | self.Layout() | |
49 | ||
50 | ||
33785d9f | 51 | class MultipleChoiceDialog(wx.Dialog): |
b881fc78 RD |
52 | def __init__(self, parent, msg, title, lst, pos = wx.DefaultPosition, |
53 | size = (200,200), style = wx.DEFAULT_DIALOG_STYLE): | |
54 | wx.Dialog.__init__(self, parent, -1, title, pos, size, style) | |
55 | ||
d14a1e28 RD |
56 | x, y = pos |
57 | if x == -1 and y == -1: | |
b881fc78 RD |
58 | self.CenterOnScreen(wx.BOTH) |
59 | ||
60 | dc = wx.ClientDC(self) | |
d14a1e28 RD |
61 | height = 0 |
62 | for line in msg.splitlines(): | |
63 | height = height + dc.GetTextExtent(line)[1] + 2 | |
b881fc78 RD |
64 | |
65 | stat = wx.StaticText(self, -1, msg) | |
66 | self.lbox = wx.ListBox(self, 100, wx.DefaultPosition, wx.DefaultSize, | |
67 | lst, wx.LB_MULTIPLE) | |
68 | ||
69 | ok = wx.Button(self, wx.ID_OK, "OK") | |
678666f2 | 70 | ok.SetDefault() |
b881fc78 | 71 | cancel = wx.Button(self, wx.ID_CANCEL, "Cancel") |
0f9da074 RD |
72 | |
73 | dlgsizer = wx.BoxSizer(wx.VERTICAL) | |
74 | dlgsizer.Add(stat, 0, wx.ALL, 4) | |
75 | dlgsizer.Add(self.lbox, 1, wx.EXPAND | wx.ALL, 4) | |
76 | ||
77 | btnsizer = wx.StdDialogButtonSizer() | |
78 | btnsizer.AddButton(ok) | |
79 | btnsizer.AddButton(cancel) | |
718903fe | 80 | btnsizer.Realize() |
0f9da074 RD |
81 | |
82 | dlgsizer.Add(btnsizer, 0, wx.ALL | wx.ALIGN_RIGHT, 4) | |
83 | ||
84 | self.SetSizer(dlgsizer) | |
b881fc78 | 85 | |
d14a1e28 RD |
86 | self.SetAutoLayout(1) |
87 | self.lst = lst | |
88 | self.Layout() | |
89 | ||
90 | def GetValue(self): | |
91 | return self.lbox.GetSelections() | |
92 | ||
93 | def GetValueString(self): | |
94 | sel = self.lbox.GetSelections() | |
95 | val = [] | |
b881fc78 | 96 | |
d14a1e28 RD |
97 | for i in sel: |
98 | val.append(self.lst[i]) | |
d14a1e28 | 99 | |
b881fc78 | 100 | return tuple(val) |
d14a1e28 RD |
101 | |
102 | ||
103 | #---------------------------------------------------------------------- | |
104 | """ | |
105 | function wrappers for wxPython system dialogs | |
106 | Author: Kevin Altis | |
107 | Date: 2003-1-2 | |
108 | Rev: 3 | |
109 | ||
110 | This is the third refactor of the PythonCard dialog.py module | |
111 | for inclusion in the main wxPython distribution. There are a number of | |
112 | design decisions and subsequent code refactoring to be done, so I'm | |
113 | releasing this just to get some feedback. | |
114 | ||
115 | rev 3: | |
116 | - result dictionary replaced by DialogResults class instance | |
117 | - should message arg be replaced with msg? most wxWindows dialogs | |
118 | seem to use the abbreviation? | |
119 | ||
120 | rev 2: | |
121 | - All dialog classes have been replaced by function wrappers | |
122 | - Changed arg lists to more closely match wxWindows docs and wxPython.lib.dialogs | |
123 | - changed 'returned' value to the actual button id the user clicked on | |
124 | - added a returnedString value for the string version of the return value | |
125 | - reworked colorDialog and fontDialog so you can pass in just a color or font | |
126 | for the most common usage case | |
127 | - probably need to use colour instead of color to match the English English | |
128 | spelling in wxWindows (sigh) | |
129 | - I still think we could lose the parent arg and just always use None | |
130 | """ | |
131 | ||
132 | class DialogResults: | |
133 | def __init__(self, returned): | |
134 | self.returned = returned | |
b881fc78 | 135 | self.accepted = returned in (wx.ID_OK, wx.ID_YES) |
d14a1e28 RD |
136 | self.returnedString = returnedString(returned) |
137 | ||
138 | def __repr__(self): | |
139 | return str(self.__dict__) | |
140 | ||
141 | def returnedString(ret): | |
b881fc78 | 142 | if ret == wx.ID_OK: |
d14a1e28 | 143 | return "Ok" |
b881fc78 | 144 | elif ret == wx.ID_CANCEL: |
d14a1e28 | 145 | return "Cancel" |
b881fc78 | 146 | elif ret == wx.ID_YES: |
d14a1e28 | 147 | return "Yes" |
b881fc78 | 148 | elif ret == wx.ID_NO: |
d14a1e28 RD |
149 | return "No" |
150 | ||
151 | ||
b881fc78 RD |
152 | ## findDialog was created before wxPython got a Find/Replace dialog |
153 | ## but it may be instructive as to how a function wrapper can | |
154 | ## be added for your own custom dialogs | |
155 | ## this dialog is always modal, while wxFindReplaceDialog is | |
156 | ## modeless and so doesn't lend itself to a function wrapper | |
d14a1e28 | 157 | def findDialog(parent=None, searchText='', wholeWordsOnly=0, caseSensitive=0): |
9e26b2b2 | 158 | dlg = wx.Dialog(parent, -1, "Find", wx.DefaultPosition, (380, 120)) |
d14a1e28 | 159 | |
b881fc78 | 160 | wx.StaticText(dlg, -1, 'Find what:', (7, 10)) |
9e26b2b2 | 161 | wSearchText = wx.TextCtrl(dlg, -1, searchText, (80, 7), (195, -1)) |
d14a1e28 | 162 | wSearchText.SetValue(searchText) |
9e26b2b2 RD |
163 | wx.Button(dlg, wx.ID_OK, "Find Next", (285, 5), wx.DefaultSize).SetDefault() |
164 | wx.Button(dlg, wx.ID_CANCEL, "Cancel", (285, 35), wx.DefaultSize) | |
165 | ||
b881fc78 RD |
166 | wWholeWord = wx.CheckBox(dlg, -1, 'Match whole word only', |
167 | (7, 35), wx.DefaultSize, wx.NO_BORDER) | |
168 | ||
d14a1e28 RD |
169 | if wholeWordsOnly: |
170 | wWholeWord.SetValue(1) | |
b881fc78 RD |
171 | |
172 | wCase = wx.CheckBox(dlg, -1, 'Match case', (7, 55), wx.DefaultSize, wx.NO_BORDER) | |
173 | ||
d14a1e28 RD |
174 | if caseSensitive: |
175 | wCase.SetValue(1) | |
b881fc78 | 176 | |
d14a1e28 RD |
177 | wSearchText.SetSelection(0, len(wSearchText.GetValue())) |
178 | wSearchText.SetFocus() | |
179 | ||
180 | result = DialogResults(dlg.ShowModal()) | |
19cc8ed9 RD |
181 | result.searchText = wSearchText.GetValue() |
182 | result.wholeWordsOnly = wWholeWord.GetValue() | |
183 | result.caseSensitive = wCase.GetValue() | |
d14a1e28 RD |
184 | dlg.Destroy() |
185 | return result | |
186 | ||
187 | ||
188 | def colorDialog(parent=None, colorData=None, color=None): | |
189 | if colorData: | |
b881fc78 | 190 | dialog = wx.ColourDialog(parent, colorData) |
d14a1e28 | 191 | else: |
b881fc78 | 192 | dialog = wx.ColourDialog(parent) |
d14a1e28 | 193 | dialog.GetColourData().SetChooseFull(1) |
b881fc78 | 194 | |
d14a1e28 RD |
195 | if color is not None: |
196 | dialog.GetColourData().SetColour(color) | |
b881fc78 | 197 | |
d14a1e28 RD |
198 | result = DialogResults(dialog.ShowModal()) |
199 | result.colorData = dialog.GetColourData() | |
200 | result.color = result.colorData.GetColour().Get() | |
201 | dialog.Destroy() | |
202 | return result | |
203 | ||
b881fc78 RD |
204 | |
205 | ## it is easier to just duplicate the code than | |
206 | ## try and replace color with colour in the result | |
d14a1e28 RD |
207 | def colourDialog(parent=None, colourData=None, colour=None): |
208 | if colourData: | |
b881fc78 | 209 | dialog = wx.ColourDialog(parent, colourData) |
d14a1e28 | 210 | else: |
b881fc78 | 211 | dialog = wx.ColourDialog(parent) |
d14a1e28 | 212 | dialog.GetColourData().SetChooseFull(1) |
b881fc78 | 213 | |
d14a1e28 RD |
214 | if colour is not None: |
215 | dialog.GetColourData().SetColour(color) | |
b881fc78 | 216 | |
d14a1e28 RD |
217 | result = DialogResults(dialog.ShowModal()) |
218 | result.colourData = dialog.GetColourData() | |
219 | result.colour = result.colourData.GetColour().Get() | |
220 | dialog.Destroy() | |
221 | return result | |
222 | ||
223 | ||
224 | def fontDialog(parent=None, fontData=None, font=None): | |
225 | if fontData is None: | |
b881fc78 | 226 | fontData = wx.FontData() |
a5deb2fb RD |
227 | fontData.SetColour(wx.BLACK) |
228 | fontData.SetInitialFont(wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)) | |
b881fc78 | 229 | |
d14a1e28 | 230 | if font is not None: |
19cc8ed9 | 231 | fontData.SetInitialFont(font) |
b881fc78 RD |
232 | |
233 | dialog = wx.FontDialog(parent, fontData) | |
d14a1e28 | 234 | result = DialogResults(dialog.ShowModal()) |
b881fc78 | 235 | |
d14a1e28 RD |
236 | if result.accepted: |
237 | fontData = dialog.GetFontData() | |
238 | result.fontData = fontData | |
239 | result.color = fontData.GetColour().Get() | |
240 | result.colour = result.color | |
241 | result.font = fontData.GetChosenFont() | |
242 | else: | |
243 | result.color = None | |
244 | result.colour = None | |
245 | result.font = None | |
b881fc78 | 246 | |
d14a1e28 RD |
247 | dialog.Destroy() |
248 | return result | |
249 | ||
250 | ||
b881fc78 RD |
251 | def textEntryDialog(parent=None, message='', title='', defaultText='', |
252 | style=wx.OK | wx.CANCEL): | |
253 | dialog = wx.TextEntryDialog(parent, message, title, defaultText, style) | |
d14a1e28 RD |
254 | result = DialogResults(dialog.ShowModal()) |
255 | result.text = dialog.GetValue() | |
256 | dialog.Destroy() | |
257 | return result | |
258 | ||
259 | ||
260 | def messageDialog(parent=None, message='', title='Message box', | |
b881fc78 RD |
261 | aStyle = wx.OK | wx.CANCEL | wx.CENTRE, |
262 | pos=wx.DefaultPosition): | |
263 | dialog = wx.MessageDialog(parent, message, title, aStyle, pos) | |
d14a1e28 RD |
264 | result = DialogResults(dialog.ShowModal()) |
265 | dialog.Destroy() | |
266 | return result | |
267 | ||
268 | ||
b881fc78 RD |
269 | ## KEA: alerts are common, so I'm providing a class rather than |
270 | ## requiring the user code to set up the right icons and buttons | |
271 | ## the with messageDialog function | |
272 | def alertDialog(parent=None, message='', title='Alert', pos=wx.DefaultPosition): | |
273 | return messageDialog(parent, message, title, wx.ICON_EXCLAMATION | wx.OK, pos) | |
d14a1e28 RD |
274 | |
275 | ||
b881fc78 RD |
276 | def scrolledMessageDialog(parent=None, message='', title='', pos=wx.DefaultPosition, |
277 | size=(500,300)): | |
278 | ||
33785d9f | 279 | dialog = ScrolledMessageDialog(parent, message, title, pos, size) |
d14a1e28 RD |
280 | result = DialogResults(dialog.ShowModal()) |
281 | dialog.Destroy() | |
282 | return result | |
283 | ||
284 | ||
285 | def fileDialog(parent=None, title='Open', directory='', filename='', wildcard='*.*', | |
b881fc78 RD |
286 | style=wx.OPEN | wx.MULTIPLE): |
287 | ||
288 | dialog = wx.FileDialog(parent, title, directory, filename, wildcard, style) | |
d14a1e28 RD |
289 | result = DialogResults(dialog.ShowModal()) |
290 | if result.accepted: | |
291 | result.paths = dialog.GetPaths() | |
292 | else: | |
293 | result.paths = None | |
294 | dialog.Destroy() | |
295 | return result | |
296 | ||
297 | ||
b881fc78 RD |
298 | ## openFileDialog and saveFileDialog are convenience functions |
299 | ## they represent the most common usages of the fileDialog | |
300 | ## with the most common style options | |
d14a1e28 | 301 | def openFileDialog(parent=None, title='Open', directory='', filename='', |
b881fc78 RD |
302 | wildcard='All Files (*.*)|*.*', |
303 | style=wx.OPEN | wx.MULTIPLE): | |
d14a1e28 RD |
304 | return fileDialog(parent, title, directory, filename, wildcard, style) |
305 | ||
306 | ||
307 | def saveFileDialog(parent=None, title='Save', directory='', filename='', | |
b881fc78 RD |
308 | wildcard='All Files (*.*)|*.*', |
309 | style=wx.SAVE | wx.HIDE_READONLY | wx.OVERWRITE_PROMPT): | |
d14a1e28 RD |
310 | return fileDialog(parent, title, directory, filename, wildcard, style) |
311 | ||
312 | ||
313 | def dirDialog(parent=None, message='Choose a directory', path='', style=0, | |
b881fc78 RD |
314 | pos=wx.DefaultPosition, size=wx.DefaultSize): |
315 | ||
316 | dialog = wx.DirDialog(parent, message, path, style, pos, size) | |
d14a1e28 RD |
317 | result = DialogResults(dialog.ShowModal()) |
318 | if result.accepted: | |
319 | result.path = dialog.GetPath() | |
320 | else: | |
321 | result.path = None | |
322 | dialog.Destroy() | |
323 | return result | |
324 | ||
325 | directoryDialog = dirDialog | |
326 | ||
327 | ||
b881fc78 RD |
328 | def singleChoiceDialog(parent=None, message='', title='', lst=[], |
329 | style=wx.OK | wx.CANCEL | wx.CENTRE): | |
19cc8ed9 | 330 | dialog = wx.SingleChoiceDialog(parent, message, title, list(lst), style | wx.DEFAULT_DIALOG_STYLE) |
d14a1e28 RD |
331 | result = DialogResults(dialog.ShowModal()) |
332 | result.selection = dialog.GetStringSelection() | |
333 | dialog.Destroy() | |
334 | return result | |
335 | ||
336 | ||
b881fc78 RD |
337 | def multipleChoiceDialog(parent=None, message='', title='', lst=[], pos=wx.DefaultPosition, |
338 | size=(200,200)): | |
339 | ||
33785d9f | 340 | dialog = MultipleChoiceDialog(parent, message, title, lst, pos, size) |
d14a1e28 RD |
341 | result = DialogResults(dialog.ShowModal()) |
342 | result.selection = dialog.GetValueString() | |
343 | dialog.Destroy() | |
344 | return result | |
345 | ||
346 | ||
347 | if __name__ == '__main__': | |
a5deb2fb RD |
348 | #import os |
349 | #print os.getpid() | |
350 | ||
b881fc78 | 351 | class MyApp(wx.App): |
d14a1e28 RD |
352 | |
353 | def OnInit(self): | |
19cc8ed9 | 354 | self.frame = frame = wx.Frame(None, -1, "Dialogs", size=(400, 240)) |
b881fc78 | 355 | panel = wx.Panel(frame, -1) |
d14a1e28 RD |
356 | self.panel = panel |
357 | ||
d14a1e28 RD |
358 | |
359 | dialogNames = [ | |
360 | 'alertDialog', | |
361 | 'colorDialog', | |
362 | 'directoryDialog', | |
363 | 'fileDialog', | |
364 | 'findDialog', | |
365 | 'fontDialog', | |
366 | 'messageDialog', | |
367 | 'multipleChoiceDialog', | |
368 | 'openFileDialog', | |
369 | 'saveFileDialog', | |
370 | 'scrolledMessageDialog', | |
371 | 'singleChoiceDialog', | |
372 | 'textEntryDialog', | |
373 | ] | |
a5deb2fb RD |
374 | |
375 | self.nameList = wx.ListBox(panel, -1, | |
376 | size=(130, 180), | |
377 | choices=dialogNames, | |
378 | style=wx.LB_SINGLE) | |
379 | self.Bind(wx.EVT_LISTBOX, self.OnNameListSelected, self.nameList) | |
d14a1e28 | 380 | |
b881fc78 | 381 | tstyle = wx.TE_RICH2 | wx.TE_PROCESS_TAB | wx.TE_MULTILINE |
a5deb2fb | 382 | self.text1 = wx.TextCtrl(panel, -1, size=(200, 180), style=tstyle) |
d14a1e28 | 383 | |
a5deb2fb RD |
384 | sizer = wx.BoxSizer(wx.HORIZONTAL) |
385 | sizer.Add(self.nameList, 0, wx.EXPAND|wx.ALL, 20) | |
386 | sizer.Add(self.text1, 1, wx.EXPAND|wx.ALL, 20) | |
387 | ||
388 | panel.SetSizer(sizer) | |
d14a1e28 | 389 | |
a5deb2fb RD |
390 | self.SetTopWindow(frame) |
391 | frame.Show(1) | |
d14a1e28 RD |
392 | return 1 |
393 | ||
a5deb2fb | 394 | |
d14a1e28 RD |
395 | def OnNameListSelected(self, evt): |
396 | import pprint | |
397 | sel = evt.GetString() | |
398 | result = None | |
399 | if sel == 'alertDialog': | |
400 | result = alertDialog(message='Danger Will Robinson') | |
401 | elif sel == 'colorDialog': | |
402 | result = colorDialog() | |
403 | elif sel == 'directoryDialog': | |
404 | result = directoryDialog() | |
405 | elif sel == 'fileDialog': | |
406 | wildcard = "JPG files (*.jpg;*.jpeg)|*.jpeg;*.JPG;*.JPEG;*.jpg|GIF files (*.gif)|*.GIF;*.gif|All Files (*.*)|*.*" | |
407 | result = fileDialog(None, 'Open', '', '', wildcard) | |
408 | elif sel == 'findDialog': | |
409 | result = findDialog() | |
410 | elif sel == 'fontDialog': | |
411 | result = fontDialog() | |
412 | elif sel == 'messageDialog': | |
413 | result = messageDialog(None, 'Hello from Python and wxPython!', | |
a5deb2fb RD |
414 | 'A Message Box', wx.OK | wx.ICON_INFORMATION) |
415 | #wx.YES_NO | wx.NO_DEFAULT | wx.CANCEL | wx.ICON_INFORMATION) | |
d14a1e28 RD |
416 | #result = messageDialog(None, 'message', 'title') |
417 | elif sel == 'multipleChoiceDialog': | |
418 | result = multipleChoiceDialog(None, "message", "title", ['one', 'two', 'three']) | |
419 | elif sel == 'openFileDialog': | |
420 | result = openFileDialog() | |
421 | elif sel == 'saveFileDialog': | |
422 | result = saveFileDialog() | |
423 | elif sel == 'scrolledMessageDialog': | |
424 | msg = "Can't find the file dialog.py" | |
425 | try: | |
426 | # read this source file and then display it | |
427 | import sys | |
428 | filename = sys.argv[-1] | |
429 | fp = open(filename) | |
430 | message = fp.read() | |
431 | fp.close() | |
432 | except: | |
433 | pass | |
434 | result = scrolledMessageDialog(None, message, filename) | |
435 | elif sel == 'singleChoiceDialog': | |
436 | result = singleChoiceDialog(None, "message", "title", ['one', 'two', 'three']) | |
437 | elif sel == 'textEntryDialog': | |
438 | result = textEntryDialog(None, "message", "title", "text") | |
439 | ||
440 | if result: | |
441 | #self.text1.SetValue(pprint.pformat(result.__dict__)) | |
442 | self.text1.SetValue(str(result)) | |
443 | ||
b881fc78 | 444 | app = MyApp(True) |
d14a1e28 | 445 | app.MainLoop() |
b881fc78 RD |
446 | |
447 |