Ejemplo n.º 1
0
    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)
Ejemplo n.º 2
0
    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)
Ejemplo n.º 3
0
    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)
Ejemplo n.º 4
0
    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)
Ejemplo n.º 5
0
    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)
Ejemplo n.º 6
0
    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)
Ejemplo n.º 7
0
    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)
Ejemplo n.º 8
0
    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)
Ejemplo n.º 9
0
    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)
Ejemplo n.º 10
0
    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)
Ejemplo n.º 11
0
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
Ejemplo n.º 12
0
 def __init__ (self, text=None):
     ToggleButton.__init__ (self, text)
Ejemplo n.º 13
0
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),
Ejemplo n.º 14
0
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
Ejemplo n.º 15
0
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
Ejemplo n.º 16
0
 def __init__(self, text=None):
     ToggleButton.__init__(self, text)
Ejemplo n.º 17
0
 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()
Ejemplo n.º 18
0
    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)
Ejemplo n.º 19
0
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