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
11 changes: 4 additions & 7 deletions rollingmill/tui.py
Original file line number Diff line number Diff line change
Expand Up @@ -774,8 +774,6 @@ def _wcs_handle_key(self, key: int) -> None:
elif key in (10, 13): # Enter — activate
self._m.set_active_wcs(self._wcs_sel)
elif key in (ord('m'), ord('M')): # Move to stored origin
if self._wcs_sel == 0:
return # MCS origin is always (0,0,0,0) — no-op / already there
if self._wcs_data and self._wcs_data[self._wcs_sel]:
ox, oy, oz, oa = self._wcs_data[self._wcs_sel]
self._m.move_to_machine_pos(ox, oy, oz, oa)
Expand Down Expand Up @@ -1040,7 +1038,7 @@ def _draw_move_dialog(self, stdscr: curses.window, rows: int, cols: int) -> None
if self._move_sel >= len(targets):
self._move_sel = len(targets) - 1

dh = min(6 + len(targets), rows - 2)
dh = min(5 + len(targets), rows - 2)
dw = min(48, cols - 2)
dy = (rows - dh) // 2
dx = (cols - dw) // 2
Expand All @@ -1053,13 +1051,12 @@ def _draw_move_dialog(self, stdscr: curses.window, rows: int, cols: int) -> None
win.erase()
win.box()

wcs_lbl = 'MCS' if self._m.active_wcs == 0 else f'WCS{self._m.active_wcs}'
wcs_lbl = _machine.wcs_label(self._m.active_wcs)
title = f' Move To (using {wcs_lbl})'
win.addstr(0, 2, title[:dw - 4], CP(_CP_HEADER) | BOLD)
win.addstr(1, 1, '─' * (dw - 2), CP(_CP_LABEL))

for i, (label, _action) in enumerate(targets):
row = 2 + i
row = 1 + i
if row >= dh - 3:
break
is_sel = (i == self._move_sel)
Expand Down Expand Up @@ -1095,7 +1092,7 @@ def _coord_entry_dialog(self, stdscr: curses.window) -> None:

CP = curses.color_pair
BOLD = curses.A_BOLD
wcs_lbl = 'MCS' if self._m.active_wcs == 0 else f'WCS{self._m.active_wcs}'
wcs_lbl = _machine.wcs_label(self._m.active_wcs)

win.erase()
win.box()
Expand Down
64 changes: 64 additions & 0 deletions tests/test_wcs_dialog_move.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
"""'M' in the coordinates dialog moves to the selected coordinate system's origin, MCS included."""
import struct

import pytest

from rollingmill.machine import MDX40A
from rollingmill.tui import TUI, _LogBuffer
from rollingmill.usb import MdxMockUSB

DOWN = 258 # curses.KEY_DOWN


class _Recording(MdxMockUSB):
def __init__(self, responses=None):
super().__init__(responses=responses)
self.sent = []

def vend_set(self, wValue, data=b""):
self.sent.append((wValue, data))
super().vend_set(wValue, data)

def moves(self):
return [d for w, d in self.sent if w == 0x04f7]


def _dialog(responses=None):
link = _Recording(responses)
tui = TUI(MDX40A(link), _LogBuffer())
tui._wcs_open_dialog()
link.sent.clear()
return tui, link


def _move_payload(x, y, z, a, speed=1800):
return struct.pack(">HH4i", speed, 0xFFFF, round(x * 1000), round(y * 1000), round(z * 1000), round(a * 1000))


def test_m_on_mcs_sends_a_move_to_machine_zero():
tui, link = _dialog()
assert tui._wcs_sel == 0 # MCS is the first row
tui._handle_key(ord("m"))
assert link.moves() == [_move_payload(0, 0, 0, 0)]


def test_m_on_mcs_is_bracketed_like_every_other_move():
tui, link = _dialog()
tui._handle_key(ord("M"))
assert [w for w, _ in link.sent] == [0x1109, 0x04f7, 0x03f2, 0x1109]
assert link.sent[0][1] == b"\x00" and link.sent[-1][1] == b"\xff"


def test_m_on_a_stored_origin_moves_to_it():
tui, link = _dialog({0x3203: struct.pack(">4i", 1000, 2000, -3000, 4000)}) # G54 (slot 3)
for _ in range(3):
tui._handle_key(DOWN)
tui._handle_key(ord("m"))
assert link.moves() == [_move_payload(1, 2, -3, 4)]


@pytest.mark.parametrize("key", [ord("x"), ord("y"), ord("z"), ord("a"), ord("0")])
def test_the_overwrite_keys_still_refuse_mcs(key):
tui, link = _dialog()
tui._handle_key(key)
assert link.sent == [] # MCS origin cannot be overwritten
81 changes: 81 additions & 0 deletions tests/test_wcs_titles.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
"""Dialog titles name the active coordinate system the same way as the header (wcs_label)."""
import curses

import pytest

from rollingmill import machine as M
from rollingmill.machine import MDX40A
from rollingmill.tui import TUI, _LogBuffer
from rollingmill.usb import MdxMockUSB


class _FakeWin:
"""Just enough of a curses window to record what a dialog draws."""

def __init__(self, h=24, w=80):
self.h, self.w = h, w
self.drawn = []

def getmaxyx(self):
return self.h, self.w

def addstr(self, y, x, text, attr=0):
self.drawn.append(text)

def erase(self):
pass

def box(self):
pass

def refresh(self):
pass

def keypad(self, flag):
pass

def nodelay(self, flag):
pass

def move(self, y, x):
pass

def getch(self):
return 27 # Esc: leave modal dialogs at once


@pytest.fixture
def fake_curses(monkeypatch):
win = _FakeWin()
monkeypatch.setattr(curses, "newwin", lambda *a, **k: win)
monkeypatch.setattr(curses, "color_pair", lambda n: 0)
monkeypatch.setattr(curses, "curs_set", lambda n: 0)
monkeypatch.setattr(curses, "noecho", lambda: None)
return win


@pytest.mark.parametrize("slot", range(0, 9))
def test_move_to_title_uses_the_slot_names(slot, fake_curses):
m = MDX40A(MdxMockUSB())
m.set_active_wcs(slot)
TUI(m, _LogBuffer())._draw_move_dialog(_FakeWin(), 30, 100)
title = next(t for t in fake_curses.drawn if "Move To" in t)
assert title.strip() == f"Move To (using {M.WCS_SLOT_NAMES[slot]})"


def test_move_to_title_for_user_and_g54_reads_naturally(fake_curses):
m = MDX40A(MdxMockUSB())
for slot, name in ((1, "User (RML-1)"), (3, "WCS1 (G54)")):
fake_curses.drawn.clear()
m.set_active_wcs(slot)
TUI(m, _LogBuffer())._draw_move_dialog(_FakeWin(), 30, 100)
assert any(name in t for t in fake_curses.drawn)


@pytest.mark.parametrize("slot", range(0, 9))
def test_move_to_position_title_uses_the_slot_names(slot, fake_curses):
m = MDX40A(MdxMockUSB())
m.set_active_wcs(slot)
TUI(m, _LogBuffer())._coord_entry_dialog(_FakeWin())
title = next(t for t in fake_curses.drawn if "Move to position" in t)
assert title.strip() == f"Move to position ({M.WCS_SLOT_NAMES[slot]})"
Loading