Ankerseite: Werte über Tastatur änderbar
This commit is contained in:
		
							parent
							
								
									986d222a98
								
							
						
					
					
						commit
						dafcfaca6b
					
				
							
								
								
									
										108
									
								
								cfgmenu.py
								
								
								
								
							
							
						
						
									
										108
									
								
								cfgmenu.py
								
								
								
								
							|  | @ -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 | ||||
|         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) | ||||
|  |  | |||
							
								
								
									
										100
									
								
								pages/anchor.py
								
								
								
								
							
							
						
						
									
										100
									
								
								pages/anchor.py
								
								
								
								
							|  | @ -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() | ||||
| 
 | ||||
|  |  | |||
|  | @ -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: | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue