""" Ankerinfo / -alarm Daten - Position des Ankers - Wassertiefe beim Ankern - Gesteckte Kettenlänge - aktuelle Position des Schiffs - aktuelle Wassertiefe an Schiffsposition - aktuelle Schiffsausrichtung bearing/heading - aktuelle Windrichtung (wahr) - aktuelle Windstärke (wahr) - Alarm aktiv J/N - Alarmradius - GPS Abweichung/ Fehler in der Horizontalen - Zeitpunkt des Ankeraus Darstellung: - Modi: Normal / Konfiguration - Anker oben / unten - Nord ist oben Es gibt verschiedene Unterseiten - Normalansicht - Konfigurationsseite """ import os import cairo import math import time from cfgmenu import Menu from .page import Page class Anchor(Page): def __init__(self, pageno, cfg, boatdata): super().__init__(pageno, cfg, boatdata) self.sym_anchor = cairo.ImageSurface.create_from_png(os.path.join(cfg['imgpath'], "anchor.png")) self.buttonlabel[1] = 'MODE' self.buttonlabel[2] = 'DROP' self.buttonlabel[5] = '' # ALARM erst möglich wenn der Anker unten ist self.mode = 'N' # (N)ormal, (C)onfiguration self.scale = 50 # Radius of display circle in meter self._bd = boatdata # Der sinnvolle Abstand ist abhängig von der Länge der gesteckten Kette # Die initial eingegebene Position des Ankers sollte nactträglich justiert # werden können self.chain_length = 60 # maximale Länge die ausgesteckt werden kann self.chain = 35 # aktuell gesteckte Länge self.anchor_set = False self.anchor_lat = 0 self.anchor_lon = 0 self.anchor_depth = -1 self.anchor_ts = None # Timestamp of dropped anchor self.lat = 0 self.lon = 0 self.heading = -1 self.depth = -1 self.alarm_range = 20 self.alarm_enabled = False self.alarm = False # Alarm ist ausgelöst und aktiv 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 def handle_key(self, buttonid): if buttonid == 1: if self.mode == 'N': self.mode = 'C' self.buttonlabel[2] = '#UP' self.buttonlabel[3] = '#DOWN' self.buttonlabel[4] = '[ - ]' self.buttonlabel[5] = '[ + ]' self.buttonlabel[6] = 'STEP' else: self.mode = 'N' self.buttonlabel[2] = 'RISE' if self.anchor_set else 'DROP' self.buttonlabel[3] = '#PREV' self.buttonlabel[4] = '#NEXT' self.buttonlabel[5] = 'ALARM' if not self.alarm_enabled else 'OFF' return True if self.mode == 'N': # Normal if buttonid == 2: if not self.anchor_set: self.anchor_lat = self._bd.lat self.anchor_lon = self._bd.lon self.anchor_set = True self.anchor_ts = time.time() self.buttonlabel[2] = 'RISE' self.buttonlabel[5] = 'ALARM' else: self.anchor_set = False self.alarm = False self.alarm_enabled = False self.anchor_ts = None self.buttonlabel[2] = 'DROP' self.buttonlabel[5] = '' return True elif buttonid == 5: # Bei aktivem Alarm kann mit dieser Taste der Alarm zurückgesetzt # werden. Die Tastenbeschriftung wechselt zwischen ALARM und OFF. if self.alarm: self.alarm = False self.buttonlabel[5] = 'ALARM' if self.alarm_enabled: self.alarm_enabled = False self.buttonlabel[5] = 'ALARM' else: self.alarm_enabled = True self.buttonlabel[5] = 'OFF' return True else: # Konfiguration if buttonid == 2: if self._mnu_sel == 1: self._mnu_sel = len(self._mnu) else: self._mnu_sel -= 1 elif buttonid == 3: if self._mnu_sel == len(self._mnu): self._mnu_sel = 1 else: self._mnu_sel += 1 return True return False def draw_normal(self, ctx): """ value1 = LAT value2 = LON value3 = HDOP value4 = DBS value5 = TWD value6 = TWS """ # self.anchor_lat = # Name ctx.select_font_face("Ubuntu", cairo.FontSlant.NORMAL, cairo.FontWeight.BOLD) ctx.set_font_size(20) ctx.move_to(2, 50) ctx.show_text("Anchor") ctx.move_to(2, 200) ctx.show_text("Depth") ctx.move_to(320, 50) ctx.show_text("Chain") ctx.set_font_size(16) ctx.move_to(2, 70) ctx.show_text("Alarm: ") if self.alarm_enabled: ctx.show_text("On") else: ctx.show_text("Off") ctx.move_to(320, 70) ctx.show_text(f"{self.chain} m") ctx.move_to(10, 220) if self._bd.dbs.valid: ctx.show_text(self._bd.dbs.format()) ctx.stroke() # Spezialseite cx = 200 cy = 150 r = 125 # Skala ctx.set_line_width(1) ctx.arc(cx, cy, r, 0, 2*math.pi) ctx.move_to(cx + 10, cy + 0.5) ctx.line_to(cx + r - 4, cy + 0.5) ctx.move_to(cx + r / 2, cy + 20) # Pfeil links ctx.move_to(cx + 10, cy + 0.5) ctx.line_to(cx + 16, cy - 4 + 0.5) ctx.move_to(cx + 10, cy + 0.5) ctx.line_to(cx + 16, cy + 4 + 0.5) # Pfeil rechts ctx.move_to(cx + r - 4, cy + 0.5) ctx.line_to(cx + r - 10, cy - 4 + 0.5) ctx.move_to(cx + r - 4, cy + 0.5) ctx.line_to(cx + r - 10, cy + 4 + 0.5) ctx.set_font_size(16) self.draw_text_center(ctx, cx + r / 2, cy + 8, str(self.scale) + " m") ctx.stroke() ctx.set_line_width(1.5) # Ankersymbol falls Anker fallen gelassen wurde # Ansonsten ist das Boot-Symbol im Mittelpunkt if self.anchor_set: ctx.save() ctx.set_source_surface(self.sym_anchor, cx-8, cy-8) ctx.paint() ctx.restore() # Boot zeichnen # Heading beachten # Wir arbeiten mit einer Kopie, weil bx/by im Laufe der Zeit von # cx/cy abweichen werden if self.anchor_set: bx = cx by = cy + 30 else: bx = cx by = cy + 8 p = ((bx - 5, by), (bx - 5, by - 10), (bx, by - 16), (bx + 5, by - 10), (bx + 5, by), (bx - 6, by)) if self._bd.hdt.value: # Rotiere Boot-Symbol um eigenes Zentrum boat = self.rotate((bx, by - 8), p, self._bd.hdt.value) else: # Kein Heading, Boot immer zeichnen boat = p ctx.move_to(*boat[0]) for point in boat[1:]: ctx.line_to(*point) ctx.stroke() # Windpfeil zeichnen if self._bd.awa.value: p = ((cx, cy - r + 25), (cx - 12, cy - r - 4), (cx, cy - r + 6), (cx + 12, cy - r - 4), (cx, cy - r + 25)) wind = self.rotate((cx, cy), p, self._bd.awa.value) ctx.move_to(*wind[0]) for point in wind[1:]: ctx.line_to(*point) ctx.fill() def draw_config(self, ctx): ctx.select_font_face("Ubuntu", cairo.FontSlant.NORMAL, cairo.FontWeight.BOLD) ctx.set_font_size(20) 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]) ctx.stroke() ctx.restore() def draw(self, ctx): if self.mode == 'N': self.draw_normal(ctx) else: self.draw_config(ctx)