Ankerseite: Werte über Tastatur änderbar

This commit is contained in:
Thomas Hooge 2025-07-22 13:12:00 +02:00
parent 986d222a98
commit dafcfaca6b
3 changed files with 151 additions and 72 deletions

View File

@ -5,44 +5,94 @@ Menüsystem für Konfiguration(en)
class MenuItem():
def __init__(self, itmname):
self.name = itmname
self.label = None
self.value = None
self.steps = (1,)
def __init__(self, valtype, label, value=None, unit=''):
validtypes = ('int', 'bool')
valtype = valtype.lower() # Groß- und Kleinschreibung lassen wir gemischt zu
if valtype not in validtypes:
raise TypeError(f"Invalid value type: '{valtype}'. Only supported: {validtypes}")
self.label = label # Anzeigetext des Menüeintrag
self.value = value # Zugeordneter Wert für diesen Eintrag
self.unit = unit
self._type = valtype
self._min = 0
self._max = 99999
self.steps = (1, 10, 100, 1000) # Sprungmöglichkeiten für +/- Tasten
self.step = 0 # index into tuple above
self.position = None # Menüposition gezählt von 0 an
def setRange(self, valmin, valmax, steps):
self.min = valmin
self.max = valmax
self.steps = steps
def setValue(self, val):
self.value = val
if self._type == 'int':
if val >= self._min and val <= self._max:
self.value = val
return True
elif self.type == 'bool':
self.value = val
return True
return False
class Menu():
def __init__(self):
title = None
x = 0
y = 0
w = 100
h = 20
items = []
itm_active = -1 # nothing activated
self._index = -1
def addItem(self, label):
itm = MenuItem(label)
items.append(itm)
class MenuIter():
def __init__(self, menu):
self._items = menu.items
self._class_size = len(self._items)
self._index = 0
def __init__(self, title, x, y):
self.title = title
self.items = {} # Items über Schlüssel zugreifbar
self.activeitem = -1 # Noch nichts aktiv
self._x = x
self._y = y
self._w = 100
self._h = 20
self._index = [] # Mapping zwischen Index(Position) und Schlüssel
self._iter_index = 0
def __iter__(self):
return self
def __next__(self):
if self._index < self._class_size:
itm = items[self._index]
self._index += 1
if self._iter_index < len(self.items):
itm = self.items[self._index[self._iter_index]]
self._iter_index += 1
return itm
raise StopIteration
self._iter_index = 0
raise StopIteration
def addItem(self, key, label, valtype, value=None, unit=''):
if key in self.items.keys():
raise KeyError(f"Duplicate menu item key: '{key}'")
itm = MenuItem(valtype, label, value, unit)
self.items[key] = itm
self._index.append(key)
itm.position = self._index.index(key)
return itm
def setItemActive(self, key):
self.activeitem = self._index.index(key)
def getActiveItem(self):
return self.items[self._index[self.activeitem]]
def getItemByIndex(self, index):
return self.items[self._index[index]]
def getItemByKey(self, key):
return self.items[key]
def getItemCount(self):
return len(self.items)
def setItemDimension(self, w, h):
self._w = w
self._h = h
def getXY(self):
return (self._x, self._y)
def getRect(self):
return (self._x, self._y, self._w, self._h * len(self.items))
def getItemRect(self, index):
y = self._y + index * self._h
return (self._x, y, self._w, self._h)

View File

@ -69,21 +69,19 @@ class Anchor(Page):
self.wind_angle = -1
# Menüsteuerung für Konfiguration
self._mnu = {
# Lfd. Name, curr unit steps type: numeric, on/off
# TODO Das sollte eine Klasse werden!
'chain': [1, "Chain out", 0, "m", (1, 5, 10), (0, 200)],
'chainmax': [2, "Chain max", 0, "m", (1, 5, 10), (0, 200)],
'zoom': [3, "Zoom", 50, "", (1,), (1, 8)],
'range': [4, "Alarm range", 35, "m", (1, 5, 10), (0, 200)]
}
self._mnu_title = "Options"
self._mnu_x = 20
self._mnu_y = 80
self._mnu_w = 120
self._mnu_h = 20
self._mnu_sel = 1
self.mnu_step = 1
self._menu = Menu("Options", 20, 80)
self._menu.setItemDimension(120, 20)
newitem = self._menu.addItem("chain", "Chain out", "int", 0, "m")
newitem.setRange(0, 200, (1, 5, 10))
newitem = self._menu.addItem("chainmax", "Chain max", "int", self.chain_length, "m")
newitem.setRange(0, 200, (1, 5, 10))
newitem = self._menu.addItem("zoom", "Zoom", "int", 2)
newitem.setRange(1, 8, (1,))
newitem = self._menu.addItem("range", "Alarm range", "int", 40, "m")
newitem.setRange(1, 200, (1, 5, 10))
self._menu.setItemActive("chain")
self._test = 0
def handle_key(self, buttonid):
if buttonid == 1:
@ -91,8 +89,10 @@ class Anchor(Page):
self.mode = 'C'
self.buttonlabel[2] = '#UP'
self.buttonlabel[3] = '#DOWN'
self.buttonlabel[4] = '[ - ]'
self.buttonlabel[5] = '[ + ]'
itm = self._menu.getActiveItem()
stepwidth = itm.steps[itm.step]
self.buttonlabel[4] = f"-{stepwidth}"
self.buttonlabel[5] = f"+{stepwidth}"
self.buttonlabel[6] = 'STEP'
else:
self.mode = 'N'
@ -134,16 +134,35 @@ class Anchor(Page):
return True
else:
# Konfiguration
itm = self._menu.getActiveItem()
if buttonid == 2:
if self._mnu_sel == 1:
self._mnu_sel = len(self._mnu)
if self._menu.activeitem == 0:
self._menu.activeitem = self._menu.getItemCount() - 1
else:
self._mnu_sel -= 1
self._menu.activeitem -= 1
elif buttonid == 3:
if self._mnu_sel == len(self._mnu):
self._mnu_sel = 1
if self._menu.activeitem == self._menu.getItemCount() - 1:
self._menu.activeitem = 0
else:
self._mnu_sel += 1
self._menu.activeitem += 1
elif buttonid == 4:
# decrease value by step
stepwidth = itm.steps[itm.step]
itm.setValue(itm.value - stepwidth)
elif buttonid == 5:
# increase value by step
stepwidth = itm.steps[itm.step]
itm.setValue(itm.value + stepwidth)
elif buttonid == 6:
ns = len(itm.steps)
if ns > 1:
if itm.step < ns - 1:
itm.step += 1
else:
itm.step = 0
stepwidth = itm.steps[itm.step]
self.buttonlabel[4] = f"-{stepwidth}"
self.buttonlabel[5] = f"+{stepwidth}"
return True
return False
@ -260,22 +279,31 @@ class Anchor(Page):
ctx.move_to(2, 50)
ctx.show_text("Anchor configuration")
# Menüwerte initialisieren
self._mnu["chain"][2] = self.chain
self._mnu["chainmax"][2] = self.chain_length
# Menü zeichnen
ctx.save()
ctx.set_font_size(16)
#ctx.rectangle(100, 100, 50, 50)
#ctx.clip()
for m in self._mnu.items():
#ctx.move_to(self._mnu_x, self._mnu_y + 24 + m[1][0] * 16)
#ctx.show_text(m[1][1])
inverted = (m[1][0] == self._mnu_sel)
self.draw_text_boxed(ctx, self._mnu_x, self._mnu_y + self._mnu_h * (m[1][0] - 1), self._mnu_w, self._mnu_h, m[1][1], inverted)
ctx.move_to(self._mnu_x + self._mnu_w + 20 , self._mnu_y + self._mnu_h * (m[1][0] - 1))
ctx.show_text(str(m[1][2]) + m[1][3])
x, y, w, h = self._menu.getRect()
ctx.set_line_width(1)
x += 0.5 # Cairo-Fix for single pixel line
y += 0.5
ctx.save()
ctx.rectangle(x, y, w, h)
ctx.clip_preserve()
ctx.stroke()
for m in self._menu:
ix, iy, iw, ih = self._menu.getItemRect(m.position)
inverted = (m.position == self._menu.activeitem)
self.draw_text_boxed(ctx, ix, iy, iw, ih, m.label, inverted, False)
ctx.stroke()
# Werte neben dem Menü
ctx.restore()
ctx.rectangle(0, 20, 400, 360) # new clipping
ctx.clip()
self._test += 1
for m in self._menu:
ix, iy, iw, ih = self._menu.getItemRect(m.position)
ctx.move_to(ix + iw + 20, iy + ih - 4) # 5 für Unterlängen
ctx.show_text(f"{m.value} {m.unit}")
ctx.stroke()
ctx.restore()

View File

@ -279,17 +279,18 @@ class Page():
ctx.show_text(content)
ctx.stroke()
def draw_text_boxed(self, ctx, x, y, w, h, content, inverted=False):
def draw_text_boxed(self, ctx, x, y, w, h, content, inverted=False, border=False):
ctx.set_line_width(1)
# Background fill
ctx.set_source_rgb(*self.fgcolor)
if inverted:
ctx.set_source_rgb(*self.fgcolor)
ctx.rectangle(x, y + 0.5, w, h)
ctx.fill()
else:
ctx.set_source_rgb(*self.bgcolor)
ctx.rectangle(x, y + 0.5, w, h)
ctx.stroke()
if border:
ctx.rectangle(x + 0.5, y + 0.5, w, h)
ctx.stroke()
# Text
if inverted:
ctx.set_source_rgb(*self.bgcolor)
else: