Commit 56f7a1283c671a4c09f79436ae308dde88cfb46a
1 parent
295c16a0
Exists in
master
and in
67 other branches
Adapted camera positions to coronal and sagital cases, and added the option to flip image
Showing
11 changed files
with
130 additions
and
59 deletions
Show diff stats
invesalius/constants.py
... | ... | @@ -109,11 +109,11 @@ IMPORT_INTERVAL = [_("Keep all slices"), _("Skip 1 for each 2 slices"), |
109 | 109 | AXIAL_SLICE_CAM_POSITION = {"AXIAL":(0, 0, 1), "CORONAL":(0, -1, 0), "SAGITAL":(1, 0, 0)} |
110 | 110 | AXIAL_SLICE_CAM_VIEW_UP = {"AXIAL":(0, 1, 0), "CORONAL":(0, 0, 1), "SAGITAL":(0, 0, 1)} |
111 | 111 | |
112 | -SAGITAL_SLICE_CAM_POSITION = {"AXIAL":(0, 1, 0), "CORONAL":(1, 0, 0), "SAGITAL":(0, 0, -1)} | |
113 | -SAGITAL_SLICE_CAM_VIEW_UP = {"AXIAL":(-1, 0, 0), "CORONAL":(0, 1, 0), "SAGITAL":(0, 1, 0)} | |
112 | +SAGITAL_SLICE_CAM_POSITION = {"AXIAL":(0, 0, 1), "CORONAL":(0, 1, 0), "SAGITAL":(-1, 0, 0)} | |
113 | +SAGITAL_SLICE_CAM_VIEW_UP = {"AXIAL":(0, -1, 0), "CORONAL":(0, 0, 1), "SAGITAL":(0, 0, 1)} | |
114 | 114 | |
115 | -CORONAL_SLICE_CAM_POSITION = {"AXIAL":(0, 1, 0), "CORONAL":(0, 0, 1), "SAGITAL":(1, 0, 0)} | |
116 | -CORONAL_SLICE_CAM_VIEW_UP = {"AXIAL":(0, 0, -1), "CORONAL":(0, 1, 0), "SAGITAL":(0, 1, 0)} | |
115 | +CORONAL_SLICE_CAM_POSITION = {"AXIAL":(0, 0, 1), "CORONAL":(0, 1, 0), "SAGITAL":(-1, 0, 0)} | |
116 | +CORONAL_SLICE_CAM_VIEW_UP = {"AXIAL":(0, -1, 0), "CORONAL":(0, 0, 1), "SAGITAL":(0, 0, 1)} | |
117 | 117 | |
118 | 118 | SLICE_POSITION = {AXIAL:[AXIAL_SLICE_CAM_VIEW_UP, AXIAL_SLICE_CAM_POSITION], |
119 | 119 | SAGITAL:[SAGITAL_SLICE_CAM_VIEW_UP, SAGITAL_SLICE_CAM_POSITION], |
... | ... | @@ -457,6 +457,9 @@ ID_DICOM_NETWORK] = [wx.NewId() for number in range(14)] |
457 | 457 | ID_ABOUT = wx.NewId() |
458 | 458 | ID_START = wx.NewId() |
459 | 459 | |
460 | +ID_FLIP_X = wx.NewId() | |
461 | +ID_FLIP_Y = wx.NewId() | |
462 | +ID_FLIP_Z = wx.NewId() | |
460 | 463 | #--------------------------------------------------------- |
461 | 464 | STATE_DEFAULT = 1000 |
462 | 465 | STATE_WL = 1001 | ... | ... |
invesalius/control.py
... | ... | @@ -432,6 +432,7 @@ class Controller(): |
432 | 432 | header['glmax']) |
433 | 433 | proj.window = proj.threshold_range[1] - proj.threshold_range[0] |
434 | 434 | proj.level = (0.5 * (proj.threshold_range[1] + proj.threshold_range[0])) |
435 | + proj.spacing = header['pixdim'][1:4] | |
435 | 436 | |
436 | 437 | self.Slice = sl.Slice() |
437 | 438 | self.Slice.matrix = matrix |
... | ... | @@ -495,8 +496,11 @@ class Controller(): |
495 | 496 | if file_range != None and file_range[1] > file_range[0]: |
496 | 497 | filelist = filelist[file_range[0]:file_range[1] + 1] |
497 | 498 | |
498 | - print ">>>>>>>>>>>>>>>>>>",filelist | |
499 | 499 | zspacing = dicom_group.zspacing * interval |
500 | + | |
501 | + print "\n=======================================" | |
502 | + print ">>>>>>>>>>>>>>>>>> zspacing", zspacing, interval | |
503 | + print "\n=======================================" | |
500 | 504 | size = dicom.image.size |
501 | 505 | bits = dicom.image.bits_allocad |
502 | 506 | sop_class_uid = dicom.acquisition.sop_class_uid | ... | ... |
invesalius/data/imagedata_utils.py
... | ... | @@ -457,6 +457,9 @@ def dcm2memmap(files, slice_size, orientation): |
457 | 457 | matrix[:, n, :] = array |
458 | 458 | elif orientation == 'SAGITTAL': |
459 | 459 | array.shape = matrix.shape[0], matrix.shape[1] |
460 | + # TODO: Verify if it's necessary to add the slices swapped only in | |
461 | + # sagittal rmi or only in # Rasiane's case or is necessary in all | |
462 | + # sagittal cases. | |
460 | 463 | matrix[:, :, n] = array |
461 | 464 | else: |
462 | 465 | print array.shape, matrix.shape | ... | ... |
invesalius/data/mask.py
... | ... | @@ -29,6 +29,8 @@ import vtk |
29 | 29 | import constants as const |
30 | 30 | import imagedata_utils as iu |
31 | 31 | |
32 | +from wx.lib.pubsub import pub as Publisher | |
33 | + | |
32 | 34 | class Mask(): |
33 | 35 | general_index = -1 |
34 | 36 | def __init__(self): |
... | ... | @@ -43,6 +45,10 @@ class Mask(): |
43 | 45 | self.is_shown = 1 |
44 | 46 | self.edited_points = {} |
45 | 47 | self.was_edited = False |
48 | + self.__bind_events() | |
49 | + | |
50 | + def __bind_events(self): | |
51 | + Publisher.subscribe(self.OnFlipVolume, 'Flip volume') | |
46 | 52 | |
47 | 53 | def SavePlist(self, filename): |
48 | 54 | mask = {} |
... | ... | @@ -79,6 +85,19 @@ class Mask(): |
79 | 85 | path = os.path.join(dirpath, mask_file) |
80 | 86 | self._open_mask(path, tuple(shape)) |
81 | 87 | |
88 | + def OnFlipVolume(self, pubsub_evt): | |
89 | + axis = pubsub_evt.data | |
90 | + submatrix = self.matrix[1:, 1:, 1:] | |
91 | + if axis == 0: | |
92 | + submatrix[:] = submatrix[::-1] | |
93 | + self.matrix[1::, 0, 0] = self.matrix[:0:-1, 0, 0] | |
94 | + elif axis == 1: | |
95 | + submatrix[:] = submatrix[:, ::-1] | |
96 | + self.matrix[0, 1::, 0] = self.matrix[0, :0:-1, 0] | |
97 | + elif axis == 2: | |
98 | + submatrix[:] = submatrix[:, :, ::-1] | |
99 | + self.matrix[0, 0, 1::] = self.matrix[0, 0, :0:-1] | |
100 | + | |
82 | 101 | def _save_mask(self, filename): |
83 | 102 | shutil.copyfile(self.temp_file, filename) |
84 | 103 | ... | ... |
invesalius/data/slice_.py
... | ... | @@ -132,6 +132,8 @@ class Slice(object): |
132 | 132 | Publisher.subscribe(self.OnRemoveMasks, 'Remove masks') |
133 | 133 | Publisher.subscribe(self.OnDuplicateMasks, 'Duplicate masks') |
134 | 134 | Publisher.subscribe(self.UpdateSlice3D,'Update slice 3D') |
135 | + | |
136 | + Publisher.subscribe(self.OnFlipVolume, 'Flip volume') | |
135 | 137 | |
136 | 138 | def GetMaxSliceNumber(self, orientation): |
137 | 139 | shape = self.matrix.shape |
... | ... | @@ -703,15 +705,15 @@ class Slice(object): |
703 | 705 | cast.ClampOverflowOn() |
704 | 706 | cast.Update() |
705 | 707 | |
706 | - if (original_orientation == const.AXIAL): | |
707 | - flip = vtk.vtkImageFlip() | |
708 | - flip.SetInput(cast.GetOutput()) | |
709 | - flip.SetFilteredAxis(1) | |
710 | - flip.FlipAboutOriginOn() | |
711 | - flip.Update() | |
712 | - widget.SetInput(flip.GetOutput()) | |
713 | - else: | |
714 | - widget.SetInput(cast.GetOutput()) | |
708 | + #if (original_orientation == const.AXIAL): | |
709 | + flip = vtk.vtkImageFlip() | |
710 | + flip.SetInput(cast.GetOutput()) | |
711 | + flip.SetFilteredAxis(1) | |
712 | + flip.FlipAboutOriginOn() | |
713 | + flip.Update() | |
714 | + widget.SetInput(flip.GetOutput()) | |
715 | + #else: | |
716 | + #widget.SetInput(cast.GetOutput()) | |
715 | 717 | |
716 | 718 | def UpdateSlice3D(self, pubsub_evt): |
717 | 719 | widget, orientation = pubsub_evt.data |
... | ... | @@ -723,15 +725,15 @@ class Slice(object): |
723 | 725 | cast.ClampOverflowOn() |
724 | 726 | cast.Update() |
725 | 727 | |
726 | - if (original_orientation == const.AXIAL): | |
727 | - flip = vtk.vtkImageFlip() | |
728 | - flip.SetInput(cast.GetOutput()) | |
729 | - flip.SetFilteredAxis(1) | |
730 | - flip.FlipAboutOriginOn() | |
731 | - flip.Update() | |
732 | - widget.SetInput(flip.GetOutput()) | |
733 | - else: | |
734 | - widget.SetInput(cast.GetOutput()) | |
728 | + #if (original_orientation == const.AXIAL): | |
729 | + flip = vtk.vtkImageFlip() | |
730 | + flip.SetInput(cast.GetOutput()) | |
731 | + flip.SetFilteredAxis(1) | |
732 | + flip.FlipAboutOriginOn() | |
733 | + flip.Update() | |
734 | + widget.SetInput(flip.GetOutput()) | |
735 | + #else: | |
736 | + #widget.SetInput(cast.GetOutput()) | |
735 | 737 | |
736 | 738 | |
737 | 739 | |
... | ... | @@ -966,6 +968,18 @@ class Slice(object): |
966 | 968 | self.matrix = numpy.memmap(filename, shape=shape, dtype=dtype, |
967 | 969 | mode='r+') |
968 | 970 | |
971 | + def OnFlipVolume(self, pubsub_evt): | |
972 | + axis = pubsub_evt.data | |
973 | + if axis == 0: | |
974 | + self.matrix[:] = self.matrix[::-1] | |
975 | + elif axis == 1: | |
976 | + self.matrix[:] = self.matrix[:, ::-1] | |
977 | + elif axis == 2: | |
978 | + self.matrix[:] = self.matrix[:, :, ::-1] | |
979 | + | |
980 | + for buffer_ in self.buffer_slices.values(): | |
981 | + buffer_.discard_buffer() | |
982 | + | |
969 | 983 | def OnExportMask(self, pubsub_evt): |
970 | 984 | #imagedata = self.current_mask.imagedata |
971 | 985 | imagedata = self.imagedata | ... | ... |
invesalius/data/surface_process.py
... | ... | @@ -97,6 +97,8 @@ class SurfaceProcess(multiprocessing.Process): |
97 | 97 | flip.FlipAboutOriginOn() |
98 | 98 | flip.Update() |
99 | 99 | |
100 | + image = flip.GetOutput() | |
101 | + | |
100 | 102 | #filename = tempfile.mktemp(suffix='_%s.vti' % (self.pid)) |
101 | 103 | #writer = vtk.vtkXMLImageDataWriter() |
102 | 104 | #writer.SetInput(mask_vtk) |
... | ... | @@ -110,7 +112,8 @@ class SurfaceProcess(multiprocessing.Process): |
110 | 112 | #if self.mode == "CONTOUR": |
111 | 113 | #print "Contour" |
112 | 114 | contour = vtk.vtkContourFilter() |
113 | - contour.SetInput(flip.GetOutput()) | |
115 | + contour.SetInput(image) | |
116 | + #contour.SetInput(flip.GetOutput()) | |
114 | 117 | if self.from_binary: |
115 | 118 | contour.SetValue(0, 127) # initial threshold |
116 | 119 | else: | ... | ... |
invesalius/data/viewer_slice.py
... | ... | @@ -1311,7 +1311,7 @@ class Viewer(wx.Panel): |
1311 | 1311 | def __update_camera(self): |
1312 | 1312 | orientation = self.orientation |
1313 | 1313 | proj = project.Project() |
1314 | - orig_orien = 1 #proj.original_orientation | |
1314 | + orig_orien = proj.original_orientation | |
1315 | 1315 | |
1316 | 1316 | self.cam.SetFocalPoint(0, 0, 0) |
1317 | 1317 | self.cam.SetViewUp(const.SLICE_POSITION[orig_orien][0][self.orientation]) | ... | ... |
invesalius/data/viewer_volume.py
... | ... | @@ -180,8 +180,6 @@ class Viewer(wx.Panel): |
180 | 180 | |
181 | 181 | Publisher.subscribe(self.RemoveVolume, 'Remove Volume') |
182 | 182 | |
183 | - | |
184 | - | |
185 | 183 | def SetStereoMode(self, pubsub_evt): |
186 | 184 | mode = pubsub_evt.data |
187 | 185 | ren_win = self.interactor.GetRenderWindow() |
... | ... | @@ -210,7 +208,6 @@ class Viewer(wx.Panel): |
210 | 208 | |
211 | 209 | self.interactor.Render() |
212 | 210 | |
213 | - | |
214 | 211 | def CreateBallReference(self): |
215 | 212 | self.ball_reference = vtk.vtkSphereSource() |
216 | 213 | self.ball_reference.SetRadius(5) |
... | ... | @@ -271,7 +268,6 @@ class Viewer(wx.Panel): |
271 | 268 | |
272 | 269 | image = image.GetOutput() |
273 | 270 | |
274 | - | |
275 | 271 | # write image file |
276 | 272 | if (filetype == const.FILETYPE_BMP): |
277 | 273 | writer = vtk.vtkBMPWriter() |
... | ... | @@ -289,8 +285,6 @@ class Viewer(wx.Panel): |
289 | 285 | writer.SetFileName(filename) |
290 | 286 | writer.Write() |
291 | 287 | Publisher.sendMessage('End busy cursor') |
292 | - | |
293 | - | |
294 | 288 | |
295 | 289 | def OnCloseProject(self, pubsub_evt): |
296 | 290 | if self.raycasting_volume: |
... | ... | @@ -844,8 +838,8 @@ class SlicePlane: |
844 | 838 | def Create(self): |
845 | 839 | plane_x = self.plane_x = vtk.vtkImagePlaneWidget() |
846 | 840 | plane_x.InteractionOff() |
847 | - Publisher.sendMessage('Input Image in the widget', | |
848 | - (plane_x, 'SAGITAL')) | |
841 | + #Publisher.sendMessage('Input Image in the widget', | |
842 | + #(plane_x, 'SAGITAL')) | |
849 | 843 | plane_x.SetPlaneOrientationToXAxes() |
850 | 844 | plane_x.TextureVisibilityOn() |
851 | 845 | plane_x.SetLeftButtonAction(0) |
... | ... | @@ -856,8 +850,8 @@ class SlicePlane: |
856 | 850 | |
857 | 851 | plane_y = self.plane_y = vtk.vtkImagePlaneWidget() |
858 | 852 | plane_y.DisplayTextOff() |
859 | - Publisher.sendMessage('Input Image in the widget', | |
860 | - (plane_y, 'CORONAL')) | |
853 | + #Publisher.sendMessage('Input Image in the widget', | |
854 | + #(plane_y, 'CORONAL')) | |
861 | 855 | plane_y.SetPlaneOrientationToYAxes() |
862 | 856 | plane_y.TextureVisibilityOn() |
863 | 857 | plane_y.SetLeftButtonAction(0) |
... | ... | @@ -869,8 +863,8 @@ class SlicePlane: |
869 | 863 | |
870 | 864 | plane_z = self.plane_z = vtk.vtkImagePlaneWidget() |
871 | 865 | plane_z.InteractionOff() |
872 | - Publisher.sendMessage('Input Image in the widget', | |
873 | - (plane_z, 'AXIAL')) | |
866 | + #Publisher.sendMessage('Input Image in the widget', | |
867 | + #(plane_z, 'AXIAL')) | |
874 | 868 | plane_z.SetPlaneOrientationToZAxes() |
875 | 869 | plane_z.TextureVisibilityOn() |
876 | 870 | plane_z.SetLeftButtonAction(0) | ... | ... |
invesalius/data/volume.py
... | ... | @@ -85,6 +85,7 @@ class Volume(): |
85 | 85 | self.plane = None |
86 | 86 | self.plane_on = False |
87 | 87 | self.volume = None |
88 | + self.image = None | |
88 | 89 | self.loaded_image = 0 |
89 | 90 | self.__bind_events() |
90 | 91 | |
... | ... | @@ -109,6 +110,8 @@ class Volume(): |
109 | 110 | |
110 | 111 | Publisher.subscribe(self.ResetRayCasting, 'Reset Reaycasting') |
111 | 112 | |
113 | + Publisher.subscribe(self.OnFlipVolume, 'Flip volume') | |
114 | + | |
112 | 115 | def ResetRayCasting(self, pub_evt): |
113 | 116 | if self.exist: |
114 | 117 | self.exist = None |
... | ... | @@ -171,6 +174,13 @@ class Volume(): |
171 | 174 | colour = self.GetBackgroundColour() |
172 | 175 | Publisher.sendMessage('Change volume viewer background colour', colour) |
173 | 176 | Publisher.sendMessage('Change volume viewer gui colour', colour) |
177 | + | |
178 | + def OnFlipVolume(self, pubsub_evt): | |
179 | + print "Flipping Volume" | |
180 | + self.loaded_image = False | |
181 | + del self.image | |
182 | + self.image = None | |
183 | + self.exist = None | |
174 | 184 | |
175 | 185 | def __load_preset_config(self): |
176 | 186 | self.config = prj.Project().raycasting_preset |
... | ... | @@ -461,19 +471,15 @@ class Volume(): |
461 | 471 | return imagedata |
462 | 472 | |
463 | 473 | def LoadImage(self): |
464 | - | |
465 | - | |
466 | 474 | slice_data = slice_.Slice() |
467 | 475 | n_array = slice_data.matrix |
468 | 476 | spacing = slice_data.spacing |
469 | 477 | slice_number = 0 |
470 | 478 | orientation = 'AXIAL' |
471 | 479 | |
472 | - | |
473 | 480 | image = converters.to_vtk(n_array, spacing, slice_number, orientation) |
474 | 481 | self.image = image |
475 | 482 | |
476 | - | |
477 | 483 | def LoadVolume(self): |
478 | 484 | proj = prj.Project() |
479 | 485 | #image = imagedata_utils.to_vtk(n_array, spacing, slice_number, orientation) |
... | ... | @@ -491,19 +497,19 @@ class Volume(): |
491 | 497 | else: |
492 | 498 | flip_image = False |
493 | 499 | |
494 | - if (flip_image): | |
495 | - update_progress= vtk_utils.ShowProgress(2 + number_filters) | |
496 | - # Flip original vtkImageData | |
497 | - flip = vtk.vtkImageFlip() | |
498 | - flip.SetInput(image) | |
499 | - flip.SetFilteredAxis(1) | |
500 | - flip.FlipAboutOriginOn() | |
501 | - flip.AddObserver("ProgressEvent", lambda obj,evt: | |
502 | - update_progress(flip, "Rendering...")) | |
503 | - flip.Update() | |
504 | - image = flip.GetOutput() | |
505 | - else: | |
506 | - update_progress= vtk_utils.ShowProgress(1 + number_filters) | |
500 | + #if (flip_image): | |
501 | + update_progress= vtk_utils.ShowProgress(2 + number_filters) | |
502 | + # Flip original vtkImageData | |
503 | + flip = vtk.vtkImageFlip() | |
504 | + flip.SetInput(image) | |
505 | + flip.SetFilteredAxis(1) | |
506 | + flip.FlipAboutOriginOn() | |
507 | + flip.AddObserver("ProgressEvent", lambda obj,evt: | |
508 | + update_progress(flip, "Rendering...")) | |
509 | + flip.Update() | |
510 | + image = flip.GetOutput() | |
511 | + #else: | |
512 | + #update_progress= vtk_utils.ShowProgress(1 + number_filters) | |
507 | 513 | |
508 | 514 | scale = image.GetScalarRange() |
509 | 515 | self.scale = scale | ... | ... |
invesalius/gui/dicom_preview_panel.py
... | ... | @@ -813,7 +813,12 @@ class SingleImagePreview(wx.Panel): |
813 | 813 | |
814 | 814 | ## Text related to slice position |
815 | 815 | value1 = STR_SPC %(dicom.image.spacing[2]) |
816 | - value2 = STR_LOCAL %(dicom.image.position[2]) | |
816 | + if dicom.image.orientation_label == 'AXIAL': | |
817 | + value2 = STR_LOCAL %(dicom.image.position[2]) | |
818 | + elif dicom.image.orientation_label == 'CORONAL': | |
819 | + value2 = STR_LOCAL %(dicom.image.position[1]) | |
820 | + elif dicom.image.orientation_label == 'SAGITTAL': | |
821 | + value2 = STR_LOCAL %(dicom.image.position[0]) | |
817 | 822 | value = "%s\n%s" %(value1, value2) |
818 | 823 | self.text_image_location.SetValue(value) |
819 | 824 | ... | ... |
invesalius/gui/frame.py
... | ... | @@ -339,6 +339,11 @@ class Frame(wx.Frame): |
339 | 339 | self.ShowPreferences() |
340 | 340 | elif id == const.ID_DICOM_NETWORK: |
341 | 341 | self.ShowRetrieveDicomPanel() |
342 | + elif id in (const.ID_FLIP_X, const.ID_FLIP_Y, const.ID_FLIP_Z): | |
343 | + axis = {const.ID_FLIP_X: 2, | |
344 | + const.ID_FLIP_Y: 1, | |
345 | + const.ID_FLIP_Z: 0}[id] | |
346 | + self.FlipVolume(axis) | |
342 | 347 | |
343 | 348 | def OnSize(self, evt): |
344 | 349 | """ |
... | ... | @@ -409,6 +414,10 @@ class Frame(wx.Frame): |
409 | 414 | """ |
410 | 415 | Publisher.sendMessage('Show analyze dialog', True) |
411 | 416 | |
417 | + def FlipVolume(self, axis): | |
418 | + Publisher.sendMessage('Flip volume', axis) | |
419 | + Publisher.sendMessage('Reload actual slice') | |
420 | + | |
412 | 421 | # ------------------------------------------------------------------ |
413 | 422 | # ------------------------------------------------------------------ |
414 | 423 | # ------------------------------------------------------------------ |
... | ... | @@ -474,12 +483,23 @@ class MenuBar(wx.MenuBar): |
474 | 483 | #file_menu.AppendSeparator() |
475 | 484 | app(const.ID_EXIT, _("Exit")) |
476 | 485 | |
477 | - # EDIT | |
478 | - #file_edit = wx.Menu() | |
479 | - #app = file_edit.Append | |
486 | + | |
487 | + ############################### EDIT############################### | |
488 | + # Flip | |
489 | + flip_menu = wx.Menu() | |
490 | + app = flip_menu.Append | |
491 | + app(const.ID_FLIP_X, _("R <-> L")) | |
492 | + app(const.ID_FLIP_Y, _("A <-> P")) | |
493 | + app(const.ID_FLIP_Z, _("T <-> B")) | |
494 | + | |
495 | + file_edit = wx.Menu() | |
496 | + app = file_edit.Append | |
497 | + file_edit.AppendMenu(wx.NewId(), _('Flip'), flip_menu) | |
480 | 498 | #app(wx.ID_UNDO, "Undo\tCtrl+Z") |
481 | 499 | #app(wx.ID_REDO, "Redo\tCtrl+Y") |
482 | 500 | #app(const.ID_EDIT_LIST, "Show Undo List...") |
501 | + ################################################################# | |
502 | + | |
483 | 503 | |
484 | 504 | # VIEW |
485 | 505 | #view_tool_menu = wx.Menu() |
... | ... | @@ -527,7 +547,7 @@ class MenuBar(wx.MenuBar): |
527 | 547 | |
528 | 548 | # Add all menus to menubar |
529 | 549 | self.Append(file_menu, _("File")) |
530 | - #self.Append(file_edit, "Edit") | |
550 | + self.Append(file_edit, "Edit") | |
531 | 551 | #self.Append(view_menu, "View") |
532 | 552 | #self.Append(tools_menu, "Tools") |
533 | 553 | self.Append(options_menu, _("Options")) | ... | ... |