Example #1
0
class MainGUI(QMainWindow):
    def __init__(self):
        super(MainGUI, self).__init__()
        self.initUI()

    def initUI(self):
        # right panel
        rightLayout = QVBoxLayout()
        gridLayout = QGridLayout()
        rightPanel = QWidget()
        rightPanel.setLayout(rightLayout)

        # Add the panel to a dock for flexibility
        rightDock = QDockWidget("Control Panel", self)
        rightDock.setAllowedAreas(Qt.LeftDockWidgetArea
                                  | Qt.RightDockWidgetArea)
        rightDock.setWidget(rightPanel)
        self.addDockWidget(Qt.RightDockWidgetArea, rightDock)

        # The main widget
        self.view = QGraphicsView()
        self.view.scale(1, -1)
        self.view.centerOn(0, 0)
        self.scene = InteractiveScene(self)  # QGraphicsScene(self)
        self.scene.setBackgroundBrush(QBrush(Qt.white, Qt.SolidPattern))

        # Add the axes
        self.scene.addLine(0, 0, 1000, 0)
        self.scene.addLine(0, 0, 0, 1000)

        test_geo = Spline([[0, 0], [100, 100], [0, 150], [50, 200]])
        test_item = SplineItem(test_geo)
        # test_item = PolylineItem([[0, 0], [100, 0], [100, 100], [0, 100]])
        # test_item = RectItem(5, 5, 55, 55)
        # test_item = CircleItem(200, 200, 50)
        # test_item = RingItem(200, 200, 50, 100)
        self.scene.addItem(test_item)

        self.view.setScene(self.scene)
        self.setCentralWidget(self.view)

        # Menus, status bar, tool bar and stuff
        exitAction = QAction(QtGui.QIcon.fromTheme('application-exit'), 'Exit',
                             self)
        exitAction.setShortcut('Ctrl+Q')
        exitAction.setStatusTip('Exit application')
        exitAction.triggered.connect(self.close)
        self.statusBar().showMessage('Hi there!')

        self.toolbar = self.addToolBar('Exit')
        self.toolbar.addAction(exitAction)

        self.setGeometry(0, 0, 1200, 800)
        self.setWindowTitle('SimpleUI 1.0')
        self.showMaximized()
Example #2
0
 def center_view_on_frame(self, gv: QGraphicsView, frame_uuid: UUID):
     item = self._frame_items.get(frame_uuid)
     if item is not None:
         gv.centerOn(item)
Example #3
0
class Filter(QWidget):
    label_map = {
        'K': 'Keep',
        'T': 'Take',
        'S': 'Stitch',
        'M': 'Compare',
        'C': 'Crop',
        'D': 'Delete',
        None: ''
    }

    def __init__(self, parent, config, new_files):
        QWidget.__init__(self, parent)
        self.zoomLevel = 1.0
        self.rotation = 0

        self.all_images = ImageList()
        self.compare_set = ImageList()
        # start with all images
        self.images = self.all_images
        self.comparing = False

        self.src = config['Directories']['mid']
        self.dst = os.getcwd()
        self.scan(self.src)
        self.new_files = new_files

        self.image = None

        self.image_actions = defaultdict(lambda: None)
        self.image_positions = {}
        self.original_position = None

        self.buildUI(parent)

        self.dir_dialog = QFileDialog(self)
        self.dir_dialog.setFileMode(QFileDialog.Directory)

    def buildUI(self, parent):
        # left labels
        self.splitter = QSplitter(self)
        self.splitter.setContentsMargins(QMargins(0, 0, 0, 0))
        self.splitter.setOrientation(Qt.Horizontal)
        self.widget = QWidget(self.splitter)
        self.label_layout = QVBoxLayout(self.widget)

        for count, name in enumerate([
                'exposure_time',
                'fnumber',
                'iso_speed',
                'focal_length',
                'date',
        ]):
            key_label = QLabel(name.replace('_', ' ').title(), self.widget)
            # setattr(self, "key_label_%02d" % count, key_label)
            self.label_layout.addWidget(key_label)

            value_label = QLabel(self.widget)
            value_label.setAlignment(Qt.AlignRight)
            setattr(self, name, value_label)
            self.label_layout.addWidget(value_label)

        # TODO
        s = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
        self.label_layout.addItem(s)

        # main view
        self.scene = QGraphicsScene()

        self.item = QGraphicsPixmapItem()
        self.scene.addItem(self.item)

        self.view = QGraphicsView(self.scene, parent)
        self.view.setFrameShadow(QFrame.Plain)
        self.view.setFrameStyle(QFrame.NoFrame)
        self.view.setDragMode(QGraphicsView.ScrollHandDrag)
        self.view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        brush = QBrush(QColor(20, 20, 20))
        brush.setStyle(Qt.SolidPattern)
        self.view.setBackgroundBrush(brush)

        self.view.show()

        # "status bar"
        self.fname = QLabel(self)
        self.fname.setTextInteractionFlags(Qt.TextSelectableByMouse)
        spacer = QSpacerItem(40, 20, QSizePolicy.Expanding,
                             QSizePolicy.Minimum)
        self.tag_view = QLabel(self)

        status_bar = QHBoxLayout()
        status_bar.addWidget(self.fname)
        status_bar.addItem(spacer)
        status_bar.addWidget(self.tag_view)

        w = QWidget(self.splitter)

        v = QVBoxLayout(w)
        v.setContentsMargins(QMargins(0, 0, 0, 0))
        v.addWidget(self.view)
        v.addLayout(status_bar)

        # TODO
        self.splitter.setSizes([10, 90])

        h = QHBoxLayout(self)
        h.setContentsMargins(QMargins(0, 0, 0, 0))
        h.addWidget(self.splitter)

        # now... ACTION!(s)
        for key, slot in (
            (Qt.Key_Home, self.first_image),
            (Qt.Key_PageUp, self.prev_ten),
            (Qt.Key_Backspace, self.prev_image),
            (Qt.Key_Space, self.next_image),
            (Qt.Key_PageDown, self.next_ten),
            (Qt.Key_End, self.last_image),
            (Qt.Key_F, self.toggle_fullsize),
            (Qt.Key_K, self.keep),
            (Qt.Key_T, self.tag),
            (Qt.Key_S, self.stitch),
            (Qt.Key_M, self.select_for_compare),
            (Qt.Key_C, self.crop),
            (Qt.Key_D, self.delete),
            (Qt.Key_U, self.untag),
            (Qt.Key_X, self.expunge),
            (Qt.Key_Return, self.apply),
            (Qt.CTRL + Qt.Key_M, self.compare),
            (Qt.CTRL + Qt.Key_O, self.new_src),
            (Qt.CTRL + Qt.Key_S, self.save),
        ):
            action = QAction(parent)
            action.setShortcut(QKeySequence(key))
            action.triggered.connect(slot)
            self.view.addAction(action)

    def scan(self, src):
        index = 0

        logger.debug('scanning %r', src)
        for r, dirs, files in os.walk(os.path.abspath(src)):
            for name in sorted(files):
                if name[-4:].lower() in ('.jpg', '.png'):
                    # logger.info ('found %s' % name)
                    self.images.append(Image(index, os.path.join(r, name)))
                    index += 1

    def rotate_view(self):
        # we have to 'undo' the rotations, so the numbers are negative
        rotate = -self.image.rotation

        # undo the last rotation and apply the new one
        self.view.rotate(-self.rotation + rotate)
        self.rotation = rotate
        logger.debug(rotate, self.rotation)

    def zoom_to_fit(self):
        winSize = self.view.size()
        logger.debug(self.image.size, winSize)

        hZoom = winSize.width() / self.image.size.width()
        vZoom = winSize.height() / self.image.size.height()
        zoomLevel = min(hZoom, vZoom)

        self.zoom(zoomLevel)

    def zoom(self, zoomLevel):
        # logger.info (zoomLevel)
        scale = zoomLevel / self.zoomLevel
        # logger.info ("scaling", scale)
        self.view.scale(scale, scale)

        self.zoomLevel = zoomLevel

    def move_index(self, to=None, how_much=0):
        if self.image is not None:
            self.save_position()

        self.images.move_index(to, how_much)

        self.image = self.images.current_image
        self.show_image()

    def view_position(self):
        view_size = self.view.size()
        center = QPoint(view_size.width() / 2, view_size.height() / 2)
        position = self.view.mapToScene(center)
        return position

    def show_image(self):
        logger.info(self.image.path)
        self.image.read()

        self.rotate_view()
        self.item.setPixmap(self.image.pixmap)
        if self.zoomLevel != 1.0:
            self.zoom_to_fit()

        # we might have rotated the view, but the scene still has the image
        # in its original size, so we use that as bounding rect
        boundingRect = QRectF(self.item.pixmap().rect())
        logger.debug(boundingRect)
        self.scene.setSceneRect(boundingRect)

        if self.image.index in self.image_positions:
            self.original_position = None
            position = self.image_positions[self.image.index]
            logger.debug("previously moved, back to that point: %f x %f",
                         position.x(), position.y())
            self.view.centerOn(position)
        else:
            # TODO: 'undo' the move
            position = self.view_position()
            logger.debug("original position: %f x %f", position.x(),
                         position.y())
            self.original_position = position
            self.view.centerOn(self.item)

        self.update_view()

    def update_view(self):
        self.fname.setText(self.image.path)
        label = self.label_map[self.image_actions[self.image]]
        self.tag_view.setText(label)

        meta = self.image.metadata
        date = read_image_date(self.image.path, meta)
        if date is None:
            self.date.setText('unknown')
        else:
            self.date.setText(date.isoformat())

        self.fnumber.setText(str(meta.get_fnumber()))
        self.focal_length.setText(str(meta.get_focal_length()))
        self.iso_speed.setText(str(meta.get_iso_speed()))

        f = meta.get_exposure_time()
        if f is None:
            s = 'unknown'
        elif f.denominator == 1:
            s = '%ds' % f.numerator
        else:
            s = '%d/%ds' % (f.numerator, f.denominator)
        self.exposure_time.setText(s)

    def save_position(self):
        position = self.view_position()
        if (self.original_position is None
                or position.x() != self.original_position.x()
                or position.y() != self.original_position.y()):

            logger.debug("saving position: %f x %f", position.x(),
                         position.y())
            # this way (I hope) I only remember those positions which changed
            self.image_positions[self.image.index] = position

    # movements
    def first_image(self, *args):
        self.move_index(to=0)

    def prev_ten(self, *args):
        self.move_index(how_much=-10)

    def prev_image(self, *args):
        self.move_index(how_much=-1)

    def next_image(self, *args):
        self.move_index(how_much=+1)

    def next_ten(self, *args):
        self.move_index(how_much=+10)

    def last_image(self, *args):
        self.move_index(to=len(self.images) - 1)

    def toggle_fullsize(self, *args):
        # noooooooooooooooothing compares...
        if abs(self.zoomLevel - 1.0) < 0.000001:
            # logger.info ('fit')
            self.zoom_to_fit()
        else:
            # logger.info ('orig')
            self.zoom(1.0)

    # image actions
    # Keep -> /gallery/foo, resized
    def keep(self, *args):
        self.image_actions[self.image] = 'K'
        self.next_image()

    # Tag -> /gallery/foo, as-is
    def tag(self, *args):
        self.image_actions[self.image] = 'T'
        self.next_image()

    # Stitch -> 02-new/stitch
    def stitch(self, *args):
        self.image_actions[self.image] = 'S'
        self.next_image()

    # coMpare
    def select_for_compare(self, *args):
        if self.image_actions[self.image] == 'M':
            # TODO?: undo/toggle
            # NOTE: this can already be achieved by Untag
            pass
        else:
            self.image_actions[self.image] = 'M'
            # ugh
            insort(self.compare_set, self.image)
            logger.debug(self.compare_set.images)

        self.next_image()

    def compare(self):
        logger.info('comparing')
        self.comparing = True
        self.images = self.compare_set
        self.move_index()

    # Crop -> launch gwenview
    def crop(self, *args):
        self.image_actions[self.image] = 'C'
        self.next_image()

    # Delete -> /dev/null
    def delete(self, *args):
        self.image_actions[self.image] = 'D'

        if self.comparing:
            # remove the image from the list and refresh the view
            self.images.remove()
            self.image = self.images.current_image
            self.show_image()
        else:
            self.next_image()

    def untag(self, *args):
        try:
            del self.image_actions[self.image]
            # don't move, most probably I'm reconsidering what to do
            # but change the label
            self.tag_view.setText('')
        except KeyError:
            # tried to untag a non-tagged image
            pass

    def resize(self, src, dst):
        src_meta = GExiv2.Metadata(src)
        src_p = QPixmap(src)
        dst_p = src_p.scaled(4500, 3000, Qt.KeepAspectRatio,
                             Qt.SmoothTransformation)

        dst_p.save(src)
        shutil.move(src, dst)

        # copy all the metadata
        dst_meta = GExiv2.Metadata(dst)
        for tag in src_meta.get_tags():
            dst_meta[tag] = src_meta[tag]
        dst_meta.save_file()

    def apply(self, *args):
        if not self.comparing:
            hugin = False

            if len([
                    action for action in self.image_actions.values()
                    if action in ('K', 'T')
            ]) > 0:
                self.new_dst()

            for img, action in sorted(
                    self.image_actions.items(),
                    key=lambda s: s[0].path):  # sort by fname
                src = img.path
                dst = os.path.join(self.dst, os.path.basename(src))

                try:
                    if src in self.new_files and action not in ('C', 'D'):
                        # rename
                        src = rename_file(src)

                    if action == 'K':
                        # Keep -> /gallery/foo, as-is
                        logger.info("%s -> %s" % (src, dst))
                        shutil.move(src, dst)

                    elif action == 'T':
                        # Tag -> /gallery/foo, resized
                        self.resize(src, dst)

                    elif action == 'S':
                        # Stitch -> 02-new/stitch
                        dst = os.path.join(
                            '/home/mdione/Pictures/incoming/02-new/stitch',
                            os.path.basename(src))
                        logger.info("%s -> %s" % (src, dst))
                        shutil.move(src, dst)
                        hugin = True

                    elif action == 'M':
                        # coMpare -> 03-cur
                        dst = os.path.join(
                            '/home/mdione/Pictures/incoming/03-cur',
                            os.path.basename(src))
                        logger.info("%s -> %s" % (src, dst))
                        shutil.move(src, dst)

                        new_root = '/home/mdione/Pictures/incoming/03-cur'
                        old_root = self.src

                    elif action == 'C':
                        # Crop -> launch gwenview
                        os.system('gwenview %s' % src)

                        # asume the file was saved under a new name
                        # logger.info ("%s -> %s" % (src, dst))
                        # shutil.move (src, dst)

                    elif action == 'D':
                        # Delete -> /dev/null
                        os.unlink(src)
                        logger.info("%s deleted" % (src, ))
                except FileNotFoundError as e:
                    logger.info(e)

            if hugin:
                os.system('hugin')

            self.reset()
        else:
            logger.info('back to all')
            self.comparing = False

            # untag all images marked for compare
            for image in self.compare_set:
                # but only those still marked 'M'
                if self.image_actions[image] == 'M':
                    del self.image_actions[image]

            self.compare_set.clear()
            self.images = self.all_images
            self.move_index()

    def expunge(self, *args):
        for img, action in self.image_actions.items():
            src = img.path
            try:
                if action == 'D':
                    # Delete -> /dev/null
                    os.unlink(src)
                    logger.info("%s deleted" % (src, ))
            except FileNotFoundError as e:
                logger.info(e)

        self.reset()

    def reset(self, new_root=None):
        if new_root is not None:
            self.src = new_root

        self.image_actions.clear()
        self.all_images.clear()
        self.compare_set.clear()
        self.comparing = False
        self.scan(self.src)

    def new_dst(self, *args):
        self.dir_dialog.setDirectory(self.dst)
        if self.dir_dialog.exec():
            self.dst = self.dir_dialog.selectedFiles()[0]

    def new_src(self, *args):
        self.dir_dialog.setDirectory(self.src)
        if self.dir_dialog.exec():
            self.src = self.dir_dialog.selectedFiles()[0]
            self.reset()

    def save(self, *args):
        src = self.image.path
        self.dir_dialog.setDirectory(self.dst)
        if self.dir_dialog.exec():
            dst_dir = self.dir_dialog.selectedFiles()[0]
            if src in self.new_files:
                src = rename_file(src)

            dst = os.path.join(dst_dir, os.path.basename(src))

            logger.info("%s -> %s" % (src, dst))
            self.resize(src, dst)

            self.next_image()
Example #4
0
yeux[1].setPos(+d / 6, -d / 8)
brush = QBrush(Qt.black)
for oeil in yeux:
    oeil.setBrush(brush)
smiley.setPos(rectGris.mapToScene(rectGris.rect().center()))
scene.addItem(smiley)
smiley.setRotation(20)
smiley.setScale(1.5)
smiley.setFlag(QGraphicsItem.ItemIsMovable)
texte.setZValue(1)

# vue principale
vue = QGraphicsView(scene)
vue.setRenderHints(QPainter.Antialiasing)
vue.resize(800, 600)
vue.centerOn(rectGris)
vue.fitInView(rectGris, Qt.KeepAspectRatio)
vue.show()

# vues auxiliaires
vues = []
for _ in range(4):
    vuex = QGraphicsView(scene)
    vues.append(vuex)
    vuex.setRenderHints(QPainter.Antialiasing)
    vuex.resize(400, 300)
    vuex.rotate(360. * random())
    vuex.scale(4. * random(), 4. * random())
    # pour éviter les déformations, remplacer l'instruction précédente par
    # f = 4. * random()
    # vuex.scale(f,f)
class WindowTime(QMainWindow):
    '''This class handles the main window.'''
    def __init__(self):
        super().__init__()

        self.menubar = self.menuBar()

        self.status = self.statusBar()

        exitAction = QAction('Exit', self)
        exitAction.setShortcut('Ctrl+Q')
        exitAction.setStatusTip('Exit application')
        exitAction.triggered.connect(self.close)

        fileMenu = self.menubar.addMenu('&File')
        fileMenu.addAction(exitAction)

        self.zoomlevel = 2
        # self.pixmaps = {2: QPixmap('yeg-2.png'), 3: QPixmap('yeg-3.png'),
        # 				4: QPixmap('yeg-4.png'), 5: QPixmap('yeg-5.png'), 6: QPixmap('yeg-6.png')}
        #
        # self.sizes = {1: 512, 2: 1024, 3: 2048, 4: 4096, 5: 8192, 6: 16384}
        self.pixmaps = {
            2: QPixmap(os.path.join(__location__, 'yeg-2.png')),
            3: QPixmap(os.path.join(__location__, 'yeg-3.png')),
            4: QPixmap(os.path.join(__location__, 'yeg-4.png')),
            5: QPixmap(os.path.join(__location__, 'yeg-5.png'))
        }

        self.sizes = {1: 512, 2: 1024, 3: 2048, 4: 4096, 5: 8192}
        self.pressed = False
        self.start = 0
        self.dest = 0
        self.center = (0, 0)
        self.howmanycars = 0
        self.customer_id = 0
        self.initUI()

        self.show()

    def initUI(self):
        #The QToolTip class provides tool tips (balloon help) for any widget.
        QToolTip.setFont(QFont('SansSerif', 10))

        w = QWidget()
        #The QGridLayout class lays out widgets in a grid.
        grid = QGridLayout()
        #setLayout(self, Qlayout) Sets the layout manager for this widget to layout.
        #The QLayout argument has it's ownership transferred to Qt.
        w.setLayout(grid)
        #The QLabel widget provides a text or image display.
        labelZoom = QLabel('Zoom here pls')
        labelPassengers = QLabel('How many Passengers')

        #The QPushButton widget provides a command button. Takes in arguments
        #For text label
        btnZoomIn = QPushButton('+')
        btnZoomIn.setToolTip('Zoom In')
        btnZoomIn.clicked.connect(self.zoomIn)
        btnZoomOut = QPushButton('-')
        btnZoomOut.setToolTip('Zoom Out')
        btnZoomOut.clicked.connect(self.zoomOut)

        spinBox = QSpinBox()
        spinBox.setMaximum(5)
        spinBox.setMinimum(1)

        self.mapScene = GraphicsScene()
        self.mapScene.setSceneRect(0, 0, self.sizes[self.zoomlevel],
                                   self.sizes[self.zoomlevel])
        self.mapScene.addPixmap(self.pixmaps[self.zoomlevel])
        #ellipse = mapScene.addEllipse(50,100,50,50)
        self.mapView = QGraphicsView()
        self.mapView.setScene(self.mapScene)
        #Set it so user can drag map via cursor
        self.mapView.setDragMode(QGraphicsView.ScrollHandDrag)
        #Hide the scroll bar
        self.mapView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.mapView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        grid.addWidget(labelZoom, 0, 4)
        grid.addWidget(self.mapView, 0, 0, 4, 4)
        grid.addWidget(btnZoomIn, 1, 4)
        grid.addWidget(btnZoomOut, 2, 4)
        grid.addWidget(labelPassengers, 3, 4)
        grid.addWidget(spinBox, 4, 4)

        #How everything will look on the screen
        self.setGeometry(300, 300, 800, 600)
        self.setWindowTitle('Uber Pool')
        self.setCentralWidget(w)

        #CHANGED: This
    def setCenter(self):
        center = self.mapView.mapToScene(self.mapView.width() // 2,
                                         self.mapView.height() // 2)
        self.center = (ConversionFunctions.x_to_longitude(
            self.zoomlevel, center.x()),
                       ConversionFunctions.y_to_latitude(
                           self.zoomlevel, center.y()))

    def zoomIn(self):
        if self.zoomlevel < 5:
            self.pressed = False
            self.setCenter()
            self.zoomlevel += 1
            self.updateSceneZoom()

    def zoomOut(self):
        if self.zoomlevel > 2:
            self.pressed = False
            self.setCenter()
            self.zoomlevel -= 1
            self.updateSceneZoom()

    #updates the scence once the zoom button has been pressed. The scene is
    #updated on the center of the last scene
    def updateSceneZoom(self):
        self.mapScene.clear()
        self.mapScene.addPixmap(self.pixmaps[self.zoomlevel])
        self.mapScene.setSceneRect(0, 0, self.sizes[self.zoomlevel],
                                   self.sizes[self.zoomlevel])
        (x, y) = (ConversionFunctions.longitude_to_x(self.zoomlevel,
                                                     self.center[0]),
                  ConversionFunctions.latitude_to_y(self.zoomlevel,
                                                    self.center[1]))
        self.mapView.centerOn(x, y)

    #returns the x,y position of the cursor on the map
    def handleClick(self, pos):
        return (pos.x(), pos.y())
        # #Grab the x,y coords
        # (x, y) = (pos.x(), pos.y())
        # #Convert them into lat,lon
        # lon = x_to_longitude(self.zoomlevel, x)
        # lat = y_to_latitude(self.zoomlevel, y)
        #
        # #Determine whether start location has already been decided
        # if self.pressed == False:
        # 	self.start = Vertex(lat, lon)
        # 	self.pressed = True
        # 	self.drawBubble(self.start)
        # else:
        # 	#Once dest has been decided, find shortest path and draw it
        # 	self.dest = Vertex(lat, lon)
        # 	self.pressed = False
        # 	self.drawBubble(self.dest)
        # 	self.controller.passRequest(self.start, self.dest, 1)

    def drawCar(self):
        #Draws the map in place
        self.setCenter()
        self.mapScene.clear()
        self.mapScene.addPixmap(self.pixmaps[self.zoomlevel])
        self.mapScene.setSceneRect(0, 0, self.sizes[self.zoomlevel],
                                   self.sizes[self.zoomlevel])
        (lat, lon) = self.center
        x = ConversionFunctions.longitude_to_x(self.zoomlevel, lon)
        y = ConversionFunctions.latitude_to_y(self.zoomlevel, lat)
        self.mapView.centerOn(x, y)
        #advance_taxi
        UberTaxi.advance_taxi(taxi_directory, cust_directory, g)
        for taxi in taxi_directory.values():
            #gets coords from vertex
            lon = server.coordinates[taxi.loc][1]
            lat = server.coordinates[taxi.loc][0]
            #stored in lat, lon, and then converted
            newx = ConversionFunctions.longitude_to_x(self.zoomlevel, lon)
            newy = ConversionFunctions.latitude_to_y(self.zoomlevel, lat)
            #draws path and car
            self.mapScene.addRect(newx, newy, 15, 10)
            self.mapScene.addEllipse(newx - 2, newy + 10, 6, 6)
            self.mapScene.addEllipse(newx + 11, newy + 10, 6, 6)
            self.drawPath(taxi.path)

    def drawPath(self, path):
        linePen = QPen()
        linePen.setWidth(3)  #Set the width of the line to be noticeable
        for i in range(len(path) - 1):
            lon1 = server.coordinates[path[i]][1]
            lat1 = server.coordinates[path[i]][0]
            lon2 = server.coordinates[path[i + 1]][1]
            lat2 = server.coordinates[path[i + 1]][0]

            self.mapScene.addLine(
                ConversionFunctions.longitude_to_x(self.zoomlevel, lon1),
                ConversionFunctions.latitude_to_y(self.zoomlevel, lat1),
                ConversionFunctions.longitude_to_x(self.zoomlevel, lon2),
                ConversionFunctions.latitude_to_y(self.zoomlevel, lat2),
                linePen)
Example #6
0
class Editor(QWidget):
    def __init__(self, song):
        super().__init__()

        self.initUI(song)

    def initUI(self, song):
        self.songLenInBeats = 100
        self.songBeatsPBar = 4
        self.reverse = 1
        self.pixPSec = 1000.0
        self.disp8 = True
        self.disp12 = False
        self.disp16 = True
        self.disp24 = False
        self.disp32 = False
        self.disp48 = False
        self.disp64 = False
        self.spectrogramDisplay = True
        self.cursorExists = False
        self.framecount = 0
        self.timeOutLength = 17

        self.timer = QTimer()
        self.editorTheme = self.getTheme()
        self.boxw = self.editorTheme['BoxWidth']
        self.topLayout = QVBoxLayout()
        self.topLayout.setContentsMargins(0, 0, 0, 0)

        self.song = song
        self.song.pos = 0
        self.setLayout(self.topLayout)
        self.gs = QGraphicsScene()
        self.gv = QGraphicsView(self.gs)
        self.drawBG()
        self.song = song
        #        self.drawArrowDemo()
        self.boxes = []
        self.topLayout.addWidget(self.gv)

    def update(self, song, level):
        self.gs.clear()
        print(self.song.pos)
        self.song = song
        self.cursorExists = False
        self.song.pos = 0
        self.play(0)
        self.pause()
        self.updatescreen()

        if self.spectrogramDisplay:
            self.spectrogramPixMap = QPixmap(spectrogram_dir + song.audioFile +
                                             '.png')
            width = self.spectrogramPixMap.width()
            height = self.spectrogramPixMap.height()

            self.spectrogramPixMap = self.gs.addPixmap(self.spectrogramPixMap)
            self.spectrogramPixMap.setRotation(90)
            self.spectrogramPixMap.setTransform(QTransform().scale(
                -1, (self.song.lengthInSeconds * self.pixPSec) / width))
        self.drawGrid(self.song.levels[level])
        self.drawArrowDemo(self.song.levels[level])
        #self.play(0)

    def levelSelected(self, level):
        print("Selected ", level)
        if level in self.song.levels:
            print('switching')
            self.update(self.song, level)
        else:
            print('creating new level')

    def play(self, pos):
        self.timer.timeout.connect(self.updatescreen)
        self.timer.start(self.timeOutLength)
        self.song.playSong(pos)

    def pause(self):
        self.timer.stop()
        self.song.pauseSong()

    def keyPressEvent(self, event):
        key = event.key()
        shiftPressed = event.modifiers() == Qt.ShiftModifier
        ctrlPressed = event.modifiers() == Qt.ControlModifier
        altPressed = event.modifiers() == Qt.AltModifier
        restart = self.song.isPlaying

        if key == Qt.Key_Space:
            if self.song.isPlaying:
                self.pause()
            else:
                self.play(self.song.pos / 1000)
        elif key == Qt.Key_BracketRight:
            restart = self.song.isPlaying
            self.pause()
            if ctrlPressed:
                self.song.pos += 10000
            elif shiftPressed:
                self.song.pos += 1000
            elif altPressed:
                self.song.pos += 10
            else:
                self.song.pos += 100

            if not (self.song.pos > self.song.lengthInSeconds * 1000):
                if restart:
                    self.play(self.song.pos / 1000)
                else:
                    self.play(self.song.pos / 1000)
                    self.pause()
            else:
                self.song.pos = self.song.lengthInSeconds * 1000 - 1
                self.play(self.song.pos / 1000)
                self.pause()
            self.updatescreen()
        elif key == Qt.Key_BracketLeft:
            self.pause()
            if ctrlPressed:
                self.song.pos -= 10000
            elif shiftPressed:
                self.song.pos -= 1000
            elif altPressed:
                self.song.pos -= 10
            else:
                self.song.pos -= 100
            if self.song.pos < 0:
                self.song.pos = 0
            if restart:
                self.play(self.song.pos / 1000)
            else:
                self.play(self.song.pos / 1000)
                self.pause()
            self.updatescreen()
        elif key == Qt.Key_BraceRight:
            restart = self.song.isPlaying
            self.pause()
            if ctrlPressed:
                self.song.pos += 10000
            elif shiftPressed:
                self.song.pos += 1000
            elif altPressed:
                self.song.pos += 10
            else:
                self.song.pos += 200

            if not (self.song.pos > self.song.lengthInSeconds * 1000):
                if restart:
                    self.play(self.song.pos / 1000)
                else:
                    self.play(self.song.pos / 1000)
                    self.pause()
            else:
                self.song.pos = self.song.lengthInSeconds * 1000 - 1
                self.play(self.song.pos / 1000)
                self.pause()

            self.updatescreen()
        elif key == Qt.Key_BraceLeft:
            self.pause()
            if ctrlPressed:
                self.song.pos -= 10000
            elif shiftPressed:
                self.song.pos -= 1000
            elif altPressed:
                self.song.pos += 10
            else:
                self.song.pos -= 200
            if self.song.pos < 0:
                self.song.pos = 0
            if restart:
                self.play(self.song.pos / 1000)
            else:
                self.play(self.song.pos / 1000)
                self.pause()

            self.updatescreen()

    def updatescreen(self):
        self.song.updatePos()

        if self.song.isPlaying:
            self.framecount += 1
            curTime = time.time()
            if (curTime - self.song.time > 1):
                print('FPS: ', self.framecount)
                self.framecount = 0
                self.song.time = curTime

        if self.cursorExists:
            self.gs.removeItem(self.cursorLine)
        ypos = (self.song.pos / 1000.0 * self.pixPSec)
        self.gv.centerOn(0, ypos)
        self.cursorLine = self.gs.addLine(0, ypos, 1000, ypos,
                                          self.editorTheme['GridMeasure'])
        self.cursorExists = True
        self.cursor = True
        if self.song.pos < 0:
            self.song.pos = 0
            self.gv.centerOn(0, 0)
            self.pause()

    def drawArrowDemo(self, level):

        boxRotation = [180, 0, 90, 270, 225, 135, 315, 45, 0]

        for beatBox in level.notes:
            if beatBox.type == 0:
                if beatBox.cutDirection == 8:
                    notePixmap = QPixmap(graphics_dir + 'redcircle.png')
                else:
                    notePixmap = QPixmap(graphics_dir + 'redarrow.png')
            elif beatBox.type == 1:
                if beatBox.cutDirection == 8:
                    notePixmap = QPixmap(graphics_dir + 'bluecircle.png')
                else:
                    notePixmap = QPixmap(graphics_dir + 'bluearrow.png')
            else:
                notePixmap = QPixmap(graphics_dir + 'mine.png')

            notePixmap = notePixmap.scaled(40, 40)
            noteBox = NoteBox()
            noteBox.setPixmap(notePixmap)
            noteBox.setBox(beatBox)
            box = self.gs.addItem(noteBox)
            print(type(noteBox))
            noteBox.setTransformOriginPoint(20, 20)
            noteBox.setRotation(boxRotation[beatBox.cutDirection])
            boxy = (level.beatToSec(beatBox.time) * self.pixPSec -
                    (self.reverse * 20)) * self.reverse

            boxx = 40 * beatBox.lineIndex + 170 * beatBox.lineLayer
            noteBox.setPos(boxx, boxy)
            self.boxes.append(noteBox)

    def drawBG(self):
        self.gs.setBackgroundBrush(self.editorTheme['BG'])

    def drawGrid(self, level):
        #DEBUG need to through a clear grid in here

        self.drawGridConstantTime(level)

    def drawGridConstantBeat(self):
        pass

    def drawGridConstantTime(self, level):

        # DONT FORGET TO ADD REVERSE SCROLL

        #        self.disp192 = True
        self.noteLayer1 = self.gs.createItemGroup([])
        self.noteLayer2 = self.gs.createItemGroup([])
        self.noteLayer3 = self.gs.createItemGroup([])
        self.obstacleLayer = self.gs.createItemGroup([])
        self.eventLayer = self.gs.createItemGroup([])
        width = self.editorTheme['BoxWidth'] * 4
        spacing = self.editorTheme['LaneSpacing']
        self.noteLayer1Values = LayerValue(0, 0, width)
        self.noteLayer2Values = LayerValue((width + spacing), 0, width)
        self.noteLayer3Values = LayerValue((width + spacing) * 2, 0, width)
        self.obstacleLayerValues = LayerValue((width + spacing) * 3, 0, width)
        self.eventLayerValues = LayerValue((width + spacing) * 4, 0, width)

        self.drawGridLaneConstantTime(self.noteLayer1, self.noteLayer1Values,
                                      level)
        self.drawGridLaneConstantTime(self.noteLayer2, self.noteLayer2Values,
                                      level)
        self.drawGridLaneConstantTime(self.noteLayer3, self.noteLayer3Values,
                                      level)
        self.drawGridLaneConstantTime(self.obstacleLayer,
                                      self.obstacleLayerValues, level)
        self.drawGridLaneConstantTime(self.eventLayer, self.eventLayerValues,
                                      level)

    def drawGridLaneConstantTime(self, lane, values, level):
        #debug songlen not a int need to address leftover time
        for beat in range(int(self.song.lengthInBeats)):
            if beat % self.song.beatsPerBar == 0:
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat)) *
                        self.pixPSec, self.editorTheme['GridMeasure']))
            else:
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat)) *
                        self.pixPSec, self.editorTheme['Grid4']))
            if self.disp8:
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .5)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .5)) *
                        self.pixPSec, self.editorTheme['Grid8']))
            if self.disp16:
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .25)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .25)) *
                        self.pixPSec, self.editorTheme['Grid16']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .75)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .75)) *
                        self.pixPSec, self.editorTheme['Grid16']))
            if self.disp32:
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .125)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .125)) *
                        self.pixPSec, self.editorTheme['Grid32']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .375)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .375)) *
                        self.pixPSec, self.editorTheme['Grid32']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .625)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .625)) *
                        self.pixPSec, self.editorTheme['Grid32']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .875)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .875)) *
                        self.pixPSec, self.editorTheme['Grid32']))
            if self.disp64:
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .0625)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .0625)) *
                        self.pixPSec, self.editorTheme['Grid64']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .1875)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .1875)) *
                        self.pixPSec, self.editorTheme['Grid64']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .3125)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .3125)) *
                        self.pixPSec, self.editorTheme['Grid64']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .4375)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .4375)) *
                        self.pixPSec, self.editorTheme['Grid64']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .5625)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .5625)) *
                        self.pixPSec, self.editorTheme['Grid64']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .6875)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .6875)) *
                        self.pixPSec, self.editorTheme['Grid64']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .8125)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .8125)) *
                        self.pixPSec, self.editorTheme['Grid64']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .9375)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .9375)) *
                        self.pixPSec, self.editorTheme['Grid64']))
            if self.disp12:
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + 1 / 3)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + 1 / 3)) *
                        self.pixPSec, self.editorTheme['Grid12']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + 2 / 3)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + 2 / 3)) *
                        self.pixPSec, self.editorTheme['Grid12']))
            if self.disp24:
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + 1 / 6)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + 1 / 6)) *
                        self.pixPSec, self.editorTheme['Grid24']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .5)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .5)) *
                        self.pixPSec, self.editorTheme['Grid24']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + 5 / 6)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + 5 / 6)) *
                        self.pixPSec, self.editorTheme['Grid24']))
            if self.disp48:
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + 1 / 12)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + 1 / 12)) *
                        self.pixPSec, self.editorTheme['Grid48']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .25)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .25)) *
                        self.pixPSec, self.editorTheme['Grid48']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + 5 / 12)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + 5 / 12)) *
                        self.pixPSec, self.editorTheme['Grid48']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + 7 / 12)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + 7 / 12)) *
                        self.pixPSec, self.editorTheme['Grid48']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .75)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .75)) *
                        self.pixPSec, self.editorTheme['Grid48']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + 11 / 12)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + 11 / 12)) *
                        self.pixPSec, self.editorTheme['Grid48']))
        lane.addToGroup(
            self.gs.addLine(
                values.x, values.y, values.x,
                self.reverse *
                (self.song.offset + level.beatToSec(self.song.lengthInBeats)) *
                self.pixPSec, self.editorTheme['GridLayer1Vert']))
        lane.addToGroup(
            self.gs.addLine(
                values.x + values.w * .25, values.y, values.x + values.w * .25,
                self.reverse *
                (self.song.offset + level.beatToSec(self.song.lengthInBeats)) *
                self.pixPSec, self.editorTheme['GridLayer1Vert']))
        lane.addToGroup(
            self.gs.addLine(
                values.x + values.w * .5, values.y, values.x + values.w * .5,
                self.reverse *
                (self.song.offset + level.beatToSec(self.song.lengthInBeats)) *
                self.pixPSec, self.editorTheme['GridLayer1Vert']))
        lane.addToGroup(
            self.gs.addLine(
                values.x + values.w * .75, values.y, values.x + values.w * .75,
                self.reverse *
                (self.song.offset + level.beatToSec(self.song.lengthInBeats)) *
                self.pixPSec, self.editorTheme['GridLayer1Vert']))
        lane.addToGroup(
            self.gs.addLine(
                values.x + values.w, values.y, values.x + values.w,
                self.reverse *
                (self.song.offset + level.beatToSec(self.song.lengthInBeats)) *
                self.pixPSec, self.editorTheme['GridLayer1Vert']))

    def getTheme(self):
        return {
            'BoxWidth': 60,
            'LaneSpacing': 20,
            'BG': QBrush(QColor(0, 0, 0), Qt.SolidPattern),
            'GridLayer1Vert': QPen(QBrush(QColor(255, 255, 255)), 1,
                                   Qt.SolidLine),
            'GridLayer1BG': QBrush(Qt.black, Qt.SolidPattern),
            'GridLayer2Vert': QPen(Qt.white, Qt.SolidLine),
            'GridLayer2BG': QBrush(Qt.black, Qt.SolidPattern),
            'GridLayer3Vert': QPen(Qt.white, Qt.SolidLine),
            'GridLayer3BG': QBrush(Qt.black, Qt.SolidPattern),
            'GridObs': QPen(Qt.blue, Qt.SolidLine),
            'GridObsBG': QBrush(Qt.black, Qt.SolidPattern),
            'GridEventVert': QPen(Qt.red, Qt.SolidLine),
            'GridEventBG': QBrush(Qt.black, Qt.SolidPattern),
            'GridMeasure': QPen(QBrush(QColor(255, 0, 0)), 2, Qt.SolidLine),
            'Grid4': QPen(QBrush(QColor(255, 255, 255)), 2, Qt.DashLine),
            'Grid8': QPen(QBrush(QColor(0, 150, 255)), 2, Qt.DotLine),
            'Grid12': QPen(QBrush(QColor(100, 255, 50)), 2, Qt.DotLine),
            'Grid16': QPen(QBrush(QColor(255, 255, 50)), 2, Qt.DotLine),
            'Grid24': QPen(QBrush(QColor(150, 100, 255)), 2, Qt.DotLine),
            'Grid32': QPen(QBrush(QColor(0, 255, 150)), 2, Qt.DotLine),
            'Grid48': QPen(QBrush(QColor(255, 100, 150)), 2, Qt.DotLine),
            'Grid64': QPen(QBrush(QColor(150, 200, 100)), 2, Qt.DotLine),
            #                    'Grid192': QPen(Qt.red,Qt.SolidLine),
            'GridLineWidth': 1
        }
class MainWindow(QMainWindow):
    InsertTextButton = 10
    items = {-2: "source", -3: "channel", -4: "sink"}

    def __init__(self):
        import _diagramscene_rc

        super(MainWindow, self).__init__()

        self.config_manipulations = FlumeConfig(self)
        properties_generator.dump_props()

        self.create_actions()
        self.create_menus()
        self.create_tool_box()
        self.clicked_button_id = 0

        self.scene = DiagramScene(self.item_menu)
        self.scene.setSceneRect(QRectF(0, 0, 5000, 5000))

        self.scene.itemInserted.connect(self.item_inserted)
        self.scene.textInserted.connect(self.text_inserted)
        self.scene.itemSelected.connect(self.item_selected)

        self.create_tool_bars()
        # self.scene.enable_grid()

        layout = QHBoxLayout()
        layout.addWidget(self.tool_box)
        self.view = QGraphicsView(self.scene)
        self.view.centerOn(0, 0)
        layout.addWidget(self.view)

        self.widget = QWidget()
        self.widget.setLayout(layout)

        self.setCentralWidget(self.widget)
        self.setWindowTitle("The Flume Illustrator")

    # noinspection PyAttributeOutsideInit,PyArgumentList
    def create_actions(self):

        self.to_front_action = QAction(QIcon(':/images/bringtofront.png'),
                                       "Bring to &Front", self, shortcut="Ctrl+F",
                                       statusTip="Bring item to front", triggered=self.bring_to_front)
        self.send_back_action = QAction(QIcon(':/images/sendtoback.png'),
                                        "Send to &Back", self, shortcut="Ctrl+B",
                                        statusTip="Send item to back", triggered=self.send_to_back)
        self.bold_action = QAction(QIcon(':/images/bold.png'),
                                   "Bold", self, checkable=True, shortcut="Ctrl+B",
                                   triggered=self.handle_font_change)
        self.italic_action = QAction(QIcon(':/images/italic.png'),
                                     "Italic", self, checkable=True, shortcut="Ctrl+I",
                                     triggered=self.handle_font_change)
        self.underline_action = QAction(QIcon(':/images/underline.png'),
                                        "Underline", self, checkable=True, shortcut="Ctrl+U",
                                        triggered=self.handle_font_change)

        self.delete_action = QAction(QIcon(':/images/delete.png'),
                                     "Delete", self, shortcut="Delete", statusTip='Delete item from diagram',
                                     triggered=self.delete_item)
        self.exit_action = QAction("Exit", self, shortcut="Ctrl+X",
                                   statusTip="Quit program", triggered=self.close)
        self.about_action = QAction("About", self, shortcut="Ctrl+B",
                                    triggered=self.about)
        self.load_config_action = QAction("Load", self, shortcut="Ctrl+O",
                                          statusTip="Load config file", triggered=self.config_manipulations.load_config)

        self.enable_grid_action = QAction("Enable grid", self, checkable=True, triggered=self.enable_grid)

    # noinspection PyAttributeOutsideInit
    def create_menus(self):
        self.file_menu = self.menuBar().addMenu("File")
        self.file_menu.addAction(self.load_config_action)
        self.file_menu.addAction(self.exit_action)

        self.item_menu = self.menuBar().addMenu("Item")
        self.item_menu.addAction(self.delete_action)
        self.item_menu.addSeparator()
        self.item_menu.addAction(self.to_front_action)
        self.item_menu.addAction(self.send_back_action)

        self.about_menu = self.menuBar().addMenu("Help")
        self.about_menu.addAction(self.about_action)

    # noinspection PyAttributeOutsideInit,PyUnresolvedReferences
    def create_tool_box(self):
        self.button_group = QButtonGroup()
        self.button_group.setExclusive(False)
        self.button_group.buttonClicked[int].connect(self.button_group_clicked)

        layout = QGridLayout()
        layout.addWidget(self.create_cell_widget("Source", "source"), 0, 0)
        layout.addWidget(self.create_cell_widget("Channel", "channel"), 0, 1)
        layout.addWidget(self.create_cell_widget("Sink", "sink"), 1, 0)

        text_button = QToolButton()
        text_button.setCheckable(True)
        self.button_group.addButton(text_button, self.InsertTextButton)
        text_button.setIcon(QIcon(QPixmap(':/images/textpointer.png').scaled(30, 30)))
        text_button.setIconSize(QSize(50, 50))

        text_layout = QGridLayout()
        text_layout.addWidget(text_button, 0, 0, Qt.AlignHCenter)
        text_layout.addWidget(QLabel("Text"), 1, 0, Qt.AlignCenter)
        text_widget = QWidget()
        text_widget.setLayout(text_layout)
        layout.addWidget(text_widget, 1, 1)

        layout.setRowStretch(3, 10)
        layout.setColumnStretch(2, 10)

        item_widget = QWidget()
        item_widget.setLayout(layout)

        self.tool_box = QToolBox()
        self.tool_box.setSizePolicy(QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Ignored))
        self.tool_box.setMinimumWidth(item_widget.sizeHint().width())
        self.tool_box.addItem(item_widget, "Basic Flume Items")

    # noinspection PyAttributeOutsideInit,PyUnresolvedReferences
    def create_tool_bars(self):

        self.edit_tool_bar = self.addToolBar("Edit")
        self.edit_tool_bar.addAction(self.delete_action)
        self.edit_tool_bar.addAction(self.to_front_action)
        self.edit_tool_bar.addAction(self.send_back_action)

        self.edit_tool_bar.addAction(self.enable_grid_action)

        self.font_combo = QFontComboBox()
        self.font_combo.currentFontChanged.connect(self.current_font_changed)

        self.font_size_combo = QComboBox()
        self.font_size_combo.setEditable(True)
        for i in range(8, 30, 2):
            self.font_size_combo.addItem(str(i))
        validator = QIntValidator(2, 64, self)
        self.font_size_combo.setValidator(validator)
        self.font_size_combo.currentIndexChanged.connect(self.font_size_changed)

        self.font_color_tool_button = QToolButton()
        self.font_color_tool_button.setPopupMode(QToolButton.MenuButtonPopup)
        self.font_color_tool_button.setMenu(
            self.create_color_menu(self.text_color_changed, Qt.black))
        self.text_action = self.font_color_tool_button.menu().defaultAction()
        self.font_color_tool_button.setIcon(
            self.create_color_tool_button_icon(':/images/textpointer.png',
                                               Qt.black))
        self.font_color_tool_button.setAutoFillBackground(True)
        self.font_color_tool_button.clicked.connect(self.text_button_triggered)

        self.fill_color_tool_button = QToolButton()
        self.fill_color_tool_button.setPopupMode(QToolButton.MenuButtonPopup)
        self.fill_color_tool_button.setMenu(
            self.create_color_menu(self.item_color_changed, Qt.white))
        self.fillAction = self.fill_color_tool_button.menu().defaultAction()
        self.fill_color_tool_button.setIcon(
            self.create_color_tool_button_icon(':/images/floodfill.png',
                                               Qt.white))
        self.fill_color_tool_button.clicked.connect(self.fill_button_triggered)

        self.line_color_tool_button = QToolButton()
        self.line_color_tool_button.setPopupMode(QToolButton.MenuButtonPopup)
        self.line_color_tool_button.setMenu(
            self.create_color_menu(self.line_color_changed, Qt.black))
        self.lineAction = self.line_color_tool_button.menu().defaultAction()
        self.line_color_tool_button.setIcon(
            self.create_color_tool_button_icon(':/images/linecolor.png',
                                               Qt.black))
        self.line_color_tool_button.clicked.connect(self.line_button_triggered)

        self.text_tool_bar = self.addToolBar("Font")
        self.text_tool_bar.addWidget(self.font_combo)
        self.text_tool_bar.addWidget(self.font_size_combo)
        self.text_tool_bar.addAction(self.bold_action)
        self.text_tool_bar.addAction(self.italic_action)
        self.text_tool_bar.addAction(self.underline_action)

        self.color_tool_bar = self.addToolBar("Color")
        self.color_tool_bar.addWidget(self.font_color_tool_button)
        self.color_tool_bar.addWidget(self.fill_color_tool_button)
        self.color_tool_bar.addWidget(self.line_color_tool_button)

        self.loading_tool_bar = self.addToolBar("Load")
        self.loading_tool_bar.addAction(self.load_config_action)

        pointer_button = QToolButton()
        pointer_button.setCheckable(True)
        pointer_button.setChecked(True)
        pointer_button.setIcon(QIcon(":/images/pointer.png"))
        line_pointer_button = QToolButton()
        line_pointer_button.setCheckable(True)
        line_pointer_button.setIcon(QIcon(":/images/linepointer.png"))

        self.pointer_type_group = QButtonGroup()
        self.pointer_type_group.addButton(pointer_button, DiagramScene.MoveItem)
        self.pointer_type_group.addButton(line_pointer_button, DiagramScene.InsertLine)
        self.pointer_type_group.buttonClicked[int].connect(self.pointer_group_clicked)

        self.scene_scale_combo = QComboBox()
        self.scene_scale_combo.addItems(["50%", "75%", "100%", "125%", "150%"])
        self.scene_scale_combo.setCurrentIndex(2)
        self.scene_scale_combo.currentIndexChanged[str].connect(self.scene_scale_changed)

        self.pointer_tool_bar = self.addToolBar("Pointer type")
        self.pointer_tool_bar.addWidget(pointer_button)
        self.pointer_tool_bar.addWidget(line_pointer_button)
        self.pointer_tool_bar.addWidget(self.scene_scale_combo)

    def button_group_clicked(self, button_id):
        buttons = self.button_group.buttons()
        self.clicked_button_id = button_id
        for button in buttons:
            if self.button_group.button(button_id) != button:
                button.setChecked(False)
        if button_id == self.InsertTextButton:
            self.scene.set_mode(DiagramScene.InsertText)
        else:
            self.scene.set_item_type(self.items[button_id])
            self.scene.set_mode(DiagramScene.InsertItem)

    def delete_item(self):
        for item in self.scene.selectedItems():
            if isinstance(item, FlumeDiagramItem):
                item.remove_arrows()
            self.scene.removeItem(item)

    # noinspection PyTypeChecker,PyCallByClass
    def about(self):

        # noinspection PyArgumentList
        QMessageBox.about(self, "About Flume Illustrator", "The Flume illustrator shows config-file details")

    def pointer_group_clicked(self):
        self.scene.set_mode(self.pointer_type_group.checkedId())

    def bring_to_front(self):
        if not self.scene.selectedItems():
            return

        selected_item = self.scene.selectedItems()[0]
        overlap_items = selected_item.collidingItems()

        z_value = 0
        for item in overlap_items:
            if item.zValue() >= z_value and isinstance(item, FlumeDiagramItem):
                z_value = item.zValue() + 0.1
        selected_item.setZValue(z_value)

    def send_to_back(self):
        if not self.scene.selectedItems():
            return

        selected_item = self.scene.selectedItems()[0]
        overlap_items = selected_item.collidingItems()

        z_value = 0
        for item in overlap_items:
            if item.zValue() <= z_value and isinstance(item, FlumeDiagramItem):
                z_value = item.zValue() - 0.1
        selected_item.setZValue(z_value)

    def scene_scale_changed(self, scale):
        new_scale = float(scale[:scale.index("%")]) / 100
        old_transform = self.view.transform()
        self.view.resetTransform()
        self.view.translate(old_transform.dx(), old_transform.dy())
        self.view.scale(new_scale, new_scale)

    def item_inserted(self, diagram_type):
        self.pointer_type_group.button(DiagramScene.MoveItem).setChecked(True)
        self.scene.set_mode(self.scene.DefaultMode)
        self.button_group.button(self.clicked_button_id).setChecked(False)

    def text_inserted(self, item):
        self.button_group.button(self.InsertTextButton).setChecked(False)
        self.scene.set_mode(self.pointer_type_group.checkedId())

    def current_font_changed(self, font):
        self.handle_font_change()

    def font_size_changed(self, font=None):
        self.handle_font_change()

    def text_color_changed(self):
        self.text_action = self.sender()
        self.font_color_tool_button.setIcon(
            self.create_color_tool_button_icon(':/images/textpointer.png',
                                               QColor(self.text_action.data())))
        self.text_button_triggered()

    def item_color_changed(self):
        self.fillAction = self.sender()
        self.fill_color_tool_button.setIcon(
            self.create_color_tool_button_icon(':/images/floodfill.png',
                                               QColor(self.fillAction.data())))
        self.fill_button_triggered()

    def line_color_changed(self):
        self.lineAction = self.sender()
        self.line_color_tool_button.setIcon(
            self.create_color_tool_button_icon(':/images/linecolor.png',
                                               QColor(self.lineAction.data())))
        self.line_button_triggered()

    def text_button_triggered(self):
        self.scene.set_text_color(QColor(self.text_action.data()))

    def fill_button_triggered(self):
        self.scene.set_item_color(QColor(self.fillAction.data()))

    def line_button_triggered(self):
        self.scene.set_line_color(QColor(self.lineAction.data()))

    def handle_font_change(self):
        font = self.font_combo.currentFont()
        font.setPointSize(int(self.font_size_combo.currentText()))
        if self.bold_action.isChecked():
            font.setWeight(QFont.Bold)
        else:
            font.setWeight(QFont.Normal)
        font.setItalic(self.italic_action.isChecked())
        font.setUnderline(self.underline_action.isChecked())

        self.scene.setFont(font)

    def item_selected(self, item):
        font = item.font()
        self.font_combo.setCurrentFont(font)
        self.font_size_combo.setEditText(str(font.pointSize()))
        self.bold_action.setChecked(font.weight() == QFont.Bold)
        self.italic_action.setChecked(font.italic())
        self.underline_action.setChecked(font.underline())

    def create_cell_widget(self, text, diagram_type):
        item = FlumeObject(diagram_type, "")
        icon = QIcon(item.pictogram.image())

        button = QToolButton()
        button.setIcon(icon)
        button.setIconSize(QSize(50, 50))
        button.setCheckable(True)
        self.button_group.addButton(button)  # , diagram_type

        layout = QGridLayout()
        layout.addWidget(button, 0, 0, Qt.AlignHCenter)
        layout.addWidget(QLabel(text), 1, 0, Qt.AlignHCenter)

        widget = QWidget()
        widget.setLayout(layout)

        return widget

    # noinspection PyArgumentList
    def create_color_menu(self, slot, default_color):
        colors = [Qt.black, Qt.white, Qt.red, Qt.blue, Qt.yellow]
        names = ["black", "white", "red", "blue", "yellow"]

        color_menu = QMenu(self)
        for color, name in zip(colors, names):
            action = QAction(self.create_color_icon(color), name, self,
                             triggered=slot)
            action.setData(QColor(color))
            color_menu.addAction(action)
            if color == default_color:
                color_menu.setDefaultAction(action)
        return color_menu

    @staticmethod
    def create_color_tool_button_icon(image_file, color):
        pixmap = QPixmap(50, 80)
        pixmap.fill(Qt.transparent)
        painter = QPainter(pixmap)
        image = QPixmap(image_file)
        target = QRect(0, 0, 50, 60)
        source = QRect(0, 0, 42, 42)
        painter.fillRect(QRect(0, 60, 50, 80), color)
        painter.drawPixmap(target, image, source)
        painter.end()

        return QIcon(pixmap)

    @staticmethod
    def create_color_icon(color):
        pixmap = QPixmap(20, 20)
        painter = QPainter(pixmap)
        painter.setPen(Qt.NoPen)
        painter.fillRect(QRect(0, 0, 20, 20), color)
        painter.end()

        return QIcon(pixmap)

    def enable_grid(self):
        if self.enable_grid_action.isChecked():
            color = Qt.black
        else:
            color = Qt.white
        for i in range(50):
            for j in range(50):
                self.scene.addEllipse(i * 100, j * 100, 2, 2, QPen(color))