def set_px_per_beat(self, px_per_beat): if self._px_per_beat != px_per_beat: orig_px_per_beat = self._px_per_beat orig_px_offset = self._px_offset self._px_per_beat = px_per_beat if not self._ui_model: return # Get old edit cursor offset grid_mgr = self._ui_model.get_grid_manager() selected_line_ts = tstamp.Tstamp(0) gp_id = grid_mgr.get_selected_grid_pattern_id() if gp_id != None: gp = grid_mgr.get_grid_pattern(gp_id) selected_line_ts = gp.get_selected_line() or tstamp.Tstamp(0) orig_relative_offset = utils.get_px_from_tstamp( selected_line_ts, orig_px_per_beat) - orig_px_offset # Adjust vertical position so that edit cursor maintains its height new_cursor_offset = utils.get_px_from_tstamp( selected_line_ts, px_per_beat) new_px_offset = new_cursor_offset - orig_relative_offset self.followCursor.emit(str(new_px_offset))
def get_tstamp_from_px(px, px_per_beat): beats = px // px_per_beat rem_px = px % px_per_beat rem = rem_px * tstamp.BEAT // px_per_beat if rem * px_per_beat < rem_px * tstamp.BEAT: rem += 1 return tstamp.Tstamp(beats, rem)
def _follow_edit_cursor(self): grid_mgr = self._ui_model.get_grid_manager() gp_id = grid_mgr.get_selected_grid_pattern_id() if gp_id == None: return gp = grid_mgr.get_grid_pattern(gp_id) selected_line_ts = gp.get_selected_line() or tstamp.Tstamp(0) cursor_abs_y = utils.get_px_from_tstamp(selected_line_ts, self._px_per_beat) cursor_rel_y = cursor_abs_y - self._px_offset is_scrolling_required = False min_snap_dist = self._config['edit_cursor']['min_snap_dist'] min_centre_dist = min(min_snap_dist, self.height() // 2) min_y_offset = min_centre_dist max_y_offset = self.height() - min_centre_dist if cursor_rel_y < min_centre_dist: is_scrolling_required = True new_px_offset = self._px_offset - (min_y_offset - cursor_rel_y) elif cursor_rel_y >= max_y_offset: is_scrolling_required = True new_px_offset = self._px_offset + (cursor_rel_y - max_y_offset) if is_scrolling_required: self.followCursor.emit(str(new_px_offset)) self.update()
def _move_edit_cursor_to_playback_cursor(self): (track, system, row) = self._session.get_playback_cursor_position() selection = self._ui_model.get_selection() current_location = selection.get_location() col_num = current_location.get_col_num() row_ts = tstamp.Tstamp(*row) new_location = TriggerPosition(track, system, col_num, row_ts, 0) selection.set_location(new_location)
def test_beat_is_divided_optimally(self): for px_per_beat in range(1, 300): offsets = [ utils.get_tstamp_from_px(offset, px_per_beat) for offset in range(px_per_beat) ] self.assertEqual(offsets[0], 0) expected_px = 0 lens = set() for start, stop in zip_longest(offsets, islice(offsets, 1, None)): if stop == None: stop = tstamp.Tstamp(1, 0) end = stop - tstamp.Tstamp(0, 1) start_px = utils.get_px_from_tstamp(start, px_per_beat) end_px = utils.get_px_from_tstamp(end, px_per_beat) self.assertEqual( expected_px, start_px, msg='start_px {} did not match expected_px {},' ' px_per_beat: {}'.format(start_px, expected_px, px_per_beat)) self.assertEqual( start_px, end_px, msg= '{} and {} resulted in different pixel offsets {} and {},' ' px_per_beat: {}'.format(start, end, start_px, end_px, px_per_beat)) interval_len = end - start self.assertTrue( interval_len in lens or len(lens) < 2, msg='Found third interval length {} at [{}, {}],' ' existing: {}, px_per_beat: {}'.format( interval_len, start, end, lens, px_per_beat)) lens.add(interval_len) expected_px += 1 lens_list = list(lens) if len(lens_list) == 2: self.assertTrue( abs(lens_list[0] - lens_list[1]) == tstamp.Tstamp(0, 1), msg='Incorrect lengths: {}, px_per_beat: {}'.format( lens_list, px_per_beat))
def _change_offset(self, new_offset): new_offset_ts = tstamp.Tstamp(new_offset) gp = self._get_selected_grid_pattern() if gp == None: return gp.set_offset(new_offset_ts) self._updater.signal_update('signal_grid_pattern_modified')
def _change_length(self, new_length): new_length_ts = tstamp.Tstamp(new_length) gp = self._get_selected_grid_pattern() if gp == None: return gp.set_length(new_length_ts) self._updater.signal_update(set(['signal_grid_pattern_modified']))
def _change_value(self, new_value, is_final): pattern = self._get_pattern() if not pattern: return sheet_mgr = self._ui_model.get_sheet_manager() length = tstamp.Tstamp(new_value) if length == pattern.get_length(): if is_final and not self._is_latest_committed: sheet_mgr.set_pattern_length(pattern, length, is_final) self._is_latest_committed = True return sheet_mgr.set_pattern_length(pattern, length, is_final) self._updater.signal_update('signal_pattern_length')
def _change_grid_pattern(self, index): gp_id = self.itemData(index) if not gp_id: return pinst = self._get_pattern_instance() if not pinst: return offset = tstamp.Tstamp(0) # TODO pattern = pinst.get_pattern() sheet_mgr = self._ui_model.get_sheet_manager() selection = self._ui_model.get_selection() if selection.has_rect_area(): top_left = selection.get_area_top_left() bottom_right = selection.get_area_bottom_right() start_col = top_left.get_col_num() stop_col = bottom_right.get_col_num() + 1 start_ts = top_left.get_row_ts() stop_ts = bottom_right.get_row_ts() pat_length = pattern.get_length() full_columns_selected = ((start_ts == tstamp.Tstamp(0)) and (stop_ts > pat_length)) all_selected = (full_columns_selected and ((start_col, stop_col) == (0, COLUMNS_MAX))) if all_selected: sheet_mgr.set_pattern_base_grid_pattern_id(pattern, gp_id, is_final=False) if all_selected or (gp_id == pattern.get_base_grid_pattern_id()): gp_id = None if (full_columns_selected and (pattern.get_base_grid_pattern_id() == gp_id) and (pattern.get_base_grid_pattern_offset() == offset)): sheet_mgr.clear_overlay_grids(pinst, start_col, stop_col) else: sheet_mgr.set_overlay_grid(pinst, start_col, stop_col, start_ts, stop_ts, gp_id, offset) else: location = selection.get_location() col_num = location.get_col_num() column = pinst.get_column(location.get_col_num()) start_ts, stop_ts = column.get_overlay_grid_range_at( location.get_row_ts()) col_gp_id, offset = column.get_overlay_grid_info_at( location.get_row_ts()) if col_gp_id != None: pat_length = pattern.get_length() full_column_selected = ((start_ts == tstamp.Tstamp(0)) and (stop_ts > pat_length)) if (full_column_selected and (pattern.get_base_grid_pattern_id() == gp_id) and (pattern.get_base_grid_pattern_offset() == offset)): sheet_mgr.clear_overlay_grids(pinst, col_num, col_num + 1) else: if gp_id == pattern.get_base_grid_pattern_id(): gp_id = None sheet_mgr.set_overlay_grid(pinst, col_num, col_num + 1, start_ts, stop_ts, gp_id, offset) else: sheet_mgr.set_pattern_base_grid_pattern_id(pattern, gp_id, is_final=True) self._updater.signal_update('signal_grid')
def _create_pixmap(self, index, grid): pixmap = QPixmap(self._width, ColumnCache.PIXMAP_HEIGHT) painter = QPainter(pixmap) # Background painter.setBackground(self._get_final_colour(self._config['bg_colour'])) painter.eraseRect(QRect(0, 0, self._width - 1, ColumnCache.PIXMAP_HEIGHT)) # Start and stop timestamps start_px = index * ColumnCache.PIXMAP_HEIGHT stop_px = (index + 1) * ColumnCache.PIXMAP_HEIGHT visible_tr_start_px = start_px - self._config['tr_height'] + 1 start_ts = tstamp.Tstamp(0, visible_tr_start_px * tstamp.BEAT // self._px_per_beat) stop_ts = tstamp.Tstamp(0, stop_px * tstamp.BEAT // self._px_per_beat) def ts_to_y_offset(ts): rems = ts.beats * tstamp.BEAT + ts.rem abs_y = rems * self._px_per_beat // tstamp.BEAT y_offset = abs_y - start_px return y_offset # Grid sheet_manager = self._ui_model.get_sheet_manager() if sheet_manager.is_grid_enabled(): pinsts = utils.get_all_pattern_instances(self._ui_model) pinst = pinsts[self._pat_index] grid_start_ts = tstamp.Tstamp(0, start_px * tstamp.BEAT // self._px_per_beat) tr_height_ts = utils.get_tstamp_from_px( self._config['tr_height'], self._px_per_beat) lines = grid.get_grid_lines( pinst, self._col_num, grid_start_ts, stop_ts, tr_height_ts) for line_info in lines: line_ts, line_style = line_info line_y_offset = ts_to_y_offset(line_ts) line_pixmap = self._gl_cache.get_line_pixmap(line_style) painter.drawPixmap(QPoint(0, line_y_offset), line_pixmap) # Trigger rows painter.setCompositionMode(QPainter.CompositionMode_SourceOver) for ts, image, next_ts in self._tr_cache.iter_images(start_ts, stop_ts): y_offset = ts_to_y_offset(ts) src_rect = image.rect() dest_rect = src_rect.translated(QPoint(0, y_offset)) if next_ts != None: next_y_offset = ts_to_y_offset(next_ts) y_dist = next_y_offset - y_offset if y_dist < dest_rect.height(): rect_height = max(1, y_dist) dest_rect.setHeight(rect_height) src_rect.setHeight(rect_height) painter.drawImage(dest_rect, image, src_rect) # Border painter.setPen(self._get_final_colour(self._config['border_colour'])) painter.drawLine( QPoint(self._width - 1, 0), QPoint(self._width - 1, ColumnCache.PIXMAP_HEIGHT)) # Testing """ painter.setBackground(Qt.black) painter.eraseRect(QRect(0, 0, self._width, ColumnCache.PIXMAP_HEIGHT)) painter.setPen(Qt.white) painter.drawRect(0, 0, self._width - 1, ColumnCache.PIXMAP_HEIGHT - 1) pixmap_desc = '{}-{}-{}'.format(self._col_num, self._pat_index, index) painter.drawText(QPoint(2, 12), pixmap_desc) """ return pixmap
def _create_pixmap(self, index): pixmap = QPixmap(self._width, RulerCache.PIXMAP_HEIGHT) cfg = self._config painter = QPainter(pixmap) # Background painter.setBackground(self._get_final_colour(cfg['bg_colour'])) painter.eraseRect( QRect(0, 0, self._width - 1, RulerCache.PIXMAP_HEIGHT)) painter.setPen(self._get_final_colour(cfg['fg_colour'])) painter.drawLine(QPoint(self._width - 1, 0), QPoint(self._width - 1, RulerCache.PIXMAP_HEIGHT - 1)) # Start border if index == 0: painter.drawLine(QPoint(0, 0), QPoint(self._width - 2, 0)) # Ruler lines start_ts = tstamp.Tstamp( 0, tstamp.BEAT * index * RulerCache.PIXMAP_HEIGHT // self._px_per_beat) stop_ts = tstamp.Tstamp( 0, tstamp.BEAT * (index + 1) * RulerCache.PIXMAP_HEIGHT // self._px_per_beat) def draw_ruler_line(painter, y, line_pos, lines_per_beat): line_length = (cfg['line_len_long'] if line_pos[1] == 0 else cfg['line_len_short']) painter.drawLine(QPoint(self._width - 1 - line_length, y), QPoint(self._width - 1, y)) self._draw_markers(painter, start_ts, stop_ts, cfg['line_min_dist'], draw_ruler_line) # Beat numbers num_extent = self._num_height // 2 start_ts = tstamp.Tstamp( 0, tstamp.BEAT * (index * RulerCache.PIXMAP_HEIGHT - num_extent) // self._px_per_beat) stop_ts = tstamp.Tstamp( 0, tstamp.BEAT * ((index + 1) * RulerCache.PIXMAP_HEIGHT + num_extent) // self._px_per_beat) text_option = QTextOption(Qt.AlignRight | Qt.AlignVCenter) def draw_number(painter, y, num_pos, nums_per_beat): if num_pos == [0, 0]: return # Text num = num_pos[0] + num_pos[1] / float(nums_per_beat) numi = int(num) text = str(numi) if num == numi else str(round(num, 3)) # Draw rect = QRectF(0, y - self._num_height, self._width - cfg['line_len_long'] - 2, self._num_height + 3) painter.drawText(rect, text, text_option) painter.setFont(self._config['font']) self._draw_markers(painter, start_ts, stop_ts, cfg['num_min_dist'], draw_number) # Draw pixmap index for debugging #painter.drawText(QPoint(2, 12), str(index)) return pixmap
def _draw_markers(self, painter, start_ts, stop_ts, min_dist, draw_fn): cfg = self._config beat_div_base = 2 if min_dist <= self._px_per_beat: markers_per_beat = self._px_per_beat // min_dist markers_per_beat = int(beat_div_base**math.floor( math.log(markers_per_beat, beat_div_base))) # First visible marker in the first beat start_beat_frac = start_ts.rem / float(tstamp.BEAT) start_marker_in_beat = int( math.ceil(start_beat_frac * markers_per_beat)) # First non-visible marker in the last beat stop_beat_frac = stop_ts.rem / float(tstamp.BEAT) stop_marker_in_beat = int( math.ceil(stop_beat_frac * markers_per_beat)) def normalise_marker_pos(pos): excess = pos[1] // markers_per_beat pos[0] += excess pos[1] -= excess * markers_per_beat assert pos[1] >= 0 assert pos[1] < markers_per_beat # Loop boundaries marker_pos = [start_ts.beats, start_marker_in_beat] normalise_marker_pos(marker_pos) stop_pos = [stop_ts.beats, stop_marker_in_beat] normalise_marker_pos(stop_pos) # Draw markers while marker_pos < stop_pos: ts = tstamp.Tstamp(marker_pos[0] + marker_pos[1] / float(markers_per_beat)) y = float(ts - start_ts) * self._px_per_beat draw_fn(painter, y, marker_pos, markers_per_beat) # Next marker marker_pos[1] += 1 normalise_marker_pos(marker_pos) else: # Zoomed far out -- skipping whole beats beats_per_marker = (min_dist + self._px_per_beat - 1) // self._px_per_beat beats_per_marker = int(beat_div_base**math.ceil( math.log(beats_per_marker, beat_div_base))) # First beat with a visible marker start_beat = (start_ts - tstamp.Tstamp(0, 1)).beats + 1 start_marker_in_beat = beats_per_marker * int( math.ceil(start_beat / float(beats_per_marker))) # First non-visible beat stop_beat = (stop_ts - tstamp.Tstamp(0, 1)).beats + 1 # Draw markers for marker_pos in range(start_marker_in_beat, stop_beat, beats_per_marker): y = float(marker_pos - start_ts) * self._px_per_beat draw_fn(painter, y, [marker_pos, 0], 1)
def _change_tstamp_value(self): new_str = self._editors[tstamp.Tstamp].text() new_value = tstamp.Tstamp(float(new_str)) self._change_value(new_value)
def _change_tstamp_value(self): value = tstamp.Tstamp(float(self._editors[tstamp.Tstamp].text())) playback_mgr = self._ui_model.get_playback_manager() playback_mgr.set_runtime_var_value(self._var_name, value)
def _create_pixmap(self, index): pixmap = QPixmap(self._width, RulerCache.PIXMAP_HEIGHT) cfg = self._config painter = QPainter(pixmap) # Background painter.setBackground(self._get_final_colour(cfg['bg_colour'])) painter.eraseRect(QRect(0, 0, self._width, RulerCache.PIXMAP_HEIGHT)) # Lines painter.save() line_width = cfg['line_width'] line_pen = QPen(self._get_final_colour(cfg['fg_colour'])) line_pen.setWidthF(line_width) painter.setPen(line_pen) painter.translate(0, -((line_width - 1) // 2)) painter.drawLine( QPoint(self._width - line_width / 2, 0), QPoint(self._width - line_width / 2, RulerCache.PIXMAP_HEIGHT - 1)) # Ruler lines slice_margin_ts = utils.get_tstamp_from_px(line_width / 2, self._px_per_beat) start_ts = tstamp.Tstamp(0, tstamp.BEAT * index * RulerCache.PIXMAP_HEIGHT // self._px_per_beat) stop_ts = tstamp.Tstamp(0, tstamp.BEAT * (index + 1) * RulerCache.PIXMAP_HEIGHT // self._px_per_beat) def draw_ruler_line(painter, y, line_pos, lines_per_beat): if line_pos[1] == 0: line_length = cfg['line_len_long'] if line_pos[0] != 0 else self._width else: line_length = cfg['line_len_short'] painter.drawLine( QPoint(self._width - 1 - line_length, y), QPoint(self._width - 1, y)) self._draw_markers( painter, start_ts - slice_margin_ts, stop_ts + slice_margin_ts, cfg['line_min_dist'], draw_ruler_line) painter.restore() # Beat numbers painter.setPen(self._get_final_colour(cfg['fg_colour'])) num_extent = self._num_height // 2 start_ts = tstamp.Tstamp(0, tstamp.BEAT * (index * RulerCache.PIXMAP_HEIGHT - num_extent) // self._px_per_beat) stop_ts = tstamp.Tstamp(0, tstamp.BEAT * ((index + 1) * RulerCache.PIXMAP_HEIGHT + num_extent) // self._px_per_beat) text_option = QTextOption(Qt.AlignRight | Qt.AlignVCenter) def draw_number(painter, y, num_pos, nums_per_beat): if num_pos == [0, 0]: return # Text num = num_pos[0] + num_pos[1] / float(nums_per_beat) numi = int(num) text = str(numi) if num == numi else str(round(num, 3)) # Draw right_offset = cfg['line_len_long'] + cfg['num_padding_right'] rect = QRectF(0, y - self._num_height, self._width - right_offset, self._num_height + 3) painter.drawText(rect, text, text_option) painter.setFont(self._config['font']) self._draw_markers( painter, start_ts, stop_ts, cfg['num_min_dist'], draw_number) # Draw pixmap index for debugging #painter.drawText(QPoint(2, 12), str(index)) return pixmap
def paintEvent(self, event): start = time.time() painter = QPainter(self) # Background painter.setBackground(self._config['canvas_bg_colour']) painter.eraseRect(QRect(0, 0, self._width, self.height())) # Get grid pattern info grid_mgr = self._ui_model.get_grid_manager() gp_id = grid_mgr.get_selected_grid_pattern_id() if gp_id == None: return gp = grid_mgr.get_grid_pattern(gp_id) gp_length = gp.get_length() gp_lines = gp.get_lines() selected_line_ts = gp.get_selected_line() # Column background painter.setBackground(self._config['bg_colour']) length_rems = gp_length.beats * tstamp.BEAT + gp_length.rem height_px = length_rems * self._px_per_beat // tstamp.BEAT bg_extent = height_px - self._px_offset painter.eraseRect(QRect(0, 0, self._width, bg_extent)) # Grid lines selected_line_found = False for line in gp_lines: line_ts_raw, line_style = line line_ts = tstamp.Tstamp(line_ts_raw) if line_ts >= gp_length: continue abs_y = utils.get_px_from_tstamp(line_ts, self._px_per_beat) y_offset = abs_y - self._px_offset if not 0 <= y_offset < self.height(): continue pen = QPen(self._config['grid']['styles'][line_style]) painter.setPen(pen) painter.drawLine(QPoint(0, y_offset), QPoint(self._width - 1, y_offset)) if line_ts == selected_line_ts: selected_line_found = True if selected_line_found: cursor_config = self._config['grid']['edit_cursor'] cursor_max_y = (cursor_config['height'] - 1) // 2 abs_y = utils.get_px_from_tstamp(selected_line_ts, self._px_per_beat) y_offset = abs_y - self._px_offset painter.setRenderHint(QPainter.Antialiasing) painter.translate(QPointF(0.5, 0.5 + y_offset)) painter.setPen(cursor_config['colour']) painter.setBrush(cursor_config['colour']) painter.drawPolygon( QPolygon([ QPoint(0, cursor_max_y), QPoint(cursor_config['width'], 0), QPoint(0, -cursor_max_y) ])) end = time.time() elapsed = end - start
def get_pat_height(length, px_per_beat): return int(math.ceil(float(length + tstamp.Tstamp(0, 1)) * px_per_beat))
def _create_pixmap(self, index, grid): pixmap = QPixmap(self._width, ColumnCache.PIXMAP_HEIGHT) painter = QPainter(pixmap) album = self._ui_model.get_module().get_album() track, system = album.get_pattern_instance_location_by_nums(*self._pinst_ref) pat_index = utils.get_pattern_index_at_location(self._ui_model, track, system) assert pat_index != None # Background border_width = self._config['border_width'] painter.setBackground(self._get_final_colour(self._config['bg_colour'])) painter.eraseRect(QRect( border_width, 0, self._width - border_width * 2, ColumnCache.PIXMAP_HEIGHT)) # Start and stop timestamps start_px = index * ColumnCache.PIXMAP_HEIGHT stop_px = (index + 1) * ColumnCache.PIXMAP_HEIGHT visible_tr_start_px = start_px - self._config['tr_height'] + 1 start_ts = tstamp.Tstamp(0, visible_tr_start_px * tstamp.BEAT // self._px_per_beat) stop_ts = tstamp.Tstamp(0, stop_px * tstamp.BEAT // self._px_per_beat) def ts_to_y_offset(ts): rems = ts.beats * tstamp.BEAT + ts.rem abs_y = rems * self._px_per_beat // tstamp.BEAT y_offset = abs_y - start_px return y_offset # Grid sheet_mgr = self._ui_model.get_sheet_manager() if sheet_mgr.is_grid_enabled(): pinsts = utils.get_all_pattern_instances(self._ui_model) pinst = pinsts[pat_index] grid_start_ts = tstamp.Tstamp(0, start_px * tstamp.BEAT // self._px_per_beat) tr_height_ts = utils.get_tstamp_from_px( self._config['tr_height'], self._px_per_beat) lines = grid.get_grid_lines( pinst, self._col_num, grid_start_ts, stop_ts, tr_height_ts) for line_info in lines: line_ts, line_style = line_info line_y_offset = ts_to_y_offset(line_ts) line_pixmap = self._gl_cache.get_line_pixmap(line_style) painter.drawPixmap(QPoint(border_width, line_y_offset), line_pixmap) # Trigger rows painter.save() for ts, images, next_ts in self._tr_cache.iter_rows(start_ts, stop_ts): y_offset = ts_to_y_offset(ts) tr_height = self._config['tr_height'] if next_ts != None: next_y_offset = ts_to_y_offset(next_ts) tr_height = min(max(1, next_y_offset - y_offset), tr_height) x_offset = border_width for image in images: if x_offset >= self._width - border_width * 2: break painter.setClipRegion( QRegion(x_offset, y_offset, image.width(), tr_height)) painter.drawImage(x_offset, y_offset, image) x_offset += image.width() painter.restore() # Borders border_light, border_dark = self._get_border_colours() if border_width > 1: painter.fillRect( QRect(QPoint(0, 0), QSize(border_width, ColumnCache.PIXMAP_HEIGHT)), border_light) painter.fillRect( QRect(QPoint(self._width - border_width, 0), QSize(border_width, ColumnCache.PIXMAP_HEIGHT)), border_dark) else: painter.setPen(border_light) painter.drawLine( QPoint(0, 0), QPoint(0, ColumnCache.PIXMAP_HEIGHT)) painter.setPen(border_dark) painter.drawLine( QPoint(self._width - 1, 0), QPoint(self._width - 1, ColumnCache.PIXMAP_HEIGHT)) # Testing """ painter.setBackground(Qt.black) painter.eraseRect(QRect(0, 0, self._width, ColumnCache.PIXMAP_HEIGHT)) painter.setPen(Qt.white) painter.drawRect(0, 0, self._width - 1, ColumnCache.PIXMAP_HEIGHT - 1) pixmap_desc = '{}-{}-{}'.format(self._col_num, pat_index, index) painter.drawText(QPoint(2, 12), pixmap_desc) """ return pixmap
def paintEvent(self, event): start = time.time() painter = QPainter(self) painter.setBackground(self._config['bg_colour']) painter.eraseRect(0, 0, self.width(), self.height()) painter.translate(QPoint(0, self.height() // 2)) width_index = count() def shift_x(): cur_width_index = next(width_index) painter.translate(QPoint(self._widths[cur_width_index], 0)) cur_width = self._widths[cur_width_index + 1] painter.setClipRect( QRectF(0, -self.height() * 0.5, cur_width, self.height())) title_y = self.height() * 0.3 # Get position information track_num = -1 system_num = -1 row_ts = tstamp.Tstamp() pat_num = -1 inst_num = -1 playback_mgr = self._ui_model.get_playback_manager() if playback_mgr.is_playback_active(): track_num, system_num, row_ts = playback_mgr.get_playback_position( ) pinst = playback_mgr.get_playback_pattern() album = self._ui_model.get_module().get_album() if pinst: pat_num, inst_num = pinst elif album.get_existence(): song = album.get_song_by_track(track_num) if song.get_existence(): pinst = song.get_pattern_instance(system_num) pat_num = pinst.get_pattern_num() inst_num = pinst.get_instance_num() assert (pat_num == -1) == (inst_num == -1) # State icon shift_x() self._draw_state_icon(painter) # Track number shift_x() shift_x() self._draw_str(painter, str(track_num) if track_num >= 0 else '-', self._config['track_digits'], 'num_font') painter.setClipping(False) painter.drawPixmap(0, title_y, self._titles['track']) # System number shift_x() shift_x() self._draw_str(painter, str(system_num) if system_num >= 0 else '-', self._config['system_digits'], 'num_font') painter.setClipping(False) painter.drawPixmap(2, title_y, self._titles['system']) # Pattern instance shift_x() shift_x() # Shift horizontally to align pattern + instance number properly pat_shift = 0 if pat_num >= 0: pat_num_width = self._get_num_width(str(pat_num), self._config['pat_digits'], 'num_font') pat_shift = 0.5 * (pat_num_width - self._get_num_width( '9', self._config['pat_digits'], 'num_font')) if inst_num >= 0: inst_num_width = self._get_num_width( str(inst_num), self._config['pat_inst_digits'], 'sub_font') inst_def_width = self._get_num_width( '9', self._config['pat_inst_digits'], 'sub_font') inst_shift = 0.5 * (inst_def_width - inst_num_width) pat_shift += inst_shift else: inst_def_width = self._get_num_width( '9', self._config['pat_inst_digits'], 'sub_font') pat_shift = 0.4 * inst_def_width painter.save() painter.translate(pat_shift, 0) painter.setClipRegion(painter.clipRegion().translated(pat_shift, 0)) self._draw_str(painter, str(pat_num) if pat_num >= 0 else '-', self._config['pat_digits'], 'num_font', Qt.AlignRight) painter.restore() shift_x() if inst_num >= 0: painter.save() painter.translate(pat_shift, 0) painter.setClipRegion(painter.clipRegion().translated( pat_shift, 0)) self._draw_str(painter, str(inst_num), self._config['pat_inst_digits'], 'sub_font', Qt.AlignLeft) painter.restore() painter.setClipping(False) painter.drawPixmap(-19, title_y, self._titles['pattern']) # Timestamp beats, rem = row_ts rem_norm = int( float(rem / float(tstamp.BEAT)) * (10**self._config['ts_rem_digits'][0])) shift_x() shift_x() self._draw_str(painter, str(beats), self._config['ts_beat_digits'], 'num_font', Qt.AlignRight) shift_x() self._draw_str(painter, '.', [1, 1], 'num_font') shift_x() self._draw_str(painter, str(rem_norm), self._config['ts_rem_digits'], 'rem_font', Qt.AlignLeft) painter.setClipping(False) painter.drawPixmap(-10, title_y, self._titles['row']) end = time.time() elapsed = end - start