def __init__ (self, text=None, group=None): ToggleButton.__init__ (self, text) # Group, the RadioButton is attached to. self._group = None # List for attached RadioButtons. self._list = [] if group: group.add_button (self) else: self._list.append (self)
def destroy (self): """R.destroy () -> None Destroys the RadioButton and removes it from its event system. """ if self.group: self.group.remove_button (self) else: while len (self.list) > 0: self.remove_button (self.list[0]) del self._list del self._group ToggleButton.destroy (self)
def destroy(self): """R.destroy () -> None Destroys the RadioButton and removes it from its event system. """ if self.group: self.group.remove_button(self) else: while len(self.list) > 0: self.remove_button(self.list[0]) del self._list del self._group ToggleButton.destroy(self)
def __init__(self, text=None, group=None): ToggleButton.__init__(self, text) # Group, the RadioButton is attached to. self._group = None # List for attached RadioButtons. self._list = [] if group: group.add_button(self) else: self._list.append(self)
def set_active (self, active): """R.set_active (...) -> None Sets the state of the radio button. Sets the state of the RadioButton. if the active argument evaluates to True, the radio button will be activated and any other button of the same group deactivated. """ l = self.list or self.group.list if active: ToggleButton.set_active (self, active) for button in l: if button != self: button.set_active (False) else: found = False for button in l: if button.active and (button != self): found = True break if found: ToggleButton.set_active (self, active)
def set_active(self, active): """R.set_active (...) -> None Sets the state of the radio button. Sets the state of the RadioButton. if the active argument evaluates to True, the radio button will be activated and any other button of the same group deactivated. """ l = self.list or self.group.list if active: ToggleButton.set_active(self, active) for button in l: if button != self: button.set_active(False) else: found = False for button in l: if button.active and (button != self): found = True break if found: ToggleButton.set_active(self, active)
def createGeneralSettings(self): #This setups the General Settings generalFrame = LabelFrame(self, text="General", padx=10) generalFrame.pack(fill=X) self.generalFrame = generalFrame cameraLabel = Label(generalFrame, text="Camera") #cameraButton = ToggleButton(generalFrame,value=True,padx=5) self.cameraButton = ToggleButton(generalFrame, value=self.config.getData("camera"), padx=5) cameraLabel.grid(row=0, column=0, pady=2, sticky="w") self.cameraButton.grid(row=0, column=1, pady=2) maskLabel = Label(generalFrame, text="Mask") self.maskButton = ToggleButton(generalFrame, value=self.config.getData("mask"), padx=5) maskLabel.grid(row=1, column=0, pady=2, sticky="w") self.maskButton.grid(row=1, column=1, pady=2) leftMouseLabel = Label(generalFrame, text="Left Mouse Click") self.leftMouseButton = ToggleButton( generalFrame, value=self.config.getData("leftMouseClick"), padx=5) leftMouseLabel.grid(row=2, column=0, pady=2, sticky="w") self.leftMouseButton.grid(row=2, column=1, pady=2) rightMouseLabel = Label(generalFrame, text="Right Mouse Click") self.rightMouseButton = ToggleButton( generalFrame, value=self.config.getData("rightMouseClick"), padx=5) rightMouseLabel.grid(row=3, column=0, pady=2, sticky="w") self.rightMouseButton.grid(row=3, column=1, pady=2)
def __createMenu(self): """Create a tkinter canvas in which to hold the menu buttons. """ # Layout: # ------- # ------------------------------------------------------------------ # | Start || Capture New Image || Add/Remove Spaces || Quit | # ------------------------------------------------------------------ # | Register || Save || Load || Clear || Add/Remove CPs || ReadMe | # ------------------------------------------------------------------ # padding around buttons PADDING = 10 # start the main program self.start_button = tk.Button(self, text="Start PiPark", command=self.clickStart, padx=PADDING) self.start_button.grid(row=0, column=0, sticky=tk.W + tk.E + tk.N + tk.S) # register the car park button self.register_button = tk.Button(self, text="Register", command=self.clickRegister, padx=PADDING) self.register_button.grid(row=1, column=0, sticky=tk.W + tk.E + tk.N + tk.S) # take new setup image button self.image_button = tk.Button(self, text="Capture New Setup Image", command=self.clickNewImage, padx=PADDING) self.image_button.grid(row=0, column=1, rowspan=1, columnspan=3, sticky=tk.W + tk.E + tk.N + tk.S) # save setup data & image self.save_button = tk.Button(self, text="Save", command=self.clickSave, padx=PADDING) self.save_button.grid(row=1, column=1, sticky=tk.W + tk.E + tk.N + tk.S) # load setup data & image self.load_button = tk.Button(self, text="Load", command=self.clickLoad, padx=PADDING) self.load_button.grid(row=1, column=2, sticky=tk.W + tk.E + tk.N + tk.S) # clear all parking spaces and CPs self.clear_button = tk.Button(self, text="Clear", command=self.clickClear, padx=PADDING) self.clear_button.grid(row=1, column=3, sticky=tk.W + tk.E + tk.N + tk.S) # add/remove spaces button self.spaces_button = ToggleButton(self) self.spaces_button.config(text="Add/Remove Spaces", command=self.clickSpaces, padx=PADDING, state=tk.DISABLED) self.spaces_button.grid(row=0, column=4, sticky=tk.W + tk.E + tk.N + tk.S) # add/remove control points button self.cps_button = ToggleButton(self) self.cps_button.config(text="Add/Remove Control Points", command=self.clickCPs, padx=PADDING, state=tk.DISABLED) self.cps_button.grid(row=1, column=4, sticky=tk.W + tk.E + tk.N + tk.S) # quit setup self.quit_button = tk.Button(self, text="Quit", command=self.clickQuit, padx=PADDING) self.quit_button.grid(row=0, column=5, sticky=tk.W + tk.E + tk.N + tk.S) # about button - display information about PiPark self.about_button = tk.Button(self, text="Open ReadMe", command=self.clickAbout, padx=PADDING) self.about_button.grid(row=1, column=5, sticky=tk.W + tk.E + tk.N + tk.S)
def _buildUi(self): self._settings = configparser.ConfigParser() ini = 'settings.ini' if os.path.isfile(ini): self._settings.read_file(codecs.open(ini, 'r', 'utf8')) if 'parameters' not in self._settings.sections(): self._settings.add_section('parameters') if 'param' not in self._settings['parameters']: self._settings['parameters']['param'] = "1" # default, values must be string main_layout = QVBoxLayout() main_layout.setSpacing(12) self._led = LedWidget(PROP_NAME, QSize(40, 20)) self._led.setRedAsBold(True) self._led.setRedAsRed(True) self._led.switchOn('gray') try: NO_SETTINGS_DIALOG if NO_SETTINGS_DIALOG: settings_button = QPushButton() settings_button.setIcon(QIcon("./images/settings.svg")) settings_button.setFlat(True) settings_button.setToolTip(self.tr("Configuration")) settings_button.setIconSize(QSize(16, 16)) settings_button.setFixedSize(QSize(24, 24)) else: settings_button = None except: settings_button = None header_layout = QHBoxLayout() header_layout.addWidget(self._led) if settings_button is not None: header_layout.addWidget(settings_button, Qt.AlignRight) settings_button.pressed.connect(self.onSettingsButton) main_layout.addLayout(header_layout) box = QGroupBox(self.tr("")) box_layout = QVBoxLayout(box) box_layout.setSpacing(12) main_layout.addWidget(box) self._dataLed = DataWidget(label=self.tr("Led"), variable='led', image_on=DATALED_IMAGE_ON, image_off=DATALED_IMAGE_OFF) box_layout.addWidget(self._dataLed) self._dataLedText = DataWidget(label=self.tr("Led (value)"), variable='led') box_layout.addWidget(self._dataLedText) self._blinkSwitch = SwitchWidget(label=self.tr("Blinking"), variable='led', image_on=DATALED_IMAGE_ON, image_off=DATALED_IMAGE_OFF, sync='blink', sync_on='yes', sync_off='no', action_on='blink:1', action_off='blink:0', topic=self._propInbox) box_layout.addWidget(self._blinkSwitch) box_layout.addWidget(QLabel("<hr>")) self._blinkOnButton = PushButton(self.tr("Start blinking"), 'blink:1', self._propInbox) box_layout.addWidget(self._blinkOnButton) self._blinkOffButton = PushButton(self.tr("Stop blinking"), 'blink:0', self._propInbox) box_layout.addWidget(self._blinkOffButton) box_layout.addWidget(QLabel("<hr>")) self._blinkToggleButton = ToggleButton(caption_on=self.tr("Start blinking"), caption_off=self.tr("Stop blinking"), variable='blink', sync_on='no', sync_off='yes', action_on='blink:1', action_off='blink:0', topic=self._propInbox) box_layout.addWidget(self._blinkToggleButton) main_layout.addStretch(0) self.setLayout(main_layout) self.switchLed.connect(self._led.switchOn) self.propDataReveived.connect(self._dataLed.onDataReceived) self.propDataReveived.connect(self._dataLedText.onDataReceived) self.propDataReveived.connect(self._blinkSwitch.onDataReceived) self.propDataReveived.connect(self._blinkToggleButton.onDataReceived) self._blinkOnButton.publishMessage.connect(self.publishMessage) self._blinkOffButton.publishMessage.connect(self.publishMessage) self._blinkSwitch.publishMessage.connect(self.publishMessage) self._blinkToggleButton.publishMessage.connect(self.publishMessage)
def __createMenu(self): """Create a tkinter canvas in which to hold the menu buttons. """ # padding around buttons PADDING = 10 # start the main program self.start_button = tk.Button(self, text="Start", command=self.clickStart, padx=PADDING) self.start_button.grid(row=0, column=0, sticky=tk.W + tk.E + tk.N + tk.S) # take new setup image button self.image_button = tk.Button(self, text="Capture New Setup Image", command=self.clickNewImage, padx=PADDING) self.image_button.grid(row=0, column=1, rowspan=1, columnspan=3, sticky=tk.W + tk.E + tk.N + tk.S) # save setup data & image self.save_button = tk.Button(self, text="Save", command=self.clickSave, padx=PADDING) self.save_button.grid(row=1, column=1, sticky=tk.W + tk.E + tk.N + tk.S) # load setup data & image self.load_button = tk.Button(self, text="Load", command=self.clickLoad, padx=PADDING) self.load_button.grid(row=1, column=2, sticky=tk.W + tk.E + tk.N + tk.S) # clear all parking spaces and CPs self.clear_button = tk.Button(self, text="Clear", command=self.clickClear, padx=PADDING) self.clear_button.grid(row=1, column=3, sticky=tk.W + tk.E + tk.N + tk.S) # add/remove spaces button self.spaces_button = ToggleButton(self) self.spaces_button.config(text="Add/Remove Spaces", command=self.clickSpaces, padx=PADDING, state=tk.DISABLED) self.spaces_button.grid(row=0, column=4, rowspan=1, columnspan=2, sticky=tk.W + tk.E + tk.N + tk.S) # add/remove control points button self.cps_button = ToggleButton(self) self.cps_button.config(text="Add/Remove Control Points", command=self.clickCPs, padx=PADDING, state=tk.DISABLED) self.cps_button.grid(row=1, column=4, rowspan=1, columnspan=2, sticky=tk.W + tk.E + tk.N + tk.S) # quit setup self.quit_button = tk.Button(self, text="Quit", command=self.clickQuit, padx=PADDING) self.quit_button.grid(row=1, column=0, sticky=tk.W + tk.E + tk.N + tk.S)
class Application(tk.Frame): __is_verbose = s.IS_VERBOSE __is_saved = False __parking_spaces = None __control_points = None __camera = None __camera_is_active = False SETUP_IMAGE = "./images/setup.jpeg" DEFAULT_IMAGE = "./images/default.jpeg" def __init__(self, master=None): tk.Frame.__init__(self, master) self.grid() self.__createDisplay() self.__createMenu() self.__parking_spaces = Boxes(self.display, type=0) self.__control_points = Boxes(self.display, type=1) self.bind("<Return>", self.returnPressHandler) self.bind("<Key>", self.keyPressHandler) self.bind("<Escape>", self.escapePressHandler) self.display.bind("<Button-1>", self.leftClickHandler) self.display.bind("<Button-3>", self.rightClickHandler) self.focus_set() def loadImage(self, image_address, canvas, width, height): canvas.delete(tk.ALL) try: if not isinstance(canvas, tk.Canvas): raise TypeError if not isinstance(image_address, str): raise TypeError if not isinstance(width, int): raise TypeError if not isinstance(height, int): raise TypeError photo = ImageTk.PhotoImage(Image.open(image_address)) canvas.create_image((width, height), image=photo) canvas.image = photo return True except TypeError: if self.__is_verbose: print "ERROR: loadImage() arguments of incorrect data type." return False except: # image failed to load if self.__is_verbose: print "ERROR: loadImage() failed to load image " + image_address return False def turnOnCamera(self): tkMessageBox.showinfo( title="", message="Press the ENTER key to take a new setup image " + "or the ESCAPE key to cancel.") try: self.__camera = imageread.setup_camera(is_fullscreen=True) self.__camera.awb_mode = 'auto' self.__camera.exposure_mode = 'auto' self.__camera.start_preview() self.__camera_is_active = True except: tkMessageBox.showerror( title="Error!", message="Error: Failed to setup and start PiCam.") def saveData(self): f1 = open('./setup_data.py', 'w+') print >> f1, 'boxes = [' for i in range(self.__parking_spaces.length()): space = self.__parking_spaces.get(i).getOutput() if space != None: o = (i) print >> f1, space, ',' for j in range(self.__control_points.length()): cp = self.__control_points.get(j).getOutput() if cp != None: o = (i) print >> f1, cp, ',' print >> f1, ']' self.__is_saved = True if self.__is_verbose: print 'INFO: Data saved in file setup_data.py.' tkMessageBox.showinfo(title="Setup", message="Data saved successfully.") def loadData(self): try: import setup_data reload(setup_data) except: if self.__is_verbose: print "ERROR: Problem loading data from ./setup_data.py" tkMessageBox.showerror( title="Error!", message="Problem loading data from setup_data.py") self.__is_saved = True return setup_data.boxes def checkData(self): if self.__is_verbose: print "INFO: Data is being checked for validity." try: import setup_data reload(setup_data) box_data = setup_data.boxes if not box_data: raise ValueError except ImportError: if self.__is_verbose: print "ERROR: Problem loading data from ./setup_data.py" except ValueError: if self.__is_verbose: print "ERROR: ./setup_data.py 'boxes' is empty." except: if self.__is_verbose: print "ERROR: ./setup_data.py does not contain 'boxes'." space_boxes = [] control_boxes = [] for data_set in box_data: if data_set[1] == 0: space_boxes.append(data_set) elif data_set[1] == 1: control_boxes.append(data_set) elif self.__is_verbose: print "ERROR: Box-type not set to either 0 or 1." if len(space_boxes) > 0 and len(control_boxes) == 3: valid_data = True else: valid_data = False if self.__is_verbose: print "INFO: Data checked. Data is", valid_data return valid_data def register(self): if not self.__is_saved: response = tkMessageBox.askokcancel( title="Save Setup", message="Setup data must be saved before the registration" + " process can be completed. Would you like to save now?") if response: self.saveData() else: tkMessageBox.showinfo(title="Setup", message="Registration not completed.") return if not self.checkData(): tkMessageBox.showinfo( title="Setup", message="Registration not complete.\n\nSaved data is " + "invalid. Please ensure that there are 3 control points and " + "at least 1 parking spaces marked.") return try: import setup_data reload(setup_data) boxes = setup_data.boxes if not isinstance(boxes, list): raise ValueError() except: print "ERROR: Setup data does not exist. Please run options 1 and 2 first." return try: import senddata except: print "ERROR: Could not import send data file." return # start fresh out = senddata.deregister_pi() try: out['error'] print "ERROR: Error in connecting to server. Please update settings.py." return except: pass for box in boxes: if box[1] == 0: output = senddata.register_area(box[0]) if "error" in output.keys(): if self.__is_verbose: print "ERROR:", output["error"] return else: if self.__is_verbose: print "INFO: Registering area", box[0], "on server." # print success message if self.__is_verbose: print "\nINFO: Server registration successful." def returnPressHandler(self, event): self.focus_set() if not self.__camera_is_active or not self.__camera: return try: self.__camera.capture(self.SETUP_IMAGE) self.__camera.stop_preview() self.__camera.close() self.__camera_is_active = False if self.__is_verbose: print "INFO: New setup image captured." print "INFO: PiCam deactivated." except: # image failed to capture, show error message tkMessageBox.showerror( title="Error!", message="Error: Failed to capture new setup image.") # load the new setup image self.loadImage(self.SETUP_IMAGE, self.display, s.PICTURE_RESOLUTION[0] / 2, s.PICTURE_RESOLUTION[1] / 2) self.cps_button.config(state=tk.ACTIVE) self.spaces_button.config(state=tk.ACTIVE) def escapePressHandler(self, event): self.focus_set() if not self.__camera_is_active or not self.__camera: return try: # close the camera without taking new image self.__camera.stop_preview() self.__camera.close() self.__camera_is_active = False if self.__is_verbose: print "INFO: PiCam deactivated." except: # image failed to close for some reason, show error message if self.__is_verbose: print "ERROR: PiCam failed to close correctly." def keyPressHandler(self, event): """Handle key-press events for numeric keys. """ key = event.char NUM_KEYS = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'] if key in NUM_KEYS: if self.spaces_button.getIsActive(): self.__parking_spaces.setCurrentBox(int(key)) if self.cps_button.getIsActive(): # ignore all other numbers, but 1, 2 and 3 as 3 is the maximum # number of control points allowed. if key not in ['1', '2', '3']: return # NB: -1 from key press, because list indices are [0, 1, 2], # but for ease of user selection the numbers 1, 2, 3 are used # for input self.__control_points.setCurrentBox(int(key) - 1) def leftClickHandler(self, event): # ensure focus on display canvas to recieve mouse clicks self.display.focus_set() # perform correct operation, dependent on which toggle button is active # add new control points (max = 3) if self.cps_button.getIsActive(): if self.__is_verbose: print "INFO: Add Control Point" self.__is_saved = False this_cp_id = self.__control_points.getCurrentBox() this_cp = self.__control_points.boxes[this_cp_id] this_cp.updatePoints(event.x, event.y) # add new parking space elif self.spaces_button.getIsActive(): if self.__is_verbose: print "INFO: Add Parking Space" self.__is_saved = False this_space_id = self.__parking_spaces.getCurrentBox() this_space = self.__parking_spaces.boxes[this_space_id] this_space.updatePoints(event.x, event.y) # do nothing -- ignore LMB clicks else: if self.__is_verbose: print "INFO: Just clicking LMB merrily =D" # return focus to the main frame for key-press events self.focus_set() def rightClickHandler(self, event): # ensure focus is set to the display canvas self.display.focus_set() # perform correct operation, dependent on which toggle button is active if self.cps_button.getIsActive(): if self.__is_verbose: print "INFO: Remove Control Point" self.__is_saved = False self.__control_points.boxes[ self.__control_points.getCurrentBox()].clear() self.__control_points.boxes[ self.__control_points.getCurrentBox()].deleteRectangle( self.display) elif self.spaces_button.getIsActive(): if self.__is_verbose: print "INFO: Remove parking space" self.__is_saved = False self.__parking_spaces.boxes[ self.__parking_spaces.getCurrentBox()].clear() self.__parking_spaces.boxes[ self.__parking_spaces.getCurrentBox()].deleteRectangle( self.display) else: if self.__is_verbose: print "INFO: Just clicking RMB merrily =)" # return focus to the main frame for key-press events self.focus_set() def clickStart(self): """ Close the current setup application, then initiate the main PiPark program. """ if self.__is_verbose: print "ACTION: Clicked 'Start'" # turn off toggle buttons self.spaces_button.setOff() self.cps_button.setOff() # set initial responses response = False response1 = False response2 = False # if setup data has not been saved. Ask user if they would like to save # before continuing. if not self.__is_saved: response = tkMessageBox.askyesno( title="Save Setup", type=tkMessageBox.YESNOCANCEL, message="Most recent changes to setup have not been saved." + "Would you like to save before running PiPark?") if response: self.saveData() # data is saved, ask the user if they are sure they wish to quit. else: response = tkMessageBox.askyesno( title="Save Setup", message="Are you ready to leave setup and run PiPark?") # user wishes to quit setup and run pipark, so do it! if response: # ensure data is valid before continuing if not self.checkData(): # data invalid, so display message and return tkMessageBox.showinfo( title="Setup", message="Saved data is invalid. Please ensure that " + "there are 3 control points and at least 1 parking " + "space marked.") return self.quit_button.invoke() if self.__is_verbose: print "INFO: Setup application terminated. " main.main() def clickRegister(self): """Register the car park with the server. """ if self.__is_verbose: print "ACTION: Clicked 'Register'" # turn off toggle buttons self.spaces_button.setOff() self.cps_button.setOff() self.register() def clickNewImage(self): """Use PiCam to take new 'setup image' for PiPark setup. """ if self.__is_verbose: print "ACTION: Clicked 'Capture New Image'" self.__is_saved = False # turn off toggle buttons self.spaces_button.setOff() self.cps_button.setOff() self.__parking_spaces.clearAll(self.display) self.__control_points.clearAll(self.display) self.turnOnCamera() def clickSave(self): if self.__is_verbose: print "ACTION: Clicked Save'" # turn off toggle buttons self.spaces_button.setOff() self.cps_button.setOff() self.saveData() def clickLoad(self): if self.__is_verbose: print "ACTION: Clicked 'Load'" # turn off toggle buttons self.spaces_button.setOff() self.cps_button.setOff() if not self.loadImage(self.SETUP_IMAGE, self.display, s.PICTURE_RESOLUTION[0] / 2, s.PICTURE_RESOLUTION[1] / 2): tkMessageBox.showerror( title="Error!", message="Error loading setup image." + " Please ensure setup image exists as ./image/setup_image.jpeg." ) return # clear all previous data, and activate buttons self.clear_button.invoke() self.cps_button.config(state=tk.ACTIVE) self.spaces_button.config(state=tk.ACTIVE) def clickClear(self): if self.__is_verbose: print "ACTION: Clicked 'Clear'" self.__is_saved = False # clear all data points, to start afresh self.__parking_spaces.clearAll(self.display) self.__control_points.clearAll(self.display) def clickSpaces(self): """Add/remove parking-space bounding boxes. """ if self.__is_verbose: print "ACTION: Clicked 'Add/Remove Spaces'" # toggle the button, and turn off other toggle buttons self.spaces_button.toggle() if self.cps_button.getIsActive(): self.cps_button.setOff() def clickCPs(self): """Add/remove control points. """ if self.__is_verbose: print "ACTION: Clicked 'Add/Remove CPs'" # toggle the button, and turn off other toggle buttons self.cps_button.toggle() if self.spaces_button.getIsActive(): self.spaces_button.setOff() def clickQuit(self): """Quit & terminate the application. """ if self.__is_verbose: print "ACTION: Clicked 'Quit'" # turn off toggle buttons self.spaces_button.setOff() self.cps_button.setOff() response = True # if the user hasn't recently saved, ask if they really wish to quit if not self.__is_saved: response = tkMessageBox.askyesno( title="Quit?", message="Are you sure you wish to quit?" + "All unsaved setup will be lost.") if response: # user wishes to quit, destroy the application self.quit() self.master.destroy() def clickAbout(self): """Open the README file for instructions on GUI use. """ if self.__is_verbose: print "ACTION: Clicked 'Open README'" # turn off toggle buttons self.spaces_button.setOff() self.cps_button.setOff() # load external README from command line # TODO: Put this in new Tkinter window with scroll bar os.system("leafpad " + "./SETUP_README.txt") if self.__is_verbose: print "INFO: Opened ./SETUP_README.txt in leafpad." def __createDisplay(self): self.display = tk.Canvas(self, width=s.PICTURE_RESOLUTION[0], height=s.PICTURE_RESOLUTION[1]) self.display.grid(row=2, column=0, rowspan=1, columnspan=6) def __createMenu(self): """Create a tkinter canvas in which to hold the menu buttons. """ # padding around buttons PADDING = 10 # start the main program self.start_button = tk.Button(self, text="Start", command=self.clickStart, padx=PADDING) self.start_button.grid(row=0, column=0, sticky=tk.W + tk.E + tk.N + tk.S) # take new setup image button self.image_button = tk.Button(self, text="Capture New Setup Image", command=self.clickNewImage, padx=PADDING) self.image_button.grid(row=0, column=1, rowspan=1, columnspan=3, sticky=tk.W + tk.E + tk.N + tk.S) # save setup data & image self.save_button = tk.Button(self, text="Save", command=self.clickSave, padx=PADDING) self.save_button.grid(row=1, column=1, sticky=tk.W + tk.E + tk.N + tk.S) # load setup data & image self.load_button = tk.Button(self, text="Load", command=self.clickLoad, padx=PADDING) self.load_button.grid(row=1, column=2, sticky=tk.W + tk.E + tk.N + tk.S) # clear all parking spaces and CPs self.clear_button = tk.Button(self, text="Clear", command=self.clickClear, padx=PADDING) self.clear_button.grid(row=1, column=3, sticky=tk.W + tk.E + tk.N + tk.S) # add/remove spaces button self.spaces_button = ToggleButton(self) self.spaces_button.config(text="Add/Remove Spaces", command=self.clickSpaces, padx=PADDING, state=tk.DISABLED) self.spaces_button.grid(row=0, column=4, rowspan=1, columnspan=2, sticky=tk.W + tk.E + tk.N + tk.S) # add/remove control points button self.cps_button = ToggleButton(self) self.cps_button.config(text="Add/Remove Control Points", command=self.clickCPs, padx=PADDING, state=tk.DISABLED) self.cps_button.grid(row=1, column=4, rowspan=1, columnspan=2, sticky=tk.W + tk.E + tk.N + tk.S) # quit setup self.quit_button = tk.Button(self, text="Quit", command=self.clickQuit, padx=PADDING) self.quit_button.grid(row=1, column=0, sticky=tk.W + tk.E + tk.N + tk.S) def getIsVerbose(): return self.__is_verbose def setIsVerbose(value): if isinstance(value, bool): self.__is_verbose = value
def __init__ (self, text=None): ToggleButton.__init__ (self, text)
pygame.init() screen_width = 1280 screen_height = 720 main_surface = pygame.display.set_mode((screen_width, screen_height)) text_container_height = 80 padding = 20 max_cont = (screen_height // (text_container_height + padding)) - 2 event_manager = EventManager() graph = Graph(event_manager, (0, 0), (screen_width, screen_height)) sidebar = Sidebar((300, screen_height), pygame.Color('#3a577b'), pygame.Color('#4d4d4d')) toggle_button = ToggleButton(event_manager, (95, 25), [screen_width - 220, 30], 'degrees', 'radians') def create_new_text_container(): if len(FunctionBox.all_function_boxes) - 1 != max_cont: place = len( FunctionBox.all_function_boxes) * (text_container_height + padding) FunctionBox(event_manager, (0, place), (300, text_container_height), 30) new_expr = Button(event_manager, (25, screen_height - 60), pygame.Color(0, 200, 0), 'ADD NEW', create_new_text_container, size=(90, 35),
class Application(tk.Frame): # -------------------------------------------------------------------------- # Instance Attributes # -------------------------------------------------------------------------- # booleans __is_verbose = s.IS_VERBOSE # print messages to terminal __is_saved = False # lists to hold parking space and control point references __parking_spaces = None __control_points = None # picamera __camera = None __camera_is_active = False # image load/save locoations SETUP_IMAGE = "./images/setup.jpeg" DEFAULT_IMAGE = "./images/default.jpeg" # -------------------------------------------------------------------------- # Constructor Method # -------------------------------------------------------------------------- def __init__(self, master = None): """Application constructor method. """ # run super constructor method tk.Frame.__init__(self, master) # set alignment inside the frame self.grid() # create widgets self.__createDisplay() # display canvas: holds the image, CPs and spaces self.__createMenu() # menu canvas: holds the buttons and menu bar image # lists to hold parking space and control point references self.__parking_spaces = Boxes(self.display, type = 0) self.__control_points = Boxes(self.display, type = 1) # create mouse button and key-press handlers -> set focus to this frame self.bind("<Return>", self.returnPressHandler) self.bind("<Key>", self.keyPressHandler) self.bind("<Escape>", self.escapePressHandler) self.display.bind("<Button-1>", self.leftClickHandler) self.display.bind("<Button-3>", self.rightClickHandler) self.focus_set() if self.__is_verbose: print "INFO: __parking_spaces length:", self.__parking_spaces.length() print "INFO: __control_points length:", self.__control_points.length() # load the default background self.loadImage(self.DEFAULT_IMAGE, self.display, s.PICTURE_RESOLUTION[0]/2, s.PICTURE_RESOLUTION[1]/2) # ============================================================================== # # Public Application Methods # # ============================================================================== # -------------------------------------------------------------------------- # Load Image # -------------------------------------------------------------------------- def loadImage(self, image_address, canvas, width, height): """ Load image at image_address. If the load is successful then return True, otherwise return False. Keyword Arguments: image_address -- The address of the image to be loaded (default = './'). canvas -- The Tkinter Canvas into which the image is loaded. width -- Width of the image to load. height -- Height of the image to load. Returns: Boolean -- True if load successful, False if not. """ # clear the old canvas canvas.delete(tk.ALL) try: # guard against incorrect argument datatypes if not isinstance(canvas, tk.Canvas): raise TypeError if not isinstance(image_address, str): raise TypeError if not isinstance(width, int): raise TypeError if not isinstance(height, int): raise TypeError # load the image into the canvas photo = ImageTk.PhotoImage(Image.open(image_address)) canvas.create_image((width, height), image = photo) canvas.image = photo # image load successful return True except TypeError: # arguments of incorrect data type, load unsuccessful if self.__is_verbose: print "ERROR: loadImage() arguments of incorrect data type." return False except: # image failed to load if self.__is_verbose: print "ERROR: loadImage() failed to load image " + image_address return False # -------------------------------------------------------------------------- # Activate the Pi Camera # -------------------------------------------------------------------------- def turnOnCamera(self): """ Instruct the user how to take a new setup image, then activate the PiCam. If the camera fails to load, catch the exception and present error message. """ # show quick dialogue box with basic instruction tkMessageBox.showinfo(title = "", message = "Press the ENTER key to take a new setup image " + "or the ESCAPE key to cancel.") try: # initialise the camera using the settings in the imageread module self.__camera = imageread.setup_camera(is_fullscreen = True) self.__camera.start_preview() self.__camera_is_active = True if self.__is_verbose: print "INFO: PiCam activated." except: # camera failed to load, display error message tkMessageBox.showerror(title = "Error!", message = "Error: Failed to setup and start PiCam.") # -------------------------------------------------------------------------- # Save Data # -------------------------------------------------------------------------- def saveData(self): """Save the CP and parking space reference data to ./setup_data.py. """ # Open the file to output the co-ordinates to f1 = open('./setup_data.py', 'w+') # Print the dictionary data to the file print >> f1, 'boxes = [' # for every parking space, save the data to ./setup_data.py for i in range(self.__parking_spaces.length()): space = self.__parking_spaces.get(i).getOutput() # ignore the space if no data present if space != None: o = (i) print >> f1, space, ',' # for every control point, save the data to ./setup_data.py for j in range(self.__control_points.length()): cp = self.__control_points.get(j).getOutput() # ignore the CP if no data present if cp != None: o = (i) print >> f1, cp, ',' # save to ./setup_data.py print >> f1, ']' self.__is_saved = True if self.__is_verbose: print 'INFO: Data saved in file setup_data.py.' tkMessageBox.showinfo(title = "PiPark Setup", message = "Data saved successfully.") # -------------------------------------------------------------------------- # Load Data # -------------------------------------------------------------------------- def loadData(self): try: # load the setup data, reload to refresh the data import setup_data reload(setup_data) except: if self.__is_verbose: print "ERROR: Problem loading data from ./setup_data.py" tkMessageBox.showerror( title = "Error!", message = "Problem loading data from setup_data.py" ) self.__is_saved = True return setup_data.boxes # -------------------------------------------------------------------------- # Check Data # -------------------------------------------------------------------------- def checkData(self): """ Check that the setup data meets the following criteria: 1) There is at least 1 parking space. 2) There are exactly 3 control points. Returns: Boolean -- True if criteria is met, False if not. """ if self.__is_verbose: print "INFO: Data is being checked for validity." # get the boxes data to check from setup_data try: # load the setup data import setup_data reload(setup_data) # ensure that boxes exists and is not empty box_data = setup_data.boxes if not box_data: raise ValueError except ImportError: if self.__is_verbose: print "ERROR: Problem loading data from ./setup_data.py" except ValueError: if self.__is_verbose: print "ERROR: ./setup_data.py 'boxes' is empty." except: if self.__is_verbose: print "ERROR: ./setup_data.py does not contain 'boxes'." # create lists to hold data of each type space_boxes = [] control_boxes = [] # append the box data to space or control list as appropriate for data_set in box_data: if data_set[1] == 0: space_boxes.append(data_set) elif data_set[1] == 1: control_boxes.append(data_set) elif self.__is_verbose: print "ERROR: Box-type not set to either 0 or 1." # data is valid if there is at least 1 space and exactly 3 control points if len(space_boxes) > 0 and len(control_boxes) == 3: valid_data = True else: valid_data = False if self.__is_verbose: print "INFO: Data checked. Data is", valid_data return valid_data # -------------------------------------------------------------------------- # Register Data # -------------------------------------------------------------------------- def register(self): """Register the Pi with the server. """ # if setup hasn't been saved recently since last change, ask the if # user to save first if not self.__is_saved: response = tkMessageBox.askokcancel(title = "Save Setup", message = "Setup data must be saved before the registration" + " process can be completed. Would you like to save now?") # if user selects 'yes' save the data and continue, else do not # register the pi if response: self.saveData() else: tkMessageBox.showinfo(title = "PiPark Setup", message = "Registration not completed.") return # check that most recent saved data is valid (#CPs == 3, #Spaces > 0) if not self.checkData(): # data invalid, so display message and return tkMessageBox.showinfo( title = "PiPark Setup", message = "Registration not complete.\n\nSaved data is " + "invalid. Please ensure that there are 3 control points and " + "at least 1 parking spaces marked." ) return # attempt to import the setup data and ensure 'boxes' is a list try: import setup_data reload(setup_data) boxes = setup_data.boxes if not isinstance(boxes, list): raise ValueError() except: print "ERROR: Setup data does not exist. Please run options 1 and 2 first." return # attempt to import the server senddata module try: import senddata except: print "ERROR: Could not import send data file." return # deregister all areas associated with this pi (start fresh) out = senddata.deregister_pi() try: out['error'] print "ERROR: Error in connecting to server. Please update settings.py." return except: pass # register each box on the server for box in boxes: if box[1] == 0: output = senddata.register_area(box[0]) if "error" in output.keys(): if self.__is_verbose: print "ERROR:", output["error"] return else: if self.__is_verbose: print "INFO: Registering area", box[0], "on server." # print success message if verbose if self.__is_verbose: print "\nINFO: Server registration successful." # ============================================================================== # # Event Handlers # # ============================================================================== # -------------------------------------------------------------------------- # Return-key-press Event Handler # -------------------------------------------------------------------------- def returnPressHandler(self, event): """ Handle Return-key-press events. Capture a new setup image when PiCam is active, and load the image. """ # ensure focus on window self.focus_set() # do nothing if camera is not active, or no camera object exists if not self.__camera_is_active or not self.__camera: return try: # capture new setup image, then close the camera self.__camera.capture(self.SETUP_IMAGE) self.__camera.stop_preview() self.__camera.close() self.__camera_is_active = False if self.__is_verbose: print "INFO: New setup image captured." print "INFO: PiCam deactivated." except: # image failed to capture, show error message tkMessageBox.showerror(title = "Error!", message = "Error: Failed to capture new setup image.") # load the new setup image self.loadImage(self.SETUP_IMAGE, self.display, s.PICTURE_RESOLUTION[0]/2, s.PICTURE_RESOLUTION[1]/2) # activate buttons if they're disabled self.cps_button.config(state = tk.ACTIVE) self.spaces_button.config(state = tk.ACTIVE) # -------------------------------------------------------------------------- # Escape-key-press Event Handler # -------------------------------------------------------------------------- def escapePressHandler(self, event): # ensure focus on window self.focus_set() # do nothing if camera is not active, or no camera object exists if not self.__camera_is_active or not self.__camera: return try: # close the camera without taking new image self.__camera.stop_preview() self.__camera.close() self.__camera_is_active = False if self.__is_verbose: print "INFO: PiCam deactivated." except: # image failed to close for some reason, show error message if self.__is_verbose: print "ERROR: PiCam failed to close correctly." # -------------------------------------------------------------------------- # Key-press Event Handler # -------------------------------------------------------------------------- def keyPressHandler(self, event): """Handle key-press events for numeric keys. """ key = event.char NUM_KEYS = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'] if key in NUM_KEYS: if self.__is_verbose: print "INFO: Number-key pressed", key if self.spaces_button.getIsActive(): self.__parking_spaces.setCurrentBox(int(key)) if self.cps_button.getIsActive(): # ignore all other numbers, but 1, 2 and 3 as 3 is the maximum # number of control points allowed. if key not in ['1', '2', '3']: return # NB: -1 from key press, because list indices are [0, 1, 2], # but for ease of user selection the numbers 1, 2, 3 are used # for input self.__control_points.setCurrentBox(int(key) - 1) # -------------------------------------------------------------------------- # LMB Event Handler # -------------------------------------------------------------------------- def leftClickHandler(self, event): """Handle LMB-click events to add/remove control points & spaces. """ # ensure focus on display canvas to recieve mouse clicks self.display.focus_set() # perform correct operation, dependent on which toggle button is active # add new control points (max = 3) if self.cps_button.getIsActive(): if self.__is_verbose: print "INFO: Add Control Point" self.__is_saved = False this_cp_id = self.__control_points.getCurrentBox() this_cp = self.__control_points.boxes[this_cp_id] this_cp.updatePoints(event.x, event.y) # add new parking space elif self.spaces_button.getIsActive(): if self.__is_verbose: print "INFO: Add Parking Space" self.__is_saved = False this_space_id = self.__parking_spaces.getCurrentBox() this_space = self.__parking_spaces.boxes[this_space_id] this_space.updatePoints(event.x, event.y) # do nothing -- ignore LMB clicks else: if self.__is_verbose: print "INFO: Just clicking LMB merrily =D" # return focus to the main frame for key-press events self.focus_set() # -------------------------------------------------------------------------- # RMB Event Handler # -------------------------------------------------------------------------- def rightClickHandler(self, event): """Handle RMB-click events to add/remove control points & spaces. """ # ensure focus is set to the display canvas self.display.focus_set() # perform correct operation, dependent on which toggle button is active if self.cps_button.getIsActive(): if self.__is_verbose: print "INFO: Remove Control Point" self.__is_saved = False self.__control_points.boxes[self.__control_points.getCurrentBox()].clear() self.__control_points.boxes[self.__control_points.getCurrentBox()].deleteRectangle(self.display) elif self.spaces_button.getIsActive(): if self.__is_verbose: print "INFO: Remove parking space" self.__is_saved = False self.__parking_spaces.boxes[self.__parking_spaces.getCurrentBox()].clear() self.__parking_spaces.boxes[self.__parking_spaces.getCurrentBox()].deleteRectangle(self.display) else: if self.__is_verbose: print "INFO: Just clicking RMB merrily =)" # return focus to the main frame for key-press events self.focus_set() # ============================================================================== # # Button Handlers # # ============================================================================== def clickStart(self): """ Close the current setup application, then initiate the main PiPark program. """ if self.__is_verbose: print "ACTION: Clicked 'Start'" # turn off toggle buttons self.spaces_button.setOff() self.cps_button.setOff() # set initial responses response = False response1 = False response2 = False # if setup data has not been saved. Ask user if they would like to save # before continuing. if not self.__is_saved: response = tkMessageBox.askyesno( title = "Save Setup", type = tkMessageBox.YESNOCANCEL, message = "Most recent changes to setup have not been saved." + "Would you like to save before running PiPark?" ) if response: self.saveData() # data is saved, ask the user if they are sure they wish to quit. else: response = tkMessageBox.askyesno( title = "Save Setup", message = "Are you ready to leave setup and run PiPark?" ) # user wishes to quit setup and run pipark, so do it! if response: # ensure data is valid before continuing if not self.checkData(): # data invalid, so display message and return tkMessageBox.showinfo( title = "PiPark Setup", message = "Saved data is invalid. Please ensure that " + "there are 3 control points and at least 1 parking " + "space marked." ) return self.quit_button.invoke() if self.__is_verbose: print "INFO: Setup application terminated. " main.main() def clickRegister(self): """Register the car park with the server. """ if self.__is_verbose: print "ACTION: Clicked 'Register'" # turn off toggle buttons self.spaces_button.setOff() self.cps_button.setOff() self.register() def clickNewImage(self): """Use PiCam to take new 'setup image' for PiPark setup. """ if self.__is_verbose: print "ACTION: Clicked 'Capture New Image'" self.__is_saved = False # turn off toggle buttons self.spaces_button.setOff() self.cps_button.setOff() # clear the Tkinter display canvas, and all related setupdata. Then # turn on PiCam to allow for new image to be taken. self.__parking_spaces.clearAll(self.display) self.__control_points.clearAll(self.display) self.turnOnCamera() def clickSave(self): if self.__is_verbose: print "ACTION: Clicked Save'" # turn off toggle buttons self.spaces_button.setOff() self.cps_button.setOff() self.saveData() def clickLoad(self): if self.__is_verbose: print "ACTION: Clicked 'Load'" # turn off toggle buttons self.spaces_button.setOff() self.cps_button.setOff() if not self.loadImage(self.SETUP_IMAGE, self.display, s.PICTURE_RESOLUTION[0]/2, s.PICTURE_RESOLUTION[1]/2): tkMessageBox.showerror(title = "Error!", message = "Error loading setup image." + " Please ensure setup image exists as ./image/setup_image.jpeg.") return # clear all previous data, and activate buttons self.clear_button.invoke() self.cps_button.config(state = tk.ACTIVE) self.spaces_button.config(state = tk.ACTIVE) def clickClear(self): if self.__is_verbose: print "ACTION: Clicked 'Clear'" self.__is_saved = False # clear all data points, to start afresh self.__parking_spaces.clearAll(self.display) self.__control_points.clearAll(self.display) def clickSpaces(self): """Add/remove parking-space bounding boxes. """ if self.__is_verbose: print "ACTION: Clicked 'Add/Remove Spaces'" # toggle the button, and turn off other toggle buttons self.spaces_button.toggle() if self.cps_button.getIsActive(): self.cps_button.setOff() def clickCPs(self): """Add/remove control points. """ if self.__is_verbose: print "ACTION: Clicked 'Add/Remove CPs'" # toggle the button, and turn off other toggle buttons self.cps_button.toggle() if self.spaces_button.getIsActive(): self.spaces_button.setOff() def clickQuit(self): """Quit & terminate the application. """ if self.__is_verbose: print "ACTION: Clicked 'Quit'" # turn off toggle buttons self.spaces_button.setOff() self.cps_button.setOff() response = True # if the user hasn't recently saved, ask if they really wish to quit if not self.__is_saved: response = tkMessageBox.askyesno( title = "Quit?", message = "Are you sure you wish to quit?" + "All unsaved setup will be lost." ) if response: # user wishes to quit, destroy the application self.quit() self.master.destroy() def clickAbout(self): """Open the README file for instructions on GUI use. """ if self.__is_verbose: print "ACTION: Clicked 'Open README'" # turn off toggle buttons self.spaces_button.setOff() self.cps_button.setOff() # load external README from command line # TODO: Put this in new Tkinter window with scroll bar os.system("leafpad " + "./SETUP_README.txt") if self.__is_verbose: print "INFO: Opened ./SETUP_README.txt in leafpad." # ============================================================================== # # Application Layout Management # # ============================================================================== # -------------------------------------------------------------------------- # Create Image Display Canvas # -------------------------------------------------------------------------- def __createDisplay(self): """ Create the display tkinter canvas to hold the images taken by the pi camera. """ self.display = tk.Canvas( self, width = s.PICTURE_RESOLUTION[0], height = s.PICTURE_RESOLUTION[1] ) self.display.grid(row = 2, column = 0, rowspan = 1, columnspan = 6) # -------------------------------------------------------------------------- # Create Options Menu # -------------------------------------------------------------------------- def __createMenu(self): """Create a tkinter canvas in which to hold the menu buttons. """ # Layout: # ------- # ------------------------------------------------------------------ # | Start || Capture New Image || Add/Remove Spaces || Quit | # ------------------------------------------------------------------ # | Register || Save || Load || Clear || Add/Remove CPs || ReadMe | # ------------------------------------------------------------------ # padding around buttons PADDING = 10; # start the main program self.start_button = tk.Button(self, text = "Start PiPark", command = self.clickStart, padx = PADDING) self.start_button.grid(row = 0, column = 0, sticky = tk.W + tk.E + tk.N + tk.S) # register the car park button self.register_button = tk.Button(self, text = "Register", command = self.clickRegister, padx = PADDING) self.register_button.grid(row = 1, column = 0, sticky = tk.W + tk.E + tk.N + tk.S) # take new setup image button self.image_button = tk.Button(self, text = "Capture New Setup Image", command = self.clickNewImage, padx = PADDING) self.image_button.grid(row = 0, column = 1, rowspan = 1, columnspan = 3, sticky = tk.W + tk.E + tk.N + tk.S) # save setup data & image self.save_button = tk.Button(self, text = "Save", command = self.clickSave, padx = PADDING) self.save_button.grid(row = 1, column = 1, sticky = tk.W + tk.E + tk.N + tk.S) # load setup data & image self.load_button = tk.Button(self, text = "Load", command = self.clickLoad, padx = PADDING) self.load_button.grid(row = 1, column = 2, sticky = tk.W + tk.E + tk.N + tk.S) # clear all parking spaces and CPs self.clear_button = tk.Button(self, text = "Clear", command = self.clickClear, padx = PADDING) self.clear_button.grid(row = 1, column = 3, sticky = tk.W + tk.E + tk.N + tk.S) # add/remove spaces button self.spaces_button = ToggleButton(self) self.spaces_button.config(text = "Add/Remove Spaces", command = self.clickSpaces, padx = PADDING, state = tk.DISABLED) self.spaces_button.grid(row = 0, column = 4, sticky = tk.W + tk.E + tk.N + tk.S) # add/remove control points button self.cps_button = ToggleButton(self) self.cps_button.config(text = "Add/Remove Control Points", command = self.clickCPs, padx = PADDING, state = tk.DISABLED) self.cps_button.grid(row = 1, column = 4, sticky = tk.W + tk.E + tk.N + tk.S) # quit setup self.quit_button = tk.Button(self, text = "Quit", command = self.clickQuit, padx = PADDING) self.quit_button.grid(row = 0, column = 5, sticky = tk.W + tk.E + tk.N + tk.S) # about button - display information about PiPark self.about_button = tk.Button(self, text = "Open ReadMe", command = self.clickAbout, padx = PADDING) self.about_button.grid(row = 1, column = 5, sticky = tk.W + tk.E + tk.N + tk.S) # ============================================================================== # # Getters and Setters # # ============================================================================== # -------------------------------------------------------------------------- # Is Verbose? # -------------------------------------------------------------------------- def getIsVerbose(): return self.__is_verbose def setIsVerbose(value): if isinstance(value, bool): self.__is_verbose = value
class Application(tk.Frame): # -------------------------------------------------------------------------- # Instance Attributes # -------------------------------------------------------------------------- # booleans __is_verbose = s.IS_VERBOSE # print messages to terminal __is_saved = False # lists to hold parking space and control point references __parking_spaces = None __control_points = None # picamera __camera = None __camera_is_active = False # image load/save locoations SETUP_IMAGE = "./images/setup.jpeg" DEFAULT_IMAGE = "./images/default.jpeg" # -------------------------------------------------------------------------- # Constructor Method # -------------------------------------------------------------------------- def __init__(self, master=None): """Application constructor method. """ # run super constructor method tk.Frame.__init__(self, master) # set alignment inside the frame self.grid() # create widgets self.__createDisplay( ) # display canvas: holds the image, CPs and spaces self.__createMenu( ) # menu canvas: holds the buttons and menu bar image # lists to hold parking space and control point references self.__parking_spaces = Boxes(self.display, type=0) self.__control_points = Boxes(self.display, type=1) # create mouse button and key-press handlers -> set focus to this frame self.bind("<Return>", self.returnPressHandler) self.bind("<Key>", self.keyPressHandler) self.bind("<Escape>", self.escapePressHandler) self.display.bind("<Button-1>", self.leftClickHandler) self.display.bind("<Button-3>", self.rightClickHandler) self.focus_set() if self.__is_verbose: print "INFO: __parking_spaces length:", self.__parking_spaces.length( ) print "INFO: __control_points length:", self.__control_points.length( ) # load the default background self.loadImage(self.DEFAULT_IMAGE, self.display, s.PICTURE_RESOLUTION[0] / 2, s.PICTURE_RESOLUTION[1] / 2) # ============================================================================== # # Public Application Methods # # ============================================================================== # -------------------------------------------------------------------------- # Load Image # -------------------------------------------------------------------------- def loadImage(self, image_address, canvas, width, height): """ Load image at image_address. If the load is successful then return True, otherwise return False. Keyword Arguments: image_address -- The address of the image to be loaded (default = './'). canvas -- The Tkinter Canvas into which the image is loaded. width -- Width of the image to load. height -- Height of the image to load. Returns: Boolean -- True if load successful, False if not. """ # clear the old canvas canvas.delete(tk.ALL) try: # guard against incorrect argument datatypes if not isinstance(canvas, tk.Canvas): raise TypeError if not isinstance(image_address, str): raise TypeError if not isinstance(width, int): raise TypeError if not isinstance(height, int): raise TypeError # load the image into the canvas photo = ImageTk.PhotoImage(Image.open(image_address)) canvas.create_image((width, height), image=photo) canvas.image = photo # image load successful return True except TypeError: # arguments of incorrect data type, load unsuccessful if self.__is_verbose: print "ERROR: loadImage() arguments of incorrect data type." return False except: # image failed to load if self.__is_verbose: print "ERROR: loadImage() failed to load image " + image_address return False # -------------------------------------------------------------------------- # Activate the Pi Camera # -------------------------------------------------------------------------- def turnOnCamera(self): """ Instruct the user how to take a new setup image, then activate the PiCam. If the camera fails to load, catch the exception and present error message. """ # show quick dialogue box with basic instruction tkMessageBox.showinfo( title="", message="Press the ENTER key to take a new setup image " + "or the ESCAPE key to cancel.") try: # initialise the camera using the settings in the imageread module self.__camera = imageread.setup_camera(is_fullscreen=True) #preview window while True: ret, frame = self.__camera.read() rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2BGRA) cv2.imshow('frame', rgb) if cv2.waitKey(1) & 0xFF == ord('\x0D'): cv2.destroyWindow('frame') break #self.__camera.awb_mode = 'auto'; #self.__camera.exposure_mode = 'auto'; #self.__camera.start_preview() #self.__camera_is_active = True #if self.__is_verbose: print "INFO: PiCam activated." except: # camera failed to load, display error message tkMessageBox.showerror( title="Error!", message="Error: Failed to setup and start PiCam.") # -------------------------------------------------------------------------- # Save Data # -------------------------------------------------------------------------- def saveData(self): """Save the CP and parking space reference data to ./setup_data.py. """ # Open the file to output the co-ordinates to f1 = open('./setup_data.py', 'w+') # Print the dictionary data to the file print >> f1, 'boxes = [' # for every parking space, save the data to ./setup_data.py for i in range(self.__parking_spaces.length()): space = self.__parking_spaces.get(i).getOutput() # ignore the space if no data present if space != None: o = (i) print >> f1, space, ',' # for every control point, save the data to ./setup_data.py for j in range(self.__control_points.length()): cp = self.__control_points.get(j).getOutput() # ignore the CP if no data present if cp != None: o = (i) print >> f1, cp, ',' # save to ./setup_data.py print >> f1, ']' self.__is_saved = True if self.__is_verbose: print 'INFO: Data saved in file setup_data.py.' tkMessageBox.showinfo(title="PiPark Setup", message="Data saved successfully.") # -------------------------------------------------------------------------- # Load Data # -------------------------------------------------------------------------- def loadData(self): try: # load the setup data, reload to refresh the data import setup_data reload(setup_data) except: if self.__is_verbose: print "ERROR: Problem loading data from ./setup_data.py" tkMessageBox.showerror( title="Error!", message="Problem loading data from setup_data.py") self.__is_saved = True return setup_data.boxes # -------------------------------------------------------------------------- # Check Data # -------------------------------------------------------------------------- def checkData(self): """ Check that the setup data meets the following criteria: 1) There is at least 1 parking space. 2) There are exactly 3 control points. Returns: Boolean -- True if criteria is met, False if not. """ if self.__is_verbose: print "INFO: Data is being checked for validity." # get the boxes data to check from setup_data try: # load the setup data import setup_data reload(setup_data) # ensure that boxes exists and is not empty box_data = setup_data.boxes if not box_data: raise ValueError except ImportError: if self.__is_verbose: print "ERROR: Problem loading data from ./setup_data.py" except ValueError: if self.__is_verbose: print "ERROR: ./setup_data.py 'boxes' is empty." except: if self.__is_verbose: print "ERROR: ./setup_data.py does not contain 'boxes'." # create lists to hold data of each type space_boxes = [] control_boxes = [] # append the box data to space or control list as appropriate for data_set in box_data: if data_set[1] == 0: space_boxes.append(data_set) elif data_set[1] == 1: control_boxes.append(data_set) elif self.__is_verbose: print "ERROR: Box-type not set to either 0 or 1." # data is valid if there is at least 1 space and exactly 3 control points if len(space_boxes) > 0 and len(control_boxes) == 3: valid_data = True else: valid_data = False if self.__is_verbose: print "INFO: Data checked. Data is", valid_data return valid_data # -------------------------------------------------------------------------- # Register Data # -------------------------------------------------------------------------- def register(self): """Register the Pi with the server. """ # if setup hasn't been saved recently since last change, ask the if # user to save first if not self.__is_saved: response = tkMessageBox.askokcancel( title="Save Setup", message="Setup data must be saved before the registration" + " process can be completed. Would you like to save now?") # if user selects 'yes' save the data and continue, else do not # register the pi if response: self.saveData() else: tkMessageBox.showinfo(title="PiPark Setup", message="Registration not completed.") return # check that most recent saved data is valid (#CPs == 3, #Spaces > 0) if not self.checkData(): # data invalid, so display message and return tkMessageBox.showinfo( title="PiPark Setup", message="Registration not complete.\n\nSaved data is " + "invalid. Please ensure that there are 3 control points and " + "at least 1 parking spaces marked.") return # attempt to import the setup data and ensure 'boxes' is a list try: import setup_data reload(setup_data) boxes = setup_data.boxes if not isinstance(boxes, list): raise ValueError() except: print "ERROR: Setup data does not exist. Please run options 1 and 2 first." return # attempt to import the server senddata module try: import senddata except: print "ERROR: Could not import send data file." return # deregister all areas associated with this pi (start fresh) out = senddata.deregister_pi() try: out['error'] print out #debug print "ERROR: Error in connecting to server. Please update settings.py." return except: pass # register each box on the server for box in boxes: if box[1] == 0: output = senddata.register_area(box[0]) if "error" in output.keys(): if self.__is_verbose: print "ERROR:", output["error"] return else: if self.__is_verbose: print "INFO: Registering area", box[0], "on server." # print success message if verbose if self.__is_verbose: print "\nINFO: Server registration successful." # ============================================================================== # # Event Handlers # # ============================================================================== # -------------------------------------------------------------------------- # Return-key-press Event Handler # -------------------------------------------------------------------------- def returnPressHandler(self, event): """ Handle Return-key-press events. Capture a new setup image when PiCam is active, and load the image. """ # ensure focus on window self.focus_set() # do nothing if camera is not active, or no camera object exists #if not self.__camera_is_active or not self.__camera: return try: # capture new setup image, then close the camera #self.__camera.capture(self.SETUP_IMAGE) ret, frame = self.__camera.read() cv2.imwrite(self.SETUP_IMAGE, frame) self.__camera.release() #self.__camera.stop_preview() #self.__camera.close() #self.__camera_is_active = False if self.__is_verbose: print "INFO: New setup image captured." print "INFO: PiCam deactivated." except: # image failed to capture, show error message tkMessageBox.showerror( title="Error!", message="Error: Failed to capture new setup image.") # load the new setup image self.loadImage(self.SETUP_IMAGE, self.display, s.PICTURE_RESOLUTION[0] / 2, s.PICTURE_RESOLUTION[1] / 2) # activate buttons if they're disabled self.cps_button.config(state=tk.ACTIVE) self.spaces_button.config(state=tk.ACTIVE) # -------------------------------------------------------------------------- # Escape-key-press Event Handler # -------------------------------------------------------------------------- def escapePressHandler(self, event): # ensure focus on window self.focus_set() # do nothing if camera is not active, or no camera object exists if not self.__camera_is_active or not self.__camera: return try: # close the camera without taking new image # TODO close the camera without taking new image using opencv cv2.destroyWindow('frame') self.__camera.release() if self.__is_verbose: print "INFO: PiCam deactivated." except: # image failed to close for some reason, show error message if self.__is_verbose: print "ERROR: PiCam failed to close correctly." # -------------------------------------------------------------------------- # Key-press Event Handler # -------------------------------------------------------------------------- def keyPressHandler(self, event): """Handle key-press events for numeric keys. """ key = event.char NUM_KEYS = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'] if key in NUM_KEYS: if self.__is_verbose: print "INFO: Number-key pressed", key if self.spaces_button.getIsActive(): self.__parking_spaces.setCurrentBox(int(key)) if self.cps_button.getIsActive(): # ignore all other numbers, but 1, 2 and 3 as 3 is the maximum # number of control points allowed. if key not in ['1', '2', '3']: return # NB: -1 from key press, because list indices are [0, 1, 2], # but for ease of user selection the numbers 1, 2, 3 are used # for input self.__control_points.setCurrentBox(int(key) - 1) # -------------------------------------------------------------------------- # LMB Event Handler # -------------------------------------------------------------------------- def leftClickHandler(self, event): """Handle LMB-click events to add/remove control points & spaces. """ # ensure focus on display canvas to recieve mouse clicks self.display.focus_set() # perform correct operation, dependent on which toggle button is active # add new control points (max = 3) if self.cps_button.getIsActive(): if self.__is_verbose: print "INFO: Add Control Point" self.__is_saved = False this_cp_id = self.__control_points.getCurrentBox() this_cp = self.__control_points.boxes[this_cp_id] this_cp.updatePoints(event.x, event.y) # add new parking space elif self.spaces_button.getIsActive(): if self.__is_verbose: print "INFO: Add Parking Space" self.__is_saved = False this_space_id = self.__parking_spaces.getCurrentBox() this_space = self.__parking_spaces.boxes[this_space_id] this_space.updatePoints(event.x, event.y) # do nothing -- ignore LMB clicks else: if self.__is_verbose: print "INFO: Just clicking LMB merrily =D" # return focus to the main frame for key-press events self.focus_set() # -------------------------------------------------------------------------- # RMB Event Handler # -------------------------------------------------------------------------- def rightClickHandler(self, event): """Handle RMB-click events to add/remove control points & spaces. """ # ensure focus is set to the display canvas self.display.focus_set() # perform correct operation, dependent on which toggle button is active if self.cps_button.getIsActive(): if self.__is_verbose: print "INFO: Remove Control Point" self.__is_saved = False self.__control_points.boxes[ self.__control_points.getCurrentBox()].clear() self.__control_points.boxes[ self.__control_points.getCurrentBox()].deleteRectangle( self.display) elif self.spaces_button.getIsActive(): if self.__is_verbose: print "INFO: Remove parking space" self.__is_saved = False self.__parking_spaces.boxes[ self.__parking_spaces.getCurrentBox()].clear() self.__parking_spaces.boxes[ self.__parking_spaces.getCurrentBox()].deleteRectangle( self.display) else: if self.__is_verbose: print "INFO: Just clicking RMB merrily =)" # return focus to the main frame for key-press events self.focus_set() # ============================================================================== # # Button Handlers # # ============================================================================== def clickStart(self): """ Close the current setup application, then initiate the main PiPark program. """ if self.__is_verbose: print "ACTION: Clicked 'Start'" # turn off toggle buttons self.spaces_button.setOff() self.cps_button.setOff() # set initial responses response = False response1 = False response2 = False # if setup data has not been saved. Ask user if they would like to save # before continuing. if not self.__is_saved: response = tkMessageBox.askyesno( title="Save Setup", type=tkMessageBox.YESNOCANCEL, message="Most recent changes to setup have not been saved." + "Would you like to save before running PiPark?") if response: self.saveData() # data is saved, ask the user if they are sure they wish to quit. else: response = tkMessageBox.askyesno( title="Save Setup", message="Are you ready to leave setup and run PiPark?") # user wishes to quit setup and run pipark, so do it! if response: # ensure data is valid before continuing if not self.checkData(): # data invalid, so display message and return tkMessageBox.showinfo( title="PiPark Setup", message="Saved data is invalid. Please ensure that " + "there are 3 control points and at least 1 parking " + "space marked.") return self.quit_button.invoke() if self.__is_verbose: print "INFO: Setup application terminated. " main.main() def clickRegister(self): """Register the car park with the server. """ if self.__is_verbose: print "ACTION: Clicked 'Register'" # turn off toggle buttons self.spaces_button.setOff() self.cps_button.setOff() self.register() def clickNewImage(self): """Use PiCam to take new 'setup image' for PiPark setup. """ if self.__is_verbose: print "ACTION: Clicked 'Capture New Image'" self.__is_saved = False # turn off toggle buttons self.spaces_button.setOff() self.cps_button.setOff() # clear the Tkinter display canvas, and all related setupdata. Then # turn on PiCam to allow for new image to be taken. self.__parking_spaces.clearAll(self.display) self.__control_points.clearAll(self.display) self.turnOnCamera() def clickSave(self): if self.__is_verbose: print "ACTION: Clicked Save'" # turn off toggle buttons self.spaces_button.setOff() self.cps_button.setOff() self.saveData() def clickLoad(self): if self.__is_verbose: print "ACTION: Clicked 'Load'" # turn off toggle buttons self.spaces_button.setOff() self.cps_button.setOff() if not self.loadImage(self.SETUP_IMAGE, self.display, s.PICTURE_RESOLUTION[0] / 2, s.PICTURE_RESOLUTION[1] / 2): tkMessageBox.showerror( title="Error!", message="Error loading setup image." + " Please ensure setup image exists as ./image/setup_image.jpeg." ) return # clear all previous data, and activate buttons self.clear_button.invoke() self.cps_button.config(state=tk.ACTIVE) self.spaces_button.config(state=tk.ACTIVE) def clickClear(self): if self.__is_verbose: print "ACTION: Clicked 'Clear'" self.__is_saved = False # clear all data points, to start afresh self.__parking_spaces.clearAll(self.display) self.__control_points.clearAll(self.display) def clickSpaces(self): """Add/remove parking-space bounding boxes. """ if self.__is_verbose: print "ACTION: Clicked 'Add/Remove Spaces'" # toggle the button, and turn off other toggle buttons self.spaces_button.toggle() if self.cps_button.getIsActive(): self.cps_button.setOff() def clickCPs(self): """Add/remove control points. """ if self.__is_verbose: print "ACTION: Clicked 'Add/Remove CPs'" # toggle the button, and turn off other toggle buttons self.cps_button.toggle() if self.spaces_button.getIsActive(): self.spaces_button.setOff() def clickQuit(self): """Quit & terminate the application. """ if self.__is_verbose: print "ACTION: Clicked 'Quit'" # turn off toggle buttons self.spaces_button.setOff() self.cps_button.setOff() response = True # if the user hasn't recently saved, ask if they really wish to quit if not self.__is_saved: response = tkMessageBox.askyesno( title="Quit?", message="Are you sure you wish to quit?" + "All unsaved setup will be lost.") if response: # user wishes to quit, destroy the application self.quit() self.master.destroy() def clickAbout(self): """Open the README file for instructions on GUI use. """ if self.__is_verbose: print "ACTION: Clicked 'Open README'" # turn off toggle buttons self.spaces_button.setOff() self.cps_button.setOff() # load external README from command line # TODO: Put this in new Tkinter window with scroll bar os.system("leafpad " + "./SETUP_README.txt") if self.__is_verbose: print "INFO: Opened ./SETUP_README.txt in leafpad." # ============================================================================== # # Application Layout Management # # ============================================================================== # -------------------------------------------------------------------------- # Create Image Display Canvas # -------------------------------------------------------------------------- def __createDisplay(self): """ Create the display tkinter canvas to hold the images taken by the pi camera. """ self.display = tk.Canvas(self, width=s.PICTURE_RESOLUTION[0], height=s.PICTURE_RESOLUTION[1]) self.display.grid(row=2, column=0, rowspan=1, columnspan=6) # -------------------------------------------------------------------------- # Create Options Menu # -------------------------------------------------------------------------- def __createMenu(self): """Create a tkinter canvas in which to hold the menu buttons. """ # Layout: # ------- # ------------------------------------------------------------------ # | Start || Capture New Image || Add/Remove Spaces || Quit | # ------------------------------------------------------------------ # | Register || Save || Load || Clear || Add/Remove CPs || ReadMe | # ------------------------------------------------------------------ # padding around buttons PADDING = 10 # start the main program self.start_button = tk.Button(self, text="Start PiPark", command=self.clickStart, padx=PADDING) self.start_button.grid(row=0, column=0, sticky=tk.W + tk.E + tk.N + tk.S) # register the car park button self.register_button = tk.Button(self, text="Register", command=self.clickRegister, padx=PADDING) self.register_button.grid(row=1, column=0, sticky=tk.W + tk.E + tk.N + tk.S) # take new setup image button self.image_button = tk.Button(self, text="Capture New Setup Image", command=self.clickNewImage, padx=PADDING) self.image_button.grid(row=0, column=1, rowspan=1, columnspan=3, sticky=tk.W + tk.E + tk.N + tk.S) # save setup data & image self.save_button = tk.Button(self, text="Save", command=self.clickSave, padx=PADDING) self.save_button.grid(row=1, column=1, sticky=tk.W + tk.E + tk.N + tk.S) # load setup data & image self.load_button = tk.Button(self, text="Load", command=self.clickLoad, padx=PADDING) self.load_button.grid(row=1, column=2, sticky=tk.W + tk.E + tk.N + tk.S) # clear all parking spaces and CPs self.clear_button = tk.Button(self, text="Clear", command=self.clickClear, padx=PADDING) self.clear_button.grid(row=1, column=3, sticky=tk.W + tk.E + tk.N + tk.S) # add/remove spaces button self.spaces_button = ToggleButton(self) self.spaces_button.config(text="Add/Remove Spaces", command=self.clickSpaces, padx=PADDING, state=tk.DISABLED) self.spaces_button.grid(row=0, column=4, sticky=tk.W + tk.E + tk.N + tk.S) # add/remove control points button self.cps_button = ToggleButton(self) self.cps_button.config(text="Add/Remove Control Points", command=self.clickCPs, padx=PADDING, state=tk.DISABLED) self.cps_button.grid(row=1, column=4, sticky=tk.W + tk.E + tk.N + tk.S) # quit setup self.quit_button = tk.Button(self, text="Quit", command=self.clickQuit, padx=PADDING) self.quit_button.grid(row=0, column=5, sticky=tk.W + tk.E + tk.N + tk.S) # about button - display information about PiPark self.about_button = tk.Button(self, text="Open ReadMe", command=self.clickAbout, padx=PADDING) self.about_button.grid(row=1, column=5, sticky=tk.W + tk.E + tk.N + tk.S) # ============================================================================== # # Getters and Setters # # ============================================================================== # -------------------------------------------------------------------------- # Is Verbose? # -------------------------------------------------------------------------- def getIsVerbose(): return self.__is_verbose def setIsVerbose(value): if isinstance(value, bool): self.__is_verbose = value
def __init__(self, text=None): ToggleButton.__init__(self, text)
def configure_menu_buttons(self): self.dda_button = ToggleButton(self.menu_frame, text="DDA", command=self.handle_on_click_menu_button, algorithm=Command.DDA_LINE, clean_buttons=self.clean_toggled_buttons) self.bresenham_line_button = ToggleButton(self.menu_frame, text="BresenhamLine", command=self.handle_on_click_menu_button, algorithm=Command.BRESENHAM_LINE, clean_buttons=self.clean_toggled_buttons) self.bresenham_circle_button = ToggleButton(self.menu_frame, text="BresenhamCircle", command=self.handle_on_click_menu_button, algorithm=Command.BRESENHAM_CIRCLE, clean_buttons=self.clean_toggled_buttons) self.cohen_sutherland_button = ToggleButton(self.menu_frame, text="Recorte CS", command=self.handle_on_click_menu_button, algorithm=Command.COHEN_SUTHERLAND_CLIP, clean_buttons=self.clean_toggled_buttons) self.liang_barsky_button = ToggleButton(self.menu_frame, text="Recorte LB", command=self.handle_on_click_menu_button, algorithm=Command.LIANG_BARSKY_CLIP, clean_buttons=self.clean_toggled_buttons) self.translation_button = tk.Button(self.menu_frame, text="Translação", width=Metrics.buttonSize, relief="raised", command=self.handle_on_click_translation_button, padx=Metrics.paddingMenuButtonsX, pady=Metrics.paddingMenuButtonsY, ).pack(side="left") self.scaling_button = tk.Button(self.menu_frame, text="Escala", width=Metrics.buttonSize, relief="raised", command=self.handle_on_click_scaling_button, padx=Metrics.paddingMenuButtonsX, pady=Metrics.paddingMenuButtonsY, ).pack(side="left") self.rotation_button = tk.Button(self.menu_frame, text="Rotação", width=Metrics.buttonSize, relief="raised", command=self.handle_on_click_rotation_button, padx=Metrics.paddingMenuButtonsX, pady=Metrics.paddingMenuButtonsY, ).pack(side="left") self.reflection_button = tk.Button(self.menu_frame, text="Reflexão", width=Metrics.buttonSize, relief="raised", command=self.handle_on_click_reflection_button, padx=Metrics.paddingMenuButtonsX, pady=Metrics.paddingMenuButtonsY, ).pack(side="left") self.clean_button = tk.Button(self.menu_frame, text="Clean Screen", width=Metrics.buttonSize, relief="raised", command=self.clean_screen, padx=Metrics.paddingMenuButtonsX, pady=Metrics.paddingMenuButtonsY, ).pack()
def __createMenu(self): """Create a tkinter canvas in which to hold the menu buttons. """ # Layout: # ------- # ------------------------------------------------------------------ # | Start || Capture New Image || Add/Remove Spaces || Quit | # ------------------------------------------------------------------ # | Register || Save || Load || Clear || Add/Remove CPs || ReadMe | # ------------------------------------------------------------------ # padding around buttons PADDING = 10; # start the main program self.start_button = tk.Button(self, text = "Start PiPark", command = self.clickStart, padx = PADDING) self.start_button.grid(row = 0, column = 0, sticky = tk.W + tk.E + tk.N + tk.S) # register the car park button self.register_button = tk.Button(self, text = "Register", command = self.clickRegister, padx = PADDING) self.register_button.grid(row = 1, column = 0, sticky = tk.W + tk.E + tk.N + tk.S) # take new setup image button self.image_button = tk.Button(self, text = "Capture New Setup Image", command = self.clickNewImage, padx = PADDING) self.image_button.grid(row = 0, column = 1, rowspan = 1, columnspan = 3, sticky = tk.W + tk.E + tk.N + tk.S) # save setup data & image self.save_button = tk.Button(self, text = "Save", command = self.clickSave, padx = PADDING) self.save_button.grid(row = 1, column = 1, sticky = tk.W + tk.E + tk.N + tk.S) # load setup data & image self.load_button = tk.Button(self, text = "Load", command = self.clickLoad, padx = PADDING) self.load_button.grid(row = 1, column = 2, sticky = tk.W + tk.E + tk.N + tk.S) # clear all parking spaces and CPs self.clear_button = tk.Button(self, text = "Clear", command = self.clickClear, padx = PADDING) self.clear_button.grid(row = 1, column = 3, sticky = tk.W + tk.E + tk.N + tk.S) # add/remove spaces button self.spaces_button = ToggleButton(self) self.spaces_button.config(text = "Add/Remove Spaces", command = self.clickSpaces, padx = PADDING, state = tk.DISABLED) self.spaces_button.grid(row = 0, column = 4, sticky = tk.W + tk.E + tk.N + tk.S) # add/remove control points button self.cps_button = ToggleButton(self) self.cps_button.config(text = "Add/Remove Control Points", command = self.clickCPs, padx = PADDING, state = tk.DISABLED) self.cps_button.grid(row = 1, column = 4, sticky = tk.W + tk.E + tk.N + tk.S) # quit setup self.quit_button = tk.Button(self, text = "Quit", command = self.clickQuit, padx = PADDING) self.quit_button.grid(row = 0, column = 5, sticky = tk.W + tk.E + tk.N + tk.S) # about button - display information about PiPark self.about_button = tk.Button(self, text = "Open ReadMe", command = self.clickAbout, padx = PADDING) self.about_button.grid(row = 1, column = 5, sticky = tk.W + tk.E + tk.N + tk.S)
class SettingsFrame(Frame): #This class is concerned with the working of Settings Frame def __init__(self, parent, container, config): Frame.__init__(self, container, padx=10, pady=10) self.config = config self.parent = parent mainLabel = Label(self, text="Settings", font=("", 15)) mainLabel.pack(anchor="w") self.createGeneralSettings() self.createColorSettings() self.changesButton() def createGeneralSettings(self): #This setups the General Settings generalFrame = LabelFrame(self, text="General", padx=10) generalFrame.pack(fill=X) self.generalFrame = generalFrame cameraLabel = Label(generalFrame, text="Camera") #cameraButton = ToggleButton(generalFrame,value=True,padx=5) self.cameraButton = ToggleButton(generalFrame, value=self.config.getData("camera"), padx=5) cameraLabel.grid(row=0, column=0, pady=2, sticky="w") self.cameraButton.grid(row=0, column=1, pady=2) maskLabel = Label(generalFrame, text="Mask") self.maskButton = ToggleButton(generalFrame, value=self.config.getData("mask"), padx=5) maskLabel.grid(row=1, column=0, pady=2, sticky="w") self.maskButton.grid(row=1, column=1, pady=2) leftMouseLabel = Label(generalFrame, text="Left Mouse Click") self.leftMouseButton = ToggleButton( generalFrame, value=self.config.getData("leftMouseClick"), padx=5) leftMouseLabel.grid(row=2, column=0, pady=2, sticky="w") self.leftMouseButton.grid(row=2, column=1, pady=2) rightMouseLabel = Label(generalFrame, text="Right Mouse Click") self.rightMouseButton = ToggleButton( generalFrame, value=self.config.getData("rightMouseClick"), padx=5) rightMouseLabel.grid(row=3, column=0, pady=2, sticky="w") self.rightMouseButton.grid(row=3, column=1, pady=2) def createColorSettings(self): #This setups the Color Settings colorFrame = LabelFrame(self, text="Colors", padx=10) colorFrame.pack(fill=X) self.colorFrame = colorFrame movementLabel = Label(colorFrame, text="Movement") self.movementColorButton = ColorRadioButton( colorFrame, self.config.getData("movementColor")) movementLabel.grid(row=0, column=0, pady=2, sticky="w") self.movementColorButton.grid(row=0, column=1, pady=2) leftMouseColorLabel = Label(colorFrame, text="Left Click") self.leftMouseColorButton = ColorRadioButton( colorFrame, self.config.getData("leftMouseColor")) leftMouseColorLabel.grid(row=1, column=0, pady=2, sticky="w") self.leftMouseColorButton.grid(row=1, column=1, pady=2) rightMouseColorLabel = Label(colorFrame, text="Right Click") self.rightMouseColorButton = ColorRadioButton( colorFrame, self.config.getData("rightMouseColor")) rightMouseColorLabel.grid(row=2, column=0, pady=2, sticky="w") self.rightMouseColorButton.grid(row=2, column=1, pady=2) def changesButton(self): #This method setups the settings button buttonFrame = Frame(self, pady=10) buttonFrame.pack(fill=X) self.buttonFrame = buttonFrame resetChanges = Button(buttonFrame, text="Reset To Default", padx=5, command=self.resetChanges) applyChanges = Button(buttonFrame, text="Apply", padx=5, command=self.applyChanges) cancelChanges = Button(buttonFrame, text="Cancel", padx=5, command=self.reloadUI) cancelChanges.pack(side=RIGHT) applyChanges.pack(side=RIGHT, padx=10) resetChanges.pack(side=RIGHT) def reloadUI(self): #Reloads the complete Settings Frame #Specially usefull when settings is changes.(Either Saved or Reset) self.generalFrame.destroy() self.colorFrame.destroy() self.buttonFrame.destroy() self.createGeneralSettings() self.createColorSettings() self.changesButton() def resetChanges(self): #Called when "Reset" Button is Pressed self.config.resetToDefault() self.reloadUI() def applyChanges(self): #Called when "Apply" Button is Pressed #Validates the changes #Save the changes to the configuration File movementColor = self.movementColorButton.getSelectedColor() leftColor = self.leftMouseColorButton.getSelectedColor() rightColor = self.rightMouseColorButton.getSelectedColor() if movementColor == leftColor or movementColor == rightColor or leftColor == rightColor: self.parent.showWarning("All 3 colors should be different") return False try: self.config.setData("camera", self.cameraButton.getValue()) self.config.setData("mask", self.maskButton.getValue()) self.config.setData("leftMouseClick", self.leftMouseButton.getValue()) self.config.setData("rightMouseClick", self.rightMouseButton.getValue()) self.config.setData("movementColor", movementColor) self.config.setData("leftMouseColor", leftColor) self.config.setData("rightMouseColor", rightColor) self.config.saveConfig() self.reloadUI() return True except Exception as e: print(e) self.parent.showError("Error in saving Changes.") return False