OBP60v/pages/page.py

234 lines
7.6 KiB
Python

"""
Basisklasse für alle Darstellungsseiten
Hinweise zu Cairo:
Das Koordinatensystem geht von (0, 0) links oben bis (400, 300) rechts unten.
Um exakte Pixel zu treffen müssen Koordinaten mit Offset 0.5 verwendet werden.
"""
import os
import cairo
import math
from datetime import datetime
class Page():
pageno = 1 # Nummer der aktuell sichtbaren Seite
backlight = False
color_normal = "dcdcdc" # Standardhintergrund
color_lighted = "d89090" # Hintergrund im Nachtmodus
bgcolor = (0.86, 0.86, 0.86)
fgcolor = (0, 0, 0)
@staticmethod
def hexcolor(hexstr):
if (len(hexstr) != 6) or (not all(c.lower in '0123456789abcdef' for c in hexstr)):
raise ValueError('Not a valid RGB Hexstring')
else:
return(int(hexstr[0:2], 16) / 255.0,
int(hexstr[2:4], 16) / 255.0,
int(hexstr[4:6], 16) / 255.0)
@staticmethod
def rotate (origin, points, angle):
# operates on tuples, angle in degrees
ox, oy = origin
phi = math.radians(angle)
fs = math.sin(phi)
fc = math.cos(phi)
rotated = []
for x, y in points:
dx = x - ox
dy = y - oy
rotated.append((ox + fc * dx - fs * dy, oy + fs * dx + fc * dy))
return rotated
def __init__(self, pageno, cfg, boatdata):
self.pageno = pageno
self.cfg = cfg
self.bd = boatdata
self.header = True
self.footer = True
self.hbled = False # Heartbeat LED
self.hbfreq = 1000 # Heartbeat Frequenz in ms
self.keylock = False
self.icon = {}
self.icon['PREV'] = cairo.ImageSurface.create_from_png(os.path.join(cfg['imgpath'], "arrow_l1.png"))
self.icon['NEXT'] = cairo.ImageSurface.create_from_png(os.path.join(cfg['imgpath'], "arrow_r1.png"))
self.icon['ILUM'] = cairo.ImageSurface.create_from_png(os.path.join(cfg['imgpath'], "lighton.png"))
self.sym_lock = cairo.ImageSurface.create_from_png(os.path.join(cfg['imgpath'], "lock.png"))
self.sym_swipe = cairo.ImageSurface.create_from_png(os.path.join(cfg['imgpath'], "swipe.png"))
self.buttonlabel = {
1: '',
2: '',
3: '#PREV',
4: '#NEXT',
5: '',
6: '#ILUM'
}
def handle_key(self, buttonid):
"""
Diese Methode sollte in der Detailseite überladen werden
"""
print(f"Button no. {buttonid} ignored")
return False
def heartbeat(self, ctx):
"""
Wie ausschalten bei Seitenwechsel?
"""
ctx.save()
if self.hbled:
ctx.set_source_rgb(0, 0, 0)
else:
ctx.set_source_rgb(0.86, 0.86, 0.86) # 0xdcdcdc
ctx.arc(210, 9, 6, 0, math.pi*2)
ctx.fill()
ctx.restore()
self.hbled = not self.hbled
def draw_header(self, ctx):
"""
Mögliche Zeichen für aktivierte Funktionen
AP - Accesspoint ist aktiv
WIFI - WIFI-Client
TCP
N2K - NMEA2000
183
USB
GPS - GPS Fix vorhanden
# TODO Umstellung auf Symbole je 16 Pixel zum Platz sparen
Neu: Nummer der aktiven Seite (1 - 10)
"""
ctx.select_font_face("Ubuntu", cairo.FontSlant.NORMAL, cairo.FontWeight.BOLD)
ctx.set_font_size(16)
ctx.move_to(0.5, 14.5)
ctx.show_text(f"N2K GPS")
ctx.stroke()
# Seitennummer neue Darstellung
ctx.set_line_width(1)
ctx.move_to(170.5, 1.5)
ctx.line_to(190.5, 1.5)
ctx.line_to(190.5, 16.5)
ctx.line_to(170.5, 16.5)
ctx.line_to(170.5, 1.5)
ctx.stroke()
self.draw_text_center(ctx, 180, 9.5, str(self.pageno))
# Tastenstatus
ctx.save()
if self.keylock:
ctx.set_source_surface(self.sym_lock, 150, 1)
else:
ctx.set_source_surface(self.sym_swipe, 150, 1)
ctx.paint()
ctx.restore()
# Heartbeat
self.heartbeat(ctx)
# Datum und Uhrzeit
ctx.move_to(230, 14.5)
ctx.show_text(datetime.today().strftime('%H:%M %Y-%m-%d LOT'))
ctx.stroke()
def draw_footer(self, ctx):
"""
Nur Belegung der Buttons (label[1] bis label[6])
"""
ctx.select_font_face("AtariST8x16SystemFont")
#ctx.select_font_face("Ubuntu", cairo.FontSlant.NORMAL, cairo.FontWeight.BOLD)
ctx.set_font_size(16)
x = (35, 101, 167, 233, 299, 365)
y = 294
for i in range(6):
if len(self.buttonlabel[i+1]) > 0 :
if self.buttonlabel[i+1][0] == "#":
# Symbol verwenden 16x16 Pixel
ctx.save()
key = self.buttonlabel[i+1][1:]
ctx.set_source_surface(self.icon[key], x[i]-8, y-13)
ctx.paint()
ctx.restore()
else:
text = "[ {} ]".format(self.buttonlabel[i+1])
w = ctx.text_extents(text).width
ctx.move_to(x[i] - w/2, y)
ctx.show_text(text)
ctx.stroke()
def clear(self):
ctx.set_source_rgb(1, 1, 1)
ctx.rectangle(0, 0, 399, 299)
ctx.fill()
ctx.set_source_rgb(0, 0, 0)
def draw_text_center(self, ctx, x, y, content, rotate=False, baseline=False, fill=False, fix1=False):
"""
Korrektur für DSEG7: Die Breite der 1 ist gleich 0.289 * Breite der anderen Ziffern
Da der Leerraum bei der Ausgabe mit berücksichtigt wird, muß die tatsächliche
Ausgabeposition links von der Mitte sein um (1 - 0.289) * Breite (=0.711)
Zusätzlich muß der Abstand zwischen der 1 und dem nachfolgenden Zeichen berücksichtigt
werden
"""
if fix1 and content[0] == '1':
print("Fix1")
ext1 = ctx.text_extents('1')
w1 = 0.289 * ext1.width
dx = ext1.width - w1
ext = ctx.text_extents(content[1:])
else:
ext = ctx.text_extents(content)
if fill:
ctx.set_source_rgb(*self.bgcolor)
xf = x + ext.x_bearing - 2
yf = y + ext.height / 2 + ext.y_bearing - 2
wf = ext.width + 4
if fix1:
wf += w1
hf = ext.height + 4
ctx.rectangle(xf, yf, wf, hf)
ctx.fill()
ctx.set_source_rgb(*self.fgcolor)
if rotate:
w = ext[2]
if fix1 and content[0] == '1':
w += w1
x = x - dx
if baseline:
ctx.move_to(x - w / 2.0, y)
else:
ctx.move_to(x - w / 2.0, y + ext[2] / 2.0)
ctx.save()
ctx.rotate(1.5 * math.pi)
ctx.show_text(content)
ctx.restore()
else:
w = ext.width
if fix1 and content[0] == '1':
w += w1
x = x - dx
if baseline:
ctx.move_to(x - w / 2.0, y)
else:
ctx.move_to(x - w / 2.0, y + ext[3] / 2.0)
ctx.show_text(content)
ctx.stroke()
def draw_text_ralign(self, ctx, x, y, content, fix1=False):
if fix1 and content[0] == '1':
w1 = ctx.text_extents('1')[2] * 0.289
ext = ctx.text_extents(content[1:])
w = ext[2] + w1
x = x - dx
else:
ext = ctx.text_extents(content)
w = ext[2]
ctx.move_to(x - w, y)
ctx.show_text(content)
ctx.stroke()