]>
Commit | Line | Data |
---|---|---|
d14a1e28 RD |
1 | #---------------------------------------------------------------------------- |
2 | # Name: BrowseImage.py | |
3 | # Purpose: Display and Select Image Files | |
4 | # | |
fe45b493 | 5 | # Original Author: Lorne White |
d14a1e28 | 6 | # |
fe45b493 RD |
7 | # Version: 2.0 |
8 | # Date: June 16, 2007 | |
d14a1e28 RD |
9 | # Licence: wxWindows license |
10 | #---------------------------------------------------------------------------- | |
fe45b493 RD |
11 | # 2.0 Release - Bill Baxter (wbaxter@gmail.com) |
12 | # Date: June 16, 2007 | |
13 | # o Changed to use sizers instead of fixed placement. | |
14 | # o Made dialog resizeable | |
15 | # o Added a splitter between file list and view pane | |
16 | # o Made directory path editable | |
17 | # o Added an "up" button" to go to the parent dir | |
18 | # o Changed to show directories in file list | |
19 | # o Don't select images on double click any more | |
20 | # o Added a 'broken image' display for files that wx fails to identify | |
21 | # o Redesigned appearance -- using bitmap buttons now, and rearranged things | |
22 | # o Fixed display of masked gifs | |
23 | # o Fixed zooming logic to show shrunken images at correct aspect ratio | |
24 | # o Added different background modes for preview (white/grey/dark/checkered) | |
25 | # o Added framing modes for preview (no frame/box frame/tinted border) | |
26 | # | |
b881fc78 RD |
27 | #---------------------------------------------------------------------------- |
28 | # | |
29 | # 12/08/2003 - Jeff Grimmett (grimmtooth@softhome.net) | |
30 | # | |
31 | # o Updated for wx namespace | |
32 | # o Corrected a nasty bug or two - see comments below. | |
33 | # o There was a duplicate ImageView.DrawImage() method. Que? | |
34 | # | |
fe45b493 RD |
35 | #---------------------------------------------------------------------------- |
36 | # 1.0 Release - Lorne White | |
37 | # Date: January 29, 2002 | |
38 | # Create list of all available image file types | |
39 | # View "All Image" File Types as default filter | |
40 | # Sort the file list | |
41 | # Use newer "re" function for patterns | |
42 | # | |
1fded56b | 43 | |
d14a1e28 RD |
44 | #--------------------------------------------------------------------------- |
45 | ||
b881fc78 RD |
46 | import os |
47 | import sys | |
b881fc78 RD |
48 | import wx |
49 | ||
d14a1e28 RD |
50 | #--------------------------------------------------------------------------- |
51 | ||
fe45b493 RD |
52 | BAD_IMAGE = -1 |
53 | ID_WHITE_BG = wx.NewId() | |
54 | ID_BLACK_BG = wx.NewId() | |
55 | ID_GREY_BG = wx.NewId() | |
56 | ID_CHECK_BG = wx.NewId() | |
57 | ID_NO_FRAME = wx.NewId() | |
58 | ID_BOX_FRAME = wx.NewId() | |
59 | ID_CROP_FRAME = wx.NewId() | |
60 | ||
d14a1e28 RD |
61 | def ConvertBMP(file_nm): |
62 | if file_nm is None: | |
63 | return None | |
64 | ||
65 | fl_fld = os.path.splitext(file_nm) | |
66 | ext = fl_fld[1] | |
67 | ext = ext[1:].lower() | |
d14a1e28 | 68 | |
fe45b493 RD |
69 | # Don't try to create it directly because wx throws up |
70 | # an annoying messasge dialog if the type isn't supported. | |
71 | if wx.Image.CanRead(file_nm): | |
72 | image = wx.Image(file_nm, wx.BITMAP_TYPE_ANY) | |
73 | return image | |
74 | ||
75 | # BAD_IMAGE means a bad image, None just means no image (i.e. directory) | |
76 | return BAD_IMAGE | |
77 | ||
d14a1e28 | 78 | |
fe45b493 RD |
79 | def GetCheckeredBitmap(blocksize=8,ntiles=4,rgb0='\xFF', rgb1='\xCC'): |
80 | """Creates a square RGB checkered bitmap using the two specified colors. | |
b881fc78 | 81 | |
fe45b493 RD |
82 | Inputs: |
83 | - blocksize: the number of pixels in each solid color square | |
84 | - ntiles: the number of tiles along width and height. Each tile is 2x2 blocks. | |
85 | - rbg0,rgb1: the first and second colors, as 3-byte strings. | |
86 | If only 1 byte is provided, it is treated as a grey value. | |
87 | ||
88 | The bitmap returned will have width = height = blocksize*ntiles*2 | |
89 | """ | |
90 | size = blocksize*ntiles*2 | |
91 | ||
92 | if len(rgb0)==1: | |
93 | rgb0 = rgb0 * 3 | |
94 | if len(rgb1)==1: | |
95 | rgb1 = rgb1 * 3 | |
96 | ||
97 | strip0 = (rgb0*blocksize + rgb1*blocksize)*(ntiles*blocksize) | |
98 | strip1 = (rgb1*blocksize + rgb0*blocksize)*(ntiles*blocksize) | |
99 | band = strip0 + strip1 | |
100 | data = band * ntiles | |
101 | return wx.BitmapFromBuffer(size, size, data) | |
102 | ||
103 | def GetNamedBitmap(name): | |
104 | return IMG_CATALOG[name].getBitmap() | |
d14a1e28 | 105 | |
b881fc78 RD |
106 | |
107 | class ImageView(wx.Window): | |
fe45b493 RD |
108 | def __init__(self, parent, id=-1, pos=wx.DefaultPosition, size=wx.DefaultSize, |
109 | style=wx.BORDER_SUNKEN | |
110 | ): | |
111 | wx.Window.__init__(self, parent, id, pos, size, style=style) | |
112 | ||
d14a1e28 | 113 | self.image = None |
fe45b493 RD |
114 | |
115 | self.check_bmp = None | |
116 | self.check_dim_bmp = None | |
117 | ||
118 | # dark_bg is the brush/bitmap to use for painting in the whole background | |
119 | # lite_bg is the brush/bitmap/pen to use for painting the image rectangle | |
120 | self.dark_bg = None | |
121 | self.lite_bg = None | |
122 | ||
123 | self.border_mode = ID_CROP_FRAME | |
124 | self.SetBackgroundMode( ID_WHITE_BG ) | |
125 | self.SetBorderMode( ID_NO_FRAME ) | |
d14a1e28 | 126 | |
b881fc78 | 127 | # Changed API of wx uses tuples for size and pos now. |
b881fc78 | 128 | self.Bind(wx.EVT_PAINT, self.OnPaint) |
fe45b493 RD |
129 | self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground) |
130 | self.Bind(wx.EVT_SIZE, self.OnSize) | |
d14a1e28 | 131 | |
d14a1e28 RD |
132 | |
133 | def SetValue(self, file_nm): # display the selected file in the panel | |
134 | image = ConvertBMP(file_nm) | |
135 | self.image = image | |
136 | self.Refresh() | |
fe45b493 RD |
137 | |
138 | def SetBackgroundMode(self, mode): | |
139 | self.bg_mode = mode | |
140 | self._updateBGInfo() | |
d14a1e28 | 141 | |
fe45b493 RD |
142 | def _updateBGInfo(self): |
143 | bg = self.bg_mode | |
144 | border = self.border_mode | |
d14a1e28 | 145 | |
fe45b493 RD |
146 | self.dark_bg = None |
147 | self.lite_bg = None | |
148 | ||
149 | if border == ID_BOX_FRAME: | |
150 | self.lite_bg = wx.BLACK_PEN | |
151 | ||
152 | if bg == ID_WHITE_BG: | |
153 | if border == ID_CROP_FRAME: | |
154 | self.SetBackgroundColour('LIGHT GREY') | |
155 | self.lite_bg = wx.WHITE_BRUSH | |
156 | else: | |
157 | self.SetBackgroundColour('WHITE') | |
158 | ||
159 | elif bg == ID_GREY_BG: | |
160 | if border == ID_CROP_FRAME: | |
161 | self.SetBackgroundColour('GREY') | |
162 | self.lite_bg = wx.LIGHT_GREY_BRUSH | |
163 | else: | |
164 | self.SetBackgroundColour('LIGHT GREY') | |
165 | ||
166 | elif bg == ID_BLACK_BG: | |
167 | if border == ID_BOX_FRAME: | |
168 | self.lite_bg = wx.WHITE_PEN | |
169 | if border == ID_CROP_FRAME: | |
170 | self.SetBackgroundColour('GREY') | |
171 | self.lite_bg = wx.BLACK_BRUSH | |
172 | else: | |
173 | self.SetBackgroundColour('BLACK') | |
174 | ||
175 | else: | |
176 | if self.check_bmp is None: | |
177 | self.check_bmp = GetCheckeredBitmap() | |
178 | self.check_dim_bmp = GetCheckeredBitmap(rgb0='\x7F', rgb1='\x66') | |
179 | if border == ID_CROP_FRAME: | |
180 | self.dark_bg = self.check_dim_bmp | |
181 | self.lite_bg = self.check_bmp | |
182 | else: | |
183 | self.dark_bg = self.check_bmp | |
184 | ||
185 | self.Refresh() | |
186 | ||
187 | def SetBorderMode(self, mode): | |
188 | self.border_mode = mode | |
189 | self._updateBGInfo() | |
d14a1e28 | 190 | |
fe45b493 RD |
191 | def OnSize(self, event): |
192 | event.Skip() | |
193 | self.Refresh() | |
b881fc78 | 194 | |
fe45b493 RD |
195 | def OnPaint(self, event): |
196 | dc = wx.PaintDC(self) | |
197 | self.DrawImage(dc) | |
198 | ||
199 | def OnEraseBackground(self, evt): | |
200 | if self.bg_mode != ID_CHECK_BG: | |
201 | evt.Skip() | |
202 | return | |
203 | dc = evt.GetDC() | |
204 | if not dc: | |
205 | dc = wx.ClientDC(self) | |
206 | rect = self.GetUpdateRegion().GetBox() | |
207 | dc.SetClippingRect(rect) | |
208 | self.PaintBackground(dc, self.dark_bg) | |
209 | ||
210 | def PaintBackground(self, dc, painter, rect=None): | |
211 | if painter is None: | |
d14a1e28 | 212 | return |
fe45b493 RD |
213 | if rect is None: |
214 | pos = self.GetPosition() | |
215 | sz = self.GetSize() | |
216 | else: | |
217 | pos = rect.Position | |
218 | sz = rect.Size | |
219 | ||
220 | if type(painter)==wx.Brush: | |
221 | dc.SetPen(wx.TRANSPARENT_PEN) | |
222 | dc.SetBrush(painter) | |
223 | dc.DrawRectangle(pos.x,pos.y,sz.width,sz.height) | |
224 | elif type(painter)==wx.Pen: | |
225 | dc.SetPen(painter) | |
226 | dc.SetBrush(wx.TRANSPARENT_BRUSH) | |
227 | dc.DrawRectangle(pos.x-1,pos.y-1,sz.width+2,sz.height+2) | |
228 | else: | |
229 | self.TileBackground(dc, painter, pos.x,pos.y,sz.width,sz.height) | |
230 | ||
231 | ||
232 | def TileBackground(self, dc, bmp, x,y,w,h): | |
233 | """Tile bmp into the specified rectangle""" | |
234 | bw = bmp.GetWidth() | |
235 | bh = bmp.GetHeight() | |
236 | ||
237 | dc.SetClippingRegion(x,y,w,h) | |
238 | ||
239 | # adjust so 0,0 so we always match with a tiling starting at 0,0 | |
240 | dx = x % bw | |
241 | x = x - dx | |
242 | w = w + dx | |
d14a1e28 | 243 | |
fe45b493 RD |
244 | dy = y % bh |
245 | y = y - dy | |
246 | h = h + dy | |
247 | ||
248 | tx = x | |
249 | x2 = x+w | |
250 | y2 = y+h | |
251 | ||
252 | while tx < x2: | |
253 | ty = y | |
254 | while ty < y2: | |
255 | dc.DrawBitmap(bmp, tx, ty) | |
256 | ty += bh | |
257 | tx += bw | |
258 | ||
259 | def DrawImage(self, dc): | |
260 | ||
261 | if not hasattr(self,'image') or self.image is None: | |
0b0849b5 | 262 | return |
d14a1e28 | 263 | |
fe45b493 RD |
264 | wwidth,wheight = self.GetSize() |
265 | image = self.image | |
266 | bmp = None | |
267 | if image != BAD_IMAGE and image.IsOk(): | |
268 | iwidth = image.GetWidth() # dimensions of image file | |
269 | iheight = image.GetHeight() | |
270 | else: | |
271 | bmp = wx.ArtProvider.GetBitmap(wx.ART_MISSING_IMAGE, wx.ART_MESSAGE_BOX, (64,64)) | |
272 | iwidth = bmp.GetWidth() | |
273 | iheight = bmp.GetHeight() | |
d14a1e28 | 274 | |
fe45b493 | 275 | # squeeze iwidth x iheight image into window, preserving aspect ratio |
d14a1e28 | 276 | |
fe45b493 RD |
277 | xfactor = float(wwidth) / iwidth |
278 | yfactor = float(wheight) / iheight | |
d14a1e28 | 279 | |
fe45b493 RD |
280 | if xfactor < 1.0 and xfactor < yfactor: |
281 | scale = xfactor | |
282 | elif yfactor < 1.0 and yfactor < xfactor: | |
283 | scale = yfactor | |
284 | else: | |
285 | scale = 1.0 | |
d14a1e28 | 286 | |
fe45b493 RD |
287 | owidth = int(scale*iwidth) |
288 | oheight = int(scale*iheight) | |
d14a1e28 | 289 | |
fe45b493 RD |
290 | diffx = (wwidth - owidth)/2 # center calc |
291 | diffy = (wheight - oheight)/2 # center calc | |
292 | ||
293 | if not bmp: | |
294 | if owidth!=iwidth or oheight!=iheight: | |
295 | sc_image = sc_image = image.Scale(owidth,oheight) | |
296 | else: | |
297 | sc_image = image | |
298 | bmp = sc_image.ConvertToBitmap() | |
299 | ||
300 | if image != BAD_IMAGE and image.IsOk(): | |
301 | self.PaintBackground(dc, self.lite_bg, wx.Rect(diffx,diffy,owidth,oheight)) | |
302 | ||
303 | dc.DrawBitmap(bmp, diffx, diffy, useMask=True) # draw the image to window | |
304 | ||
305 | ||
306 | class ImagePanel(wx.Panel): | |
307 | def __init__(self, parent, id=-1, pos=wx.DefaultPosition, size=wx.DefaultSize, | |
308 | style=wx.NO_BORDER | |
309 | ): | |
310 | wx.Panel.__init__(self, parent, id, pos, size, style=style) | |
311 | ||
312 | vbox = wx.BoxSizer(wx.VERTICAL) | |
313 | self.SetSizer(vbox) | |
314 | ||
315 | self.view = ImageView(self) | |
316 | vbox.Add(self.view, 1, wx.GROW|wx.ALL, 0) | |
317 | ||
318 | hbox_ctrls = wx.BoxSizer(wx.HORIZONTAL) | |
319 | vbox.Add(hbox_ctrls, 0, wx.ALIGN_RIGHT|wx.TOP, 4) | |
320 | ||
321 | bmp = GetNamedBitmap('White') | |
322 | btn = wx.BitmapButton(self, ID_WHITE_BG, bmp, style=wx.BU_EXACTFIT) | |
323 | self.Bind(wx.EVT_BUTTON, self.OnSetImgBackground, btn) | |
324 | btn.SetToolTipString("Set background to white") | |
325 | hbox_ctrls.Add(btn, 0, wx.ALIGN_LEFT|wx.LEFT, 4) | |
d14a1e28 | 326 | |
fe45b493 RD |
327 | bmp = GetNamedBitmap('Grey') |
328 | btn = wx.BitmapButton(self, ID_GREY_BG, bmp, style=wx.BU_EXACTFIT) | |
329 | self.Bind(wx.EVT_BUTTON, self.OnSetImgBackground, btn) | |
330 | btn.SetToolTipString("Set background to grey") | |
331 | hbox_ctrls.Add(btn, 0, wx.ALIGN_LEFT|wx.LEFT, 4) | |
d14a1e28 | 332 | |
fe45b493 RD |
333 | bmp = GetNamedBitmap('Black') |
334 | btn = wx.BitmapButton(self, ID_BLACK_BG, bmp, style=wx.BU_EXACTFIT) | |
335 | self.Bind(wx.EVT_BUTTON, self.OnSetImgBackground, btn) | |
336 | btn.SetToolTipString("Set background to black") | |
337 | hbox_ctrls.Add(btn, 0, wx.ALIGN_LEFT|wx.LEFT, 4) | |
338 | ||
339 | bmp = GetNamedBitmap('Checked') | |
340 | btn = wx.BitmapButton(self, ID_CHECK_BG, bmp, style=wx.BU_EXACTFIT) | |
341 | self.Bind(wx.EVT_BUTTON, self.OnSetImgBackground, btn) | |
342 | btn.SetToolTipString("Set background to chekered pattern") | |
343 | hbox_ctrls.Add(btn, 0, wx.ALIGN_LEFT|wx.LEFT, 4) | |
344 | ||
345 | ||
346 | hbox_ctrls.AddSpacer(7) | |
347 | ||
348 | bmp = GetNamedBitmap('NoFrame') | |
349 | btn = wx.BitmapButton(self, ID_NO_FRAME, bmp, style=wx.BU_EXACTFIT) | |
350 | self.Bind(wx.EVT_BUTTON, self.OnSetBorderMode, btn) | |
351 | btn.SetToolTipString("No framing around image") | |
352 | hbox_ctrls.Add(btn, 0, wx.ALIGN_LEFT|wx.LEFT, 4) | |
353 | ||
354 | bmp = GetNamedBitmap('BoxFrame') | |
355 | btn = wx.BitmapButton(self, ID_BOX_FRAME, bmp, style=wx.BU_EXACTFIT) | |
356 | self.Bind(wx.EVT_BUTTON, self.OnSetBorderMode, btn) | |
357 | btn.SetToolTipString("Frame image with a box") | |
358 | hbox_ctrls.Add(btn, 0, wx.ALIGN_LEFT|wx.LEFT, 4) | |
359 | ||
360 | bmp = GetNamedBitmap('CropFrame') | |
361 | btn = wx.BitmapButton(self, ID_CROP_FRAME, bmp, style=wx.BU_EXACTFIT|wx.BORDER_SIMPLE) | |
362 | self.Bind(wx.EVT_BUTTON, self.OnSetBorderMode, btn) | |
363 | btn.SetToolTipString("Frame image with a dimmed background") | |
364 | hbox_ctrls.Add(btn, 0, wx.ALIGN_LEFT|wx.LEFT, 4) | |
365 | ||
366 | ||
367 | def SetValue(self, file_nm): # display the selected file in the panel | |
368 | self.view.SetValue(file_nm) | |
369 | ||
370 | def SetBackgroundMode(self, mode): | |
371 | self.view.SetBackgroundMode(mode) | |
372 | ||
373 | def SetBorderMode(self, mode): | |
374 | self.view.SetBorderMode(mode) | |
375 | ||
376 | def OnSetImgBackground(self, event): | |
377 | mode = event.GetId() | |
378 | self.SetBackgroundMode(mode) | |
379 | ||
380 | def OnSetBorderMode(self, event): | |
381 | mode = event.GetId() | |
382 | self.SetBorderMode(mode) | |
383 | ||
384 | ||
385 | ||
386 | class ImageDialog(wx.Dialog): | |
387 | def __init__(self, parent, set_dir = None): | |
388 | wx.Dialog.__init__(self, parent, -1, "Image Browser", wx.DefaultPosition, (400, 400),style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER) | |
d14a1e28 RD |
389 | |
390 | self.set_dir = os.getcwd() | |
391 | self.set_file = None | |
392 | ||
393 | if set_dir != None: | |
394 | if os.path.exists(set_dir): # set to working directory if nothing set | |
395 | self.set_dir = set_dir | |
396 | ||
fe45b493 RD |
397 | vbox_top = wx.BoxSizer(wx.VERTICAL) |
398 | self.SetSizer(vbox_top) | |
399 | ||
400 | hbox_loc = wx.BoxSizer(wx.HORIZONTAL) | |
401 | vbox_top.Add(hbox_loc, 0, wx.GROW|wx.ALIGN_LEFT|wx.ALL, 0) | |
d14a1e28 | 402 | |
fe45b493 RD |
403 | loc_label = wx.StaticText( self, -1, "Folder:") |
404 | hbox_loc.Add(loc_label, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL|wx.ADJUST_MINSIZE, 5) | |
d14a1e28 | 405 | |
fe45b493 RD |
406 | self.dir = wx.TextCtrl( self, -1, self.set_dir, style=wx.TE_RICH|wx.TE_PROCESS_ENTER) |
407 | self.Bind(wx.EVT_TEXT_ENTER, self.OnDirectoryTextSet, self.dir) | |
408 | hbox_loc.Add(self.dir, 1, wx.GROW|wx.ALIGN_LEFT|wx.ALL, 5) | |
d14a1e28 | 409 | |
fe45b493 RD |
410 | up_bmp = wx.ArtProvider.GetBitmap(wx.ART_GO_DIR_UP, wx.ART_BUTTON, (16,16)) |
411 | btn = wx.BitmapButton(self, -1, up_bmp) | |
412 | btn.SetHelpText("Up one level") | |
413 | btn.SetToolTipString("Up one level") | |
414 | self.Bind(wx.EVT_BUTTON, self.OnUpDirectory, btn) | |
415 | hbox_loc.Add(btn, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 2) | |
416 | ||
417 | folder_bmp = wx.ArtProvider.GetBitmap(wx.ART_FOLDER_OPEN, wx.ART_BUTTON, (16,16)) | |
418 | btn = wx.BitmapButton(self, -1, folder_bmp) | |
419 | btn.SetHelpText("Browse for a &folder...") | |
420 | btn.SetToolTipString("Browse for a folder...") | |
421 | self.Bind(wx.EVT_BUTTON, self.OnChooseDirectory, btn) | |
422 | hbox_loc.Add(btn, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5) | |
423 | ||
424 | hbox_nav = wx.BoxSizer(wx.HORIZONTAL) | |
425 | vbox_top.Add(hbox_nav, 0, wx.ALIGN_LEFT|wx.ALL, 0) | |
426 | ||
427 | ||
428 | label = wx.StaticText( self, -1, "Files of type:") | |
429 | hbox_nav.Add(label, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 5) | |
d14a1e28 RD |
430 | |
431 | self.fl_ext = '*.bmp' # initial setting for file filtering | |
432 | self.GetFiles() # get the file list | |
433 | ||
fe45b493 RD |
434 | self.fl_ext_types = ( |
435 | # display, filter | |
436 | ("All supported formats", "All"), | |
437 | ("BMP (*.bmp)", "*.bmp"), | |
438 | ("GIF (*.gif)", "*.gif"), | |
439 | ("PNG (*.png)", "*.png"), | |
440 | ("JPEG (*.jpg)", "*.jpg"), | |
441 | ("ICO (*.ico)", "*.ico"), | |
442 | ("PNM (*.pnm)", "*.pnm"), | |
443 | ("PCX (*.pcx)", "*.pcx"), | |
444 | ("TIFF (*.tif)", "*.tif"), | |
445 | ("All Files", "*.*"), | |
446 | ) | |
447 | self.set_type,self.fl_ext = self.fl_ext_types[0] # initial file filter setting | |
448 | self.fl_types = [ x[0] for x in self.fl_ext_types ] | |
449 | self.sel_type = wx.ComboBox( self, -1, self.set_type, | |
450 | wx.DefaultPosition, wx.DefaultSize, self.fl_types, | |
451 | wx.CB_DROPDOWN ) | |
452 | # after this we don't care about the order any more | |
453 | self.fl_ext_types = dict(self.fl_ext_types) | |
454 | ||
455 | self.Bind(wx.EVT_COMBOBOX, self.OnSetType, self.sel_type) | |
456 | hbox_nav.Add(self.sel_type, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) | |
457 | ||
458 | splitter = wx.SplitterWindow( self, -1, wx.DefaultPosition, wx.Size(100, 100), 0 ) | |
459 | splitter.SetMinimumPaneSize(100) | |
460 | ||
461 | split_left = wx.Panel( splitter, -1, wx.DefaultPosition, wx.DefaultSize, | |
462 | wx.NO_BORDER|wx.TAB_TRAVERSAL ) | |
463 | vbox_left = wx.BoxSizer(wx.VERTICAL) | |
464 | split_left.SetSizer(vbox_left) | |
d14a1e28 | 465 | |
fe45b493 RD |
466 | |
467 | self.tb = tb = wx.ListBox( split_left, -1, wx.DefaultPosition, wx.DefaultSize, | |
468 | self.fl_list, wx.LB_SINGLE ) | |
b881fc78 RD |
469 | self.Bind(wx.EVT_LISTBOX, self.OnListClick, tb) |
470 | self.Bind(wx.EVT_LISTBOX_DCLICK, self.OnListDClick, tb) | |
fe45b493 | 471 | vbox_left.Add(self.tb, 1, wx.GROW|wx.ALL, 0) |
d14a1e28 | 472 | |
b881fc78 | 473 | width, height = self.tb.GetSize() |
d14a1e28 | 474 | |
fe45b493 RD |
475 | split_right = wx.Panel( splitter, -1, wx.DefaultPosition, wx.DefaultSize, |
476 | wx.NO_BORDER|wx.TAB_TRAVERSAL ) | |
477 | vbox_right = wx.BoxSizer(wx.VERTICAL) | |
478 | split_right.SetSizer(vbox_right) | |
d14a1e28 | 479 | |
fe45b493 RD |
480 | self.image_view = ImagePanel( split_right ) |
481 | vbox_right.Add(self.image_view, 1, wx.GROW|wx.ALL, 0) | |
d14a1e28 | 482 | |
fe45b493 RD |
483 | splitter.SplitVertically(split_left, split_right, 150) |
484 | vbox_top.Add(splitter, 1, wx.GROW|wx.ALL, 5) | |
d14a1e28 | 485 | |
fe45b493 RD |
486 | hbox_btns = wx.BoxSizer(wx.HORIZONTAL) |
487 | vbox_top.Add(hbox_btns, 0, wx.ALIGN_RIGHT|wx.ALL, 5) | |
d14a1e28 | 488 | |
fe45b493 RD |
489 | ok_btn = wx.Button( self, wx.ID_OPEN, "", wx.DefaultPosition, wx.DefaultSize, 0 ) |
490 | self.Bind(wx.EVT_BUTTON, self.OnOk, ok_btn) | |
491 | #ok_btn.SetDefault() | |
492 | hbox_btns.Add(ok_btn, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) | |
493 | ||
494 | cancel_btn = wx.Button( self, wx.ID_CANCEL, "", | |
495 | wx.DefaultPosition, wx.DefaultSize, 0 ) | |
496 | hbox_btns.Add(cancel_btn, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) | |
d14a1e28 RD |
497 | |
498 | self.ResetFiles() | |
499 | ||
fe45b493 | 500 | |
d14a1e28 RD |
501 | def GetFiles(self): # get the file list using directory and extension values |
502 | if self.fl_ext == "All": | |
503 | all_files = [] | |
b881fc78 | 504 | |
d14a1e28 RD |
505 | for ftypes in self.fl_types[1:-1]: # get list of all available image types |
506 | filter = self.fl_ext_types[ftypes] | |
b881fc78 | 507 | #print "filter = ", filter |
d14a1e28 RD |
508 | self.fl_val = FindFiles(self, self.set_dir, filter) |
509 | all_files = all_files + self.fl_val.files # add to list of files | |
b881fc78 | 510 | |
d14a1e28 RD |
511 | self.fl_list = all_files |
512 | else: | |
513 | self.fl_val = FindFiles(self, self.set_dir, self.fl_ext) | |
514 | self.fl_list = self.fl_val.files | |
515 | ||
fe45b493 | 516 | |
d14a1e28 | 517 | self.fl_list.sort() # sort the file list |
fe45b493 RD |
518 | # prepend the directories |
519 | self.fl_ndirs = len(self.fl_val.dirs) | |
520 | self.fl_list = sorted(self.fl_val.dirs) + self.fl_list | |
d14a1e28 RD |
521 | |
522 | def DisplayDir(self): # display the working directory | |
0c8f2860 | 523 | if self.dir: |
fe45b493 RD |
524 | ipt = self.dir.GetInsertionPoint() |
525 | self.dir.SetValue(self.set_dir) | |
526 | self.dir.SetInsertionPoint(ipt) | |
d14a1e28 RD |
527 | |
528 | def OnSetType(self, event): | |
529 | val = event.GetString() # get file type value | |
530 | self.fl_ext = self.fl_ext_types[val] | |
531 | self.ResetFiles() | |
532 | ||
533 | def OnListDClick(self, event): | |
fe45b493 | 534 | self.OnOk('dclick') |
d14a1e28 RD |
535 | |
536 | def OnListClick(self, event): | |
537 | val = event.GetSelection() | |
538 | self.SetListValue(val) | |
539 | ||
540 | def SetListValue(self, val): | |
541 | file_nm = self.fl_list[val] | |
542 | self.set_file = file_val = os.path.join(self.set_dir, file_nm) | |
fe45b493 RD |
543 | if val>=self.fl_ndirs: |
544 | self.image_view.SetValue(file_val) | |
545 | else: | |
546 | self.image_view.SetValue(None) | |
d14a1e28 | 547 | |
fe45b493 RD |
548 | def OnDirectoryTextSet(self,event): |
549 | event.Skip() | |
550 | path = event.GetString() | |
551 | if os.path.isdir(path): | |
552 | self.set_dir = path | |
553 | self.ResetFiles() | |
554 | return | |
555 | ||
556 | if os.path.isfile(path): | |
557 | dname,fname = os.path.split(path) | |
558 | if os.path.isdir(dname): | |
559 | self.ResetFiles() | |
560 | # try to select fname in list | |
561 | try: | |
562 | idx = self.fl_list.index(fname) | |
563 | self.tb.SetSelection(idx) | |
564 | self.SetListValue(idx) | |
565 | return | |
566 | except ValueError: | |
567 | pass | |
568 | ||
569 | wx.Bell() | |
570 | ||
571 | def OnUpDirectory(self, event): | |
572 | sdir = os.path.split(self.set_dir)[0] | |
573 | self.set_dir = sdir | |
574 | self.ResetFiles() | |
575 | ||
576 | def OnChooseDirectory(self, event): # set the new directory | |
b881fc78 | 577 | dlg = wx.DirDialog(self) |
d14a1e28 | 578 | dlg.SetPath(self.set_dir) |
b881fc78 RD |
579 | |
580 | if dlg.ShowModal() == wx.ID_OK: | |
d14a1e28 RD |
581 | self.set_dir = dlg.GetPath() |
582 | self.ResetFiles() | |
b881fc78 | 583 | |
d14a1e28 RD |
584 | dlg.Destroy() |
585 | ||
586 | def ResetFiles(self): # refresh the display with files and initial image | |
587 | self.DisplayDir() | |
588 | self.GetFiles() | |
b881fc78 RD |
589 | |
590 | # Changed 12/8/03 jmg | |
591 | # | |
592 | # o Clear listbox first | |
593 | # o THEN check to see if there are any valid files of the selected | |
594 | # type, | |
595 | # o THEN if we have any files to display, set the listbox up, | |
596 | # | |
597 | # OTHERWISE | |
598 | # | |
599 | # o Leave it cleared | |
600 | # o Clear the image viewer. | |
601 | # | |
602 | # This avoids a nasty assert error. | |
603 | # | |
604 | self.tb.Clear() | |
605 | ||
606 | if len(self.fl_list): | |
607 | self.tb.Set(self.fl_list) | |
608 | ||
fe45b493 RD |
609 | for idir in xrange(self.fl_ndirs): |
610 | d = self.fl_list[idir] | |
611 | # mark directories as 'True' with client data | |
612 | self.tb.SetClientData(idir, True) | |
613 | self.tb.SetString(idir,'['+d+']') | |
614 | ||
b881fc78 RD |
615 | try: |
616 | self.tb.SetSelection(0) | |
617 | self.SetListValue(0) | |
618 | except: | |
619 | self.image_view.SetValue(None) | |
620 | else: | |
d14a1e28 RD |
621 | self.image_view.SetValue(None) |
622 | ||
623 | def GetFile(self): | |
624 | return self.set_file | |
625 | ||
626 | def GetDirectory(self): | |
627 | return self.set_dir | |
628 | ||
629 | def OnCancel(self, event): | |
630 | self.result = None | |
b881fc78 | 631 | self.EndModal(wx.ID_CANCEL) |
d14a1e28 RD |
632 | |
633 | def OnOk(self, event): | |
fe45b493 RD |
634 | if os.path.isdir(self.set_file): |
635 | sdir = os.path.split(self.set_file) | |
636 | ||
637 | #os.path.normapth? | |
638 | if sdir and sdir[-1]=='..': | |
639 | sdir = os.path.split(sdir[0])[0] | |
640 | sdir = os.path.split(sdir) | |
641 | self.set_dir = os.path.join(*sdir) | |
642 | self.set_file = None | |
643 | self.ResetFiles() | |
644 | elif event != 'dclick': | |
645 | self.result = self.set_file | |
646 | self.EndModal(wx.ID_OK) | |
b881fc78 | 647 | |
b881fc78 | 648 | |
d14a1e28 RD |
649 | |
650 | class FindFiles: | |
fe45b493 | 651 | def __init__(self, parent, dir, mask, with_dirs=True): |
d14a1e28 RD |
652 | filelist = [] |
653 | dirlist = [".."] | |
654 | self.dir = dir | |
655 | self.file = "" | |
656 | mask = mask.upper() | |
657 | pattern = self.MakeRegex(mask) | |
b881fc78 | 658 | |
d14a1e28 RD |
659 | for i in os.listdir(dir): |
660 | if i == "." or i == "..": | |
661 | continue | |
b881fc78 | 662 | |
d14a1e28 | 663 | path = os.path.join(dir, i) |
fe45b493 RD |
664 | |
665 | if os.path.isdir(path): | |
666 | dirlist.append(i) | |
667 | continue | |
668 | ||
d14a1e28 RD |
669 | path = path.upper() |
670 | value = i.upper() | |
671 | ||
672 | if pattern.match(value) != None: | |
673 | filelist.append(i) | |
674 | ||
fe45b493 | 675 | |
04c4117b | 676 | self.files = filelist |
fe45b493 RD |
677 | if with_dirs: |
678 | self.dirs = dirlist | |
d14a1e28 RD |
679 | |
680 | def MakeRegex(self, pattern): | |
681 | import re | |
682 | f = "" # Set up a regex for file names | |
b881fc78 | 683 | |
d14a1e28 RD |
684 | for ch in pattern: |
685 | if ch == "*": | |
686 | f = f + ".*" | |
687 | elif ch == ".": | |
688 | f = f + "\." | |
689 | elif ch == "?": | |
690 | f = f + "." | |
691 | else: | |
692 | f = f + ch | |
b881fc78 | 693 | |
d14a1e28 RD |
694 | return re.compile(f+'$') |
695 | ||
696 | def StripExt(self, file_nm): | |
697 | fl_fld = os.path.splitext(file_nm) | |
698 | fl_name = fl_fld[0] | |
699 | ext = fl_fld[1] | |
700 | return ext[1:] | |
fe45b493 RD |
701 | |
702 | ||
703 | #---------------------------------------------------------------------- | |
704 | # This part of the file was generated by C:\Python25\Scripts\img2py | |
705 | # then edited slightly. | |
706 | ||
707 | import cStringIO, zlib | |
708 | ||
709 | ||
710 | IMG_CATALOG = {} | |
711 | ||
712 | class ImageClass: pass | |
713 | ||
714 | def getWhiteData(): | |
715 | return zlib.decompress( | |
716 | 'x\xda\xeb\x0c\xf0s\xe7\xe5\x92\xe2b``\xe0\xf5\xf4p\t\x02\xd2< \xcc\xc1\x04$\ | |
717 | o\x8a\x9f\xde\x00\xa4\x98\x8b\x9d<C888n?\xf4\x7f\x00\xe4*z\xba8\x86HLMNP`202\ | |
718 | 0\xf8\xf3\xff\xbf\xfc|.77\xb5$\x1f\xa9P\x979J\x8b\x18\x18N\\d\x16\t\xfd\xfc\ | |
719 | \xce\x07\xa8\x98\xc1\xd3\xd5\xcfe\x9dSB\x13\x00\xcc1\x1b\xb3' ) | |
720 | ||
721 | def getWhiteBitmap(): | |
722 | return wx.BitmapFromImage(getWhiteImage()) | |
723 | ||
724 | def getWhiteImage(): | |
725 | stream = cStringIO.StringIO(getWhiteData()) | |
726 | return wx.ImageFromStream(stream) | |
727 | ||
728 | IMG_CATALOG['White'] = ImageClass() | |
729 | IMG_CATALOG['White'].getData = getWhiteData | |
730 | IMG_CATALOG['White'].getImage = getWhiteImage | |
731 | IMG_CATALOG['White'].getBitmap = getWhiteBitmap | |
732 | ||
733 | ||
734 | #---------------------------------------------------------------------- | |
735 | def getGreyData(): | |
736 | return zlib.decompress( | |
737 | 'x\xda\xeb\x0c\xf0s\xe7\xe5\x92\xe2b``\xe0\xf5\xf4p\t\x02\xd2< \xcc\xc1\x04$\ | |
738 | o\x8a\x9f\xde\x00\xa4\x98\x8b\x9d<C888n?\xf4\x7f\x00\xe4*y\xba8\x86HLMNP`202\ | |
739 | 0\x98cY\xcc\xd6\xcf%,,\xac\x96\xe4#\x15\xea2Gi\x11\x03\xc3\xb6\xc7\xcc":A7%\ | |
740 | \x80\xaa\x19<]\xfd\\\xd69%4\x01\x00{m\x18s' ) | |
741 | ||
742 | def getGreyBitmap(): | |
743 | return wx.BitmapFromImage(getGreyImage()) | |
744 | ||
745 | def getGreyImage(): | |
746 | stream = cStringIO.StringIO(getGreyData()) | |
747 | return wx.ImageFromStream(stream) | |
748 | ||
749 | IMG_CATALOG['Grey'] = ImageClass() | |
750 | IMG_CATALOG['Grey'].getData = getGreyData | |
751 | IMG_CATALOG['Grey'].getImage = getGreyImage | |
752 | IMG_CATALOG['Grey'].getBitmap = getGreyBitmap | |
753 | ||
754 | ||
755 | #---------------------------------------------------------------------- | |
756 | def getBlackData(): | |
757 | return zlib.decompress( | |
758 | 'x\xda\xeb\x0c\xf0s\xe7\xe5\x92\xe2b``\xe0\xf5\xf4p\t\x02\xd2< \xcc\xc1\x04$\ | |
759 | o\x8a\x9f\xde\x00\xa4\x98\x8b\x9d<C888n?\xf4\x7f\x00\xe4\xf2y\xba8\x86HLMN\ | |
760 | \x90`u\x16e``\xdc\xc3\xc0h\\3\xdb\x0c(\xc3\xe0\xe9\xea\xe7\xb2\xce)\xa1\t\ | |
761 | \x00\xb6`\x12\x08' ) | |
762 | ||
763 | def getBlackBitmap(): | |
764 | return wx.BitmapFromImage(getBlackImage()) | |
765 | ||
766 | def getBlackImage(): | |
767 | stream = cStringIO.StringIO(getBlackData()) | |
768 | return wx.ImageFromStream(stream) | |
769 | ||
770 | IMG_CATALOG['Black'] = ImageClass() | |
771 | IMG_CATALOG['Black'].getData = getBlackData | |
772 | IMG_CATALOG['Black'].getImage = getBlackImage | |
773 | IMG_CATALOG['Black'].getBitmap = getBlackBitmap | |
774 | ||
775 | ||
776 | #---------------------------------------------------------------------- | |
777 | def getCheckedData(): | |
778 | return zlib.decompress( | |
779 | 'x\xda\xeb\x0c\xf0s\xe7\xe5\x92\xe2b``\xe0\xf5\xf4p\t\x02\xd2< \xcc\xc1\x04$\ | |
780 | o\x8a\x9f\xde\x00\xa4\x98\x8b\x9d<C888n?\xf4\x7f\x00\xe4\x1az\xba8\x86HLMNP`\ | |
781 | 2020\x98cY\xcc\x16y\xe2\xc6\r\tWVeeaC\xb5\x8b\x91\x82\xdc\xccm\xde\xe7\xe7\ | |
782 | \xd9Zo\xc8S\xf2\x12\x0cd`\xd0\xd8\xc5&\xf6\xeb\xd5\xe5t\xa0f\x06OW?\x97uN\tM\ | |
783 | \x00qL\x1f\x94' ) | |
784 | ||
785 | def getCheckedBitmap(): | |
786 | return wx.BitmapFromImage(getCheckedImage()) | |
787 | ||
788 | def getCheckedImage(): | |
789 | stream = cStringIO.StringIO(getCheckedData()) | |
790 | return wx.ImageFromStream(stream) | |
791 | ||
792 | IMG_CATALOG['Checked'] = ImageClass() | |
793 | IMG_CATALOG['Checked'].getData = getCheckedData | |
794 | IMG_CATALOG['Checked'].getImage = getCheckedImage | |
795 | IMG_CATALOG['Checked'].getBitmap = getCheckedBitmap | |
796 | ||
797 | ||
798 | #---------------------------------------------------------------------- | |
799 | def getNoFrameData(): | |
800 | return zlib.decompress( | |
801 | "x\xda\xeb\x0c\xf0s\xe7\xe5\x92\xe2b``\xe0\xf5\xf4p\t\x02\xd2< \xcc\xc1\x04$\ | |
802 | o\x8a\x9f\xde\x00\xa4\x98\x8b\x9d<C888n?\xf4\x7f\x00\xe4\x9ay\xba8\x86HL]\ | |
803 | \xdb\xef\xc8\xc5\xa0 \xc04\xf7\xc5\xff\xf8m\xd1\x01.\xba\x93\x9e'\x86\xac\ | |
804 | \x14P\xb9\xb9O\xf0\x82\xd62\x0e\xa6\x06\xf9e\x8f;Yg\xc5F'\xd7g]\xf2\xadd;=\ | |
805 | \x87S\xfe\xf3\xc7\x15\x8f\x80&0x\xba\xfa\xb9\xacsJh\x02\x00\x07\xac't" ) | |
806 | ||
807 | def getNoFrameBitmap(): | |
808 | return wx.BitmapFromImage(getNoFrameImage()) | |
809 | ||
810 | def getNoFrameImage(): | |
811 | stream = cStringIO.StringIO(getNoFrameData()) | |
812 | return wx.ImageFromStream(stream) | |
813 | ||
814 | IMG_CATALOG['NoFrame'] = ImageClass() | |
815 | IMG_CATALOG['NoFrame'].getData = getNoFrameData | |
816 | IMG_CATALOG['NoFrame'].getImage = getNoFrameImage | |
817 | IMG_CATALOG['NoFrame'].getBitmap = getNoFrameBitmap | |
818 | ||
819 | ||
820 | #---------------------------------------------------------------------- | |
821 | def getBoxFrameData(): | |
822 | return zlib.decompress( | |
823 | "x\xda\xeb\x0c\xf0s\xe7\xe5\x92\xe2b``\xe0\xf5\xf4p\t\x02\xd2< \xcc\xc1\x04$\ | |
824 | o\x8a\x9f\xde\x00\xa4\x98\x8b\x9d<C888n?\xf4\x7f\x00\xe4:{\xba8\x86HL\x9d\ | |
825 | \xdbw\x91\x8bA\x81\x83\xb9\xfc\xd2\xff\xff\x9bl9\x02\x15\xd5\xdefnJ\xf6\xcb\ | |
826 | \xe2\xf0|\x17'\x980W\xed\xaa\xaf\xe0\xcd:\xfd\xaa\xef\xec!/\xda.]ggaH\xfcT\ | |
827 | \xbaRI\xca_\xef\xe6\x97\xf5\x9c;\xa2\x15\xfe\xbe^S\xbe\th\x1c\x83\xa7\xab\ | |
828 | \x9f\xcb:\xa7\x84&\x00k\xdd.\x08" ) | |
829 | ||
830 | def getBoxFrameBitmap(): | |
831 | return wx.BitmapFromImage(getBoxFrameImage()) | |
832 | ||
833 | def getBoxFrameImage(): | |
834 | stream = cStringIO.StringIO(getBoxFrameData()) | |
835 | return wx.ImageFromStream(stream) | |
836 | ||
837 | IMG_CATALOG['BoxFrame'] = ImageClass() | |
838 | IMG_CATALOG['BoxFrame'].getData = getBoxFrameData | |
839 | IMG_CATALOG['BoxFrame'].getImage = getBoxFrameImage | |
840 | IMG_CATALOG['BoxFrame'].getBitmap = getBoxFrameBitmap | |
841 | ||
842 | ||
843 | #---------------------------------------------------------------------- | |
844 | def getCropFrameData(): | |
845 | return zlib.decompress( | |
846 | "x\xda\xeb\x0c\xf0s\xe7\xe5\x92\xe2b``\xe0\xf5\xf4p\t\x02\xd2< \xcc\xc1\x04$\ | |
847 | o\x8a\x9f\xde\x00\xa4\x98\x8b\x9d<C888n?\xf4\x7f\x00\xe4zz\xba8\x86HL\xdd;\ | |
848 | \xc1\x90\xeb\x80\x03\x07K\xba\xf3\xbf\xd5\xfe\x17\xc5g;\xedh\x16i\xcf\xdc\ | |
849 | \xd4z\xc2\xa8G\x81GIA\x89\xafew\xbc\xf0e\x8e]\xd7\xd3\xd2\x1aT\x16\xacj8\xf3\ | |
850 | '\xa1\xca\xf9\xad\x85\xe3\xa4_1\xe7\xef~~\xcd\xedV\xc9\xf0\x7f#\xbftm\xb5\ | |
851 | \x8d\t\x03\xc8TW?\x97uN\tM\x00\x9c@0\x82" ) | |
852 | ||
853 | def getCropFrameBitmap(): | |
854 | return wx.BitmapFromImage(getCropFrameImage()) | |
855 | ||
856 | def getCropFrameImage(): | |
857 | stream = cStringIO.StringIO(getCropFrameData()) | |
858 | return wx.ImageFromStream(stream) | |
859 | ||
860 | IMG_CATALOG['CropFrame'] = ImageClass() | |
861 | IMG_CATALOG['CropFrame'].getData = getCropFrameData | |
862 | IMG_CATALOG['CropFrame'].getImage = getCropFrameImage | |
863 | IMG_CATALOG['CropFrame'].getBitmap = getCropFrameBitmap |