Example #1
0
 def onRightClick(self, event):
     if self.slot.status == 'Full ':
         popup = Menu(self,tearoff=0)
         popup.add_command(label= u'load',
                     command=partial(self.menu_action, self.slot.slot))
         try:
             popup.tk_popup(event.x_root, event.y_root, 0)
         finally:
             popup.grab_release()
             self.updated()
Example #2
0
 def onRightClick(self, event):
     if self.slot.status != 'Empty':
         popup = Menu(self,tearoff=0)
         unloadmenu = Menu(self, tearoff = 0)
         for slot in self.slot.device.storage_slots:
             if slot.status == 'Empty':
                 unloadmenu.add_command(label= u'storage slot %s' % slot.slot,
                     command=partial(self.menu_action, slot.slot))
         popup.add_cascade(label='unload',menu =unloadmenu)
         try:
             popup.tk_popup(event.x_root, event.y_root, 0)
         finally:
             popup.grab_release()
             self.updated()
Example #3
0
    def _launch_menu(self, coords):
        """
        Callback function in response to the pressing of the Return key

        Launches a context menu based on the location of the mouse
        :param coords:
        :return:
        """
        # Configure the "static" menu entries -- they can't be static without seriously destroying readability
        # due to the Python version that is being used -.- so now it has to be not optimal until I find a better
        # solution
        p_menu = Menu(self._canvas)
        item = self._get_current_item((self._cache["x"], self._cache["y"]))
        updated_coords = self._canvas_to_screen((self._cache["x"], self._cache["y"]))
        if item is None:
            # No node is currently selected, create the general menu
            p_menu.add_command(label="Place Room", command=lambda: self.create_new_node((self._cache["x"], self._cache["y"])))
            p_menu.add_command(label="Delete All", command=lambda: self.delete_all())
            p_menu.tk_popup(updated_coords[0], updated_coords[1])
            return

        if self._is_node(item):
            # Create the node specific menu
            p_menu.add_command(label="Place Object", command=lambda: self._mark_object((self._cache["x"], self._cache["y"])))
            p_menu.add_command(label="Edit Room", command=lambda: self._selection_operation((self._cache["x"], self._cache["y"])))
            p_menu.add_command(label="Delete Room", command=lambda: self.delete_node(self._get_current_item((self._cache["x"], self._cache["y"]))))
            p_menu.add_command(label="Mark as start", command=lambda: self._mark_start_node(self._get_current_item((self._cache["x"], self._cache["y"]))))

            if self._is_object(item):
                # Launch the node menu as well as an an added option for selecting stuff to edit an object
                p_menu.add_command(label="Edit Object", command=lambda: self._edit_object(coords))
                p_menu.add_command(label="Delete Object", command=lambda: self._delete_object(self._get_current_item((self._cache["x"], self._cache["y"]))))
                p_menu.delete(0)
            p_menu.tk_popup(updated_coords[0], updated_coords[1])
            return

        if self._is_edge(item):
            p_menu.add_command(label="Edit Corridor", command=lambda: self._selection_operation((self._cache["x"], self._cache["y"])))
            p_menu.add_command(label="Delete Corridor", command=lambda: self.delete_edge(self._get_current_item((self._cache["x"], self._cache["y"]))))
            p_menu.tk_popup(updated_coords[0], updated_coords[1])
            return

        self._clear_cache(coords)
Example #4
0
class LintGui(object):
    """Build and control a window to interact with pylint"""
    def __init__(self, root=None):
        """init"""
        self.root = root or Tk()
        self.root.title('Pylint')
        #reporter
        self.reporter = None
        #message queue for output from reporter
        self.msg_queue = Queue.Queue()
        self.msgs = []
        self.visible_msgs = []
        self.filenames = []
        self.rating = StringVar()
        self.tabs = {}
        self.report_stream = BasicStream(self)
        self.differ = differ.Differ()
        #gui objects
        self.lbMessages = None
        self.showhistory = None
        self.results = None
        self.btnRun = None
        self.information_box = None
        self.convention_box = None
        self.refactor_box = None
        self.warning_box = None
        self.error_box = None
        self.fatal_box = None
        self.txtModule = None
        self.status = None
        self.msg_type_dict = None
        self.init_gui()

    def init_gui(self):
        """init helper"""
        #setting up frames
        top_frame = Frame(self.root)
        mid_frame = Frame(self.root)
        radio_frame = Frame(self.root)
        res_frame = Frame(self.root)
        msg_frame = Frame(self.root)
        check_frame = Frame(self.root)
        history_frame = Frame(self.root)
        btn_frame = Frame(self.root)
        rating_frame = Frame(self.root)
        top_frame.pack(side=TOP, fill=X)
        mid_frame.pack(side=TOP, fill=X)
        history_frame.pack(side=TOP, fill=BOTH, expand=True)
        radio_frame.pack(side=TOP, fill=BOTH, expand=True)
        rating_frame.pack(side=TOP, fill=BOTH, expand=True)
        res_frame.pack(side=TOP, fill=BOTH, expand=True)
        check_frame.pack(side=TOP, fill=BOTH, expand=True)
        msg_frame.pack(side=TOP, fill=BOTH, expand=True)
        btn_frame.pack(side=TOP, fill=X)

        # Binding F5 application-wide to run lint
        self.root.bind('<F5>', self.run_lint)

        #Message ListBox
        rightscrollbar = Scrollbar(msg_frame)
        rightscrollbar.pack(side=RIGHT, fill=Y)
        bottomscrollbar = Scrollbar(msg_frame, orient=HORIZONTAL)
        bottomscrollbar.pack(side=BOTTOM, fill=X)
        self.lbMessages = Listbox(msg_frame,
                                  yscrollcommand=rightscrollbar.set,
                                  xscrollcommand=bottomscrollbar.set,
                                  bg="white")
        self.lbMessages.bind("<Double-Button-1>", self.show_sourcefile)
        self.lbMessages.pack(expand=True, fill=BOTH)
        rightscrollbar.config(command=self.lbMessages.yview)
        bottomscrollbar.config(command=self.lbMessages.xview)

        #Message context menu
        self.mnMessages = Menu(self.lbMessages, tearoff=0)
        self.mnMessages.add_command(label="View in sourcefile",
                                    command=self.show_sourcefile)
        self.mnMessages.add_command(label="Add to ignore patchfile",
                                    command=self.add_to_ignore_patchfile)
        self.lbMessages.bind("<Button-3>", self.show_messages_context)

        #History ListBoxes
        rightscrollbar2 = Scrollbar(history_frame)
        rightscrollbar2.pack(side=RIGHT, fill=Y)
        bottomscrollbar2 = Scrollbar(history_frame, orient=HORIZONTAL)
        bottomscrollbar2.pack(side=BOTTOM, fill=X)
        self.showhistory = Listbox(history_frame,
                                   yscrollcommand=rightscrollbar2.set,
                                   xscrollcommand=bottomscrollbar2.set,
                                   bg="white")
        self.showhistory.pack(expand=True, fill=BOTH)
        rightscrollbar2.config(command=self.showhistory.yview)
        bottomscrollbar2.config(command=self.showhistory.xview)
        self.showhistory.bind('<Double-Button-1>', self.select_recent_file)
        self.set_history_window()

        #status bar
        self.status = Label(self.root, text="", bd=1, relief=SUNKEN, anchor=W)
        self.status.pack(side=BOTTOM, fill=X)

        #labels
        self.lblRatingLabel = Label(rating_frame, text='Rating:')
        self.lblRatingLabel.pack(side=LEFT)
        self.lblRating = Label(rating_frame, textvariable=self.rating)
        self.lblRating.pack(side=LEFT)
        Label(mid_frame, text='Recently Used:').pack(side=LEFT)
        Label(top_frame, text='Module or package').pack(side=LEFT)

        #file textbox
        self.txtModule = Entry(top_frame, background='white')
        self.txtModule.bind('<Return>', self.run_lint)
        self.txtModule.pack(side=LEFT, expand=True, fill=X)

        #results box
        rightscrollbar = Scrollbar(res_frame)
        rightscrollbar.pack(side=RIGHT, fill=Y)
        bottomscrollbar = Scrollbar(res_frame, orient=HORIZONTAL)
        bottomscrollbar.pack(side=BOTTOM, fill=X)
        self.results = Listbox(res_frame,
                               yscrollcommand=rightscrollbar.set,
                               xscrollcommand=bottomscrollbar.set,
                               bg="white",
                               font="Courier")
        self.results.pack(expand=True, fill=BOTH, side=BOTTOM)
        rightscrollbar.config(command=self.results.yview)
        bottomscrollbar.config(command=self.results.xview)

        #buttons
        Button(top_frame, text='Open', command=self.file_open).pack(side=LEFT)
        Button(top_frame,
               text='Open Package',
               command=(lambda: self.file_open(package=True))).pack(side=LEFT)

        self.btnRun = Button(top_frame, text='Run', command=self.run_lint)
        self.btnRun.pack(side=LEFT)
        Button(btn_frame, text='Quit', command=self.quit).pack(side=BOTTOM)

        #radio buttons
        self.information_box = IntVar()
        self.convention_box = IntVar()
        self.refactor_box = IntVar()
        self.warning_box = IntVar()
        self.error_box = IntVar()
        self.fatal_box = IntVar()
        i = Checkbutton(check_frame,
                        text="Information",
                        fg=COLORS['(I)'],
                        variable=self.information_box,
                        command=self.refresh_msg_window)
        c = Checkbutton(check_frame,
                        text="Convention",
                        fg=COLORS['(C)'],
                        variable=self.convention_box,
                        command=self.refresh_msg_window)
        r = Checkbutton(check_frame,
                        text="Refactor",
                        fg=COLORS['(R)'],
                        variable=self.refactor_box,
                        command=self.refresh_msg_window)
        w = Checkbutton(check_frame,
                        text="Warning",
                        fg=COLORS['(W)'],
                        variable=self.warning_box,
                        command=self.refresh_msg_window)
        e = Checkbutton(check_frame,
                        text="Error",
                        fg=COLORS['(E)'],
                        variable=self.error_box,
                        command=self.refresh_msg_window)
        f = Checkbutton(check_frame,
                        text="Fatal",
                        fg=COLORS['(F)'],
                        variable=self.fatal_box,
                        command=self.refresh_msg_window)
        i.select()
        c.select()
        r.select()
        w.select()
        e.select()
        f.select()
        i.pack(side=LEFT)
        c.pack(side=LEFT)
        r.pack(side=LEFT)
        w.pack(side=LEFT)
        e.pack(side=LEFT)
        f.pack(side=LEFT)

        #check boxes
        self.box = StringVar()
        # XXX should be generated
        report = Radiobutton(radio_frame,
                             text="Report",
                             variable=self.box,
                             value="Report",
                             command=self.refresh_results_window)
        rawMet = Radiobutton(radio_frame,
                             text="Raw metrics",
                             variable=self.box,
                             value="Raw metrics",
                             command=self.refresh_results_window)
        dup = Radiobutton(radio_frame,
                          text="Duplication",
                          variable=self.box,
                          value="Duplication",
                          command=self.refresh_results_window)
        ext = Radiobutton(radio_frame,
                          text="External dependencies",
                          variable=self.box,
                          value="External dependencies",
                          command=self.refresh_results_window)
        stat = Radiobutton(radio_frame,
                           text="Statistics by type",
                           variable=self.box,
                           value="Statistics by type",
                           command=self.refresh_results_window)
        msgCat = Radiobutton(radio_frame,
                             text="Messages by category",
                             variable=self.box,
                             value="Messages by category",
                             command=self.refresh_results_window)
        msg = Radiobutton(radio_frame,
                          text="Messages",
                          variable=self.box,
                          value="Messages",
                          command=self.refresh_results_window)
        sourceFile = Radiobutton(radio_frame,
                                 text="Source File",
                                 variable=self.box,
                                 value="Source File",
                                 command=self.refresh_results_window)
        report.select()
        report.grid(column=0, row=0, sticky=W)
        rawMet.grid(column=1, row=0, sticky=W)
        dup.grid(column=2, row=0, sticky=W)
        msg.grid(column=3, row=0, sticky=W)
        stat.grid(column=0, row=1, sticky=W)
        msgCat.grid(column=1, row=1, sticky=W)
        ext.grid(column=2, row=1, sticky=W)
        sourceFile.grid(column=3, row=1, sticky=W)

        #dictionary for check boxes and associated error term
        self.msg_type_dict = {
            'I': lambda: self.information_box.get() == 1,
            'C': lambda: self.convention_box.get() == 1,
            'R': lambda: self.refactor_box.get() == 1,
            'E': lambda: self.error_box.get() == 1,
            'W': lambda: self.warning_box.get() == 1,
            'F': lambda: self.fatal_box.get() == 1
        }
        self.txtModule.focus_set()

    def select_recent_file(self, event):
        """adds the selected file in the history listbox to the Module box"""
        if not self.showhistory.size():
            return

        selected = self.showhistory.curselection()
        item = self.showhistory.get(selected)
        #update module
        self.txtModule.delete(0, END)
        self.txtModule.insert(0, item)

    def refresh_msg_window(self):
        """refresh the message window with current output"""
        #clear the window
        self.lbMessages.delete(0, END)
        self.visible_msgs = []
        for msg in self.msgs:
            if (self.msg_type_dict.get(msg.C)()):
                self.visible_msgs.append(msg)
                msg_str = convert_to_string(msg)
                self.lbMessages.insert(END, msg_str)
                fg_color = COLORS.get(msg_str[:3], 'black')
                self.lbMessages.itemconfigure(END, fg=fg_color)

    def refresh_results_window(self):
        """refresh the results window with current output"""
        #clear the window
        self.results.delete(0, END)
        try:
            for res in self.tabs[self.box.get()]:
                self.results.insert(END, res)
        except:
            pass

    def process_incoming(self):
        """process the incoming messages from running pylint"""
        while self.msg_queue.qsize():
            try:
                msg = self.msg_queue.get(0)
                if msg == "DONE":
                    self.report_stream.output_contents()
                    return False

                #adding message to list of msgs
                self.msgs.append(msg)

                #displaying msg if message type is selected in check box
                if (self.msg_type_dict.get(msg.C)()):
                    self.visible_msgs.append(msg)
                    msg_str = convert_to_string(msg)
                    self.lbMessages.insert(END, msg_str)
                    fg_color = COLORS.get(msg_str[:3], 'black')
                    self.lbMessages.itemconfigure(END, fg=fg_color)

            except Queue.Empty:
                pass
        return True

    def periodic_call(self):
        """determine when to unlock the run button"""
        if self.process_incoming():
            self.root.after(100, self.periodic_call)
        else:
            #enabling button so it can be run again
            self.btnRun.config(state=NORMAL)

    def mainloop(self):
        """launch the mainloop of the application"""
        self.root.mainloop()

    def quit(self, _=None):
        """quit the application"""
        self.root.quit()

    def halt(self):
        """program halt placeholder"""
        return

    def file_open(self, package=False, _=None):
        """launch a file browser"""
        if not package:
            filename = askopenfilename(parent=self.root,
                                       filetypes=[('pythonfiles', '*.py'),
                                                  ('allfiles', '*')],
                                       title='Select Module')
        else:
            filename = askdirectory(title="Select A Folder", mustexist=1)

        if filename == ():
            return

        self.txtModule.delete(0, END)
        self.txtModule.insert(0, filename)

    def update_filenames(self):
        """update the list of recent filenames"""
        filename = self.txtModule.get()
        if not filename:
            filename = os.getcwd()
        if filename + '\n' in self.filenames:
            index = self.filenames.index(filename + '\n')
            self.filenames.pop(index)

        #ensure only 10 most recent are stored
        if len(self.filenames) == 10:
            self.filenames.pop()
        self.filenames.insert(0, filename + '\n')

    def set_history_window(self):
        """update the history window with info from the history file"""
        #clear the window
        self.showhistory.delete(0, END)
        # keep the last 10 most recent files
        try:
            view_history = open(HOME + HISTORY, 'r')
            for hist in view_history.readlines():
                if not hist in self.filenames:
                    self.filenames.append(hist)
                self.showhistory.insert(END, hist.split('\n')[0])
            view_history.close()
        except IOError:
            # do nothing since history file will be created later
            return

    def run_lint(self, _=None):
        """launches pylint"""
        self.update_filenames()
        self.root.configure(cursor='watch')
        self.reporter = GUIReporter(self, output=self.report_stream)
        module = self.txtModule.get()
        if not module:
            module = os.getcwd()

        #cleaning up msgs and windows
        self.msgs = []
        self.visible_msgs = []
        self.lbMessages.delete(0, END)
        self.tabs = {}
        self.results.delete(0, END)
        self.btnRun.config(state=DISABLED)

        #setting up a worker thread to run pylint
        worker = Thread(target=lint_thread,
                        args=(
                            module,
                            self.reporter,
                            self,
                        ))
        self.periodic_call()
        worker.start()

        # Overwrite the .pylint-gui-history file with all the new recently added files
        # in order from filenames but only save last 10 files
        write_history = open(HOME + HISTORY, 'w')
        write_history.writelines(self.filenames)
        write_history.close()
        self.set_history_window()

        self.root.configure(cursor='')

    def show_sourcefile(self, event=None):
        selected = self.lbMessages.curselection()
        if not selected:
            return

        msg = self.visible_msgs[int(selected[0])]
        scroll = msg.line - 3
        if scroll < 0:
            scroll = 0

        self.tabs["Source File"] = open(msg.abspath, "r").readlines()
        self.box.set("Source File")
        self.refresh_results_window()
        self.results.yview(scroll)
        self.results.select_set(msg.line - 1)

    def show_messages_context(self, event):
        """Show the message listbox's context menu"""
        # Select the item that was clicked
        index = self.lbMessages.nearest(event.y)
        self.lbMessages.selection_clear(0, END)
        self.lbMessages.selection_set(index)
        self.lbMessages.activate(index)

        self.mnMessages.tk_popup(event.x_root, event.y_root)

    def add_to_ignore_patchfile(self, event=None):
        """
        Add the selected message to the ignore patchfile.
        This means that this message will now be ignored by pylint-patcher.
        """
        selected = self.lbMessages.curselection()
        if not selected:
            return

        selected_index = int(selected[0])
        msg = self.visible_msgs[selected_index]
        self.differ.add_disable_pragma(msg.abspath, msg.line, msg.symbol)
        self.differ.diff()

        del self.msgs[self.msgs.index(msg)]
        del self.visible_msgs[selected_index]
        self.lbMessages.delete(selected_index)
Example #5
0
class SuperText(Text):
    
    def __init__(self, parent, scrollbar=True, **kw):
        
        self.parent = parent
        
        frame = Frame(parent)
        frame.pack(fill='both', expand=True)
        
        # text widget
        Text.__init__(self, frame, **kw)
        self.pack(side='left', fill='both', expand=True)
        
        # scrollbar
        if scrollbar:
            scrb = Scrollbar(frame, orient='vertical', command=self.yview) 
            self.config(yscrollcommand=scrb.set)
            scrb.pack(side='right', fill='y')
        
        # pop-up menu
        self.popup = Menu(self, tearoff=0)
        self.popup.add_command(label='Cut', command=self._cut)
        self.popup.add_command(label='Copy', command=self._copy)
        self.popup.add_command(label='Paste', command=self._paste)
        self.popup.add_separator()
        self.popup.add_command(label='Select All', command=self._select_all)
        self.popup.add_command(label='Clear All', command=self._clear_all)
        self.bind('<Button-3>', self._show_popup)
        
    def apply_theme(self, theme='standard'):
        '''theme=['standard', 'typewriter', 'terminal']'''

        if theme == 'typewriter':
            '''takes all inserted text and inserts it one char every 100ms'''
            text = self.get('1.0', 'end')
            self.delete('1.0', 'end')
            self.char_index = 0
            self._typewriter([char for char in text])
            
        elif theme == 'terminal':
            '''blocky insert cursor'''
            self.cursor = '1.0'
            self.fg = self.cget('fg')
            self.bg = self.cget('bg')
            self.switch = self.fg
            self.config(insertwidth=0)
            self._blink_cursor()
            self._place_cursor()
        
    def _show_popup(self, event):
        '''right-click popup menu'''
        
        if self.parent.focus_get() != self:
            self.focus_set()
        
        try:
            self.popup.tk_popup(event.x_root, event.y_root, 0)
        finally:
            self.popup.grab_release()
            
    def _cut(self):
        
        try:
            selection = self.get(*self.tag_ranges('sel'))
            self.clipboard_clear()
            self.clipboard_append(selection)
            self.delete(*self.tag_ranges('sel'))
        except TypeError:
            pass
    
    def _copy(self):
        
        try:
            selection = self.get(*self.tag_ranges('sel'))
            self.clipboard_clear()
            self.clipboard_append(selection)
        except TypeError:
            pass
        
    def _paste(self):
        
        self.insert('insert', self.selection_get(selection='CLIPBOARD'))
        
    def _select_all(self):
        '''selects all text'''
        
        self.tag_add('sel', '1.0', 'end-1c')
        
    def _clear_all(self):
        '''erases all text'''
        
        isok = askokcancel('Clear All', 'Erase all text?', parent=self,
                           default='ok')
        if isok:
            self.delete('1.0', 'end')

    def _typewriter(self, text): # theme: typewriter
        '''after the theme is applied, this method takes all the inserted text
        and types it out one character every 100ms'''

        self.insert('insert', text[self.char_index])
        self.char_index += 1

        if self.char_index == len(text):
            self.after_cancel(self.typer)
        else:
            self.typer = self.after(100, self._typewriter, text)

    def _place_cursor(self): # theme: terminal
        '''check the position of the cursor against the last known position
        every 15ms and update the cursorblock tag as needed'''

        current_index = self.index('insert')

        if self.cursor != current_index:
            self.cursor = current_index
            self.tag_delete('cursorblock')
            
            start = self.index('insert')
            end = self.index('insert+1c')
            
            if start[0] != end[0]:
                self.insert(start, ' ')
                end = self.index('insert')
                
            self.tag_add('cursorblock', start, end)
            self.mark_set('insert', self.cursor)

        self.after(15, self._place_cursor)

    def _blink_cursor(self): # theme: terminal
        '''alternate the background color of the cursorblock tagged text
        every 600 milliseconds'''
        
        if self.switch == self.fg:
            self.switch = self.bg
        else:
            self.switch = self.fg

        self.tag_config('cursorblock', background=self.switch)

        self.after(600, self._blink_cursor)
Example #6
0
class VisualVolumes(MyFrame):
    #Paths need to be changed when used in a different environment
    #Also segmentation accepts only one file now!
    
    def __init__(self,
                 image_paths=None,
                 segm_path=None,
                 supervoxel_id_path=None,
                 topframe=None):

        MyFrame.__init__(self,
                         topframe=None)
        Style().theme_use('clam')
        self.set_title('Visualise Volumes')


        self.set_variables(image_paths,
                           segm_path=segm_path,
                           supervoxel_id_path=supervoxel_id_path)

        self.create_ui(image_paths=image_paths,
                       supervoxel_id_path=supervoxel_id_path)


    ########## variable setting ###########################F

    def set_variables(self,
                      image_paths,
                      segm_path=None,
                      supervoxel_id_path=None):
        """Set initial alpha for opacity, boundaries, undo-redo stacks,
        and paths for modalities, segmentation and supervoxels"""

        #Alpha value for opacity initialization
        self.alpha = 0.2

        self._axis = 0

        self.show_supervoxels = True

        self._set_images(segm_path, image_paths, supervoxel_id_path)

        # set boundaries for all images:
        self.boundaries = ms.get_boundaries_series(image_paths)

        # set stacks for CTRL+Z and CTRL+Y
        # CTRL+Z to undo
        # CTRL+Y to redo
        self.undo_stack = []
        self.redo_stack = []
        self.image_nb = len(image_paths)
        self.selected_id_list = []
        #Keybindings for undo and redo actions
        self.bind('<Control-z>', self.undo_action)
        self.bind('<Control-y>', self.redo_action)
        self.bind('<t>', self.toggle_segm)     
        self.bind("<h>", self.set_healthy)
        self.bind("<r>", self.unselect_all)
        self.bind("<c>", self.print_com)
        self.bind("<i>", self.inverse_selection)
        for j in range(len(label_hot_keys)):
            self.bind("<%s>" % label_hot_keys[j],
                     lambda event, arg0=j : self.change_label(arg0))   
        self.bind("<Right>", self.slice_up)
        self.bind("<Left>", self.slice_down)
        self.focus_set()

    def _set_images(self, segm_path, image_paths, supervoxel_id_path):
        """ Set and check image and segmentation arrays and dimensions. """

        # Shapes for all modalities
        shapes = [oitk.get_itk_array(path).shape \
                  for path in image_paths]
        if len(set(shapes)) != 1:
            err = 'Images are not of same dimension'
            raise  ValueError(err)
        self.dim = shapes[0]

        # set the images and the image paths
        self.images = [oitk.get_itk_array(path) \
                       for path in image_paths]
        self.images_original = np.copy(self.images)

        # Get segmentation from segmentation path if given
        self.segm = None
        self.segm_path = None
        if segm_path is not None:
            self.segm = oitk.get_itk_array(segm_path)
            self.segm_path = segm_path

        # Get supervoxels from supervoxel path if given
        self.supervoxel_border = None
        self.supervoxel_id = None
        if supervoxel_id_path is not None:

            # get supervoxels and adapt if segmentation is at hand
            self.supervoxel_id = oitk.get_itk_array(supervoxel_id_path)
            if self.segm is not None:
                self.supervoxel_id = utils.adapt_borders(self.segm, 
                                                         self.supervoxel_id)

            # get borders of the supervoxels
            self.supervoxel_border = utils.get_borders(self.supervoxel_id)

    ########## Frame setting ############

    def create_ui(self, image_paths, supervoxel_id_path):
        """This function creates the UI elements."""

        sub_frame = Frame(self)
        sub_frame.grid(column=1,
                       row=0,
                       columnspan=self.image_nb)

        # create a sub frame to select the image slices that are displayed
        slice_frame = Frame(sub_frame)
        slice_frame.grid(column=0,
                         row=1,
                         columnspan=self.image_nb)

        pic_frame = Frame(sub_frame)
        pic_frame.grid(column=0,
                       row=0,
                       columnspan=self.image_nb)

        self.configure_images(pic_frame, image_paths)
        self.add_slice_bar(slice_frame)
        self.set_optional_buttons(supervoxel_id_path)


    def configure_images(self,
                         pic_frame,
                         image_paths):
        """Create widgets to place images, descriptions and slice scrollers."""

        # create a sub frame to display the images
        self._imagelabel = [None for _ in range(self.image_nb)]
        self._image_view = [None for _ in range(self.image_nb)]
        _descrlabel = [None for _ in range(self.image_nb)]

        # descriptions of the images defaults to their path basenames
        descriptions = [os.path.basename(image_paths[i]) 
                        for i in range(self.image_nb)]

        self.histogram_sliders = []
        for i in range(self.image_nb):

            _sub_pic_frame = Frame(pic_frame)
            _sub_pic_frame.grid(column=int(i%2),
                                row=int(i/2),
                                pady=5)

            # set Label for a description above the images
            _descrlabel[i] = Label(_sub_pic_frame,
                                   text=descriptions[i])
            _descrlabel[i].grid(column=0, row=0)


            # set Label to depict the images
            self._imagelabel[i] = Label(_sub_pic_frame)
            self._imagelabel[i].grid(column=0, row=1)


            # set Scales for the intensity slides
            _sub_sub_frame = Frame(_sub_pic_frame)
            _sub_sub_frame.grid(column=0,
                                row=2)

            min_val = np.min(self.images_original[i])
            max_val = np.max(self.images_original[i])

            intensity_scale1 = Scale(_sub_sub_frame,
                                     from_=min_val,
                                     to=max_val/2,
                                     orient=HORIZONTAL)
            intensity_scale1.set(min_val)
            intensity_scale1.grid(column=0,
                                  row=0,
                                  sticky=['e', 'w', 's'])

            intensity_scale2 = Scale(_sub_sub_frame,
                                     from_=max_val/2,
                                     to=max_val,
                                     orient=HORIZONTAL)
            intensity_scale2.set(max_val)
            intensity_scale2.grid(column=1,
                                  row=0,
                                  sticky=['e', 'w', 's'])

            self.histogram_sliders.append(intensity_scale1)
            self.histogram_sliders.append(intensity_scale2)
            intensity_scale1.bind("<B1-Motion>", self.change_intensity)
            intensity_scale2.bind("<B1-Motion>", self.change_intensity)

            # Attach commands to the image frames
            self._imagelabel[i].bind("<Button-1>", self.click_image)
            self._imagelabel[i].bind("<Button-3>", self.label_dropdown)
            self._imagelabel[i].bind("<Button 4>", self.slice_up)
            self._imagelabel[i].bind("<Button 5>", self.slice_down)
            self._imagelabel[i].bind("<B1-Motion>", self.motion_image)
            self._imagelabel[i].bind("<Double-Button-1>", self.select_connected)

    def add_slice_bar(self, slice_frame):
        """Add a slice selection options to slice_frame.

        Returns
        -------
        this_slice_label_number : Label
            the field displaying the current slice number
        this_new_slice : Entry
            the field allowing the user to fill in a slice number
        new_value : int
            the initial slice number to be set

        """

        # Have a line displaying slice number
        _slice_label = Label(slice_frame, text='Slice displayed : ')
        _slice_label.grid(column=0, row=0, sticky=['w', 'e'])
        this_slice_label_number = Label(slice_frame)
        this_slice_label_number.grid(column=1, row=0,
                                     sticky=['w', 'e'])

        # Allow to change slice number
        _goto = Label(slice_frame, text=' - go to slice :')
        _goto.grid(column=2, row=0, sticky=['w', 'e'])

        this_new_slice = Entry(slice_frame, width=6)
        this_new_slice.bind('<Return>', self.goto_slice)
        this_new_slice.bind('<KP_Enter>', self.goto_slice)
        this_new_slice.grid(column=3, row=0, sticky=['w', 'e'])

        self.image_scale = (self.screen_width - 200) / 4

        # Allow to scroll through the slices
        self._slice_scroll = lsb.LinkedScrollBar(master=slice_frame,
                                                 command=self.disp_im,
                                                 minVal=self._get_min_slice(),
                                                 maxVal=self._get_max_slice(),
                                                 step=1,
                                                 orient='horizontal')
        self._slice_scroll.grid(column=0,
                                row=1,
                                columnspan=self.image_nb,
                                sticky=['e', 'w', 's'])


        self._slice_label_number = this_slice_label_number
        self._new_slice = this_new_slice
        self.reset_slice_scroll()

    ##### allow to show segmentations, change axis and quit #########

    def set_optional_buttons(self, supervoxel_id_path=None):
        """ Set bottoms to quit, change axis, show and hide segmentation, ...
        at the upper row of the main frame.
        """

        _sub_frame1 = Frame(self)
        _sub_frame1.grid(column=0,
                         row=0,
                         padx=10,
                         sticky=['n', 'e', 'w'])

        _sub_sub_frame1 = Frame(_sub_frame1)
        _sub_sub_frame1.grid(column=0,
                             row=0,
                             sticky=['e', 'w'],
                             pady=10)

        ind = 0
        self.button_axis = Button(_sub_sub_frame1,
                                  text="Change axis",
                                  command=self.change_axis)
        self.button_axis.grid(column=0, row=ind, pady=3)
        
        ind += 1
        self.button_axis = Button(_sub_sub_frame1,
                                  text="Mirror Images",
                                  command=self.mirror_image)
        self.button_axis.grid(column=0, row=ind, pady=3)

        ind = 0
        if self.segm is not None:

            _sub_sub_frame2 = Frame(_sub_frame1)
            _sub_sub_frame2.grid(column=0,
                                 row=1,
                                 sticky=['e', 'w'],
                                 pady=10)

            _sub_sub_frame3 = Frame(_sub_frame1)
            _sub_sub_frame3.grid(column=0,
                                 row=2,
                                 sticky=['e', 'w'],
                                 pady=10)

            self.button_supervoxels = Button(_sub_sub_frame2,
                                             text="Show/Hide supervoxels",
                                             command=self.change_supervoxels)
            self.button_supervoxels.grid(column=0,
                                         row=ind,
                                         sticky=['w', 'n', 'e'])

            if supervoxel_id_path is None:
                self.button_supervoxels['state'] = 'disabled'
            ind += 1

            self.tumor_checkbox_label = Label(_sub_sub_frame2,
                                              text="Display tumor type: ",
                                              relief=FLAT)
            self.tumor_checkbox_label.grid(column=0, row=ind)

            ind += 1
            self.tumor_cb = []
            for i in range(len(labels)):
                tumor_button = IntVar()
                this_text = '%s (%s <%s>)' % (labels[i], 
                                              label_colors_d[i], 
                                              label_hot_keys[i+1])
                button = Checkbutton(_sub_sub_frame2,
                                        text=this_text,
                                        variable=tumor_button,
                                        command=lambda arg0=i: self.change_segm(arg0))
                button.grid(column=0, row=ind, sticky=['w', 'n', 'e'])
                self.tumor_cb.append(tumor_button)
                ind += 1
                
            self.all_tumor_bc = IntVar()
            button = Checkbutton(_sub_sub_frame2,
                                    text="All tumors",
                                    variable=self.all_tumor_bc,
                                    command=lambda : self.change_segm(3))
            button.grid(column=0,
                        row=ind,
                        sticky=['w', 'n', 'e'])

            ind += 1
            self.no_tumor_bc = IntVar()
            button = Checkbutton(_sub_sub_frame2,
                                    text="No tumors",
                                    variable=self.no_tumor_bc,
                                    command=lambda : self.change_segm(4))
            button.grid(column=0,
                           row=ind,
                           sticky=['w', 'n', 'e'])

            ind += 1
            alpha_label = Label(_sub_sub_frame2, text="Opacity:")
            alpha_label.grid(column=0, row=ind)
            self.alpha_scale = Scale(_sub_sub_frame2,
                                     from_=0.0,
                                     to=1.0,
                                     command=self.set_alpha,
                                     orient=HORIZONTAL)
            ind += 1
            self.alpha_scale.set(self.alpha)
            self.alpha_scale.grid(column=0,
                                  row=ind,
                                  columnspan=self.image_nb,
                                  sticky=['w', 'n', 'e'])

            ind = 0
            self.button_save_segm = Button(_sub_sub_frame3,
                                           text="Save segmentation",
                                           command=self.save_segm)
            self.button_save_segm.grid(column=0, row=ind, sticky=['w', 'n', 'e'])

            ind += 1
            self.button_open_segm = Button(_sub_sub_frame3,
                                           text="Open segmentation",
                                           command=self.open_segm)
            self.button_open_segm.grid(column=0, row=ind, sticky=['w', 'n', 'e'])


    #################### Display images ###########################

    def disp_im(self):
        """use the size, slice and zoom to display the image"""
        self.focus_set()
        slice_index = int(self._slice_scroll.val)

        for i in range(self.image_nb):
            pix = np.array(\
                    ms.get_slice(self.images[i],
                                 boundaries=self.boundaries,
                                 visual_center=slice_index,
                                 axis=self._axis),
                    dtype='float')

            temp_im, im_size = pil.get_image_pil(pix, 
                                                 self.image_scale, 
                                                 return_image_size=True)
            self.image_size = im_size
            temp_im = temp_im.convert('RGB')

            if self.segm is not None:
                temp_im = self.add_segmentation(temp_im, slice_index)
                
            if self.show_supervoxels and type(self.supervoxel_border) is np.ndarray:
                temp_im = self.add_supervoxels(temp_im, slice_index)

            # create the 2d view with or without the bounding box
            self._image_view[i] = ImageTk.PhotoImage(temp_im)
            self._imagelabel[i]['image'] = self._image_view[i]

        # update slice label
        self._slice_label_number['text'] = str(int(self._slice_scroll.val))

    def add_segmentation(self, image, slice_ind=None):
        """ Add a segmentation to the image (colors will be overlaid). """

        #Segmentation is separated into binary segmentations
        #Also, segm contains 3 binary segmentations
        if len(self.selected_id_list) > 0:
            segm = utils.get_separate_labels(self.segm_disp, length=len(labels)+1)
        else:
            segm = utils.get_separate_labels(self.segm, length=len(labels))
        r, g, b = image.convert('RGB').split()
        rgb = [r, g, b]

        #Variable that contains selected colors
        colors = [None for _ in range(len(segm))]

        #Add labels if their check box is selected
        if hasattr(self, 'tumor_cb'):
            for i in range(len(labels)):
                if self.tumor_cb[i].get() == 1:
                    colors[i] = label_colors[i]

        if len(colors)==4:
            colors[3] = selected

        #Do the painting with respect to colors variable
        for i in range(len(segm)):
            if colors[i] is None:
                continue
            pix = np.array(ms.get_slice(segm[i],
                                        boundaries=self.boundaries,
                                        visual_center=slice_ind,
                                        axis=self._axis))
            pix[pix > 0.5] = 1
            pix = pix.astype('uint8')

            if np.any(pix):
                color_region = pil.get_image_pil(pix, self.image_scale)
                rgb = pil.set_color_custom(color_region, colors[i], rgb=rgb)

        #Merge operation for all
        segm_im = ImagePIL.merge("RGB", rgb)
        return ImagePIL.blend(image, segm_im, self.alpha)
    
    def add_supervoxels(self, image, slice_ind=None):
        """ Add supervoxels to the image (boundaries will be drawn)."""

        r, g, b = image.convert('RGB').split()
        pix = np.array(ms.get_slice(self.supervoxel_id,
                                    boundaries=self.boundaries,
                                    visual_center=slice_ind,
                                    axis=self._axis))

        self.supervoxel_id_slice = pix

        if np.any(pix):
            pix = pix *50000

        #Get image with supervoxels that has borders calculated with contours
        sup_im = pil.get_image_pil(pix, self.image_scale)\
                        .convert("RGB")\
                         .filter(ImageFilter.CONTOUR)\
                         .filter(ImageFilter.EDGE_ENHANCE_MORE)\
                         .filter(ImageFilter.EDGE_ENHANCE_MORE)

        r_border, g_border, b_border = sup_im.split()
        r = pil.set_color_empty(r, r_border)
        g = pil.set_color_empty(g, g_border)
        b = pil.set_color_empty(b, b_border)

        #Merge operation for all colors
        sup_im = ImagePIL.merge("RGB", (r, g, b))
        return ImagePIL.blend(image, sup_im, self.alpha)

    #################### EVENTS: Change slice ######################
        
    def reset_slice_scroll(self):

        max_slice = self._get_max_slice()
        min_slice = self._get_min_slice()
        diff = max_slice - min_slice
        new_value = int(min_slice + np.floor(diff / 2))
        self._slice_scroll.set_value(new_value)
        
    def slice_up(self, *args):
        """increase slice number"""
        new_value = self._slice_scroll.val + 1
        if new_value <= self._get_max_slice(in_boundaries=True):
            self._slice_scroll.set_value(new_value)

    def slice_down(self, *args):
        """decrease slice number"""
        new_value = self._slice_scroll.val - 1
        if new_value >= self._get_min_slice(in_boundaries=True):
            self._slice_scroll.set_value(new_value)

    def _get_max_slice(self, in_boundaries=True):
        """Gets the maximum slice of the numpy array."""
        if in_boundaries:
            return self.boundaries[self._axis][1]
        else:
            return self.dim[self._axis] - 1

    def _get_min_slice(self, in_boundaries=True):
        """Gets the minimum slice of the numpy array."""
        if in_boundaries:
            return self.boundaries[self._axis][0]
        else:
            return 0
        
    def change_axis(self):
        """It changes the axis of the image."""
        self._axis = (self._axis + 1) % 3
        self.reset_slice_scroll()
        self.disp_im()

    def mirror_image(self):
        """It mirrors the image."""
        for i in range(self.image_nb):
            self.images[i] = np.flip(self.images[i], axis=(self._axis + 1) % 3)
            self.images_original[i] = np.flip(self.images_original[i], axis=(self._axis + 1) % 3)
        if self.segm is not None:
            self.segm = np.flip(self.segm, axis=(self._axis + 1) % 3)

        if self.show_supervoxels and type(self.supervoxel_border) is np.ndarray:
            self.supervoxel_id = np.flip(self.supervoxel_id, axis=(self._axis + 1) % 3)
            self.boundaries = ms.get_boundaries_series(self.images)
        self.disp_im()
        
    def goto_slice(self, *args):
        """moves to the desired slice"""

        z = self._new_slice.get()
        max_valid_z = self._get_max_slice(in_boundaries=True)
        min_valid_z = self._get_min_slice(in_boundaries=True)
        # if not an integer
        try:
            z = int(z)
            # if out of range
            if z < 0:
                msg = 'Please select a positive slice index. ' +\
                        'Lowest non-zero slice is shown.'
                self._slice_scroll.set_value(min_valid_z)
                self._new_slice.delete(0, END)
            elif z < min_valid_z:
                msg = 'Slice %d has only zeros. ' % z
                msg += 'Lowest non-zero slice is shown.'
                self._slice_scroll.set_value(min_valid_z)
                self._new_slice.delete(0, END)
            elif z > self._get_max_slice(in_boundaries=False):
                msg = 'Slice %d exceeds the image dimension. ' % z
                msg += 'Highest non-zero slice is shown.'
                self._slice_scroll.set_value(max_valid_z)
                self._new_slice.delete(0, END)
            elif z > max_valid_z:
                msg = 'Slice %d consists of zeros. ' % z
                msg += 'Highest non-zero slice is shown.'
                self._slice_scroll.set_value(max_valid_z)
                self._new_slice.delete(0, END)
            else:
                self._slice_scroll.set_value(z)
                self._new_slice.delete(0, END)
        except ValueError as e:
            print e
            self._new_slice.delete(0, END)   
            
    ############### EVENTS : select and change #########################
    
    def click_image(self, event):
        """ Select a supervoxel and color it in blue. 
        Called when clicked on an image. """
        
        supervoxel_id = self._get_supervoxel_id(event.x, event.y)
        self._update_selected_id_list(supervoxel_id)
        
    def motion_image(self, event):
        """ Select multiple supervoxels and color it in blue. 
        Called when clicked and motioned on an image. """
        
        supervoxel_id = self._get_supervoxel_id(event.x, event.y)
        self._update_selected_id_list(supervoxel_id, unselect=False)
        
    def select_connected(self, event):
        
        supervoxel_id = self._get_supervoxel_id(event.x, event.y)
        label = self.segm[self.supervoxel_id == supervoxel_id][0]
        
        im = sitk.GetImageFromArray((self.segm==label).astype(np.int))
        connected = sitk.GetArrayFromImage(sitk.ConnectedComponent(im))
        clabel = connected[self.supervoxel_id == supervoxel_id][0]
        supervoxel_ids = list(np.unique(self.supervoxel_id[connected==clabel]))
        self._update_selected_id_list(supervoxel_ids)
        
    def unselect_all(self, *args):
        """ Unselect all selected supervoxels. """
         
        print 'Emptying selection'
        self.selected_id_list = []
        self.disp_im()
        
    def set_healthy(self, *args):
        """ Select all supervoxels in this slice and set them to 
        background. """
         
        print 'Setting all supervoxels in slice to background'
        supervoxel_ids = list(np.unique(self.supervoxel_id_slice))
        if 0 in supervoxel_ids:
            supervoxel_ids.remove(0)
        self.change_label(0, supervoxel_ids=supervoxel_ids)
        
    def inverse_selection(self, *args):
        
        all_ids = np.unique(self.supervoxel_id)
        new_ids = [sup_id for sup_id in all_ids 
                   if id not in self.selected_id_list]
        self.selected_id_list = new_ids
        self.update_segm_display()        
        
    def _get_supervoxel_id(self, eventx, eventy):
        """ Get the supervoxel id of the given mouse position. """
        
        #the size of the image:
        #0 element of image corresponds to 1 element
        #of supervoxel_id_slice and vice versa

        #converting the coordinates on the clicked image into the 
        #coordinates of the voxel
        #Since the displayed pixels range from 1 to lenght+1,
        #need to subtract 1 from the coordinates
#         print self.supervoxel_id_slice.shape
        x_coordinate_supervoxel = (eventx - 1) *\
                                  len(self.supervoxel_id_slice[0]) /\
                                  self.image_size[0]

        y_coordinate_supervoxel = (eventy - 1) *\
                                  len(self.supervoxel_id_slice) /\
                                  self.image_size[1]

        z_coordinate_supervoxel = int(self._slice_scroll.val)

        coordinates = [x_coordinate_supervoxel,
                       y_coordinate_supervoxel,
                       z_coordinate_supervoxel]
        
        selected_id = self.supervoxel_id_slice[coordinates[1], coordinates[0]]

        return selected_id
        
    def _update_selected_id_list(self, selected_id, add_to_undo=True, unselect=True):
        """ Depending whether this supervoxel is already selected, mark
        or unmark the supervoxel. """
        
        if isinstance(selected_id, list):
            if unselect:
                if all([sid in self.selected_id_list for sid in selected_id]):
                    map(self.selected_id_list.remove, selected_id)
                else:
                    self.selected_id_list.extend(selected_id)
            else:
                if not all([sid in self.selected_id_list for sid in selected_id]):
                    self.selected_id_list.extend(selected_id)
                else:
                    return #nothing changed                    
        else:
            if unselect:
                if selected_id in self.selected_id_list:
                    self.selected_id_list.remove(selected_id)
                else:
                    self.selected_id_list.append(selected_id)
            else:
                if selected_id not in self.selected_id_list:
                    self.selected_id_list.append(selected_id)
                else:
                    return #nothing changed
        print 'Selected supervoxels: %s' % str(self.selected_id_list)
            
        if add_to_undo:
            action = selected_id, None, None
            self.undo_stack.append(action)
            
        self.update_segm_display()
        
    def update_segm_display(self):
        """ Color all supervoxels with ids in self.selected_id_list blue
        in self.segm_disp. """
        
        #Selection is updated for visualisation
        self.segm_disp = self.segm.copy()
        if len(self.selected_id_list) == 1:
            mask = self.supervoxel_id == self.selected_id_list[0]            
        elif len(self.selected_id_list) > 1:
            ind1d = np.in1d(self.supervoxel_id.flatten(), self.selected_id_list)
            mask = np.reshape(ind1d, self.supervoxel_id.shape)
        else:
            mask = np.zeros_like(self.supervoxel_id)
        
        selected_idx = np.where(mask)
        self.segm_disp[selected_idx[0], selected_idx[1], selected_idx[2]] = 4
            
        self.disp_im()
        
    def print_com(self, *args):
        
        ind1d = np.in1d(self.supervoxel_id.flatten(), self.selected_id_list)
        ind3d = np.reshape(ind1d, self.supervoxel_id.shape)        
        com = spim.measurements.center_of_mass(ind3d)
        print 'Center of mass'
        print '\t com : %s' % str(com)
        if self.segm_path is not None:
            ID = os.path.basename(self.segm_path).split('.')[0]
            print '\t path : %s' % ID
            print 'com_dict["%s"] = %s' % (ID, str(com))
            
    def label_dropdown(self, event):
        """When clicking right on a supervoxel, give a drop-down list
        with labels to change to."""

        if len(self.selected_id_list) == 0:
            return

        # Adding the selection menu with radio  buttons.
        self.menu = Menu(self, tearoff=0)
        self.menu\
            .add_radiobutton(label="Background",
                             value=0,
                             command=lambda arg0=0: \
                                        self.change_label(arg0))

        self.menu\
            .add_radiobutton(label=labels[0],
                             value=3,
                             command=lambda arg0=1: \
                                        self.change_label(arg0))

        self.menu\
            .add_radiobutton(label=labels[1],
                             value=2,
                             command=lambda arg0=2: \
                                        self.change_label(arg0))
        self.menu\
            .add_radiobutton(label=labels[2],
                             value=1,
                             command=lambda arg0=3: \
                                        self.change_label(arg0))
        self.menu.tk_popup(event.x_root, event.y_root)

    def change_label(self, new_label, supervoxel_ids=None):
        """Changing the label of the supervoxel

        new label is the type of pixel 0 - background,
        #3 - edema, 2 - Non-active tumor and 1 - Active tumor

        self.segm is the array with segmentations
        self.supervoxel_ids is the the array with the supervoxels

        """
        
        empty_selected_id_list = False
        if supervoxel_ids is None:
            empty_selected_id_list = True
            supervoxel_ids = self.selected_id_list

        #Empty the redo_stack whenever segmentation is changed by user
        self.redo_stack = []

        for selected_id in (supervoxel_ids):
            #Segmentation is updated with new labels
            #Old label is saved for undo and redo actions
            region = self.supervoxel_id == selected_id
            old_label = self.segm[region]
            old_label = old_label[0]
            self.segm[region] = new_label
    
            # if the checkboxes are unselected but changed, they are automatically checked.
            if new_label > 0:
                self.tumor_cb[new_label-1].set(1)
                self.no_tumor_bc.set(0)
    
            #Actions as coordinates, old_label and new_label to go switch between segmentation states
            action = selected_id, old_label, new_label
            self.undo_stack.append(action)
            
        if empty_selected_id_list:
            self.selected_id_list = []
        self.disp_im()

    def change_intensity(self, event):
        """ Change the intensity of the images based on the hist slider."""
        slider = event.widget
        i = self.histogram_sliders.index(slider)

        # find the image index based on the slider
        image_i = 3
        if i == 0 or i == 1:
            image_i = 0
        elif i == 2 or i == 3:
            image_i = 1
        elif i == 4 or i == 5:
            image_i = 2

        original_image = self.images_original[image_i]
        image = self.images[image_i]

        if (i + 1) % 2 == 0:
            slider_upper = slider
            slider_lower = self.histogram_sliders[i - 1]
        else:
            slider_lower = slider
            slider_upper = self.histogram_sliders[i + 1]

        lower = slider_lower.get()
        upper = slider_upper.get()
        lower = np.float(lower)
        upper = np.float(upper)
        np.clip(original_image, lower, upper, image)

        np.subtract(image, lower, out=image, casting='unsafe')
        self.disp_im()

    def change_segm(self, button_ind):
        """ Show or hide the segmentation from the images."""

        # if tumor type is (un)selected, set all_tumors and no_tumors 
        # accordingly
        if button_ind <= 2:
            checked = [self.tumor_cb[i].get() for i in range(len(labels))]
            checked_sum = sum(checked)
            if checked_sum < len(labels):
                self.all_tumor_bc.set(0)
            else:
                self.all_tumor_bc.set(1)
            if checked_sum > 0:
                self.no_tumor_bc.set(0)
            else:
                self.no_tumor_bc.set(1)

        # if all_tumors or no_tumors is (un)selected, allign the other
        # buttons
        if button_ind == 3:
            for i in range(len(labels)):
                self.tumor_cb[i].set(1)
            self.all_tumor_bc.set(1)
            self.no_tumor_bc.set(0)
        if button_ind == 4:
            for i in range(len(labels)):
                self.tumor_cb[i].set(0)
            self.all_tumor_bc.set(0)
            self.no_tumor_bc.set(1)
        self.disp_im()
        
    def toggle_segm(self, *args):
        
        # if at least one tumor type is visualized, 
        # remove all tumors (set no_tumors) and supervoxels
        checked = [self.tumor_cb[i].get() for i in range(len(labels))]
        checked_sum = sum(checked)
        if checked_sum > 0:
            print 'Visualizing no tumors'
            self.change_segm(4)
        # if no tumor type is visualized, set all_tumors
        # visualize all tumors (set all_tumors) and supervoxels
        else:
            print 'Visualizing all tumors'
            self.change_segm(3)
        
    def change_supervoxels(self):
        """ Toggle between showing supervoxels or not."""
        self.show_supervoxels = not self.show_supervoxels
        self.disp_im()

    def set_alpha(self, *args):
        """ Change the opacity level."""
        self.alpha = self.alpha_scale.get()
        self.disp_im()

    def undo_action(self, *args):
        """ Execute undo action on CTRL-Z."""

        #If respective stack is not empty
        #Go to the last state of segmentation
        #and update the redo_stack
        print 'undo!'
        if len(self.undo_stack) > 0:
            action = self.undo_stack.pop()
            self.redo_stack.append(action)
            selected_id, old_label, _ = action
            if old_label is not None:
                self._change_label_supervoxel(old_label, selected_id)
            else:
                self._update_selected_id_list(selected_id, add_to_undo=False)
            self.disp_im()

    def redo_action(self, *args):
        """Execute redo action on CTRL-Y"""

        #If respective stack is not empty
        #Go to the last state of segmentation
        #and update the undo_stack
        print 'redo!'
        if len(self.redo_stack) > 0:
            action = self.redo_stack.pop()
            self.undo_stack.append(action)
            selected_id, _, new_label = action
            if new_label is not None:
                self._change_label_supervoxel(new_label, selected_id)
            else:
                self._update_selected_id_list(selected_id, add_to_undo=False)
            self.disp_im()    
            
    def _change_label_supervoxel(self, new_label, selected_id):
        """ Change the label of the supervoxel

        cooordinates is a list of the ids of the selected voxel.
        coordinates[0] - x coordinate, coordinate[1] - y coordinate, coordinate[2] - z coordinate
        new label is the type of pixel 0 - background,
        3 - edema, 2 - Non-active tumor and 1 - Active tumor
        self.segms is the array with segmentations
        self.supervoxel_ids is the the array with the supervoxels"""
        #Segmentation is updated with new labels
        self.segm[self.supervoxel_id == selected_id] = new_label
        self.disp_im()   
        
    #################### Save or load a segmentation ###################        

    def save_segm(self):
        """ Save the current custom segmentation into a file."""
        kwargs = {}
        if self.segm_path is not None:
            dirname, basename = os.path.split(self.segm_path)
            if not basename.startswith('corrected_'):
                basename = 'corrected_'+basename
            kwargs['initialfile'] = basename
            kwargs['initialdir'] = dirname
        path = asksaveasfilename(title="Please select a path to save your segmentation",
                                 filetypes=[('Image files',
                                             ('.nii',
                                              '.mha',
                                              '.nii.gz'))],
                                 **kwargs)

        #TODO: change here self.segm_path
        if self.segm_path is not None:
            old_segm = oitk.get_itk_image(self.segm_path)
        image = oitk.make_itk_image(self.segm, old_segm)
        oitk.write_itk_image(image, path)

    def open_segm(self):
        """ Open a new custom segmentation from a file."""
        kwargs = {}
        kwargs['initialdir'] = os.environ.get('HOME')
        if self.segm_path is not None:
            dirname, basename = os.path.split(self.segm_path)
            if not basename.startswith('corrected_'):
                basename = 'corrected_'+basename
            kwargs['initialfile'] = basename
            kwargs['initialdir'] = dirname
        msg = 'Please select a segmentation'
        segm_path = askopenfilename(title=msg,
                                    filetypes=[('Image files',
                                                ('.nii',
                                                 '.mha',
                                                 '.nii.gz'))],
                                     **kwargs)
        if os.path.exists(segm_path):
            self.segm_path = segm_path
            self.segm = oitk.get_itk_array(self.segm_path)
            self.disp_im()
Example #7
0
class Gamelist():
    def __init__(self, drive, platform):
        GameListData.game_list_data_json = GameListData().get_game_list()
        self.json_game_list_data = GameListData.game_list_data_json

        if drive == 'USB(*)':
            self.drive_to_show = '/dev_' + drive.lower().replace('(*)', '')
        else:
            self.drive_to_show = '/dev_' + drive.lower() + '/'

        self.platform_to_show = platform + '_games'
        self.WCM_BASE_PATH  = AppPaths.wcm_gui
        self.last_selection = (None, 0)
        self.list_of_items = []

        self.selected_title_id   = None
        self.selected_title      = None
        self.selected_path       = None
        self.selected_filename   = None
        self.drive_system_path_array = None

        self.is_cleared = False


    def create_main_frame(self, entry_field_title_id, entry_field_title, entry_field_filename, entry_field_iso_path, entry_field_platform, drive_system_array):
        self.entry_field_title_id       = entry_field_title_id
        self.entry_field_title          = entry_field_title
        self.entry_field_filename       = entry_field_filename
        self.entry_field_iso_path       = entry_field_iso_path
        self.entry_field_platform       = entry_field_platform
        self.drive_system_path_array    = drive_system_array

        self.corrected_index = []
        self.main_frame = Frame()

        self.popup_menu = Menu(self.main_frame, tearoff=0)

        self.popup_menu.add_command(label="Delete",
                                    command=self.delete_selected)
        self.popup_menu.add_command(label="Rename",
                                    command=self.rename_selected)
        # self.popup_menu.add_command(label="Refetch",
        #                             command=self.refetch)
        # self.popup_menu.add_command(label="Select All",
        #                             command=self.select_all)




        s = Scrollbar(self.main_frame)
        self._listbox = Listbox(self.main_frame, width=465)
        self._listbox.bind('<Enter>', self._bound_to_mousewheel)
        self._listbox.bind('<Leave>', self._unbound_to_mousewheel)
        self._listbox.bind("<Button-3>", self.popup) # Button-2 on Aqua

        s.pack(side=RIGHT, fill=Y)
        self._listbox.pack(side=LEFT, fill=Y)

        s['command'] = self._listbox.yview
        self._listbox['yscrollcommand'] = s.set



        # default filters
        if 'ALL_games' == self.platform_to_show:
            # iterate all platforms
            for platform in self.json_game_list_data:
                for list_game in self.json_game_list_data[platform]:
                    # titles in the list has been designed to be unique
                    if '/dev_all/' == self.drive_to_show or self.drive_to_show in list_game['path']:
                        self.add_item(list_game['title'])

        else:
            for list_game in self.json_game_list_data[self.platform_to_show]:
                if '/dev_all/' == self.drive_to_show or self.drive_to_show in list_game['path']:
                    self.add_item(list_game['title'])

        for x in range(19 - self._listbox.size()):
            self.add_item('')


        # adding shade to every other row of the list
        for x in range(0, self._listbox.size()):
            if x % 2 == 0:
                self._listbox.itemconfig(x, {'fg': 'white'}, background='#001738')
            else:
                self._listbox.itemconfig(x, {'fg': 'white'}, background='#001F4C')

        self.label = Label(self.main_frame)
        self.selection_poller()

        return self.main_frame

    def selection_poller(self):
        self.label.after(200, self.selection_poller)
        self.new_selection = self._listbox.curselection()
        # cursor har been initiated
        if self._listbox.curselection() is not ():
            if self.new_selection[0] is not self.last_selection[0] or self.is_cleared:
                self.entry_fields_update(self.new_selection)
                self.is_cleared = False
                self.last_selection = self.new_selection


    def entry_fields_update(self, new_selection):
        for platform in self.json_game_list_data:

            for list_game in self.json_game_list_data[platform]:
                self.selected_title = self._listbox.get(new_selection[0])
                tmp_title = list_game['title']

                match = self.selected_title == str(tmp_title)
                if match:
                    self.selected_title_id   = str(list_game['title_id']).replace('-', '')
                    self.selected_title      = str(list_game['title'])
                    self.selected_path       = str(list_game['path'])
                    self.selected_filename   = str(list_game['filename'])
                    self.selected_platform   = str(list_game['platform'])

                    # parse drive and system from json data
                    path_array = filter(None, self.selected_path.split('/'))
                    self.drive_system_path_array[0] = path_array[0]
                    self.drive_system_path_array[1] = path_array[1]
                    self.drive_system_path_array[2] = '/'.join(path_array[2:len(path_array)]).replace('//', '')


                    self.entry_field_title_id.delete(0, len(self.entry_field_title_id.get())-1)
                    self.entry_field_title_id.delete(0, END)
                    self.entry_field_title_id.insert(0, self.selected_title_id)

                    self.entry_field_title.delete(0, END)
                    self.entry_field_title.insert(0, self.selected_title)

                    self.entry_field_filename.delete(0, END)
                    self.entry_field_filename.insert(0, self.selected_filename)

                    self.entry_field_platform.delete(0, END)
                    self.entry_field_platform.insert(0, self.selected_platform)

                    return True



    def get_selected_path(self):
        return self.current_iso_path

    def get_listbox(self):
        return self._listbox

    def get_ascending_index(self, list_of_items, item, ignore_case=True):
        lo = 0
        hi = len(list_of_items)

        if ignore_case:
            item = item.lower()
            while lo < hi:
                mid = (lo + hi) // 2

                if item < list_of_items[mid].lower():
                    hi = mid
                else:
                    lo = mid + 1
        else:
            while lo < hi:
                mid = (lo + hi) // 2

                if item < list_of_items[mid]:
                    hi = mid
                else:
                    lo = mid + 1
        return lo

    def add_item(self, item):
        if item != '':
            self.list_of_items = self._listbox.get(0, END)
            # getting ascending index in order to sort alphabetically
            index = self.get_ascending_index(self.list_of_items, item)

            self._listbox.insert(index, item)
        else:
            self._listbox.insert(END, item)

    def get_items(self):
        return self.list_of_items

    def _bound_to_mousewheel(self, event):
        self._listbox.bind_all("<MouseWheel>", self._on_mousewheel)

    def _unbound_to_mousewheel(self, event):
        self._listbox.unbind_all("<MouseWheel>")

    def _on_mousewheel(self, event):
        self._listbox.yview_scroll(int(-1*(event.delta/30)), "units")

    def popup(self, event):
        try:
            self._listbox.selection_clear(0, END)
            self._listbox.selection_set(self._listbox.nearest(event.y))
            self._listbox.activate(self._listbox.nearest(event.y))
        finally:
            if self._listbox.get(self._listbox.curselection()[0]) is not '':
                self.popup_menu.tk_popup(event.x_root + 43, event.y_root + 12, 0)
                self.popup_menu.grab_release()
                self.popup_menu.focus_set()

    def delete_selected(self):
        import tkMessageBox
        game_folder_path = os.path.join(AppPaths.game_work_dir, '..')
        response = tkMessageBox.askyesno('Delete game folder', 'Delete \'' + self.entry_field_title.get() + '\'?\n\nFolder path: ' + os.path.realpath(game_folder_path))
        # yes
        if response:
            # remove game from visual game list
            for i in self._listbox.curselection()[::-1]:
                self._listbox.delete(i)
                removed_index = i

            # remove game from json game list
            platform_key = self.entry_field_platform.get() + '_games'
            self.json_game_list_data[platform_key] = [x for x in self.json_game_list_data[platform_key] if x['title'] != self.selected_title]

            # update the json game list file
            with open(GameListData.GAME_LIST_DATA_PATH, 'w') as newFile:
                json_text = json.dumps(self.json_game_list_data, indent=4, separators=(",", ":"))
                newFile.write(json_text)

            # remove the game build folder too
            if AppPaths.game_work_dir != os.path.join(AppPaths.wcm_gui, 'work_dir'):
                if os.path.isdir(game_folder_path):
                    if 'webman-classics-maker' in game_folder_path:
                        shutil.rmtree(game_folder_path)
                # clear entry_fields
                self.clear_entries_and_path()
                # set cursor
                self._listbox.select_set(removed_index) #This only sets focus on the first item.

    def rename_selected(self):
        self.entry_field_title.selection_range(0, END)
        self.entry_field_title.focus_set()

    def select_all(self):
        self._listbox.selection_set(0, 'end')


    def clear_entries_and_path(self):
        self.entry_field_title_id.delete(0, len(self.entry_field_title_id.get())-1)
        self.entry_field_title_id.delete(0, END)
        self.entry_field_title.delete(0, END)
        self.entry_field_platform.delete(0, END)
        self.entry_field_filename.delete(0, END)

        self.is_cleared = True



    def get_selected_build_dir_path(self):
        self.build_dir_path = ''
        if self.selected_filename not in {'', None}:
            filename = self.selected_filename
            title_id = self.selected_title_id.replace('-', '')
            build_base_path = AppPaths.builds

            tmp_filename = filename
            # removes the file extension from tmp_filename
            for file_ext in GlobalVar.file_extensions:
                if filename.upper().endswith(file_ext):
                    tmp_filename = filename[0:len(filename)-len(file_ext)]
                    break
            game_folder_name = tmp_filename.replace(' ', '_') + '_(' + title_id.replace('-', '') + ')'

            self.build_dir_path = os.path.join(build_base_path, game_folder_name)
        return self.build_dir_path
Example #8
0
File: qgui.py Project: jkpr/QTools2
class PmaConvert:
    def __init__(self, config):
        root = Tk()

        # Root Definition
        root.geometry('1100x700')
        root.title('PMA Convert')

        # Configuration and Variables
        self.file_selection = ''
        self.is_converting = False
        self.options = config['option_definitions']
        gui_config = config['gui_config']

        # UI
        ## Frames
        self.main_frame = Frame(root)
        self.position_main_frame(gui_config['screen_orientation'])

        ## Components
        self.log = Text(self.main_frame, bd=1, relief=SUNKEN, width=140,
                        height=23, state=DISABLED, spacing3=1, wrap=WORD)

        choose_text = ('1. Choose XLSForm (.xls or .xlsx) file(s) for '
                       'conversion.')
        self.choose_files_label = Label(self.main_frame, text=choose_text)
        # TODO: Get spacing to work.
        # self.choose_files_label.grid(row=3, column=3, padx=(50, 50))
        # self.choose_files_label.grid(row=3, column=3, pady=(50, 50))
        self.choose_files_label.pack()
        self.choose_files_button = Button(self.main_frame,
                                          text='Choose file...', fg='black',
                                          command=self.on_open)
        self.choose_files_button.pack()

        out_text = 'Choose location for output file(s).'
        self.output_location_label = Label(self.main_frame, text=out_text)
        self.output_location_button = Button(self.main_frame,
                                             text='Choose location...',
                                             fg='black')
        if gui_config['output_location_on'] is True:
            self.output_location_label.pack()
            self.output_location_button.pack()

        self.choose_options_label = Label(self.main_frame,
                                          text='2. Choose conversion options.')
        self.choose_options_label.pack()

        ### Create Options Checkboxes
        # Task: Dynamically generate: http://stackoverflow.com/questions/...
        # ...553784/can-you-use-a-string-to-instantiate-a-class-in-python
        self.preexisting = BooleanVar()
        pre_text = self.options['preexisting']['label']
        self.preexisting_opt = Checkbutton(self.main_frame, text=pre_text,
                                           variable=self.preexisting)
        self.preexisting_opt.pack()
        self.regular = BooleanVar()
        reg_text = self.options['regular']['label']
        self.regular_opt = Checkbutton(self.main_frame, text=reg_text,
                                       variable=self.regular)
        self.regular_opt.pack()
        self.novalidate = BooleanVar()
        noval_text = self.options['novalidate']['label']
        self.novalidate_opt = Checkbutton(self.main_frame, text=noval_text,
                                          variable=self.novalidate)
        self.novalidate_opt.pack()
        self.ignore_version = BooleanVar()
        ig_text = self.options['ignore_version']['label']
        self.ignore_version_opt = Checkbutton(self.main_frame, text=ig_text,
                                              variable=self.ignore_version)
        self.ignore_version_opt.pack()
        self.linking_warn = BooleanVar()
        link_text = self.options['linking_warn']['label']
        self.linking_warn_option = Checkbutton(self.main_frame, text=link_text,
                                               variable=self.linking_warn)
        self.linking_warn_option.pack()
        self.debug = BooleanVar()
        debug_text = self.options['debug']['label']
        self.debug_option = Checkbutton(self.main_frame, text=debug_text,
                                        variable=self.debug)
        self.debug_option.pack()
        self.extras = BooleanVar()
        extras_text = self.options['extras']['label']
        self.extras_option = Checkbutton(self.main_frame, text=extras_text,
                                         variable=self.extras)
        self.extras_option.pack()

        self.convert_label = Label(self.main_frame, text='3. Run conversion.')
        self.convert_label.pack()

        # Task: Add xscrollcommand and yscrollcommand.
        self.convert_button = Button(self.main_frame, text='Convert',
                                     fg='black', command=self.convert)
        self.convert_button.pack()
        self.log.pack(fill=X, expand=1)
        self.log_text('PMA Convert allows you to convert .xls or .xlsx form '
                      'definition files to files which are compatible with ODK '
                      'Collect.\n\nIf you need to copy and paste from this '
                      'log, highlight the text and press CTRL+C to copy. Then '
                      'press CTRL+V to paste.\n\n'
                      '====================================================\n\n'
                      'Awaiting file selection.')

        # Task: Fix menus. They're not working.
        self.context_menu = Menu(self.main_frame, tearoff=0)
        self.context_menu.add_command(label="Convert", command=self.convert)
        self.main_frame.bind("<Button-3>", self.popup)

        # - Note: Strangely this stopped anchoring to bottom suddenly, for some
        # reason. So it is temporarily disabled.
        self.status_bar = Label(self.main_frame,
                                text='Awaiting file selection.',
                                bd=1, relief=SUNKEN, anchor=W)
        if gui_config['status_bar_on'] is True:
            self.status_bar.pack(side=BOTTOM, fill=X)

        # Run
        root.mainloop()

    # Functions
    def popup(self, event):
        # Note: Currently doesn't work.
        self.context_menu.post(event.x_root, event.y_root)
        # display the popup menu
        try:
            self.context_menu.tk_popup(event.x_root, event.y_root, 0)
        finally:
            # make sure to release the grab (Tk 8.0a1 only)
            self.context_menu.grab_release()

    def position_main_frame(self, orientation):
        if orientation == 'center':
            x, y, a = .5, .5, 'c'
            return self.main_frame.place(relx=x, rely=y, anchor=a)
        elif orientation == 'top':
            return self.main_frame.pack()
        else:
            return self.main_frame.pack()

    def on_open(self):
        file_types = [
            ('XLS Files', '*.xls'),
            ('XLSX Files', '*.xlsx'),
            ('All files', '*')
        ]
        try:
            self.file_selection = tkFileDialog.askopenfilename(
                filetypes=file_types, title='Open one or more files.',
                message='Open one or more files', multiple=1
            )
        except:
            self.file_selection = tkFileDialog.askopenfilename(
                filetypes=file_types, title='Open one or more files.', multiple=1
            )
        if self.file_selection != '':
            self.set_status('Click on Convert to convert files.')
            log_output = 'Ready for conversion: \n'
            for file in self.file_selection:
                log_output += '* ' + str(file) + '\n'
            log_output = log_output[:-1] # Removes the last '\n'.
            self.log.configure(self.log_text(log_output))

    def set_status(self, new_status):
        self.status_bar.configure(text=new_status)

    def log_text(self, new_text):
        self.log.configure(state=NORMAL)
        self.log.insert(END, str(new_text) + '\n\n')
        self.log.configure(state=DISABLED)
        self.log.bind("<1>", lambda event: self.log.focus_set())

    def convert(self):
        if self.file_selection != '':
            f = self.file_selection

            kwargs = {
                SUFFIX: u'',
                PREEXISTING: self.preexisting.get(),
                PMA: not self.regular.get(),
                CHECK_VERSIONING: not self.ignore_version.get(),
                STRICT_LINKING: not self.linking_warn.get(),
                VALIDATE: not self.novalidate.get(),
                EXTRAS: self.extras.get(),
                DEBUG: self.debug.get()
            }

            buffer = StringIO.StringIO()
            if not kwargs[DEBUG]:
                sys.stdout = buffer
                sys.stderr = buffer
            else:
                self.log_text('--> DEBUG MODE: check console output')

            try:
                xlsform_convert(f, **kwargs)
            except ConvertError as e:
                print unicode(e)
            except OSError as e:
                # Should catch WindowsError, impossible to test on Mac
                traceback.print_exc()
                print e

            if not kwargs[DEBUG]:
                sys.stdout = sys.__stdout__
                sys.stderr = sys.__stderr__

            self.log_text(buffer.getvalue())
Example #9
0
class LintGui(object):
    """Build and control a window to interact with pylint"""

    def __init__(self, root=None):
        """init"""
        self.root = root or Tk()
        self.root.title('Pylint')
        #reporter
        self.reporter = None
        #message queue for output from reporter
        self.msg_queue = Queue.Queue()
        self.msgs = []
        self.visible_msgs = []
        self.filenames = []
        self.rating = StringVar()
        self.tabs = {}
        self.report_stream = BasicStream(self)
        self.differ = differ.Differ()
        #gui objects
        self.lbMessages = None
        self.showhistory = None
        self.results = None
        self.btnRun = None
        self.information_box = None
        self.convention_box = None
        self.refactor_box = None
        self.warning_box = None
        self.error_box = None
        self.fatal_box = None
        self.txtModule = None
        self.status = None
        self.msg_type_dict = None
        self.init_gui()

    def init_gui(self):
        """init helper"""
        #setting up frames
        top_frame = Frame(self.root)
        mid_frame = Frame(self.root)
        radio_frame = Frame(self.root)
        res_frame = Frame(self.root)
        msg_frame = Frame(self.root)
        check_frame = Frame(self.root)
        history_frame = Frame(self.root)
        btn_frame = Frame(self.root)
        rating_frame = Frame(self.root)
        top_frame.pack(side=TOP, fill=X)
        mid_frame.pack(side=TOP, fill=X)
        history_frame.pack(side=TOP, fill=BOTH, expand=True)
        radio_frame.pack(side=TOP, fill=BOTH, expand=True)
        rating_frame.pack(side=TOP, fill=BOTH, expand=True)
        res_frame.pack(side=TOP, fill=BOTH, expand=True)
        check_frame.pack(side=TOP, fill=BOTH, expand=True)
        msg_frame.pack(side=TOP, fill=BOTH, expand=True)
        btn_frame.pack(side=TOP, fill=X)

        # Binding F5 application-wide to run lint
        self.root.bind('<F5>', self.run_lint)

        #Message ListBox
        rightscrollbar = Scrollbar(msg_frame)
        rightscrollbar.pack(side=RIGHT, fill=Y)
        bottomscrollbar = Scrollbar(msg_frame, orient=HORIZONTAL)
        bottomscrollbar.pack(side=BOTTOM, fill=X)
        self.lbMessages = Listbox(msg_frame,
                  yscrollcommand=rightscrollbar.set,
                  xscrollcommand=bottomscrollbar.set,
                  bg="white")
        self.lbMessages.bind("<Double-Button-1>", self.show_sourcefile)
        self.lbMessages.pack(expand=True, fill=BOTH)
        rightscrollbar.config(command=self.lbMessages.yview)
        bottomscrollbar.config(command=self.lbMessages.xview)

        #Message context menu
        self.mnMessages = Menu(self.lbMessages, tearoff=0)
        self.mnMessages.add_command(label="View in sourcefile",
                                    command=self.show_sourcefile)
        self.mnMessages.add_command(label="Add to ignore patchfile",
                                    command=self.add_to_ignore_patchfile)
        self.lbMessages.bind("<Button-3>", self.show_messages_context)

        #History ListBoxes
        rightscrollbar2 = Scrollbar(history_frame)
        rightscrollbar2.pack(side=RIGHT, fill=Y)
        bottomscrollbar2 = Scrollbar(history_frame, orient=HORIZONTAL)
        bottomscrollbar2.pack(side=BOTTOM, fill=X)
        self.showhistory = Listbox(history_frame,
                    yscrollcommand=rightscrollbar2.set,
                    xscrollcommand=bottomscrollbar2.set,
                    bg="white")
        self.showhistory.pack(expand=True, fill=BOTH)
        rightscrollbar2.config(command=self.showhistory.yview)
        bottomscrollbar2.config(command=self.showhistory.xview)
        self.showhistory.bind('<Double-Button-1>', self.select_recent_file)
        self.set_history_window()

        #status bar
        self.status = Label(self.root, text="", bd=1, relief=SUNKEN, anchor=W)
        self.status.pack(side=BOTTOM, fill=X)

        #labels
        self.lblRatingLabel = Label(rating_frame, text='Rating:')
        self.lblRatingLabel.pack(side=LEFT)
        self.lblRating = Label(rating_frame, textvariable=self.rating)
        self.lblRating.pack(side=LEFT)
        Label(mid_frame, text='Recently Used:').pack(side=LEFT)
        Label(top_frame, text='Module or package').pack(side=LEFT)

        #file textbox
        self.txtModule = Entry(top_frame, background='white')
        self.txtModule.bind('<Return>', self.run_lint)
        self.txtModule.pack(side=LEFT, expand=True, fill=X)

        #results box
        rightscrollbar = Scrollbar(res_frame)
        rightscrollbar.pack(side=RIGHT, fill=Y)
        bottomscrollbar = Scrollbar(res_frame, orient=HORIZONTAL)
        bottomscrollbar.pack(side=BOTTOM, fill=X)
        self.results = Listbox(res_frame,
                  yscrollcommand=rightscrollbar.set,
                  xscrollcommand=bottomscrollbar.set,
                  bg="white", font="Courier")
        self.results.pack(expand=True, fill=BOTH, side=BOTTOM)
        rightscrollbar.config(command=self.results.yview)
        bottomscrollbar.config(command=self.results.xview)

        #buttons
        Button(top_frame, text='Open', command=self.file_open).pack(side=LEFT)
        Button(top_frame, text='Open Package', 
               command=(lambda : self.file_open(package=True))).pack(side=LEFT)

        self.btnRun = Button(top_frame, text='Run', command=self.run_lint)
        self.btnRun.pack(side=LEFT)
        Button(btn_frame, text='Quit', command=self.quit).pack(side=BOTTOM)

        #radio buttons
        self.information_box = IntVar()
        self.convention_box = IntVar()
        self.refactor_box = IntVar()
        self.warning_box = IntVar()
        self.error_box = IntVar()
        self.fatal_box = IntVar()
        i = Checkbutton(check_frame, text="Information", fg=COLORS['(I)'],
                        variable=self.information_box, command=self.refresh_msg_window)
        c = Checkbutton(check_frame, text="Convention", fg=COLORS['(C)'],
                        variable=self.convention_box, command=self.refresh_msg_window)
        r = Checkbutton(check_frame, text="Refactor", fg=COLORS['(R)'],
                        variable=self.refactor_box, command=self.refresh_msg_window)
        w = Checkbutton(check_frame, text="Warning", fg=COLORS['(W)'],
                        variable=self.warning_box, command=self.refresh_msg_window)
        e = Checkbutton(check_frame, text="Error", fg=COLORS['(E)'],
                        variable=self.error_box, command=self.refresh_msg_window)
        f = Checkbutton(check_frame, text="Fatal", fg=COLORS['(F)'],
                        variable=self.fatal_box, command=self.refresh_msg_window)
        i.select()
        c.select()
        r.select()
        w.select()
        e.select()
        f.select()
        i.pack(side=LEFT)
        c.pack(side=LEFT)
        r.pack(side=LEFT)
        w.pack(side=LEFT)
        e.pack(side=LEFT)
        f.pack(side=LEFT)

        #check boxes
        self.box = StringVar()
        # XXX should be generated
        report = Radiobutton(radio_frame, text="Report", variable=self.box,
                             value="Report", command=self.refresh_results_window)
        rawMet = Radiobutton(radio_frame, text="Raw metrics", variable=self.box,
                             value="Raw metrics", command=self.refresh_results_window)
        dup = Radiobutton(radio_frame, text="Duplication", variable=self.box,
                          value="Duplication", command=self.refresh_results_window)
        ext = Radiobutton(radio_frame, text="External dependencies",
                          variable=self.box, value="External dependencies",
                          command=self.refresh_results_window)
        stat = Radiobutton(radio_frame, text="Statistics by type",
                           variable=self.box, value="Statistics by type",
                           command=self.refresh_results_window)
        msgCat = Radiobutton(radio_frame, text="Messages by category",
                             variable=self.box, value="Messages by category",
                             command=self.refresh_results_window)
        msg = Radiobutton(radio_frame, text="Messages", variable=self.box,
                            value="Messages", command=self.refresh_results_window)
        sourceFile = Radiobutton(radio_frame, text="Source File", variable=self.box,
                                   value="Source File", command=self.refresh_results_window)
        report.select()
        report.grid(column=0, row=0, sticky=W)
        rawMet.grid(column=1, row=0, sticky=W)
        dup.grid(column=2, row=0, sticky=W)
        msg.grid(column=3, row=0, sticky=W)
        stat.grid(column=0, row=1, sticky=W)
        msgCat.grid(column=1, row=1, sticky=W)
        ext.grid(column=2, row=1, sticky=W)
        sourceFile.grid(column=3, row=1, sticky=W)

        #dictionary for check boxes and associated error term
        self.msg_type_dict = {
            'I' : lambda : self.information_box.get() == 1,
            'C' : lambda : self.convention_box.get() == 1,
            'R' : lambda : self.refactor_box.get() == 1,
            'E' : lambda : self.error_box.get() == 1,
            'W' : lambda : self.warning_box.get() == 1,
            'F' : lambda : self.fatal_box.get() == 1
        }
        self.txtModule.focus_set()


    def select_recent_file(self, event):
        """adds the selected file in the history listbox to the Module box"""
        if not self.showhistory.size():
            return

        selected = self.showhistory.curselection()
        item = self.showhistory.get(selected)
        #update module
        self.txtModule.delete(0, END)
        self.txtModule.insert(0, item)

    def refresh_msg_window(self):
        """refresh the message window with current output"""
        #clear the window
        self.lbMessages.delete(0, END)
        self.visible_msgs = []
        for msg in self.msgs:
            if (self.msg_type_dict.get(msg.C)()):
                self.visible_msgs.append(msg)
                msg_str = convert_to_string(msg)
                self.lbMessages.insert(END, msg_str)
                fg_color = COLORS.get(msg_str[:3], 'black')
                self.lbMessages.itemconfigure(END, fg=fg_color)

    def refresh_results_window(self):
        """refresh the results window with current output"""
        #clear the window
        self.results.delete(0, END)
        try:
            for res in self.tabs[self.box.get()]:
                self.results.insert(END, res)
        except:
            pass

    def process_incoming(self):
        """process the incoming messages from running pylint"""
        while self.msg_queue.qsize():
            try:
                msg = self.msg_queue.get(0)
                if msg == "DONE":
                    self.report_stream.output_contents()
                    return False

                #adding message to list of msgs
                self.msgs.append(msg)

                #displaying msg if message type is selected in check box
                if (self.msg_type_dict.get(msg.C)()):
                    self.visible_msgs.append(msg)
                    msg_str = convert_to_string(msg)
                    self.lbMessages.insert(END, msg_str)
                    fg_color = COLORS.get(msg_str[:3], 'black')
                    self.lbMessages.itemconfigure(END, fg=fg_color)

            except Queue.Empty:
                pass
        return True

    def periodic_call(self):
        """determine when to unlock the run button"""
        if self.process_incoming():
            self.root.after(100, self.periodic_call)
        else:
            #enabling button so it can be run again
            self.btnRun.config(state=NORMAL)

    def mainloop(self):
        """launch the mainloop of the application"""
        self.root.mainloop()

    def quit(self, _=None):
        """quit the application"""
        self.root.quit()

    def halt(self):
        """program halt placeholder"""
        return

    def file_open(self, package=False, _=None):
        """launch a file browser"""
        if not package:
            filename = askopenfilename(parent=self.root, filetypes=[('pythonfiles', '*.py'),
                                                    ('allfiles', '*')], title='Select Module')
        else:
            filename = askdirectory(title="Select A Folder", mustexist=1)

        if filename == ():
            return

        self.txtModule.delete(0, END)
        self.txtModule.insert(0, filename)

    def update_filenames(self):
        """update the list of recent filenames"""
        filename = self.txtModule.get()
        if not filename:
            filename = os.getcwd()
        if filename+'\n' in self.filenames:
            index = self.filenames.index(filename+'\n')
            self.filenames.pop(index)

        #ensure only 10 most recent are stored
        if len(self.filenames) == 10:
            self.filenames.pop()
        self.filenames.insert(0, filename+'\n')

    def set_history_window(self):
        """update the history window with info from the history file"""
        #clear the window
        self.showhistory.delete(0, END)
        # keep the last 10 most recent files
        try:
            view_history = open(HOME+HISTORY, 'r')
            for hist in view_history.readlines():
                if not hist in self.filenames:
                    self.filenames.append(hist)
                self.showhistory.insert(END, hist.split('\n')[0])
            view_history.close()
        except IOError:
            # do nothing since history file will be created later
            return

    def run_lint(self, _=None):
        """launches pylint"""
        self.update_filenames()
        self.root.configure(cursor='watch')
        self.reporter = GUIReporter(self, output=self.report_stream)
        module = self.txtModule.get()
        if not module:
            module = os.getcwd()

        #cleaning up msgs and windows
        self.msgs = []
        self.visible_msgs = []
        self.lbMessages.delete(0, END)
        self.tabs = {}
        self.results.delete(0, END)
        self.btnRun.config(state=DISABLED)

        #setting up a worker thread to run pylint
        worker = Thread(target=lint_thread, args=(module, self.reporter, self,))
        self.periodic_call()
        worker.start()

        # Overwrite the .pylint-gui-history file with all the new recently added files
        # in order from filenames but only save last 10 files
        write_history = open(HOME+HISTORY, 'w')
        write_history.writelines(self.filenames)
        write_history.close()
        self.set_history_window()

        self.root.configure(cursor='')

    def show_sourcefile(self, event=None):
        selected = self.lbMessages.curselection()
        if not selected:
            return

        msg = self.visible_msgs[int(selected[0])]
        scroll = msg.line - 3
        if scroll < 0:
            scroll = 0

        self.tabs["Source File"] = open(msg.abspath, "r").readlines()
        self.box.set("Source File")
        self.refresh_results_window()
        self.results.yview(scroll)
        self.results.select_set(msg.line - 1)

    def show_messages_context(self, event):
        """Show the message listbox's context menu"""
        # Select the item that was clicked
        index = self.lbMessages.nearest(event.y)
        self.lbMessages.selection_clear(0, END);
        self.lbMessages.selection_set(index)
        self.lbMessages.activate(index)

        self.mnMessages.tk_popup(event.x_root, event.y_root)

    def add_to_ignore_patchfile(self, event=None):
        """
        Add the selected message to the ignore patchfile.
        This means that this message will now be ignored by pylint-patcher.
        """
        selected = self.lbMessages.curselection()
        if not selected:
            return

        selected_index = int(selected[0])
        msg = self.visible_msgs[selected_index]
        self.differ.add_disable_pragma(msg.abspath, msg.line, msg.symbol)
        self.differ.diff()

        del self.msgs[self.msgs.index(msg)]
        del self.visible_msgs[selected_index]
        self.lbMessages.delete(selected_index)