def Init(self, plugins, pluginsDisabled): """Method called after the panel has been initialized.""" # Set window icon if not guiutil.IsMac(): self.SetIcon(guiutil.get_icon()) # Initialize controls self.tcPlugins = XRCCTRL(self, 'tcPlugins') self.panelTreeView = XRCCTRL(self, 'panelTreeView') self.panelProperties = XRCCTRL(self, 'panelProperties') self.lblName = XRCCTRL(self, 'lblName') self.lblAuthor = XRCCTRL(self, 'lblAuthor') self.lblPluginType = XRCCTRL(self, 'lblPluginType') self.lblVersion = XRCCTRL(self, 'lblVersion') self.lblVersionNumber = XRCCTRL(self, 'lblVersionNumber') self.lblDescription = XRCCTRL(self, 'lblDescription') self.checkEnabled = XRCCTRL(self, 'checkEnabled') self.lblMessage = XRCCTRL(self, 'lblMessage') self.btnGetMorePlugins = XRCCTRL(self, 'btnGetMorePlugins') self.btnDeletePlugin = XRCCTRL(self, 'btnDeletePlugin') self.plugins = plugins self.pluginsDisabled = set(pluginsDisabled) # Bind interface events to the proper methods # wx.EVT_BUTTON(self, XRCID('btnDeletePlugin'), self.DeletePlugin) wx.EVT_CHECKBOX(self, XRCID('checkEnabled'), self.OnEnablePlugin) wx.EVT_TREE_ITEM_ACTIVATED(self, XRCID('tcPlugins'), self.OnEnablePlugin) wx.EVT_TREE_SEL_CHANGED(self, XRCID('tcPlugins'), self.OnSelectTreeItem) wx.EVT_TREE_SEL_CHANGING(self, XRCID('tcPlugins'), self.OnSelectRootItem) # Modify the control and font size as needed font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) if guiutil.IsMac(): children = list(self.Children) + \ list(self.panelTreeView.Children) + \ list(self.panelProperties.Children) for control in children: control.SetFont(font) control.SetWindowVariant(wx.WINDOW_VARIANT_SMALL) XRCCTRL(self, 'wxID_OK').SetWindowVariant(wx.WINDOW_VARIANT_NORMAL) font.SetWeight(wx.FONTWEIGHT_BOLD) if guiutil.IsMSWindows(): self.tcPlugins.SetPosition((0, 3)) self.panelTreeView.SetWindowStyle(wx.STATIC_BORDER) if (guiutil.IsMac() or guiutil.IsGtk()): self.tcPlugins.SetPosition((-30, 0)) self.panelTreeView.SetWindowStyle(wx.SUNKEN_BORDER) self.lblName.SetFont(font) self.lblMessage.SetFont(font) self.Layout() self.InitPluginList() self.LoadPlugins()
def Init(self): """Method called after the dialog has been initialized.""" # Set window icon if not guiutil.IsMac(): self.SetIcon(guiutil.get_icon()) # Initialize controls self.txtDICOMFolder = XRCCTRL(self, 'txtDICOMFolder') self.checkPatientName = XRCCTRL(self, 'checkPatientName') self.txtFirstName = XRCCTRL(self, 'txtFirstName') self.txtLastName = XRCCTRL(self, 'txtLastName') self.checkPatientID = XRCCTRL(self, 'checkPatientID') self.txtPatientID = XRCCTRL(self, 'txtPatientID') self.checkPrivateTags = XRCCTRL(self, 'checkPrivateTags') self.bmpError = XRCCTRL(self, 'bmpError') self.lblDescription = XRCCTRL(self, 'lblDescription') # Bind interface events to the proper methods wx.EVT_BUTTON(self, XRCID('btnFolderBrowse'), self.OnFolderBrowse) wx.EVT_CHECKBOX(self, XRCID('checkPatientName'), self.OnCheckPatientName) wx.EVT_CHECKBOX(self, XRCID('checkPatientID'), self.OnCheckPatientID) wx.EVT_BUTTON(self, wx.ID_OK, self.OnOK) # Set and bold the font of the description label if guiutil.IsMac(): font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) font.SetWeight(wx.FONTWEIGHT_BOLD) self.lblDescription.SetFont(font) # Initialize the import location via pubsub pub.subscribe(self.OnImportPrefsChange, 'general.dicom.import_location') pub.sendMessage('preferences.requested.value', 'general.dicom.import_location') # Pre-select the text on the text controls due to a Mac OS X bug self.txtFirstName.SetSelection(-1, -1) self.txtLastName.SetSelection(-1, -1) self.txtPatientID.SetSelection(-1, -1) # Load the error bitmap self.bmpError.SetBitmap(wx.Bitmap(util.GetResourcePath('error.png'))) # Initialize variables self.name = self.txtLastName.GetValue( ) + '^' + self.txtFirstName.GetValue() self.patientid = self.txtPatientID.GetValue() self.privatetags = True
def Init(self, name=None, appname=""): """Method called after the panel has been initialized.""" # Hide the close button on Mac if guiutil.IsMac(): XRCCTRL(self, 'wxID_OK').Hide() # Set window icon else: self.SetIcon(guiutil.get_icon()) # Set the dialog title if name: self.SetTitle(name) # Initialize controls self.notebook = XRCCTRL(self, 'notebook') # Modify the control and font size on Mac for child in self.GetChildren(): guiutil.adjust_control(child) # Bind ui events to the proper methods self.Bind(wx.EVT_CLOSE, self.OnClose) self.Bind(wx.EVT_WINDOW_DESTROY, self.OnClose) wx.EVT_BUTTON(self, XRCID('wxID_OK'), self.OnClose) # Initialize variables self.preftemplate = [] self.values = {} self.appname = appname
def OnUpdatePositionValues(self, evt=None): """Update the current position and value(s) of the mouse cursor.""" if (evt == None): pos = np.array(self.mousepos) else: pos = np.array(evt.GetPosition()) # On the Mac, the cursor position is shifted by 1 pixel to the left if guiutil.IsMac(): pos = pos - 1 # Determine the coordinates with respect to the current zoom and pan w, h = self.GetClientSize() xpos = int(pos[0] / self.zoom - self.pan[0] - (w - self.bwidth * self.zoom) / (2 * self.zoom)) ypos = int(pos[1] / self.zoom - self.pan[1] - (h - self.bheight * self.zoom) / (2 * self.zoom)) # Save the coordinates so they can be used by the 2dview plugins self.xpos = xpos self.ypos = ypos # Set an empty text placeholder if the coordinates are not within range text = "" value = "" # Only display if the mouse coordinates are within the image size range if ((0 <= xpos < len(self.structurepixlut[0])) and (0 <= ypos < len(self.structurepixlut[1])) and self.mouse_in_window): text = "X: " + unicode('%.2f' % self.structurepixlut[0][xpos]) + \ " mm Y: " + unicode('%.2f' % self.structurepixlut[1][ypos]) + \ " mm / X: " + unicode(xpos) + \ " px Y:" + unicode(ypos) + " px" # Lookup the current image and find the value of the current pixel image = self.images[self.imagenum - 1] # Rescale the slope and intercept of the image if present if (image.ds.has_key('RescaleIntercept') and image.ds.has_key('RescaleSlope')): pixel_array = image.ds.pixel_array*image.ds.RescaleSlope + \ image.ds.RescaleIntercept else: pixel_array = image.ds.pixel_array value = "Value: " + unicode(pixel_array[ypos, xpos]) # Lookup the current dose plane and find the value of the current # pixel, if the dose has been loaded if not (self.dose == []): xdpos = np.argmin(np.fabs(np.array(self.dosepixlut[0]) - xpos)) ydpos = np.argmin(np.fabs(np.array(self.dosepixlut[1]) - ypos)) dosegrid = self.dose.GetDoseGrid(float(self.z)) if not (dosegrid == []): dose = dosegrid[ydpos, xdpos] * \ self.dosedata['dosegridscaling'] value = value + " / Dose: " + \ unicode('%.4g' % dose) + " Gy / " + \ unicode('%.4g' % float(dose*10000/self.rxdose)) + " %" # Send a message with the text to the 2nd and 3rd statusbar sections pub.sendMessage('main.update_statusbar', {1: text, 2: value})
def OnInit(self): # no-op in wxPython2.8 and later: wx.InitAllImageHandlers() wx.GetApp().SetAppName("dicompyler") # Load the XRC file for our gui resources self.res = XmlResource(util.GetResourcePath('main.xrc')) # Use the native listctrl on Mac OS X if guiutil.IsMac(): wx.SystemOptions.SetOptionInt("mac.listctrl.always_use_generic", 0) dicompylerFrame = MainFrame(None, -1, "dicompyler", self.res) self.SetTopWindow(dicompylerFrame) dicompylerFrame.Show() return 1
def Init(self, res): """Method called after the panel has been initialized.""" # Initialize the panel controls self.choiceDICOM = XRCCTRL(self, 'choiceDICOM') self.tlcTreeView = DICOMTree(self) res.AttachUnknownControl('tlcTreeView', self.tlcTreeView, self) # Bind interface events to the proper methods self.Bind(wx.EVT_CHOICE, self.OnLoadTree, id=XRCID('choiceDICOM')) self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy) # Decrease the font size on Mac font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) if guiutil.IsMac(): font.SetPointSize(10) self.tlcTreeView.SetFont(font) # Set up pubsub pub.subscribe(self.OnUpdatePatient, 'patient.updated.raw_data')
def Init(self, rxdose): """Method called after the dialog has been initialized.""" # Set window icon if not guiutil.IsMac(): self.SetIcon(guiutil.get_icon()) # Initialize controls self.txtOriginalRxDose = XRCCTRL(self, 'txtOriginalRxDose') self.txtNewRxDose = XRCCTRL(self, 'txtNewRxDose') # Bind interface events to the proper methods wx.EVT_BUTTON(self, wx.ID_OK, self.OnOK) # Pre-select the text on the text controls due to a Mac OS X bug self.txtOriginalRxDose.SetSelection(-1, -1) self.txtNewRxDose.SetSelection(-1, -1) # Initialize variables self.txtOriginalRxDose.SetValue(str(int(rxdose))) self.txtNewRxDose.SetValue(str(int(rxdose) / 2))
def __init__(self, parent, id, title, res): # Initialize logging logger = logging.getLogger('dicompyler') # Configure the exception hook to process threads as well self.InstallThreadExcepthook() # Remap the exception hook so that we can log and display exceptions def LogExcepthook(*exc_info): # Log the exception text = "".join(traceback.format_exception(*exc_info)) logger.error("Unhandled exception: %s", text) pub.sendMessage('logging.exception', msg=text) sys.excepthook = LogExcepthook # Modify the logging system from pydicom to capture important messages pydicom_logger = logging.getLogger('pydicom') for l in pydicom_logger.handlers: pydicom_logger.removeHandler(l) # Add file logger logpath = os.path.join(guiutil.get_data_dir(), 'logs') if not os.path.exists(logpath): os.makedirs(logpath) self.fh = logging.handlers.RotatingFileHandler(os.path.join( logpath, 'dicompyler.log'), maxBytes=524288, backupCount=7) self.fh.setFormatter( logging.Formatter( '%(asctime)s - %(name)s - %(levelname)s - %(message)s')) self.fh.setLevel(logging.WARNING) logger.addHandler(self.fh) pydicom_logger.addHandler(self.fh) # Add console logger if not frozen if not util.main_is_frozen(): self.ch = logging.StreamHandler() self.ch.setFormatter( logging.Formatter('%(levelname)s: %(message)s')) self.ch.setLevel(logging.WARNING) logger.addHandler(self.ch) pydicom_logger.addHandler(self.ch) # Otherwise if frozen, send stdout/stderror to /dev/null since # logging the messages seems to cause instability due to recursion else: devnull = open(os.devnull, 'w') sys.stdout = devnull sys.stderr = devnull # Set the window size if guiutil.IsMac(): size = (900, 700) else: size = (850, 625) wx.Frame.__init__(self, parent, id, title, pos=wx.DefaultPosition, size=size, style=wx.DEFAULT_FRAME_STYLE) # Set up the status bar self.sb = self.CreateStatusBar(3) # set up resource file and config file self.res = res # Set window icon if not guiutil.IsMac(): self.SetIcon(guiutil.get_icon()) # Load the main panel for the program self.panelGeneral = self.res.LoadPanel(self, 'panelGeneral') # Initialize the General panel controls self.notebook = XRCCTRL(self, 'notebook') self.notebookTools = XRCCTRL(self, 'notebookTools') self.lblPlanName = XRCCTRL(self, 'lblPlanName') self.lblRxDose = XRCCTRL(self, 'lblRxDose') self.lblPatientName = XRCCTRL(self, 'lblPatientName') self.lblPatientID = XRCCTRL(self, 'lblPatientID') self.lblPatientGender = XRCCTRL(self, 'lblPatientGender') self.lblPatientDOB = XRCCTRL(self, 'lblPatientDOB') self.choiceStructure = XRCCTRL(self, 'choiceStructure') self.lblStructureVolume = XRCCTRL(self, 'lblStructureVolume') self.lblStructureMinDose = XRCCTRL(self, 'lblStructureMinDose') self.lblStructureMaxDose = XRCCTRL(self, 'lblStructureMaxDose') self.lblStructureMeanDose = XRCCTRL(self, 'lblStructureMeanDose') self.cclbStructures = guiutil.ColorCheckListBox( self.notebookTools, 'structure') self.cclbIsodoses = guiutil.ColorCheckListBox(self.notebookTools, 'isodose') # Modify the control size on Mac controls = [self.notebookTools, self.choiceStructure] if guiutil.IsMac(): for control in controls: control.SetWindowVariant(wx.WINDOW_VARIANT_SMALL) # Setup the layout for the frame mainGrid = wx.BoxSizer(wx.VERTICAL) hGrid = wx.BoxSizer(wx.HORIZONTAL) if guiutil.IsMac(): hGrid.Add(self.panelGeneral, 1, flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTRE, border=4) else: hGrid.Add(self.panelGeneral, 1, flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTRE) mainGrid.Add(hGrid, 1, flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTRE) # Load the menu for the frame menuMain = self.res.LoadMenuBar('menuMain') # If we are running on Mac OS X, alter the menu location if guiutil.IsMac(): wx.PyApp.SetMacAboutMenuItemId(XRCID('menuAbout')) wx.PyApp.SetMacPreferencesMenuItemId(XRCID('menuPreferences')) wx.PyApp.SetMacExitMenuItemId(XRCID('menuExit')) # Set the menu as the default menu for this frame self.SetMenuBar(menuMain) # Setup Tools menu self.menuShowLogs = menuMain.FindItemById( XRCID('menuShowLogs')).GetMenu() self.menuPlugins = menuMain.FindItemById( XRCID('menuPluginManager')).GetMenu() # Setup Import menu self.menuImport = menuMain.FindItemById( XRCID('menuImportPlaceholder')).GetMenu() self.menuImport.Delete( menuMain.FindItemById(XRCID('menuImportPlaceholder')).GetId()) self.menuImportItem = menuMain.FindItemById(XRCID('menuImport')) self.menuImportItem.Enable(False) # Setup Export menu self.menuExport = menuMain.FindItemById( XRCID('menuExportPlaceholder')).GetMenu() self.menuExport.Delete( menuMain.FindItemById(XRCID('menuExportPlaceholder')).GetId()) self.menuExportItem = menuMain.FindItemById(XRCID('menuExport')) self.menuExportItem.Enable(False) # Bind menu events to the proper methods self.Bind(wx.EVT_MENU, self.OnOpenPatient, id=XRCID('menuOpen')) self.Bind(wx.EVT_MENU, self.OnClose, id=wx.ID_EXIT) self.Bind(wx.EVT_MENU, self.OnPreferences, id=wx.ID_PREFERENCES) self.Bind(wx.EVT_MENU, self.OnShowLogs, id=XRCID('menuShowLogs')) self.Bind(wx.EVT_MENU, self.OnPluginManager, id=XRCID('menuPluginManager')) self.Bind(wx.EVT_MENU, self.OnAbout, id=wx.ID_ABOUT) self.Bind(wx.EVT_MENU, self.OnHomepage, id=XRCID('menuHomepage')) self.Bind(wx.EVT_MENU, self.OnLicense, id=XRCID('menuLicense')) # Load the toolbar for the frame toolbarMain = self.res.LoadToolBar(self, 'toolbarMain') self.SetToolBar(toolbarMain) self.toolbar = self.GetToolBar() # Setup main toolbar controls folderbmp = wx.Bitmap(util.GetResourcePath('folder_user.png')) self.maintools = [{ 'label': "Open Patient", 'bmp': folderbmp, 'shortHelp': "Open Patient...", 'eventhandler': self.OnOpenPatient }] for m, tool in enumerate(self.maintools): self.toolbar.AddTool(m + 1, tool['label'], tool['bmp'], shortHelp=tool['shortHelp']) self.Bind(wx.EVT_TOOL, tool['eventhandler'], id=m + 1) self.toolbar.Realize() # Bind interface events to the proper methods self.Bind(wx.EVT_CHOICE, self.OnStructureSelect, id=XRCID('choiceStructure')) self.Bind(wx.EVT_ACTIVATE, self.OnActivate) self.Bind(wx.EVT_CLOSE, self.OnClose) self.notebook.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnPageChanged) # Events to work around a focus bug in Windows self.notebook.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) self.notebook.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheel) self.notebookTools.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) self.notebookTools.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheel) self.SetSizer(mainGrid) self.Layout() #Set the Minumum size self.SetMinSize(size) self.Centre(wx.BOTH) # Initialize the welcome notebook tab panelWelcome = self.res.LoadPanel(self.notebook, 'panelWelcome') self.notebook.AddPage(panelWelcome, 'Welcome') # Set the version on the welcome notebook tab XRCCTRL(self, 'lblVersion').SetLabel('Version ' + __version__) # Initialize the tools notebook self.notebookTools.AddPage(self.cclbStructures, 'Structures') self.notebookTools.AddPage(self.cclbIsodoses, 'Isodoses') # Create the data folder datapath = guiutil.get_data_dir() if not os.path.exists(datapath): os.mkdir(datapath) # Initialize the preferences if guiutil.IsMac(): self.prefmgr = preferences.PreferencesManager(parent=self, appname='dicompyler') else: self.prefmgr = preferences.PreferencesManager(parent=self, appname='dicompyler', name='Options') sp = wx.StandardPaths.Get() self.generalpreftemplate = [{ 'DICOM Import Settings': [{ 'name': 'Import Location', 'type': 'choice', 'values': ['Remember Last Used', 'Always Use Default'], 'default': 'Remember Last Used', 'callback': 'general.dicom.import_location_setting' }, { 'name': 'Default Location', 'type': 'directory', 'default': sp.GetDocumentsDir(), 'callback': 'general.dicom.import_location' }] }, { 'Plugin Settings': [{ 'name': 'User Plugins Location', 'type': 'directory', 'default': os.path.join(datapath, 'plugins'), 'callback': 'general.plugins.user_plugins_location', 'restart': True }] }, { 'Calculation Settings': [{ 'name': 'DVH Calculation', 'type': 'choice', 'values': ['Use RT Dose DVH if Present', 'Always Recalculate DVH'], 'default': 'Use RT Dose DVH if Present', 'callback': 'general.calculation.dvh_recalc' }] }, { 'Advanced Settings': [{ 'name': 'Enable Detailed Logging', 'type': 'checkbox', 'default': False, 'callback': 'general.advanced.detailed_logging' }] }] self.preftemplate = [{'General': self.generalpreftemplate}] pub.sendMessage('preferences.updated.template', msg=self.preftemplate) # Initialize variables self.ptdata = {} # Set up pubsub pub.subscribe(self.OnLoadPatientData, 'patient.updated.raw_data') pub.subscribe(self.OnStructureCheck, 'colorcheckbox.checked.structure') pub.subscribe(self.OnStructureUncheck, 'colorcheckbox.unchecked.structure') pub.subscribe(self.OnIsodoseCheck, 'colorcheckbox.checked.isodose') pub.subscribe(self.OnIsodoseUncheck, 'colorcheckbox.unchecked.isodose') pub.subscribe(self.OnUpdatePlugins, 'general.plugins.user_plugins_location') pub.subscribe(self.OnUpdatePreferences, 'general') pub.subscribe(self.OnUpdateStatusBar, 'main.update_statusbar') pub.subscribe(self.OnOpenPatient, 'dicomgui.show') # Send a message to the logging system to turn on/off detailed logging pub.sendMessage('preferences.requested.value', msg='general.advanced.detailed_logging') # Create the default user plugin path self.userpluginpath = os.path.join(datapath, 'plugins') if not os.path.exists(self.userpluginpath): os.mkdir(self.userpluginpath) # Load and initialize plugins self.plugins = [] self.pluginsDisabled = [] pub.sendMessage('preferences.requested.value', msg='general.plugins.user_plugins_location') pub.sendMessage('preferences.requested.value', msg='general.calculation.dvh_recalc') pub.sendMessage('preferences.requested.value', msg='general.plugins.disabled_list') pub.sendMessage('preferences.requested.values', msg='general.window')
def Init(self, res): """Method called after the panel has been initialized.""" # Set window icon if not guiutil.IsMac(): self.SetIcon(guiutil.get_icon()) # Initialize controls self.txtDicomImport = XRCCTRL(self, 'txtDicomImport') self.btnDicomImport = XRCCTRL(self, 'btnDicomImport') self.checkSearchSubfolders = XRCCTRL(self, 'checkSearchSubfolders') self.lblDirections = XRCCTRL(self, 'lblDirections') self.lblDirections2 = XRCCTRL(self, 'lblDirections2') self.lblProgressLabel = XRCCTRL(self, 'lblProgressLabel') self.lblProgress = XRCCTRL(self, 'lblProgress') self.gaugeProgress = XRCCTRL(self, 'gaugeProgress') self.lblProgressPercent = XRCCTRL(self, 'lblProgressPercent') self.lblProgressPercentSym = XRCCTRL(self, 'lblProgressPercentSym') self.tcPatients = XRCCTRL(self, 'tcPatients') self.bmpRxDose = XRCCTRL(self, 'bmpRxDose') self.lblRxDose = XRCCTRL(self, 'lblRxDose') self.txtRxDose = XRCCTRL(self, 'txtRxDose') self.lblRxDoseUnits = XRCCTRL(self, 'lblRxDoseUnits') self.btnSelect = XRCCTRL(self, 'wxID_OK') # Bind interface events to the proper methods wx.EVT_BUTTON(self, XRCID('btnDicomImport'), self.OnBrowseDicomImport) wx.EVT_CHECKBOX(self, XRCID('checkSearchSubfolders'), self.OnCheckSearchSubfolders) wx.EVT_TREE_SEL_CHANGED(self, XRCID('tcPatients'), self.OnSelectTreeItem) wx.EVT_TREE_ITEM_ACTIVATED(self, XRCID('tcPatients'), self.OnOK) wx.EVT_BUTTON(self, wx.ID_OK, self.OnOK) wx.EVT_BUTTON(self, wx.ID_CANCEL, self.OnCancel) # Set the dialog font and bold the font of the directions label font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) if guiutil.IsMac(): self.txtDicomImport.SetFont(font) self.btnDicomImport.SetFont(font) self.checkSearchSubfolders.SetFont(font) self.lblDirections.SetFont(font) self.lblDirections2.SetFont(font) self.lblProgressLabel.SetFont(font) self.lblProgress.SetFont(font) self.lblProgressPercent.SetFont(font) self.lblProgressPercentSym.SetFont(font) self.tcPatients.SetFont(font) self.txtRxDose.SetFont(font) self.lblRxDoseUnits.SetFont(font) font.SetWeight(wx.FONTWEIGHT_BOLD) self.lblDirections2.SetFont(font) self.lblRxDose.SetFont(font) # Initialize the patients tree control self.root = self.InitTree() # Initialize the patients dictionary self.patients = {} # Initialize the import location via pubsub pub.subscribe(self.OnImportPrefsChange, 'general.dicom') pub.sendMessage('preferences.requested.values', 'general.dicom') # Search subfolders by default self.import_search_subfolders = True # Set the threading termination status to false intially self.terminate = False # Hide the progress bar until it needs to be shown self.gaugeProgress.Show(False) self.lblProgressPercent.Show(False) self.lblProgressPercentSym.Show(False) # Start the directory search as soon as the panel loads self.OnDirectorySearch()
def Init(self, res): """Method called after the panel has been initialized.""" self.guiDVH = guidvh.guiDVH(self) res.AttachUnknownControl("panelDVH", self.guiDVH.panelDVH, self) # Initialize the Constraint selector controls self.lblType = XRCCTRL(self, "lblType") self.choiceConstraint = XRCCTRL(self, "choiceConstraint") self.txtConstraint = XRCCTRL(self, "txtConstraint") self.sliderConstraint = XRCCTRL(self, "sliderConstraint") self.lblResultType = XRCCTRL(self, "lblResultType") self.lblConstraintUnits = XRCCTRL(self, "lblConstraintUnits") self.lblConstraintTypeUnits = XRCCTRL(self, "lblConstraintTypeUnits") # Initialize the result labels self.lblConstraintType = XRCCTRL(self, "lblConstraintType") self.lblResultDivider = XRCCTRL(self, "lblResultDivider") self.lblConstraintPercent = XRCCTRL(self, "lblConstraintPercent") # Modify the control and font size on Mac controls = [ self.lblType, self.choiceConstraint, self.sliderConstraint, self.lblResultType, self.lblConstraintUnits, self.lblConstraintPercent, self.lblConstraintType, self.lblConstraintTypeUnits, self.lblResultDivider, ] # Add children of composite controls to modification list compositecontrols = [self.txtConstraint] for control in compositecontrols: for child in control.GetChildren(): controls.append(child) # Add the constraint static box to the modification list controls.append(self.lblType.GetContainingSizer().GetStaticBox()) if guiutil.IsMac(): for control in controls: control.SetWindowVariant(wx.WINDOW_VARIANT_SMALL) # Adjust the control size for the result value labels te = self.lblType.GetTextExtent("0") self.lblConstraintUnits.SetMinSize((te[0] * 10, te[1])) self.lblConstraintPercent.SetMinSize((te[0] * 6, te[1])) self.Layout() # Bind ui events to the proper methods self.Bind(wx.EVT_CHOICE, self.OnToggleConstraints, id=XRCID("choiceConstraint")) self.Bind(wx.EVT_SPINCTRL, self.OnChangeConstraint, id=XRCID("txtConstraint")) self.Bind( wx.EVT_COMMAND_SCROLL_THUMBTRACK, self.OnChangeConstraint, id=XRCID("sliderConstraint"), ) self.Bind( wx.EVT_COMMAND_SCROLL_CHANGED, self.OnChangeConstraint, id=XRCID("sliderConstraint"), ) self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy) # Initialize variables self.structures = {} # structures from initial DICOM data self.checkedstructures = {} # structures that need to be shown self.dvhs = {} # raw dvhs from initial DICOM data self.dvharray = {} # dict of dvh data processed from dvhdata self.dvhscaling = {} # dict of dvh scaling data self.plan = {} # used for rx dose self.structureid = 1 # used to indicate current constraint structure # Set up pubsub pub.subscribe(self.OnUpdatePatient, "patient.updated.parsed_data") pub.subscribe(self.OnStructureCheck, "structures.checked") pub.subscribe(self.OnStructureSelect, "structure.selected")
def OnPaint(self, evt): """Update the panel when it needs to be refreshed.""" # Bind motion event when the panel has been painted to avoid a blank # image on Windows if a file is loaded too quickly before the plugin # is initialized self.Bind(wx.EVT_MOTION, self.OnMouseMotion) # Special case for Windows to account for flickering # if and only if images are loaded if (guiutil.IsMSWindows() and len(self.images)): dc = wx.BufferedPaintDC(self) self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) else: dc = wx.PaintDC(self) width, height = self.GetClientSize() try: gc = wx.GraphicsContext.Create(dc) except NotImplementedError: dc.DrawText( "This build of wxPython does not support the " "wx.GraphicsContext family of classes.", 25, 25) return # If we have images loaded, process and show the image if len(self.images): # Save the original drawing state gc.PushState() # Scale the image by the zoom factor gc.Scale(self.zoom, self.zoom) # Redraw the background on Windows if guiutil.IsMSWindows(): gc.SetBrush(wx.Brush(wx.Colour(0, 0, 0))) gc.SetPen(wx.Pen(wx.Colour(0, 0, 0))) gc.DrawRectangle(0, 0, width, height) image = guiutil.convert_pil_to_wx( self.images[self.imagenum - 1].GetImage( self.window, self.level)) bmp = wx.Bitmap(image) self.bwidth, self.bheight = image.GetSize() # Center the image transx = self.pan[0] + (width - self.bwidth * self.zoom) / (2 * self.zoom) transy = self.pan[1] + (height - self.bheight * self.zoom) / (2 * self.zoom) gc.Translate(transx, transy) gc.DrawBitmap(bmp, 0, 0, self.bwidth, self.bheight) gc.SetBrush(wx.Brush(wx.Colour(0, 0, 255, 30))) gc.SetPen(wx.Pen(wx.Colour(0, 0, 255, 30))) # Draw the structures if present imdata = self.images[self.imagenum - 1].GetImageData() self.z = '%.2f' % imdata['position'][2] # Determine whether the patient is prone or supine if 'p' in imdata['patientposition'].lower(): prone = True else: prone = False # Determine whether the patient is feet first or head first if 'ff' in imdata['patientposition'].lower(): feetfirst = True else: feetfirst = False for id, structure in self.structures.items(): self.DrawStructure(structure, gc, self.z, prone, feetfirst) # Draw the isodoses if present if len(self.isodoses): grid = self.dose.GetDoseGrid(float(self.z)) if not (grid == []): x, y = np.meshgrid(np.arange(grid.shape[1]), np.arange(grid.shape[0])) # Instantiate the isodose generator for this slice isodosegen = cntr.Cntr(x, y, grid) for id, isodose in iter(sorted(self.isodoses.items())): self.DrawIsodose(isodose, gc, isodosegen) # Restore the translation and scaling gc.PopState() # Prepare the font for drawing the information text font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) if guiutil.IsMac(): font.SetPointSize(10) gc.SetFont(font, wx.WHITE) # Draw the information text imtext = "Image: " + str(self.imagenum) + "/" + str( len(self.images)) te = gc.GetFullTextExtent(imtext) gc.DrawText(imtext, 10, 7) impos = "Position: " + str(self.z) + " mm" gc.DrawText(impos, 10, 7 + te[1] * 1.1) if ("%.3f" % self.zoom == "1.000"): zoom = "1" else: zoom = "%.3f" % self.zoom imzoom = "Zoom: " + zoom + ":1" gc.DrawText(imzoom, 10, height - 17) imsize = "Image Size: " + str(self.bheight) + "x" + str( self.bwidth) + " px" gc.DrawText(imsize, 10, height - 17 - te[1] * 1.1) imwinlevel = "W/L: " + str(self.window) + ' / ' + str(self.level) te = gc.GetFullTextExtent(imwinlevel) gc.DrawText(imwinlevel, width - te[0] - 7, 7) impatpos = "Patient Position: " + imdata['patientposition'] te = gc.GetFullTextExtent(impatpos) gc.DrawText(impatpos, width - te[0] - 7, height - 17) # Send message with the current image number and various properties pub.sendMessage( '2dview.updated.image', msg={ 'number': self.imagenum, # slice number 'z': self.z, # slice location 'window': self.window, # current window value 'level': self.level, # curent level value 'gc': gc, # wx.GraphicsContext 'scale': self.zoom, # current zoom level 'transx': transx, # current x translation 'transy': transy, # current y translation 'imdata': imdata, # image data dictionary 'patientpixlut': self.structurepixlut })
def __init__(self, parent, id, title, res): # Initialize logging logger = logging.getLogger("dicompyler") # Configure the exception hook to process threads as well self.InstallThreadExcepthook() # Remap the exception hook so that we can log and display exceptions def LogExcepthook(*exc_info): # Log the exception text = "".join(traceback.format_exception(*exc_info)) logger.error("Unhandled exception: %s", text) pub.sendMessage("logging.exception", msg=text) sys.excepthook = LogExcepthook # Modify the logging system from pydicom to capture important messages pydicom_logger = logging.getLogger("pydicom") for l in pydicom_logger.handlers: pydicom_logger.removeHandler(l) # Add file logger logpath = os.path.join(guiutil.get_data_dir(), "logs") if not os.path.exists(logpath): os.makedirs(logpath) self.fh = logging.handlers.RotatingFileHandler(os.path.join( logpath, "dicompyler.log"), maxBytes=524288, backupCount=7) self.fh.setFormatter( logging.Formatter( "%(asctime)s - %(name)s - %(levelname)s - %(message)s")) self.fh.setLevel(logging.WARNING) logger.addHandler(self.fh) pydicom_logger.addHandler(self.fh) # Add console logger if not frozen if not util.main_is_frozen(): self.ch = logging.StreamHandler() self.ch.setFormatter( logging.Formatter("%(levelname)s: %(message)s")) self.ch.setLevel(logging.WARNING) logger.addHandler(self.ch) pydicom_logger.addHandler(self.ch) # Otherwise if frozen, send stdout/stderror to /dev/null since # logging the messages seems to cause instability due to recursion else: devnull = open(os.devnull, "w") sys.stdout = devnull sys.stderr = devnull # Set the window size if guiutil.IsMac(): size = (1200, 700) else: size = (1200, 700) wx.Frame.__init__( self, parent, id, title, pos=wx.DefaultPosition, size=size, style=wx.DEFAULT_FRAME_STYLE, ) # Set up the status bar self.sb = self.CreateStatusBar(3) # set up resource file and config file self.res = res # Set window icon if not guiutil.IsMac(): self.SetIcon(guiutil.get_icon()) # Load the main panel for the program self.panelGeneral = self.res.LoadPanel(self, "panelGeneral") # Initialize the General panel controls self.notebook = XRCCTRL(self, "notebook") self.notebookTools = XRCCTRL(self, "notebookTools") self.lblPlanName = XRCCTRL(self, "lblPlanName") self.lblRxDose = XRCCTRL(self, "lblRxDose") self.lblPatientName = XRCCTRL(self, "lblPatientName") self.lblPatientID = XRCCTRL(self, "lblPatientID") self.lblPatientGender = XRCCTRL(self, "lblPatientGender") self.lblPatientDOB = XRCCTRL(self, "lblPatientDOB") self.choiceStructure = XRCCTRL(self, "choiceStructure") self.lblStructureVolume = XRCCTRL(self, "lblStructureVolume") self.lblStructureMinDose = XRCCTRL(self, "lblStructureMinDose") self.lblStructureMaxDose = XRCCTRL(self, "lblStructureMaxDose") self.lblStructureMeanDose = XRCCTRL(self, "lblStructureMeanDose") self.cclbStructures = guiutil.ColorCheckListBox( self.notebookTools, "structure") self.cclbIsodoses = guiutil.ColorCheckListBox(self.notebookTools, "isodose") """test code""" self.sidePanel = XRCCTRL(self, "sidePanel") sizer = wx.BoxSizer(wx.VERTICAL) self.sidePanel.SetSizer(sizer) self.histPanel = HistPanel(self.sidePanel) self.histPanel.plot_histogram_img(util.GetResourcePath("book.png")) sizer.Add(self.histPanel, 0, wx.ALL | wx.EXPAND) """test code""" # Modify the control size on Mac controls = [self.notebookTools, self.choiceStructure] if guiutil.IsMac(): for control in controls: control.SetWindowVariant(wx.WINDOW_VARIANT_SMALL) # Setup the layout for the frame mainGrid = wx.BoxSizer(wx.VERTICAL) hGrid = wx.BoxSizer(wx.HORIZONTAL) if guiutil.IsMac(): hGrid.Add( self.panelGeneral, 1, flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTRE, border=4, ) else: hGrid.Add(self.panelGeneral, 1, flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTRE) mainGrid.Add(hGrid, 1, flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTRE) # Load the menu for the frame menuMain = self.res.LoadMenuBar("menuMain") # If we are running on Mac OS X, alter the menu location if guiutil.IsMac(): wx.PyApp.SetMacAboutMenuItemId(XRCID("menuAbout")) wx.PyApp.SetMacPreferencesMenuItemId(XRCID("menuPreferences")) wx.PyApp.SetMacExitMenuItemId(XRCID("menuExit")) # Set the menu as the default menu for this frame self.SetMenuBar(menuMain) # Setup Tools menu self.menuShowLogs = menuMain.FindItemById( XRCID("menuShowLogs")).GetMenu() self.menuPlugins = menuMain.FindItemById( XRCID("menuPluginManager")).GetMenu() # Setup Import menu self.menuImport = menuMain.FindItemById( XRCID("menuImportPlaceholder")).GetMenu() self.menuImport.Delete( menuMain.FindItemById(XRCID("menuImportPlaceholder")).GetId()) self.menuImportItem = menuMain.FindItemById(XRCID("menuImport")) self.menuImportItem.Enable(False) # Setup Export menu self.menuExport = menuMain.FindItemById( XRCID("menuExportPlaceholder")).GetMenu() self.menuExport.Delete( menuMain.FindItemById(XRCID("menuExportPlaceholder")).GetId()) self.menuExportItem = menuMain.FindItemById(XRCID("menuExport")) self.menuExportItem.Enable(False) # Bind menu events to the proper methods self.Bind(wx.EVT_MENU, self.OnOpenPatient, id=XRCID("menuOpen")) self.Bind(wx.EVT_MENU, self.OnClose, id=wx.ID_EXIT) self.Bind(wx.EVT_MENU, self.OnPreferences, id=wx.ID_PREFERENCES) self.Bind(wx.EVT_MENU, self.OnShowLogs, id=XRCID("menuShowLogs")) self.Bind(wx.EVT_MENU, self.OnPluginManager, id=XRCID("menuPluginManager")) self.Bind(wx.EVT_MENU, self.OnAbout, id=wx.ID_ABOUT) self.Bind(wx.EVT_MENU, self.OnHomepage, id=XRCID("menuHomepage")) self.Bind(wx.EVT_MENU, self.OnLicense, id=XRCID("menuLicense")) # Load the toolbar for the frame toolbarMain = self.res.LoadToolBar(self, "toolbarMain") self.SetToolBar(toolbarMain) self.toolbar = self.GetToolBar() # Setup main toolbar controls folderbmp = wx.Bitmap(util.GetResourcePath("folder_user.png")) self.maintools = [{ "label": "Open Patient", "bmp": folderbmp, "shortHelp": "Open Patient...", "eventhandler": self.OnOpenPatient, }] for m, tool in enumerate(self.maintools): self.toolbar.AddTool(m + 1, tool["label"], tool["bmp"], shortHelp=tool["shortHelp"]) self.Bind(wx.EVT_TOOL, tool["eventhandler"], id=m + 1) self.toolbar.Realize() # Bind interface events to the proper methods self.Bind(wx.EVT_CHOICE, self.OnStructureSelect, id=XRCID("choiceStructure")) self.Bind(wx.EVT_ACTIVATE, self.OnActivate) self.Bind(wx.EVT_CLOSE, self.OnClose) self.notebook.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnPageChanged) # Events to work around a focus bug in Windows self.notebook.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) self.notebook.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheel) self.notebookTools.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) self.notebookTools.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheel) self.SetSizer(mainGrid) self.Layout() # Set the Minumum size self.SetMinSize(size) self.Centre(wx.BOTH) # Initialize the welcome notebook tab panelWelcome = self.res.LoadPanel(self.notebook, "panelWelcome") self.notebook.AddPage(panelWelcome, "Welcome") # Set the version on the welcome notebook tab XRCCTRL(self, "lblVersion").SetLabel("Version " + __version__) # Initialize the tools notebook self.notebookTools.AddPage(self.cclbStructures, "Structures") self.notebookTools.AddPage(self.cclbIsodoses, "Isodoses") # Create the data folder datapath = guiutil.get_data_dir() if not os.path.exists(datapath): os.mkdir(datapath) # Initialize the preferences if guiutil.IsMac(): self.prefmgr = preferences.PreferencesManager(parent=self, appname="dicompyler") else: self.prefmgr = preferences.PreferencesManager(parent=self, appname="dicompyler", name="Options") sp = wx.StandardPaths.Get() self.generalpreftemplate = [ { "DICOM Import Settings": [ { "name": "Import Location", "type": "choice", "values": ["Remember Last Used", "Always Use Default"], "default": "Remember Last Used", "callback": "general.dicom.import_location_setting", }, { "name": "Default Location", "type": "directory", "default": sp.GetDocumentsDir(), "callback": "general.dicom.import_location", }, ] }, { "Plugin Settings": [{ "name": "User Plugins Location", "type": "directory", "default": os.path.join(datapath, "plugins"), "callback": "general.plugins.user_plugins_location", "restart": True, }] }, { "Calculation Settings": [{ "name": "DVH Calculation", "type": "choice", "values": [ "Use RT Dose DVH if Present", "Always Recalculate DVH", ], "default": "Use RT Dose DVH if Present", "callback": "general.calculation.dvh_recalc", }] }, { "Advanced Settings": [{ "name": "Enable Detailed Logging", "type": "checkbox", "default": False, "callback": "general.advanced.detailed_logging", }] }, ] self.preftemplate = [{"General": self.generalpreftemplate}] pub.sendMessage("preferences.updated.template", msg=self.preftemplate) # Initialize variables self.ptdata = {} # Set up pubsub pub.subscribe(self.OnLoadPatientData, "patient.updated.raw_data") pub.subscribe(self.OnStructureCheck, "colorcheckbox.checked.structure") pub.subscribe(self.OnStructureUncheck, "colorcheckbox.unchecked.structure") pub.subscribe(self.OnIsodoseCheck, "colorcheckbox.checked.isodose") pub.subscribe(self.OnIsodoseUncheck, "colorcheckbox.unchecked.isodose") pub.subscribe(self.OnUpdatePlugins, "general.plugins.user_plugins_location") pub.subscribe(self.OnUpdatePreferences, "general") pub.subscribe(self.OnUpdateStatusBar, "main.update_statusbar") pub.subscribe(self.OnOpenPatient, "dicomgui.show") # Send a message to the logging system to turn on/off detailed logging pub.sendMessage("preferences.requested.value", msg="general.advanced.detailed_logging") # Create the default user plugin path self.userpluginpath = os.path.join(datapath, "plugins") if not os.path.exists(self.userpluginpath): os.mkdir(self.userpluginpath) # Load and initialize plugins self.plugins = [] self.pluginsDisabled = [] pub.sendMessage("preferences.requested.value", msg="general.plugins.user_plugins_location") pub.sendMessage("preferences.requested.value", msg="general.calculation.dvh_recalc") pub.sendMessage("preferences.requested.value", msg="general.plugins.disabled_list") pub.sendMessage("preferences.requested.values", msg="general.window")