def generateData(self, canvas, lines, params): scene = QGraphicsScene() scene.setSceneRect(canvas) group = scene.createItemGroup([]) for line in lines: clone = QGraphicsLineItem(line) clone.setLine(line.line()) clone.setPen(line.pen()) scene.addItem(clone) group.addToGroup(clone) pixmaps = [] for i in xrange(params.count): pixmaps.append(self.generateRandom(scene, group, canvas, params)) return pixmaps
class MarkedHistogram(QWidget): """Histogram with color-indication markers MarkedHistogram shows a histogram of a data set and an optional label for the numeric range of the data set. Color markers can be placed on the histogram by the user and moved interactively, either with the mouse or by typing in a particular data value. A color button is used to control the color of the "current" marker (the one most recently selected with the mouse). Markers can either be vertical bars or squares. Vertical bars can only be moved left/right whereas squares can also be moved up/down. Squares are also connected from left to right by line segments. A row of associated widgets (such as the marker color button) is placed below the histogram. User-specified widgets can also be placed in this row with the add_custom_widget() method. Individual markers are grouped into HistogramMarkers instances, and several HistogramMarkers instances can be associated with a single histogram, though only one instance is active/shown at a time. MarkedHistogram has the following constructor options: [Options noted as init options can only be specified at widget creation. Others can be changed later via the corresponding property name.] color_button -- controls whether a color button is offered in the user interface for changing marker colors. default: True data_source -- either a string or a 3-tuple. If a string, then no histogram is displayed and instead the string is displayed in the histogram area as a text message. The first 2 components of a 3-tuple should be the minimum and maximum values of the histogram, The third component should either be an array of numbers (i.e. the histogram) or a callback function that takes as its single argument the number of bins to histogram into and that returns a histogram array. default: 'no data' layout -- [init option] how to organize the megawidget layout. Choices are 'single', 'top', and 'below'. 'single' should be used when you are using a single histogram in your GUI, or histograms that aren't arrayed vertically. 'top' and 'below' should be used for histograms that are laid out in a vertical array ('top' for the top-most one, and 'below' for all others). Certain repeated elements will be omitted in 'below' histograms (e.g. some widget labels). default: single max_label/min_label [init options] show the max/min histogram values as labels below the histogram on the right/left. If neither is True, then the range will be shown in a single label widget below the histogram. default: False redraw_delay -- amount of time (in seconds) to delay between needing to redraw and actually starting to redraw. Used to avoid multiple (possibly slow) redraws during a resize. default: 0.25 scaling -- how to scale the vertical height of the histogram. Either 'logarithmic' or 'linear'. default: logarithmic select_callback -- [init option] function to call when the "current" marker changes. The function receives 4 argments: previous active marker set/marker, new active marker set/marker. The marker set can be None to indicate no active marker set and the marker can be None if no marker was/is current. show_marker_help -- [init option] whether to show the help text over the histogram describing how to add/delete markers. default: True status_line -- function to use to output messages (such as warning when trying to add more markers than allowed). The function should take a single string argument. default: None value_label -- [init option] label to use next to the entry widget describing the current marker value. default: 'Value' value_width -- width of the current marker value entry widget. default: 7 Constructor options that begin with 'Markers_' specify default constructor options for HistogramMarkers objects created in the add_markers method (e.g. Markers_connect_color='red' will supply connect_color='red' to the HistogramMarkers constructor). Options for specific instances can still be provided to the add_ markers() method as keyword arguments (without the 'Markers_' prefix). """ def __init__(self, *args, color_button=True, data_source='no data', layout='single', max_label=False, min_label=False, redraw_delay=0.25, scaling='logarithmic', select_callback=None, show_marker_help=True, status_line=None, value_label='Value', value_width=7, **kw): # Get HistogramMarkers options and initialise base class self._histogram_markers_kw = markers_kw = {} for opt_name in list(kw.keys()): if opt_name.startswith('Markers_'): markers_kw[opt_name[8:]] = kw.pop(opt_name) super().__init__(*args, **kw) # initialize variables self._layout = layout self.status_line = status_line self._show_marker_help = show_marker_help self._active_markers = None self._markers = [] self._markable = False self._drag_marker = None self._scaling = scaling self._select_callback = select_callback if select_callback: self._prev_markers = None self._prev_marker = None overall_layout = QVBoxLayout() self.setLayout(overall_layout) # Create the add/delete marker help if show_marker_help and layout != 'below': self._marker_help = QLabel( "Ctrl-click on histogram to add or delete thresholds") self._marker_help.setAlignment(Qt.AlignCenter) overall_layout.addWidget(self._marker_help) else: self._marker_help = None # Create the data area class HistFrame(QFrame): def sizeHint(self): return QSize(300, 64) data_frame = QFrame() data_frame.setLineWidth(1) data_frame.setMidLineWidth(2) data_frame.setFrameStyle(data_frame.Panel | data_frame.Sunken) data_frame.setContentsMargins(0, 0, 0, 0) data_frame_layout = QHBoxLayout() data_frame.setLayout(data_frame_layout) self._data_widgets = QStackedWidget() data_frame_layout.addWidget(self._data_widgets) # Crate the histogram widget self._hist_scene = QGraphicsScene() self._hist_bars = self._hist_scene.createItemGroup([]) self._hist_view = QGraphicsView(self._hist_scene) self._hist_view.resizeEvent = self._redraw self._hist_scene.mousePressEvent = lambda event: self._add_or_delete_marker_cb(event) \ if event.modifiers() & mod_key_info("control")[0] else self._select_marker_cb(event) self._hist_scene.mouseMoveEvent = lambda event: self._move_marker_cb(event) \ if self._drag_marker else super().mouseMoveEvent(event) self._hist_scene.mouseReleaseEvent = self._button_up_cb self._redraw_timer = QTimer() self._redraw_timer.timeout.connect(self._redraw_cb) self._redraw_timer.start(1000 * redraw_delay) self._redraw_timer.stop() self._data_widgets.addWidget(self._hist_view) # Create the histogram replacement label self._no_histogram_label = QLabel() self._no_histogram_label.setAlignment(Qt.AlignCenter) self._data_widgets.addWidget(self._no_histogram_label) overall_layout.addWidget(self._data_widgets, stretch=1) # Create range label(s) self._widget_area = QWidget() self._widget_layout = QHBoxLayout() self._min_label = self._max_label = None if min_label or max_label: min_max_layout = QHBoxLayout() if min_label: self._min_label = QLabel() min_max_layout.addWidget(self._min_label, alignment=Qt.AlignLeft & Qt.AlignTop) if max_label: self._max_label = QLabel() min_max_layout.addWidget(self._max_label, alignment=Qt.AlignRight & Qt.AlignTop) overall_layout.addLayout(min_max_layout) else: self._range_label = QLabel() if layout == 'below': self._widget_layout.addWidget(self._range_label) else: lab = QLabel("Range") if layout == 'single': self._widget_layout.addWidget(lab, alignment=Qt.AlignRight) self._widget_layout.addWidget(self._range_label, alignment=Qt.AlignLeft) else: # layout == 'top' range_layout = QVBoxLayout() range_layout.addWidget(lab, alignment=Qt.AlignBottom) range_layout.addWidget(self._range_label, alignment=Qt.AlignTop) self._widget_layout.addLayout(range_layout) self._widget_area.setLayout(self._widget_layout) overall_layout.addWidget(self._widget_area) # Create value widget self._value_entry = QLineEdit() self._value_entry.setEnabled(False) self._value_entry.returnPressed.connect(self._set_value_cb) self.value_width = value_width if layout == 'below': self._widget_layout.addWidget(self._value_entry) else: lab = QLabel(value_label) if layout == 'single': self._widget_layout.addWidget(lab, alignment=Qt.AlignRight) self._widget_layout.addWidget(self._value_entry, alignment=Qt.AlignLeft) else: value_layout = QVBoxLayout() value_layout.addWidget(lab, alignment=Qt.AlignBottom) value_layout.addWidget(self._value_entry, alignment=Qt.AlignTop) self._widget_layout.addLayout(value_layout) # Create color button widget from .color_button import ColorButton self._color_button = cb = ColorButton() cb.color_changed.connect( lambda rgba8: self._color_button_cb([c / 255.0 for c in rgba8])) cb.setEnabled(False) self._color_button_label = cbl = QLabel("Color") if layout == 'below': self._widget_layout.addWidget(self._color_button) else: if layout == 'single': self._widget_layout.addWidget(cbl, alignment=Qt.AlignRight) self._widget_layout.addWidget(cb, alignment=Qt.AlignLeft) else: color_layout = QVBoxLayout() color_layout.addWidget(cbl, alignment=Qt.AlignBottom) color_layout.addWidget(cb, alignment=Qt.AlignTop) self._widget_layout.addLayout(color_layout) self._color_button_shown = True # Show the histogram or the no-data label self.data_source = data_source def activate(self, markers): """Make the given set of markers the currently active set Any previously-active set will be hidden. """ if markers is not None and markers not in self._markers: raise ValueError("activate() called with bad value") if markers == self._active_markers: return if self._active_markers is not None: self._active_markers._hide() elif self.layout != 'below' and self._show_marker_help: self._marker_help.setHidden(False) self._active_markers = markers if self._active_markers is not None: self._active_markers.shown = True self._set_sel_marker(self._active_markers._sel_marker) else: if self.layout != 'below' and self._show_marker_help: self._marker_help.setHidden(True) if self._select_callback: if self._prev_marker is not None: self._select_callback(self._prev_markers, self._prev_marker, None, None) self._prev_markers = None self._prev_marker = None def add_custom_widget(self, widget, left_side=True): self._widget_layout.addWidget(0 if left_side else -1, widget) def add_markers(self, activate=True, **kw): """Create and return a new set of markers. If 'activate' is true, the new set will also become the active set. Other keyword arguments will be passed to the HistogramMarkers constructor. """ final_kw = {k: v for k, v in self._histogram_markers_kw.items()} final_kw.update(kw) final_kw['histogram'] = self markers = HistogramMarkers(**final_kw) self._markers.append(markers) if activate: self.activate(markers) return markers @property def color_button(self): return self._color_button_shown @color_button.setter def color_button(self, show): if show == self._color_button_shown: return if self.layout != 'below': self._color_button_label.setHidden(not show) self._color_button.setHidden(not show) self._color_button_shown = show def current_marker_info(self): """Identify the marker currently selected by the user. Returns a HistogramMarkers instance and a marker. The instance will be None if no marker set has been activated. The marker will be None if no marker has been selected by the user. """ if self._active_markers is None: return None, None return self._active_markers, self._active_markers._sel_marker @property def data_source(self): return self._data_source @data_source.setter def data_source(self, data_source): self._data_source = data_source self._new_data() def delete_markers(self, markers): """Delete the given set of markers. If the markers were active, there will be no active set of markers afterward. """ if markers not in self._markers: raise ValueError("Bad value for delete()") if markers == self._active_markers: self.activate(None) self._markers.remove(markers) @property def layout(self): return self._layout @property def redraw_delay(self): return self._redraw_timer.interval() / 1000.0 @redraw_delay.setter def redraw_delay(self, secs): self._redraw_timer.setInterval(secs * 1000) @property def scaling(self): return self._scaling @scaling.setter def scaling(self, scaling): if self._scaling != scaling: self._scaling = scaling self._redraw_cb() def snapshot_data(self): info = { 'version': 1, 'draw_min': self._draw_min, 'draw_max': self._draw_max, 'markers': [markers.snapshot_data() for markers in self._markers], } if self._active_markers is None: info['active markers'] = None else: info['active markers'] = self._markers.index(self._active_markers) if self['color_button']: info['color well'] = self._color_button.color else: info['color well'] = None return info def snapshot_restore(self, data): self._draw_min = data['draw_min'] self._draw_max = data['draw_max'] if data['color well'] is not None: self._color_button.color = data['color well'] if len(data['markers']) != len(self._markers): # don't know how to deal with this situation return for markers, markers_data in zip(self._markers, data['markers']): markers.snapshot_restore(markers_data) if data['active markers'] is not None: self.activate(self._markers[data['active markers']]) self._set_sel_marker(self._active_markers._sel_marker) @property def value_width(self): return self._value_width @value_width.setter def value_width(self, vw): self._value_width = vw ve = self._value_entry fm = ve.fontMetrics() tm = ve.textMargins() cm = ve.contentsMargins() w = vw * fm.width('w') + tm.left() + tm.right() + cm.left() + cm.right( ) + 8 ve.setMaximumWidth(w) def _abs2rel(self, abs_xy): x, y = abs_xy rel_x = (x - self._min_val) / float(self._max_val - self._min_val) rel_y = y / float(self._ymax) return rel_x, rel_y def _abs_xy(self, scene_xy): scene_x, scene_y = scene_xy dy = min(max(self._bottom - scene_y, 0), self._hist_height - 1) if self.scaling == 'logarithmic': exp = dy / float(self._hist_height - 1) abs_y = (self._max_height + 1)**exp - 1 else: abs_y = self._max_height * dy / float(self._hist_height - 1) cx = scene_x - self._border num_bins = len(self._bins) if num_bins == self._hist_width: fract = cx / (num_bins - 1) abs_x = self._min_val + fract * (self._max_val - self._min_val) elif num_bins == 2: abs_x = self._min_val + (self._max_val - self._min_val) * ( 2 * cx / self._hist_width - 0.5) else: extra = self._hist_width / (2.0 * (num_bins - 1)) abs_x = self._min_val + (self._max_val - self._min_val) * ( cx - extra) / (self._hist_width - 2.0 * extra) abs_x = max(self._min_val, abs_x) abs_x = min(self._max_val, abs_x) return abs_x, abs_y def _add_or_delete_marker_cb(self, event=None): if self._active_markers is None: return marker = self._active_markers._pick_marker(event.scenePos()) if marker is None: max_marks = self._active_markers.max_marks if max_marks is not None and len( self._active_markers) >= max_marks: if self.status_line: self.status_line("Maximum of %d markers\n" % max_marks) return xy = self._abs_xy((event.scenePos().x(), event.scenePos().y())) if self._active_markers.coord_type == 'relative': xy = self._abs2rel(xy) sel_marker = self._active_markers._sel_marker if sel_marker: color = sel_marker.rgba else: color = self._active_markers.new_color marker = self._active_markers.append((xy, color)) self._set_sel_marker(marker, drag_start=event) else: min_marks = self._active_markers.min_marks if min_marks is not None and len( self._active_markers) <= min_marks: if self.status_line: self.status_line("Minimum of %d markers\n" % min_marks) return self._active_markers.remove(marker) self._set_sel_marker(None) def _button_up_cb(self, event=None): if self._drag_marker: self._drag_marker = None if self._active_markers.move_callback: self._active_markers.move_callback('end') def _scene_xy(self, abs_xy): # minimum is in the _center_ of the first bin, # likewise, maximum is in the center of the last bin abs_x, abs_y = abs_xy abs_y = max(0, abs_y) abs_y = min(self._max_height, abs_y) if self.scaling == 'logarithmic': import math abs_y = math.log(abs_y + 1) scene_y = self._bottom - (self._hist_height - 1) * (abs_y / self._max_height) abs_x = max(self._min_val, abs_x) abs_x = min(self._max_val, abs_x) num_bins = len(self._bins) if num_bins == self._hist_width: bin_width = (self._max_val - self._min_val) / float(num_bins - 1) left_edge = self._min_val - 0.5 * bin_width scene_x = int((abs_x - left_edge) / bin_width) else: # histogram is effectively one bin wider (two half-empty bins on each end) if num_bins == 1: scene_x = 0.5 * (self._hist_width - 1) else: extra = (self._max_val - self._min_val) / (2.0 * (num_bins - 1)) eff_min_val = self._min_val - extra eff_max_val = self._max_val + extra eff_range = float(eff_max_val - eff_min_val) scene_x = (self._hist_width - 1) * (abs_x - eff_min_val) / eff_range return self._border + scene_x, scene_y def _color_button_cb(self, rgba): m = self._active_markers._sel_marker if not m: if self.status_line: self.status_line("No marker selected") return m.rgba = rgba def _marker2abs(self, marker): if self._active_markers.coord_type == 'absolute': return marker.xy else: return self._rel2abs(marker.xy) def _move_cur_marker(self, x, yy=None): # # Don't allow dragging out of the scene box. # m = self._active_markers._sel_marker if x < self._min_val: x = self._min_val elif x > self._max_val: x = self._max_val if yy is None: y = m.xy[1] else: y = yy if y < 0: y = 0 elif y > self._ymax: y = self._ymax if self._active_markers.coord_type == 'absolute': m.xy = (x, y) else: m.xy = self._abs2rel((x, y)) if yy is None: m.xy = (m.xy[0], y) self._set_value_entry(x) self._active_markers._update_plot() if self._active_markers.move_callback: self._active_markers.move_callback(m) def _move_marker_cb(self, event): mouse_xy = self._abs_xy((event.scenePos().x(), event.scenePos().y())) dx = mouse_xy[0] - self._last_mouse_xy[0] dy = mouse_xy[1] - self._last_mouse_xy[1] self._last_mouse_xy = mouse_xy if event.modifiers() & mod_key_info("shift")[0]: dx *= .1 dy *= .1 m = self._drag_marker mxy = self._marker2abs(m) x, y = mxy[0] + dx, mxy[1] + dy self._move_cur_marker(x, y) def _new_data(self): ds = self.data_source if isinstance(ds, str): self._no_histogram_label.setText(ds) self._data_widgets.setCurrentWidget(self._no_histogram_label) if self._min_label: self._min_label.setText("") if self._max_label: self._max_label.setText("") if self.layout != 'below' and self._show_marker_help: self._marker_help.setHidden(True) self._widget_area.setHidden(True) else: self._data_widgets.setCurrentWidget(self._hist_view) if self.layout != 'below' and self._show_marker_help: self._marker_help.setHidden(False) self._widget_area.setHidden(False) self._draw_min = self._draw_max = None self._redraw_cb() def _redraw(self, event=None): self._markable = False self._redraw_timer.start() def _redraw_cb(self): self._redraw_timer.stop() ds = self.data_source if isinstance(ds, str): # displaying a text label right now return view = self._hist_view scene = self._hist_scene hist_size = view.viewport().size() self._hist_width, self._hist_height = hist_width, hist_height = hist_size.width( ), hist_size.height() self._min_val, self._max_val, self._bins = ds filled_range = self._max_val - self._min_val empty_ranges = [0, 0] if self._draw_min != None: empty_ranges[0] = self._min_val - self._draw_min self._min_val = self._draw_min if self._draw_max != None: empty_ranges[1] = self._draw_max - self._max_val self._max_val = self._draw_max if callable(self._bins): if empty_ranges[0] or empty_ranges[1]: full_range = filled_range + empty_ranges[0] + empty_ranges[1] filled_bins = self._bins( int(hist_width * filled_range / full_range)) left = [0] * int(hist_width * empty_ranges[0] / full_range) right = [0] * (hist_width - len(filled_bins) - len(left)) self._bins = left + filled_bins + right else: self._bins = self._bins(hist_width) elif empty_ranges[0] or empty_ranges[1]: full_range = filled_range + empty_ranges[0] + empty_ranges[1] left = [0] * int(len(self._bins) * empty_ranges[0] / full_range) right = [0] * int(len(self._bins) * empty_ranges[1] / full_range) self._bins = left + self._bins + right if self._min_label: self._min_label.setText(self._str_val(self._min_val)) if self._max_label: self._max_label.setText(self._str_val(self._max_val)) if not self._min_label and not self._max_label: self._range_label.setText( "%s - %s" % (self._str_val(self._min_val), self._str_val(self._max_val))) bars = self._hist_bars.childItems() for bar in bars: self._hist_bars.removeFromGroup(bar) self._hist_scene.removeItem(bar) self._ymax = max(self._bins) if self.scaling == 'logarithmic': from numpy import array, log, float32 self._bins = array(self._bins, float32) self._bins += 1.0 log(self._bins, self._bins) max_height = max(self._bins) self._max_height = max_height h_scale = float(hist_height - 1) / max_height self._border = border = 0 bottom = hist_height + border - 1 self._bottom = bottom num_bins = len(self._bins) if num_bins == hist_width: for b, n in enumerate(self._bins): x = border + b h = int(h_scale * n) line = self._hist_scene.addLine(x, bottom, x, bottom - h) self._hist_bars.addToGroup(line) line.setZValue(-1) # keep bars below markers else: x_scale = (hist_width - 1) / float(num_bins) for b, n in enumerate(self._bins): x1 = border + b * x_scale x2 = border + (b + 1) * x_scale h = int(h_scale * n) rect = self._hist_scene.addRect(x1, bottom - h, x2 - x1, h) self._hist_bars.addToGroup(rect) rect.setZValue(-1) # keep bars below markers self._markable = True if self._active_markers is not None: self._active_markers._update_plot() marker = self._active_markers._sel_marker if marker: self._set_value_entry(self._marker2abs(marker)[0]) self._hist_scene.setSceneRect(self._hist_scene.itemsBoundingRect()) def _rel2abs(self, rel_xy): x, y = rel_xy abs_x = self._min_val * (1 - x) + x * self._max_val abs_y = y * self._ymax return abs_x, abs_y def _select_marker_cb(self, event=None): if self._active_markers is not None: marker = self._active_markers._pick_marker(event.scenePos()) self._set_sel_marker(marker, drag_start=event) if marker is not None: return # show value where histogram clicked self._set_value_entry(self._abs_xy((event.scenePos().x(), 0))[0]) def _set_sel_marker(self, marker, drag_start=None): self._active_markers._sel_marker = marker if not marker: self._color_button.color = "gray" self._color_button.setEnabled(False) self._set_value_entry("") self._value_entry.setEnabled(False) else: self._color_button.setEnabled(True) self._color_button.color = marker.rgba self._value_entry.setEnabled(True) self._set_value_entry(self._marker2abs(marker)[0]) if self._select_callback: if marker is not None or self._prev_marker is not None: self._select_callback(self._prev_markers, self._prev_marker, self._active_markers, marker) self._prev_markers = self._active_markers self._prev_marker = marker if not drag_start: return self._drag_marker = marker if not marker: return self._last_mouse_xy = self._abs_xy( (drag_start.scenePos().x(), drag_start.scenePos().y())) if self._active_markers.move_callback: self._active_markers.move_callback('start') def _set_value_cb(self): try: v = eval(self._value_entry.text()) except Exception: raise ValueError("Invalid histogram value") if type(self._min_val) != type(v): v = type(self._min_val)(v) if v < self._min_val: self._draw_min = v self._redraw_cb() elif v > self._max_val: self._draw_max = v self._redraw_cb() self._move_cur_marker(v) def _set_value_entry(self, val): if isinstance(val, str): self._value_entry.setText(val) return if isinstance(self._min_val, int): val = int(val + 0.5) self._value_entry.setText("%g" % val) def _str_val(self, val): if isinstance(val, (int, bool)): return str(val) return "%g" % val
class MainWindow(QtWidgets.QMainWindow): def __init__(self, qApp): super(MainWindow, self).__init__() self.ui = wnd.Ui_MainWindow() #создаём простой объект ui self.ui.setupUi(self) self.qApp = qApp self.scn = QGraphicsScene(self) self.scn.setSceneRect(0, 0, self.width() - 2, self.height() - 2) self.gv = QtWidgets.QGraphicsView(self) self.gv.setObjectName("gv") self.gv.setStyleSheet( "border-width: 0px; border-style: none; outline:0px;") self.gv.setRenderHint(QPainter.Antialiasing) self.gv.setScene(self.scn) self.gv.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.gv.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setCentralWidget(self.gv) self.gv.show() self.gv.mousePressEvent = self.mousePress self.gv.mouseMoveEvent = self.mouseMove set = QSettings("Tree", "config") x = int(set.value("Main/Left", "-1")) y = int(set.value("Main/Top", "-1")) if x > 0 and y > 0: self.move(x, y) else: self.move(QApplication.desktop().screen().rect().center() - self.rect().center()) self.elimg = self.scn.addPixmap(QPixmap(":/images/Tree.png")) self.elimg.setTransformationMode(QtCore.Qt.SmoothTransformation) self.elimg.setZValue(2) self.gv.setContextMenuPolicy(Qt.CustomContextMenu) self.gv.customContextMenuRequested.connect(self.initContextMenu) self.mx = 0 self.my = 0 self.ps = None self.lamps = [] self.setLamps() self.curlight = -1 self.snowalphach_len = self.height() / 3 self.snows = [] self.snowgroups = [] self.snowing = set.value("Main/Snowing", "true") == "true" self.setSnows() self.timer = QTimer(self) self.timer.timeout.connect(self.onTimer) self.timerinterval = 50 self.timer.start(self.timerinterval) self.speed = int(set.value("Main/speed", "1")) self.lampturn = int(set.value("Main/turncnt", "1")) self.sparr = [0.1, 0.4, 0.6] self.cols = 6 self.snowfallspeed = [2, 1.25, 0.8] def initContextMenu(self, pos): menu = QMenu(self) menu.setStyleSheet("background: #333; color: white;") smenu = menu.addMenu("Скорость") act = QAction("Медленно", self) act.triggered.connect(self.slowspeed) smenu.addAction(act) act = QAction("Средне", self) act.triggered.connect(self.midspeed) smenu.addAction(act) act = QAction("Быстро", self) act.triggered.connect(self.fastspeed) smenu.addAction(act) kmenu = menu.addMenu("Переключения") act = QAction("По 1 лампочке", self) act.triggered.connect(self.onelamp) kmenu.addAction(act) act = QAction("По 2 лампочки", self) act.triggered.connect(self.twolamp) kmenu.addAction(act) act = QAction("По 3 лампочки", self) act.triggered.connect(self.treelamp) kmenu.addAction(act) act = QAction("По 4 лампочки", self) act.triggered.connect(self.forelamp) kmenu.addAction(act) act = QAction("Снег", self) act.triggered.connect(self.snowOffOn) menu.addAction(act) menu.addSeparator() act = QAction("Закрыть", self) act.triggered.connect(self.close) menu.addAction(act) p = self.mapToGlobal(pos) p.setX(p.x() + 1) p.setY(p.y() + 1) menu.exec_(p) def slowspeed(self): self.speed = 0 def midspeed(self): self.speed = 1 def fastspeed(self): self.speed = 2 def snowOffOn(self): #i = QtWidgets.QGraphicsItem self.snowing = not self.snowing for snows in self.snows: for snow in snows: if self.snowing: snow.item.show() else: snow.item.hide() def setlampsTurn(self, n): self.timer.stop() self.lampturn = n for lamps in self.lamps: for lamp in lamps: lamp.alpha = 0 lamp.item.setOpacity(0) self.curlight = -1 self.timer.start(self.timerinterval) def onelamp(self): self.setlampsTurn(1) def twolamp(self): self.setlampsTurn(2) def treelamp(self): self.setlampsTurn(3) def forelamp(self): self.setlampsTurn(4) def setLamps(self): ''' pts = [[vect(22,239),vect(86,281),vect(169,256),vect(46,224),vect(122,240),vect(50,178), vect(122,200),vect(74,157),vect(138,149),vect(119,133),vect(90,95),vect(85,47)], [vect(32,255),vect(110,281),vect(181,240),vect(59,237),vect(137,236),vect(62,192), vect(139,192),vect(87,165),vect(65,108),vect(136,123),vect(106,98),vect(102,54)], [vect(49,271),vect(133,274),vect(22,191),vect(79,242),vect(153,224),vect(82,200), vect(156,182),vect(106,165),vect(78,125),vect(126,92),vect(150,109),vect(119,45)], [vect(65,278),vect(152,268),vect(32,208),vect(100,243),vect(168,217),vect(103,204), vect(57,149),vect(124,160),vect(97,134),vect(73,83),vect(137,77),vect(99,25)]] ''' pts = [[ vect(25, 238), vect(120, 277), vect(44, 218), vect(147, 236), vect(82, 201), vect(59, 133), vect(149, 153), vect(128, 125), vect(113, 94), vect(111, 63) ], [ vect(36, 250), vect(137, 271), vect(54, 232), vect(161, 225), vect(101, 204), vect(72, 147), vect(160, 137), vect(141, 116), vect(126, 92), vect(126, 58) ], [ vect(51, 263), vect(156, 267), vect(71, 241), vect(175, 215), vect(121, 202), vect(87, 158), vect(55, 95), vect(158, 105), vect(134, 80), vect(93, 32) ], [ vect(64, 275), vect(172, 256), vect(88, 246), vect(43, 157), vect(140, 199), vect(100, 169), vect(74, 114), vect(73, 66), vect(149, 71), vect(108, 40) ], [ vect(80, 277), vect(187, 245), vect(108, 245), vect(51, 178), vect(154, 192), vect(116, 167), vect(89, 123), vect(86, 79), vect(89, 47), vect(121, 34) ], [ vect(101, 279), vect(28, 198), vect(129, 244), vect(66, 191), vect(171, 179), vect(135, 161), vect(108, 127), vect(99, 88), vect(100, 59), vect(108, 17) ]] clrs = [["red1", "red2", "red3", "red4", "red5"], ["aqua1", "aqua2", "aqua2", "aqua4", "aqua5"], ["fuji1", "fuji2", "fuji3", "fuji4", "fuji5"], ["green1", "green2", "green3", "green4", "green5"], ["blue1", "blue2", "blue3", "blue4", "blue5"], ["yellow1", "yellow2", "yellow3", "yellow4", "yellow5"]] cv = 0 for c in range(len(pts)): lamps = [] for v in pts[c]: lamp = Lamp(self.scn, ":/images/" + clrs[c][cv] + ".png", v.y, v.x) lamp.item.setZValue(4) lamps.append(lamp) cv += 1 if cv > 4: cv = 0 self.lamps.append(lamps) def setSnows(self): maxminsnows = 50 sc = [ random.randint(0, 14) + maxminsnows, random.randint(0, 14) + maxminsnows, random.randint(0, 14) + maxminsnows ] for i in range(len(sc)): snows = [] items = [] for j in range(sc[i]): imgfn = ":/images/snow" + str(i + 1) + ".png" x = random.randint(8, self.width() - 8) y = random.randint(10, self.height()) a = 1 hl = self.height() - self.snowalphach_len if y > hl: a = 1 - (y - hl) / self.snowalphach_len lamp = Lamp(self.scn, imgfn, x, y, a) if not self.snowing: lamp.item.hide() snows.append(lamp) items.append(lamp.item) group = self.scn.createItemGroup(items) if i < 2: group.setZValue(4) else: group.setZValue(0) self.snows.append(snows) self.snowgroups.append(items) def onTimer(self): finished = False nl = 0 if self.curlight == self.cols - 1: nl = 0 else: nl = self.curlight + 1 for lamp in self.lamps[nl]: lamp.alpha += self.sparr[self.speed] if lamp.alpha >= 1.0: lamp.alpha = 1.0 finished = True lamp.item.setOpacity(lamp.alpha) #for t in range(self.lampturn): if self.curlight >= 0: n = self.curlight - self.lampturn + 1 if n < 0: n = self.cols + n for lamp in self.lamps[n]: if lamp.alpha > 0: lamp.alpha -= self.sparr[self.speed] if lamp.alpha < 0: lamp.alpha = 0 lamp.item.setOpacity(lamp.alpha) if finished: self.curlight += 1 if self.curlight >= self.cols: self.curlight = 0 if self.snowing: for i in range(len(self.snows)): for snow in self.snows[i]: a = snow.alpha snow.y += self.snowfallspeed[i] if snow.y > self.height(): snow.y = -10 - random.randint(0, 15) snow.x = random.randint(8, self.width() - 8) snow.alpha = 1 else: hl = self.height() - self.snowalphach_len if snow.y > hl: snow.alpha = 1 - (snow.y - hl) / self.snowalphach_len snow.item.setPos( QPointF(snow.x - snow.hw, snow.y - snow.hh)) if snow.alpha != a: snow.item.setOpacity(snow.alpha) def mousePress(self, event): """Событие нажатия мыши на QGraphicsView, в данной функции переменным присваивается глобальная позиция мыши и позиция окна, для того, чтобы при перемещении мыши вызывать перемещение главного окна.""" self.mx = event.globalPos().x() self.my = event.globalPos().y() self.ps = self.pos() def mouseMove(self, event): """Событие перемещения мыши на QGraphicsView, в данной функции перемещаем главное окно по экрану.""" x = event.globalPos().x() - self.mx y = event.globalPos().y() - self.my self.move(self.ps.x() + x, self.ps.y() + y) def closeEvent(self, event): set = QSettings("Tree", "config") p = self.pos() set.setValue("Main/Left", p.x()) set.setValue("Main/Top", p.y()) set.setValue("Main/Snowing", self.snowing) set.setValue("Main/speed", self.speed) set.setValue("Main/turncnt", self.lampturn) self.qApp.quit()
class View(QGraphicsView): projections = OrderedDict([ ('Spherical', Proj('+proj=ortho +lat_0=48 +lon_0=17')), ('Mercator', Proj(init='epsg:3395')), ('WGS84', Proj(init='epsg:3857')), ('ETRS89 - LAEA Europe', Proj("+init=EPSG:3035")) ]) def __init__(self, controller): super().__init__() self.controller = controller self.scene = QGraphicsScene(self) self.setScene(self.scene) self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) self.setRenderHint(QPainter.Antialiasing) self.proj = 'Spherical' self.ratio, self.offset = 1 / 400, (0, 0) self.display = True self.shapefile = join(controller.path_shapefiles, 'World countries_1.shp') # brush for water and lands self.water_brush = QBrush(QColor(64, 164, 223)) self.land_brush = QBrush(QColor(52, 165, 111)) self.land_pen = QPen(QColor(0, 0, 0)) # draw the map self.polygons = self.scene.createItemGroup(self.draw_polygons()) self.draw_water() # set of graphical nodes self.nodes = set() ## Zoom system def zoom_in(self): self.scale(1.25, 1.25) def zoom_out(self): self.scale(1 / 1.25, 1 / 1.25) def wheelEvent(self, event): self.zoom_in() if event.angleDelta().y() > 0 else self.zoom_out() ## Mouse bindings def mouseMoveEvent(self, event): # sliding the scrollbar with the right-click button if event.buttons() == Qt.RightButton: self.trigger_menu = False offset = self.cursor_pos - event.pos() self.cursor_pos = event.pos() x_value = self.horizontalScrollBar().value() + offset.x() y_value = self.verticalScrollBar().value() + offset.y() self.horizontalScrollBar().setValue(x_value) self.verticalScrollBar().setValue(y_value) super().mouseMoveEvent(event) def mousePressEvent(self, event): # activate rubberband for selection # by default, the rubberband is active for both clicks, we have to # deactivate it explicitly for the right-click if event.buttons() == Qt.LeftButton: self.setDragMode(QGraphicsView.RubberBandDrag) if event.button() == Qt.RightButton: self.cursor_pos = event.pos() super().mousePressEvent(event) ## Drag & Drop system def dragEnterEvent(self, event): if event.mimeData().hasFormat('application/x-dnditemdata'): event.acceptProposedAction() dragMoveEvent = dragEnterEvent def dropEvent(self, event): pos = self.mapToScene(event.pos()) geo_pos = self.to_geographical_coordinates(pos.x(), pos.y()) if event.mimeData().hasFormat('application/x-dnditemdata'): new_node = Node(self.controller, pos) ## Map functions def to_geographical_coordinates(self, x, y): px, py = (x - self.offset[0]) / self.ratio, (self.offset[1] - y) / self.ratio return self.projections[self.proj](px, py, inverse=True) def to_canvas_coordinates(self, longitude, latitude): px, py = self.projections[self.proj](longitude, latitude) return px * self.ratio + self.offset[ 0], -py * self.ratio + self.offset[1] def move_to_geographical_coordinates(self): for node in self.nodes: node.setPos( QPointF(*self.to_canvas_coordinates(node.longitude, node.latitude))) def draw_polygons(self): sf = shapefile.Reader(self.shapefile) polygons = sf.shapes() for polygon in polygons: # convert shapefile geometries into shapely geometries # to extract the polygons of a multipolygon polygon = shapely.geometry.shape(polygon) # if it is a polygon, we use a list to make it iterable if polygon.geom_type == 'Polygon': polygon = [polygon] for land in polygon: qt_polygon = QPolygonF() for lon, lat in land.exterior.coords: px, py = self.to_canvas_coordinates(lon, lat) if px > 1e+10: continue qt_polygon.append(QPointF(px, py)) polygon_item = QGraphicsPolygonItem(qt_polygon) polygon_item.setBrush(self.land_brush) polygon_item.setPen(self.land_pen) polygon_item.setZValue(1) yield polygon_item def draw_water(self): if self.proj in ('Spherical', 'ETRS89 - LAEA Europe'): cx, cy = self.to_canvas_coordinates(17, 48) # if the projection is ETRS89, we need the diameter and not the radius R = 6371000 * self.ratio * (1 if self.proj == 'Spherical' else 2) earth_water = QGraphicsEllipseItem(cx - R, cy - R, 2 * R, 2 * R) earth_water.setZValue(0) earth_water.setBrush(self.water_brush) self.polygons.addToGroup(earth_water) else: # we compute the projected bounds of the Mercator (3395) projection # upper-left corner x and y coordinates: ulc_x, ulc_y = self.to_canvas_coordinates(-180, 84) # lower-right corner x and y coordinates lrc_x, lrc_y = self.to_canvas_coordinates(180, -84.72) # width and height of the map (required for the QRectItem) width, height = lrc_x - ulc_x, lrc_y - ulc_y earth_water = QGraphicsRectItem(ulc_x, ulc_y, width, height) earth_water.setZValue(0) earth_water.setBrush(self.water_brush) self.polygons.addToGroup(earth_water) def show_hide_map(self): self.display = not self.display self.polygons.show() if self.display else self.polygons.hide() def delete_map(self): self.scene.removeItem(self.polygons) def redraw_map(self): self.delete_map() self.polygons = self.scene.createItemGroup(self.draw_polygons()) self.draw_water() # replace the nodes at their geographical location self.move_to_geographical_coordinates()
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 }