Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion automation/views/sequencer.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
import dearpygui.dearpygui as dpg

from automation.dearpygui.bridge import Bridge
from automation.dearpygui.geometry import Point
from automation.dearpygui.geometry import Point, Rect
from automation.dearpygui.hand import Hand
from automation.dearpygui.items.colors import read_theme_text_color
from automation.dearpygui.items.reading import read_item
from automation.dearpygui.items.regions import read_region_view, read_table
from automation.dearpygui.items.texts import read_label
Expand Down Expand Up @@ -207,6 +208,19 @@ def positions(self) -> int:
lambda: len(read_table(TAG_SEQUENCER_ORDER_TABLE)[MASTER_ORDER_ROW]) - ORDER_LABEL_CELLS
)

def cell_box(self, channel: Optional[ChannelName], position: int) -> Optional[Rect]:
"""Where the entry of ``channel`` at frame ``position`` stands on the screen."""
return self._bridge.ask(lambda: read_item(_order_entry(channel, position)).rect)

def text_color(self, channel: Optional[ChannelName], position: int) -> Optional[Tuple[float, ...]]:
"""The text color the theme bound to the entry of ``channel`` at frame ``position`` sets."""

def read() -> Optional[Tuple[float, ...]]:
theme = dpg.get_item_info(_order_entry(channel, position))["theme"]
return read_theme_text_color(theme) if theme is not None else None

return self._bridge.ask(read)

def click(self, channel: Optional[ChannelName], position: int) -> None:
"""Clicks the entry of ``channel`` at frame ``position``, scrolling it into view first."""
entry = self._bridge.ask(lambda: _order_entry(channel, position))
Expand Down
33 changes: 23 additions & 10 deletions automation/views/tracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import dearpygui.dearpygui as dpg

from automation.dearpygui.bridge import Bridge
from automation.dearpygui.geometry import Point
from automation.dearpygui.geometry import Point, Rect
from automation.dearpygui.hand import Hand
from automation.dearpygui.items.colors import read_theme_text_color
from automation.dearpygui.items.reading import read_item
Expand Down Expand Up @@ -61,7 +61,7 @@ def _table_rows() -> Tuple[Item, ...]:
return tuple(dpg.get_item_children(TAG_SEQUENCER_TRACKER_TABLE, 1))


def _frame_rows() -> Dict[int, int]:
def frame_rows() -> Dict[int, int]:
"""Where each pattern row of the shown frame stands among the table's rows, by its index. Runs on the render
thread.
"""
Expand Down Expand Up @@ -181,6 +181,10 @@ def has_caret(self, row: int, channel: Optional[ChannelName]) -> bool:
"""Whether the caret stands in ``channel``'s cell on ``row``, as the box drawn over the grid shows it."""
return self._bridge.ask(_caret_cell) == (row, channel)

def caret_box(self) -> Optional[Rect]:
"""Where the caret's mark stands on the screen, while it shows one."""
return self._bridge.ask(caret_mark)

def caret_row(self, channel: Optional[ChannelName]) -> Optional[int]:
"""The pattern row the caret stands on in ``channel``'s column, if it stands in that column."""
cell = self._bridge.ask(_caret_cell)
Expand Down Expand Up @@ -208,7 +212,7 @@ def read() -> Optional[int]:
return None

middle = band.y + band.height * HALF
for row, table_index in _frame_rows().items():
for row, table_index in frame_rows().items():
number = read_item(_number(table_index))
if number.rect is None or not number.visible:
continue
Expand Down Expand Up @@ -237,7 +241,7 @@ def numbers_below(self, count: int) -> Tuple[str, ...]:
"""What the row numbers of the ``count`` rows nearest below the frame read, top to bottom."""

def read() -> Tuple[str, ...]:
last = max(_frame_rows().values())
last = max(frame_rows().values())
return tuple(read_label(_number(index)) for index in range(last + 1, last + 1 + count))

return self._bridge.ask(read)
Expand All @@ -262,7 +266,7 @@ def tinted_rows_in_view(self) -> FrozenSet[int]:
def read() -> FrozenSet[int]:
return frozenset(
row
for row, table_index in _frame_rows().items()
for row, table_index in frame_rows().items()
if read_item(_number(table_index)).visible
and dpg.is_table_row_highlighted(TAG_SEQUENCER_TRACKER_TABLE, table_index)
)
Expand Down Expand Up @@ -304,7 +308,7 @@ def _caret_cell() -> Optional[Tuple[int, Optional[ChannelName]]]:
return None

x, y = middle
for row, table_index in _frame_rows().items():
for row, table_index in frame_rows().items():
number = read_item(_number(table_index))
if number.rect is None or not number.visible or not number.rect.y <= y < number.rect.y + number.rect.height:
continue
Expand All @@ -318,9 +322,9 @@ def _caret_cell() -> Optional[Tuple[int, Optional[ChannelName]]]:
return None


def _caret_middle() -> Optional[Tuple[float, float]]:
"""The middle of the box the caret overlay draws, while it shows one. Runs on the render thread."""
rectangle = CaretOverlay._rectangle # pylint: disable=protected-access
def caret_mark() -> Optional[Rect]:
"""The mark the caret overlay draws under the active character, while it shows one. Runs on the render thread."""
rectangle = CaretOverlay._mark # pylint: disable=protected-access
if rectangle is None or not dpg.does_item_exist(rectangle):
return None

Expand All @@ -329,4 +333,13 @@ def _caret_middle() -> Optional[Tuple[float, float]]:
return None

corner, far = configuration["pmin"], configuration["pmax"]
return (corner[0] + far[0]) * HALF, (corner[1] + far[1]) * HALF
return Rect(x=corner[0], y=corner[1], width=far[0] - corner[0], height=far[1] - corner[1])


def _caret_middle() -> Optional[Tuple[float, float]]:
"""The middle of the caret's mark, while it shows one. Runs on the render thread."""
mark = caret_mark()
if mark is None:
return None

return mark.x + mark.width * HALF, mark.y + mark.height * HALF
2 changes: 2 additions & 0 deletions docs/development/application/sequencer-blocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ Both panels read the cell under a held pointer off their own geometry, because D

The tracker's row lookup is arithmetic. It measures from the first row's top edge and divides by the row height, which holds while the rows are evenly pitched. That is what the pattern table's zero vertical cell padding and item spacing are for: a vertical padding there would drift the lookup further down the grid. The order's position lookup is arithmetic in the same way and takes its pitch from the first two columns. Its channel lookup walks the rows, because the master row stands apart from the channels beneath it.

The caret (`ui/elements/table/caret.py`) draws on a front viewport drawlist from the rectangle the active cell reported: a mark under one character, measured off the label's width in the cell's font, and a frame around the cell. Both tables give their selectables zero item spacing, so a label starts at its rectangle's left edge and the character arithmetic holds in each. A table answers a scroll on the frame after the one that draws its highlights, so a move that re-centers the grid holds its painting one frame, the way the playhead does, and hands the caret the distance the pending scroll will carry the row.

### A drag past the edge carries the view

A pointer held past the cells on screen travels the grid under it, so a selection reaches further than the viewport holds. `grid/scroll/` holds the travel. A grid says which axis it scrolls along and where its cells stand along it, and one class reads the two each frame. The tracker travels vertically and the order horizontally, from that same class.
Expand Down
Binary file modified docs/images/guide/converting/source-settings.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/guide/interface/tabs.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/guide/reconstruction/export-menu.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/guide/sequencer/history.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/guide/sequencer/nsf-window.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/guide/sequencer/playback.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/guide/sequencer/project-properties.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/guide/sequencer/render.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/guide/sequencer/tracker.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/guide/sequencer/voices.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/sampletones.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 7 additions & 4 deletions src/sampletones_application/layout/general/caret.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@


class CaretLayout(BaseModel, extra="forbid", frozen=True):
offset: int
width_padding: int
fill: WrittenColor
border: WrittenColor
"""How the tracker's caret is drawn: the underline's height and color, and the color of the frame around the
cell.
"""

height: int
color: WrittenColor
frame: WrittenColor
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,14 @@ class TrackerColors(BaseModel, extra="forbid", frozen=True):
is what the slot wears while it names nothing, and ``sample`` and ``instrument`` are
the two kinds a named voice can be, so the slot's color reports what it holds.
``transpose`` and ``volume`` carry the other two slots, and the ``frame`` and ``row``
indices and the ``order`` entries carry the grids around them. Defining them once
indices and the ``order`` entries carry the grids around them. ``pending`` is what a slot
wears while an entry is being typed into it, whatever kind the entry will turn out to be,
so the digits being written stand out from everything around them. Defining them once
keeps every panel in step.
"""

voice: WrittenColor
pending: WrittenColor
transpose: WrittenColor
volume: WrittenColor
sample: WrittenColor
Expand Down
Loading
Loading