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()
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)
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()
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)
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))