From b15f0545c7fccdff3f03f62a130d5a5b8ee4115c Mon Sep 17 00:00:00 2001 From: Sam Korn Date: Wed, 2 Mar 2022 15:20:39 -0700 Subject: [PATCH] touchscreen! --- docs/emulator_setup.md | 10 + docs/touchscreen_setup.md | 295 ++++++++++++++++++++ requirements.txt | 8 +- src/main.py | 10 +- src/seedsigner/controller.py | 34 ++- src/seedsigner/helpers/ST7789.py | 4 +- src/seedsigner/helpers/buttons.py | 132 ++++++--- src/seedsigner/helpers/pivideostream.py | 8 +- src/seedsigner/helpers/touchscreen.py | 218 +++++++++++++++ src/seedsigner/resources/arrow.png | Bin 0 -> 1084 bytes src/seedsigner/resources/buttons/DOWN.png | Bin 0 -> 3886 bytes src/seedsigner/resources/buttons/K1.png | Bin 0 -> 1527 bytes src/seedsigner/resources/buttons/K2.png | Bin 0 -> 1929 bytes src/seedsigner/resources/buttons/K3.png | Bin 0 -> 2131 bytes src/seedsigner/resources/buttons/LL.png | Bin 0 -> 847 bytes src/seedsigner/resources/buttons/RR.png | Bin 0 -> 1496 bytes src/seedsigner/resources/buttons/SELECT.png | Bin 0 -> 2822 bytes src/seedsigner/resources/buttons/UP.png | Bin 0 -> 1753 bytes src/seedsigner/views/menu_view.py | 9 +- src/seedsigner/views/screensaver.py | 20 +- src/seedsigner/views/seed_tools_view.py | 4 +- src/seedsigner/views/settings_tools_view.py | 4 +- src/seedsigner/views/view.py | 19 +- 23 files changed, 701 insertions(+), 74 deletions(-) create mode 100644 docs/emulator_setup.md create mode 100644 docs/touchscreen_setup.md create mode 100644 src/seedsigner/helpers/touchscreen.py create mode 100644 src/seedsigner/resources/arrow.png create mode 100644 src/seedsigner/resources/buttons/DOWN.png create mode 100644 src/seedsigner/resources/buttons/K1.png create mode 100644 src/seedsigner/resources/buttons/K2.png create mode 100644 src/seedsigner/resources/buttons/K3.png create mode 100644 src/seedsigner/resources/buttons/LL.png create mode 100644 src/seedsigner/resources/buttons/RR.png create mode 100644 src/seedsigner/resources/buttons/SELECT.png create mode 100644 src/seedsigner/resources/buttons/UP.png diff --git a/docs/emulator_setup.md b/docs/emulator_setup.md new file mode 100644 index 00000000..66883dca --- /dev/null +++ b/docs/emulator_setup.md @@ -0,0 +1,10 @@ +# Emulator Setup + +## Create/Enter virtualenv +mkvirtualenv seedsigner-gui + +## Pip installs +pip install -r requirements.txt + +## Install Tkinter +sudo apt install python3-tk diff --git a/docs/touchscreen_setup.md b/docs/touchscreen_setup.md new file mode 100644 index 00000000..d162b7eb --- /dev/null +++ b/docs/touchscreen_setup.md @@ -0,0 +1,295 @@ +# Initial Pi Setup +touch /media/skorn/boot/ssh + +nano /media/skorn/boot/wpa_supplicant.conf +``` +country=us +update_config=1 +ctrl_interface=/var/run/wpa_supplicant + +network={ + scan_ssid=1 + ssid="MyNetworkSSID" + psk="Pa55w0rd1234" +} +``` + +https://wirelessthings.io/index.php/2021/05/01/720x720-lcd-screen-using-dpi-on-raspberry-pi-4/ + + + +Download and extract overlay files: +https://www.waveshare.com/wiki/File:28DPIB_DTBO.zip + +copy files to /media/user/boot/overlays +cp ~/Downloads/28DPI_DTBO/waveshare-28dpi-* /media/skorn/boot/overlays + + + +```bash +nano /media/skorn/boot/config.txt +``` + +``` +# Update existing +#dtoverlay=vc4-kms-v3d +dtparam=i2c_arm=on +dtparam=i2s=on +dtparam=spi=on + +# Add new +gpio=0-9=a2 +gpio=12-17=a2 +gpio=20-25=a2 +dtoverlay=dpi24 +enable_dpi_lcd=1 +display_default_lcd=1 +extra_transpose_buffer=2 +dpi_group=2 +dpi_mode=87 +dpi_output_format=0x7F216 +hdmi_timings=480 0 26 16 10 640 0 25 10 15 0 0 0 60 0 32000000 1 +dtoverlay=waveshare-28dpi-3b-4b +dtoverlay=waveshare-28dpi-3b +dtoverlay=waveshare-28dpi-4b +display_rotate=1 +``` + + +sudo raspi-config + +set to boot to desktop +set screen resolution: DMT 4 480 x 640 +expand filesystem + + +# rotate display +sudo apt install xserver-xorg-input-libinput +sudo mkdir /etc/X11/xorg.conf.d +sudo cp /usr/share/X11/xorg.conf.d/40-libinput.conf /etc/X11/xorg.conf.d/ +sudo nano /etc/X11/xorg.conf.d/40-libinput.conf +``` +# add to touchscreen section +Option "CalibrationMatrix" "0 1 0 -1 0 1 0 0 1" +``` + +# current seedsigner application installs +sudo apt-get update && sudo apt-get install -y \ +python3-pip \ +python-pil \ +libopenjp2-7 \ +git \ +libatlas-base-dev \ +qrencode \ +python3-opencv \ +python3-numpy \ +python3-picamera + +sudo apt-get update && sudo apt-get install -y wiringpi python3-pip \ + python3-numpy python-pil libopenjp2-7 git python3-opencv \ + python3-picamera libatlas-base-dev qrencode + + +apt-get install python-tk + +sudo apt install imagemagick + + +pip install pillow tk pyautogui + + +sudo apt-get install -y python3-pip \ + python3-numpy libopenjp2-7 git python3-opencv \ + python3-picamera libatlas-base-dev qrencode + + +# Tkinter +sudo apt install python3-tk + +# OPENBOX +sudo apt install openbox xinit lightdm + + +To run Openbox from the commandline, setup the .xinitrc file in your home directory and insert the following line: + +exec openbox-session + + +application startup config +/etc/xdg/openbox/autostart +``` +. /home/pi/env/bin/activate +cd /home/pi/seedsigner/src +nohup python3 main.py > /home/pi/seedsigner.log & +``` + + +# Lightdm +sudo apt install lightdm + +https://gist.github.com/kuanyui/2972b15639e78940cd1349844ca0e4fc + +sudo nano /etc/lightdm/lightdm.conf +``` +start-default-seat=true +autologin-user=pi +autologin-user-timeout=0 +autologin-session=openbox +``` + +# ENV Vars +export DISPLAY=:0.0 +export NOTAPI=true + +# TKINTER Examples +https://tkdocs.com/tutorial/eventloop.html +https://python-textbok.readthedocs.io/en/1.0/Introduction_to_GUI_Programming.html +https://www.journaldev.com/48165/tkinter-working-with-classes + +``` +from PIL import Image +i = Image.open("cube.png") +i.show() +``` + +``` +import tkinter as tk +from PIL import Image, ImageTk + +def callback(event): + print("clicked at", event.x, event.y) + +window = tk.Tk() +window.attributes('-fullscreen',True) + + +x = window.winfo_pointerx() +y = window.winfo_pointery() + + + +window.bind("", callback) + + +imagefile2 = "../../cube.png" +imgpil2 = Image.open(imagefile) +img2 = ImageTk.PhotoImage(imgpil) + +imagefile = "seedsigner/resources/logo_black_240.png" +imgpil = Image.open(imagefile) +img = ImageTk.PhotoImage(imgpil) + +#lbl = tk.Label(window, image = img).pack() +frame = tk.Label(window) +frame.configure(image=img) +frame.place(x=333,y=233) + +lbl.configure(image=img2) + +def button_press_move(): + frame.place(x=random.randint(0,640), y=random.randint(0,480)) + +btn_KEY_UP = tk.Button(window, text="KEY1") +btn_KEY_UP.place(x=50, y=50) +btn_KEY_UP.configure(width=10,height=4) +btn_KEY_UP.configure(command=button_press_move) + + +myglobal = None +myglobal1 = None + + +def press(event): + print(event.state) + print(dir(event)) + global myglobal + myglobal1 = event + +def release(event): + print(event.state) + print(dir(event)) + global myglobal1 + myglobal1 = event + +btn_KEY_UP.bind("", press) +btn_KEY_UP.bind("", release) + +window.mainloop() +``` + +``` +w = tk.Canvas(window, width=240, height=240, bg="green").pack() +``` + + +``` +from queue import Queue +from seedsigner.helpers import touchscreen +import tkinter as tk +from PIL import Image, ImageTk +import threading + +a = Queue() +sq = touchscreen.touchscreen(a) +sq.Init() + +import random +from time import sleep + +def showimages(): + while True: + print("looping images") + imagefile2 = "../../cube.png" + imgpil2 = Image.open(imagefile2) + a.put((imgpil2, random.randint(0,400), random.randint(0,400))) + sleep(0.1) + +x = threading.Thread(target=showimages) +x.start() + + + +img2 = ImageTk.PhotoImage(imgpil) +``` + + +``` +import tkinter as tk +import threading +import signal +import sys + + +class MyTkApp(object): + def poll(self): + sys.stderr.write("poll\n") + self.root.after(500, self.poll) + def quit(self, event): + print("you pressed control c") + self.root.quit() + def run(self): + self.root = tk.Tk() + self.root.after(500, self.poll) + self.root.bind('', self.quit) + self.root.mainloop() + + +app = MyTkApp() +app.start() + +import time + +while app.is_alive(): + try: + time.sleep(0.5) + except KeyboardInterrupt: + app.root.destroy() + break +``` + + +``` +from queue import Queue +from seedsigner.helpers import touchscreen + +``` \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index f24a8e7e..8fa58fd9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,10 +1,12 @@ embit==0.4.10 numpy==1.21.1 -picamera==1.13 +# need to not install this on x86... +#picamera==1.13 Pillow==8.2.0 -e git+https://github.com/kdmukai/pyzbar.git@c3c237821c6a20b17953efe59b90df0b514a1c03#egg=pyzbar qrcode==7.3.1 -RPi.GPIO==0.7.0 +#RPi.GPIO==0.7.1 six==1.16.0 spidev==3.5 --e src/vendor/urtypes \ No newline at end of file +urtypes @ git+https://github.com/jreesun/urtypes.git@e0d0db277ec2339650343eaf7b220fffb9233241 +#-e src/vendor/urtypes diff --git a/src/main.py b/src/main.py index deb8df17..d8152fe0 100644 --- a/src/main.py +++ b/src/main.py @@ -2,15 +2,21 @@ import configparser import sys import time -from seedsigner.controller import Controller +import threading +from seedsigner.controller import Controller +from seedsigner.helpers import touchscreen config = configparser.ConfigParser() config.read("settings.ini") # One-time setup to intialize the one and only Controller +# Controller.configure_instance(config, disable_hardware=True) Controller.configure_instance(config) # Get the one and only Controller instance and start our main loop controller = Controller.get_instance() -controller.start() +x = threading.Thread(target=controller.start) +x.start() +controller.disp.mainloop() +# controller.start() diff --git a/src/seedsigner/controller.py b/src/seedsigner/controller.py index ab238d2b..a41f7d0b 100644 --- a/src/seedsigner/controller.py +++ b/src/seedsigner/controller.py @@ -9,6 +9,7 @@ from embit.networks import NETWORKS from embit.descriptor import Descriptor from binascii import hexlify from threading import Thread +from queue import Queue # Internal file class dependencies from .views import (View, MenuView, SeedToolsView,SigningToolsView, @@ -16,6 +17,8 @@ from .views import (View, MenuView, SeedToolsView,SigningToolsView, from .helpers import Buttons, B, Path, Singleton from .models import (EncodeQRDensity, QRType, Seed, SeedStorage, Settings, DecodeQR, DecodeQRStatus, EncodeQR, PSBTParser) +from seedsigner.helpers import touchscreen + class Controller(Singleton): """ The Controller is a globally available singleton that maintains SeedSigner state. @@ -65,11 +68,19 @@ class Controller(Singleton): controller = cls.__new__(cls) cls._instance = controller + controller.q = Queue() + print("init display") + controller.disp = touchscreen.touchscreen(controller.q) + controller.disp.Init() + + + # Input Buttons if disable_hardware: + print("disabling the buttons for now") controller.buttons = None else: - controller.buttons = Buttons() + controller.buttons = Buttons(controller.disp) # models controller.storage = SeedStorage() @@ -81,25 +92,28 @@ class Controller(Singleton): controller.color = controller.settings.text_color controller.current_bg_qr_color = controller.settings.qr_background_color + + # Views - controller.menu_view = MenuView() - controller.seed_tools_view = SeedToolsView() - controller.io_test_view = IOTestView() - controller.signing_tools_view = SigningToolsView(controller.storage) - controller.settings_tools_view = SettingsToolsView() - controller.screensaver = ScreensaverView(controller.buttons) + controller.menu_view = MenuView(controller.disp, controller.q) + controller.seed_tools_view = SeedToolsView(controller.disp, controller.q) + # controller.io_test_view = IOTestView() + # controller.signing_tools_view = SigningToolsView(controller.storage) + controller.settings_tools_view = SettingsToolsView(controller.disp, controller.q) + controller.screensaver = ScreensaverView(controller.buttons, controller.disp, controller.q) controller.screensaver_activation_ms = 120 * 1000 @property def camera(self): - from .camera import Camera - return Camera.get_instance() + if not os.getenv("NOTAPI", False): + from .camera import Camera + return Camera.get_instance() def start(self) -> None: - opening_splash = OpeningSplashView() + opening_splash = OpeningSplashView(self.disp, self.q) opening_splash.start() if self.DEBUG: diff --git a/src/seedsigner/helpers/ST7789.py b/src/seedsigner/helpers/ST7789.py index 8f8de657..af38a9f3 100644 --- a/src/seedsigner/helpers/ST7789.py +++ b/src/seedsigner/helpers/ST7789.py @@ -1,5 +1,7 @@ import spidev -import RPi.GPIO as GPIO +import os +if not os.getenv("NOTAPI", False): + import RPi.GPIO as GPIO import time import numpy as np diff --git a/src/seedsigner/helpers/buttons.py b/src/seedsigner/helpers/buttons.py index 3956a5b0..5b478f3c 100644 --- a/src/seedsigner/helpers/buttons.py +++ b/src/seedsigner/helpers/buttons.py @@ -1,7 +1,9 @@ -import RPi.GPIO as GPIO + import time - +import os +if not os.getenv("NOTAPI", False): + import RPi.GPIO as GPIO class Buttons: KEY_UP_PIN = 6 @@ -14,22 +16,34 @@ class Buttons: KEY2_PIN = 20 KEY3_PIN = 16 - def __init__(self) -> None: + def __init__(self, disp) -> None: #init GPIO - GPIO.setmode(GPIO.BCM) - GPIO.setup(Buttons.KEY_UP_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up - GPIO.setup(Buttons.KEY_DOWN_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up - GPIO.setup(Buttons.KEY_LEFT_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up - GPIO.setup(Buttons.KEY_RIGHT_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up - GPIO.setup(Buttons.KEY_PRESS_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up - GPIO.setup(Buttons.KEY1_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up - GPIO.setup(Buttons.KEY2_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up - GPIO.setup(Buttons.KEY3_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up + # GPIO.setmode(GPIO.BCM) + # GPIO.setup(Buttons.KEY_UP_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up + # GPIO.setup(Buttons.KEY_DOWN_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up + # GPIO.setup(Buttons.KEY_LEFT_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up + # GPIO.setup(Buttons.KEY_RIGHT_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up + # GPIO.setup(Buttons.KEY_PRESS_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up + # GPIO.setup(Buttons.KEY1_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up + # GPIO.setup(Buttons.KEY2_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up + # GPIO.setup(Buttons.KEY3_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up - self.GPIO = GPIO + self.disp = disp + + + # self.GPIO = GPIO self.override_ind = False - self.add_events([B.KEY_UP, B.KEY_DOWN, B.KEY_PRESS, B.KEY_LEFT, B.KEY_RIGHT, B.KEY1, B.KEY2, B.KEY3]) + self.add_events([ + B.KEY_UP, + B.KEY_DOWN, + B.KEY_PRESS, + B.KEY_LEFT, + B.KEY_RIGHT, + B.KEY1, + B.KEY2, + B.KEY3 + ]) # Track state over time so we can apply input delays/ignores as needed self.cur_input = None # Track which direction or button was last pressed @@ -39,7 +53,10 @@ class Buttons: self.next_repeat_threshold = 250 # Amount of time where we no longer consider input a continuous hold + + def wait_for(self, keys=[], check_release=True, release_keys=[]) -> int: + print("wait_for") # TODO: Refactor to keep control in the Controller and not here from seedsigner.controller import Controller controller = Controller.get_instance() @@ -48,27 +65,47 @@ class Buttons: release_keys = keys self.override_ind = False + x = 0 + counter = 0 while True: + counter += 1 cur_time = int(time.time() * 1000) - if cur_time - self.last_input_time > controller.screensaver_activation_ms and not controller.screensaver.is_running: - # Start the screensaver. Will block execution until input detected. - controller.start_screensaver() + # DONT WORRY ABOUT SCREENSAVER FOR NOW + # if cur_time - self.last_input_time > controller.screensaver_activation_ms and not controller.screensaver.is_running: + # # Start the screensaver. Will block execution until input detected. + # controller.start_screensaver() - # We're back. Update last_input_time to now. - self.update_last_input_time() + # # We're back. Update last_input_time to now. + # self.update_last_input_time() - # Freeze any further processing for a moment to avoid having the wakeup - # input register in the resumed UI. - time.sleep(self.next_repeat_threshold / 1000.0) + # # Freeze any further processing for a moment to avoid having the wakeup + # # input register in the resumed UI. + # time.sleep(self.next_repeat_threshold / 1000.0) - # Resume from a fresh loop - continue + # # Resume from a fresh loop + # continue + + # x += 1 + # # if x == 10: + # # self.window.update() + if counter == 1000: + counter = 0 + print(f"lock status: {B.release_lock}") for key in keys: - if not check_release or ((check_release and key in release_keys and B.release_lock) or check_release and key not in release_keys): + # self.window.update() + # print(f"looking for key: {key}") + # if self.disp.button_state[key] == True: + # return key + # time.sleep(0.1) + + if not check_release or \ + ((check_release and key in release_keys and B.release_lock) or check_release and key not in release_keys): # when check release is False or the release lock is released (True) - if self.GPIO.input(key) == GPIO.LOW or self.override_ind: + if self.disp.button_state[key] == False or self.override_ind: B.release_lock = False + print("setting lock") + print if self.override_ind: self.override_ind = False return B.OVERRIDE @@ -77,6 +114,7 @@ class Buttons: self.cur_input = key self.cur_input_started = int(time.time() * 1000) # in milliseconds self.last_input_time = self.cur_input_started + print(f"new key press: {key}") return key else: @@ -86,12 +124,14 @@ class Buttons: # continuous input. Treat as a new separate press. self.cur_input_started = cur_time self.last_input_time = cur_time + print(f"still pressing: {key}") return key elif cur_time - self.cur_input_started > self.first_repeat_threshold: # We're good to relay this immediately as continuous # input. self.last_input_time = cur_time + print(f"continuous press: {key}") return key else: @@ -110,13 +150,17 @@ class Buttons: time.sleep(0.01) # wait 10 ms to give CPU chance to do other things + def lock_input(self, lock): + pass + def update_last_input_time(self): self.last_input_time = int(time.time() * 1000) def add_events(self, keys=[]): - for key in keys: - GPIO.add_event_detect(key, self.GPIO.RISING, callback=Buttons.rising_callback) + pass + # for key in keys: + # GPIO.add_event_detect(key, self.GPIO.RISING, callback=Buttons.rising_callback) def rising_callback(channel): @@ -137,7 +181,7 @@ class Buttons: return True def check_for_low(self, key) -> bool: - if self.GPIO.input(key) == self.GPIO.LOW: + if self.disp.button_state[key] == False: self.update_last_input_time() return True else: @@ -145,7 +189,7 @@ class Buttons: def has_any_input(self) -> bool: for key in B.ALL_KEYS: - if self.GPIO.input(key) == GPIO.LOW: + if self.disp.button_state[key] == False: return True return False @@ -156,14 +200,26 @@ class Buttons: # TODO: Implement `release_lock` functionality as a global somewhere. Mixes up design # patterns to have a static constants class plus a settable global value. class B: - KEY_UP = 6 - KEY_DOWN = 19 - KEY_LEFT = 5 - KEY_RIGHT = 26 - KEY_PRESS = 13 - KEY1 = 21 - KEY2 = 20 - KEY3 = 16 + # KEY_UP = 6 + # KEY_DOWN = 19 + # KEY_LEFT = 5 + # KEY_RIGHT = 26 + # KEY_PRESS = 13 + # KEY1 = 21 + # KEY2 = 20 + # KEY3 = 16 + + KEY_UP = "UP" + KEY_DOWN = "DOWN" + KEY_LEFT = "LL" + KEY_RIGHT = "RR" + KEY_PRESS = "PRESS" + KEY1 = "KEY1" + KEY2 = "KEY2" + KEY3 = "KEY3" + # KEY1 = "K1" + # KEY2 = "K2" + # KEY3 = "K3" OVERRIDE = 1000 ALL_KEYS = [ diff --git a/src/seedsigner/helpers/pivideostream.py b/src/seedsigner/helpers/pivideostream.py index cb3031b3..486dc848 100644 --- a/src/seedsigner/helpers/pivideostream.py +++ b/src/seedsigner/helpers/pivideostream.py @@ -1,6 +1,8 @@ -# import the necessary packages -from picamera.array import PiRGBArray -from picamera import PiCamera +import os +if not os.getenv("NOTAPI", False): + # import the necessary packages + from picamera.array import PiRGBArray + from picamera import PiCamera from threading import Thread import time diff --git a/src/seedsigner/helpers/touchscreen.py b/src/seedsigner/helpers/touchscreen.py new file mode 100644 index 00000000..5ca12dff --- /dev/null +++ b/src/seedsigner/helpers/touchscreen.py @@ -0,0 +1,218 @@ +from pathlib import Path +from time import sleep +from threading import Thread +import os + +import tkinter as tk +from tkinter import ttk +from PIL import Image, ImageTk +import tkinter.font as font +# myFont = font.Font(family='Helvetica') + +from pprint import pprint + +from .buttons import B + + +class touchscreen(tk.Tk): + def __init__(self, q): + super().__init__() + # Thread.__init__(self) + print("inside touchscreen _init_") + # self.window = tk.Tk() + # self.window.attributes('-fullscreen', True) + self.config(cursor="circle") + self.latest_img = None + self.q = q + sleep(1) + self.title('SeedSigner') + if not os.getenv("NOTAPI", False): + self.attributes("-fullscreen", True) + else: + self.geometry("640x480") + + self.myFont = font.Font(family='Helvetica', size=35, weight='bold') + self.myFont2 = font.Font(family='Helvetica', size=20, weight='bold') + + # self.img_path = Path("/home/pi/seedsigner/src/seedsigner/resources") + + self.img_path = Path("seedsigner/resources") + + + def Init(self): + """Initialize display""" + print("inside Init") + + self.button_state = { + "UP": True, + "DOWN": True, + "LL": True, + "RR": True, + "PRESS": True, + "KEY1": True, + "KEY2": True, + "KEY3": True + } + + self.style = ttk.Style() + self.style.theme_use("clam") + self.style.configure('TButton', font=('Helvetica', 20)) + + self.btn_right = Image.open(self.img_path.joinpath("buttons/RR.png")) + self.btn_up = Image.open(self.img_path.joinpath("buttons/UP.png")) + self.btn_left = Image.open(self.img_path.joinpath("buttons/LL.png")) + self.btn_down = Image.open(self.img_path.joinpath("buttons/DOWN.png")) + self.btn_select = Image.open(self.img_path.joinpath("buttons/SELECT.png")) + self.btn_k1 = Image.open(self.img_path.joinpath("buttons/K1.png")) + self.btn_k2 = Image.open(self.img_path.joinpath("buttons/K2.png")) + self.btn_k3 = Image.open(self.img_path.joinpath("buttons/K3.png")) + + self.btn_right_tk = ImageTk.PhotoImage(self.btn_right) + self.btn_up_tk = ImageTk.PhotoImage(self.btn_up) + self.btn_left_tk = ImageTk.PhotoImage(self.btn_left) + self.btn_down_tk = ImageTk.PhotoImage(self.btn_down) + self.btn_select_tk = ImageTk.PhotoImage(self.btn_select) + self.btn_k1_tk = ImageTk.PhotoImage(self.btn_k1) + self.btn_k2_tk = ImageTk.PhotoImage(self.btn_k2) + self.btn_k3_tk = ImageTk.PhotoImage(self.btn_k3) + + + self.label = tk.Label(self) + self.label.place(x=160, y=0) + + self.btn_KEY_PRESS = tk.Button(self, text="PRESS", image=self.btn_select_tk) + self.btn_KEY_PRESS.place(x=160,y=400) + # self.btn_KEY_PRESS.configure(ipady=10, ipadx=10) + # self.btn_KEY_PRESS.configure(width=30, height=5) + + self.btn_KEY_UP = tk.Button(self, text="UP", image=self.btn_up_tk) + self.btn_KEY_UP.place(x=0,y=0) + # self.btn_KEY_UP.configure(width=5, height=5) + + self.btn_KEY_DOWN = tk.Button(self, text="DOWN", image=self.btn_down_tk) + self.btn_KEY_DOWN.place(x=0,y=320) + # self.btn_KEY_DOWN.configure(width=5, height=5) + + self.btn_KEY_LEFT = tk.Button(self, text="LL", image=self.btn_left_tk) + self.btn_KEY_LEFT.place(x=0,y=160) + # self.btn_KEY_LEFT.configure(width=5, height=5) + + self.btn_KEY_RIGHT = tk.Button(self, text="RR", image=self.btn_right_tk) + self.btn_KEY_RIGHT.place(x=80,y=160) + # self.btn_KEY_RIGHT.configure(width=5, height=5) + + self.btn_KEY_1 = tk.Button(self, text="KEY1", image=self.btn_k1_tk) + self.btn_KEY_1.place(x=560, y=0) + # self.btn_KEY_1.configure(width=5, height=5) + + self.btn_KEY_2 = tk.Button(self, text="KEY2", image=self.btn_k2_tk) + self.btn_KEY_2.place(x=560, y=160) + # self.btn_KEY_2.configure(width=5, height=5) + + self.btn_KEY_3 = tk.Button(self, text="KEY3", image=self.btn_k3_tk) + self.btn_KEY_3.place(x=560, y=320) + # self.btn_KEY_3.configure(width=5, height=5) + + self.btn_KEY_UP.bind("", self.update_button_state) + self.btn_KEY_DOWN.bind("", self.update_button_state) + self.btn_KEY_PRESS.bind("", self.update_button_state) + self.btn_KEY_LEFT.bind("", self.update_button_state) + self.btn_KEY_RIGHT.bind("", self.update_button_state) + self.btn_KEY_1.bind("", self.update_button_state) + self.btn_KEY_2.bind("", self.update_button_state) + self.btn_KEY_3.bind("", self.update_button_state) + + + # self.btn_KEY_UP.bind("", self.update_button_state) + # self.btn_KEY_DOWN.bind("", self.update_button_state) + # self.btn_KEY_PRESS.bind("", self.update_button_state) + # self.btn_KEY_LEFT.bind("", self.update_button_state) + # self.btn_KEY_RIGHT.bind("", self.update_button_state) + # self.btn_KEY_1.bind("", self.update_button_state) + # self.btn_KEY_2.bind("", self.update_button_state) + # self.btn_KEY_3.bind("", self.update_button_state) + + + self.refresh() + # self.mainloop() + + def run(self): + self.window = tk.Tk() + self.window.attributes('-fullscreen', True) + + + + # self.btn_KEY_LEFT = tk.Button(self.window, text="LL") + # self.btn_KEY_RIGHT = tk.Button(self.window, text="RR") + + # self.btn_KEY_1 = tk.Button(self.window, text="KEY1") + # self.btn_KEY_2 = tk.Button(self.window, text="KEY2") + # self.btn_KEY_3 = tk.Button(self.window, text="KEY3") + + + # while True: + # r = self.q.get() + # print(r) + # self.ShowImage(r[0],r[1],r[2]) + # self.window.update() + # sleep(0.05) + + self.refresh() + print("after refresh") + self.mainloop() + + def refresh(self): + self.draw() + self.after(2, self.refresh) + + def draw(self): + try: + data = self.q.get(timeout=0.25) + print("got data") + self.ShowImage(*data) + except Exception as e: + pass + + def update_button_state(self, event): + button_name = event.widget.cget("text") + event_type = event.type.value + set_value = None + # 4 is press, 5 is release + # Active HIGH + # set_value = True if event_type == "4" else False + # Active LOW + set_value = False if event_type == "4" else True + + # if set_value == True: + # print("releasing lock") + # B.release_lock = True + + print(f"Setting button {button_name} to {set_value}\n") + self.button_state[button_name] = set_value + pprint(self.button_state) + self.after(5, self.reset_press, button_name, True) + + def reset_press(self, button_name, button_value): + self.button_state[button_name] = button_value + print("releasing lock") + B.release_lock = True + + def ShowImage(self, Image, Xstart, Ystart): + """Set buffer to value of Python Imaging Library image.""" + """Write display buffer to physical display""" + print("inside ShowImage") + + Image = Image.resize(size=(400,400)) + img = ImageTk.PhotoImage(Image) + self.latest_img = img + + + self.label["image"] = self.latest_img + # self.label.place(x=Xstart, y=Ystart) + # sleep(1) + print("updated") + + + def reset(self): + """Reset the display""" + print("DO SOMETHING!") \ No newline at end of file diff --git a/src/seedsigner/resources/arrow.png b/src/seedsigner/resources/arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..62c5fba392ed662ffa6f6d23806d86aee8fbdbee GIT binary patch literal 1084 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 literal 0 HcmV?d00001 diff --git a/src/seedsigner/resources/buttons/K1.png b/src/seedsigner/resources/buttons/K1.png new file mode 100644 index 0000000000000000000000000000000000000000..cb52271fecb59d226ae71c3d74f5134da5fc3b41 GIT binary patch literal 1527 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 literal 0 HcmV?d00001 diff --git a/src/seedsigner/resources/buttons/K3.png b/src/seedsigner/resources/buttons/K3.png new file mode 100644 index 0000000000000000000000000000000000000000..3edbe4f905bfce959304c3d6fe1798e8d8b4510f GIT binary patch literal 2131 zcmcIlX*d)L7oHhoH(4Ud(ils!MAC{Cj ziCsFawU>4U>2vL&Z)hf4g_qcKwDW++_3m~hFj}DVbh3xnYH&_o;#X#KN>+8)#m9d~ zZw!s(e<MdUxG(DVCB?^W^{-(|n{#4z+=K6dl1Q=OX5f;>ANxtrk^%f}YyLUCwd ze0QJme+)SCo;M}@s)XQ{b9Zh#Wk>-JXWF|%oNRuQKS<){P4XdA*#{a)hQM${NkBj7 zi4!I4BjZJV)+i^`+(j;coPfenu~TbO-#1p)8DG?29K`@$a|d-Cz^JaQvvAxr!=M4j zzk||Rp37pm1F;Ul0Kf&A-vEY}B0^atC&|Rzh;x|@#0C>~wHUy$C^3?eJqZ=y=jZ89 z0-%CC-AJAu&@ep72Z}K9IxH2jNGBEaT-qW(pTW23&+Qy7Po^3W3GIi4IX@8ZXdKx;aYAhfdYZtSS08Y zSQZN8?i092W;G}zNa!A!@BbJ8#eQ#qJ-Ap>LieOuQcMLSP1=>lYvM_A*7CY#+U?W~ zG^z2_f}&=pt=sUkPG~yJ*_D4^vcyMx1LfeYes^c4tSYwi@L;7}BlE-;l~^6CH*Y1v zD|Uum5Y>s~Xx@C8a~F-S#{TFxYMBUJe!!UZgQswA`qA(blIu~-vcN=2d&j_M?S;er zfKu@HV_Da;2{fG{T)7Top`cS;L~-4zg=3qKI}UCwOk{r2i5jtsobjgVtDgAX^zFU_K|3Z*Ax(UXKxSa?w0-FXnIJ z<<`f@VuQ+F-iv8J*avtf+ygf1u*1FJ)go8^wkl-+Lg+iKmS?5z`dQuLMx{_z(~ueQPAvS-^NJs#_Q z&cOPsa#NEV6$*x}k;+TqTm5Rv>4hR1`%%mnZylt_h4inBnMn~==kwy4$2(kGf}e0{ zRVyup8<+CzJ*t%ZU>xCu!oDNsax{(>B|~_Xt++aw;_*0%B1#30elSN97kkkQ$n>h4ma zrj8dDN6So^P>Wb(DU=5J=g#!jGNN1h`vH1IvW^}|XBQ6DG&lJrJ;m9x3fl^CoMUS` zy5uWUs}jr}GZZOUecI~-9Zu+Cpg-XFKPAk?00Mi)QyWwtBvozu8ju}I4Vo{UnNmOL zW`Z@Sx^OkfdMlcCgW2y@JSQ`(nm*}h%SUL~;i?}fN^iwmCRc6yTcdM((@GMGnbZ}~ zV?;FgTmhj6lLDPD-D|QJ^(;8DnUvnIZCdThlbPe%H=yg}HGIyh9^zrw`sf17(i~Pv zpL7lZ)$@9&|jf7Vw5^@EKMYGh7uFvD3#mpg1?mDz3uDn{TMn&a(lb2BP%rp|8B zHlKZ5O8iX9ZCw5C(~p`wg}vOxhG|o)T*{xsv+>xjn>Lq7+Evk>FY-6H+imyQOa-q? zzt2-PP$rZ8#%)gOmrtPEZ(1aE7u~jG+5~0UmD`#{{{YRzT5x+ literal 0 HcmV?d00001 diff --git a/src/seedsigner/resources/buttons/LL.png b/src/seedsigner/resources/buttons/LL.png new file mode 100644 index 0000000000000000000000000000000000000000..4dc41baf5771939fa01b9890bd91ab30a1df1f73 GIT binary patch literal 847 zcmeAS@N?(olHy`uVBq!ia0vp^0YJQfgAGW|ZhpOmfq}6l)7d$|)7e>}peR2rGbfdS zL1SX=L|c!;4l+mMgO@6awwDRK6j)*vDI!{UMN4F%(+bh3QiGj!PLtbIjvfsx(6#un zF`~4f@Y>abp#m)S4l;A+h{P^A@?W)8%ur6|`{TQNkKeU+$OxH{Ro2VADot{wOU#*+ z@S_K`SzH7TNwlS;y(*qGrRDjLUG4qr%MIr}t$la?;`GzAc|LR=+3aJk^N9D+OJDEj zd;De6R4v_W{A{u=uy)GtT({%Tv7IkA956oYW@YLxqbAlZyQaiITT<(zNTJE{tSR~_ zG3N^JJz5i%wWien-=T!K=*VYQXE}r-jtHrA1Ozxsibix?Ts1LC$@O<3|NjM#r=M6l zVKt9iA8W`$r?Ni}>Obs`-fUp`P>uDm!}spodLHJ+*aeZ>-@Z@2oi~r+U-|>D?BA<- z6P``}QWf1T$N2a5fup6-!QUEA%O*VVoX&f5;vbV%C&mi<#rdb07Dg{9Kl^s=*8a=v z3cj(b`3=p^2}?X~zLtCc?&X`e_l?*7t7F*0S#`sfGiD}cMe#RT=Olqbk|nMYCC>S|xv6<249-QV zi6yBi3gww484B*6z5(HleB!|9R`+yq45_&F_U=aBCI^v*hwX8v1=P&jbr^ylL~QCl zr^xxnVfDejOHCRFpZwmf{Z2Ig-qrAs{?9T|cNrNS8W90Cg% zm{>Rh7#NvYG=K`2L{OFCQ2cJ+mtMu6GagsHn)dn2oJEqa@1EP*h-^HDzPylMM=uyn zEj;}_v|Qg=`tR!dCF^*0k~5*!3~H*VLzO3uHuNKUtJei|^`85lfW{an^L HB{Ts53oScG literal 0 HcmV?d00001 diff --git a/src/seedsigner/resources/buttons/RR.png b/src/seedsigner/resources/buttons/RR.png new file mode 100644 index 0000000000000000000000000000000000000000..6a1cb14e79204c371abe55126d48ef916cb093bd GIT binary patch literal 1496 zcmeAS@N?(olHy`uVBq!ia0vp^0YJQfgAGW|ZhpOmfq}6l)7d$|)7e>}peR2rGbfdS zL1SX=L|c!;4l+mMgO@6awwDRK6j)*vDI!{UMN4F%(+bh3QiGj!PLtbIjvfsx(6#un zF`~4f@Y>abp#m)S4l;A+h{P^A@?W)8%ur6|`{TQNkKeU+$OxH{Ro2VADot{wOU#*+ z@S_K`SzH7TNwlS;y(*qGrRDjLUG4qr%MIr}t$la?;`GzAc|LR=+3aJk^N9D+OJDEj zd;De6R4v_W{A{u=uy)GtT({%Tv7IkA956oYW@YLxqbAlZyQaiITT<(zNTJE{tSR~_ zG3N^JJz5i%wWien-=T!K=*VYQXE}r-jtHrA1Ozxsibix?Ts1LC$@O<3|NjM#r=M6l zVKt9iA8W`$r?Ni}>Obs`-fUp`P>uDm!}spodLHJ+*aeZ>-@Z@2oi~r+U-|>D?BA<- z6P``}QWf1T$N2a5fup6-!QUEA%O*VVoX&f5;vbV%C&mi<#rdb07Dg{9Kl^s=*8a=v z3cj(b`3=p^2}?X~zLtCc?&X`e_l?*7t7F*0S#`sfGiD}cMdh>itkwX9BuiW)N}Tg^b5rw57@Uhz z6H8K46v{J8G8EiBeFMT9`NSC*m^XO3IEGZ*dVAM5L!?~h*vItrw9TGp(yqUFW%j`P z$oJ{1)RotAg)VVfdSv#ZCXE#rlDFDcid^yjc)=_*yIWlM(dmU#y0-BqEx6vr6&Bc| z=H_cQ8;EM9`B|@DY+gHK=AXmgcb+}-&hEoQ^UwEh#@@K_O7{N_rS~%2Obm=H0uD?H z4Gc^k3_unGCy>RVzzAe9s(@GxEI<~^1O_0BK?q$j9wo_k=XTp{@6KB*`rDYjg zg0`0ghOlqze{tgFKg0XtH(2aEr(dm8UVnIb@U7wx3*}0m+8n=LcV|J$8KZ6IuLu7q zjE`*JSGg!?Ws&3hb=$6d3S4`!c3&KGewkS5_quDF^AFCETKu~v-bJpwzhYbR*FK;u zGvD)5`D-SregDZ95&U?qjz|np1^b+Djz>2C-LpQSWd8aF`Evy(*~`jB|NJhy_QLKy zgY@HR`)*C2lG`5l?)7W^7kB16yM6C{B{ZWWD$3w+;O9?KYoi3i|7w@BE#0(Q{=D5) zkBfKqeP@&CwaWUR`R#v%q_U zv0n1jdr{Pl5YxP0Zf`Ho@GMn4J74bFq@99mBPGL=Ki%IhEc`gJcH{QIb078oehNR= zvClzmL-~cPU!yB)%MBOn#+Lz&{Q4;(^v0!qvYw{C8++e={wrd4GlOgX`E>lsubu%bEC0?On z=A6~q>wS;5mGW}ke)g61+vUD(pP9Y*L+obHz7nwX?(A2+ueo^&c072s-F{E-$Cv8D zqJ?K(aeq1PdOuz&AbypR=*NhN>ZoM5udP4I!<*Hisha4tjFIp$lRH$&h5kJZdyY*H U@>s{64b0#Sp00i_>zopr0GiN~y#N3J literal 0 HcmV?d00001 diff --git a/src/seedsigner/resources/buttons/SELECT.png b/src/seedsigner/resources/buttons/SELECT.png new file mode 100644 index 0000000000000000000000000000000000000000..c240bc67dd741b147b0514a433e8967793e1f980 GIT binary patch literal 2822 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 J*XudO{|m}6CMy5{ literal 0 HcmV?d00001 diff --git a/src/seedsigner/resources/buttons/UP.png b/src/seedsigner/resources/buttons/UP.png new file mode 100644 index 0000000000000000000000000000000000000000..dbd1c5ab68dc7564edb873996de5df00b6ff8e7d GIT binary patch literal 1753 zcmbW1dpOg39LImtWE@J`#5r!M>4p>@xoxr;tK7<%=CWc!2XnX97E>r)Fl!RA(A+Pn zvnG}M$fb1QDQR+VfUKA1)Muv*004A82!(RNqEI^Ih_Ha5-$?+lGo6-h?a*wa(dv7wNEenI zqbyb~wD5$&!e8x%a%_uX$D@t-bX#W9_SRNcvcZ8LHTY<9c;D+roH7_`qmi2f^)75# zgABGWbX^XlWDZmK7XxWnF22dI{RA%ip85VGkIs+@zM|AMhzMBlG@@2n93H@83QWEK2e_M$ew^1)IY|6_H7 zaWlrk)LBDMHC3}b%4m=J?ipyf2{$-%ufJDM`1|2<_u%qq=anX+55ZGp(G5|-x2SAS zadAPZ!|*A+rRgVi?H0o~uI7)h+l$i56fsw2-8i-}OGD?T9};Sf%s=SKj@ZnlhMZGe zm*Ac6$&*a^4TRnTR!$8aI=xt?L=-W!i$}tSEdT(n!J-ek#l4jb5CRF&fM7<5ePP1( zxmzS@A`e=aaSu#S9-6RFgY0)#+pusn%^E@_r=$!`H?kdPIyg>H&QZN$zuWhkOOI$@ z+WDwUY-mx``|Go_Yh|vd zq#grgz#thgM2fN$9Vs?a;-vrw;{gx@kpBL2!@q3%Y0kSeZq~-iPeZc`At5>5SLxp` zwE0qur1j)=DMYRK-u_+oVzg~ZD%(E~QFd{o zW#KCm&~RU^l@{Mxi=PN$VcbiG6BaW=DPA6k$>-<+SHng;qc^|&NcxWBxNk4$7#sbo zQMw#XZpG@#sD0CJK9$K(BDlT5@8t=R4-LLLB<9elP~^KFND5(_u?p@}S(s_eP+C$R z?O+e9xW>AEWS{4ULo#R(rX$ZVaP+lVX1Bjc&$uz3VW|zbfhNs%?}E!EUyfesj@_iA zu;ZJcnv&?#2v?Ie@f#4`9GR1f0!_v2&8$%<=r;M#>HaJx6Mq?SReQfc9rNY&;n_IxLHBQ>oOo{yFv6;H+lw(74dV8eyhTw~UaDnQET`S5&$aMSif2>*@X5*V@#PCdQzgT_M~>!-DB66h0X|EvWOR7$Lvc7+$G_l-wcl$}=*`<`NU)-9v?XA;Rke z4sQpz9}`eeRQxZ@xN%w$eIAFS9*5z5*|QTlfo^`e-r0dji~%? None: - View.__init__(self) + def __init__(self, disp, q) -> None: + View.__init__(self, disp, q) self.menu_lines = [] self.selected_menu_num = 1 @@ -38,6 +38,7 @@ class MenuView(View): # Wait for Button Input (specifically menu selection/press) while True: + print("wait for button press MAIN MENU") if ret_val == 0: input = self.buttons.wait_for([B.KEY_UP, B.KEY_DOWN, B.KEY_PRESS], check_release=True, release_keys=[B.KEY_PRESS]) else: @@ -77,6 +78,7 @@ class MenuView(View): # Wait for Button Input (specifically menu selection/press) while True: + print("wait for button press SEED TOOLS MENU") input = self.buttons.wait_for([B.KEY_UP, B.KEY_DOWN, B.KEY_PRESS], check_release=True, release_keys=[B.KEY_PRESS]) if input == B.KEY_UP: self.menu_up() @@ -107,6 +109,7 @@ class MenuView(View): # Wait for Button Input (specifically menu selection/press) while True: + print("wait for button press SIGNING TOOLS MENU") input = self.buttons.wait_for([B.KEY_UP, B.KEY_DOWN, B.KEY_PRESS], check_release=True, release_keys=[B.KEY_PRESS]) if input == B.KEY_UP: self.menu_up() @@ -145,6 +148,7 @@ class MenuView(View): # Wait for Button Input (specifically menu selection/press) while True: + print("wait for button press SETTINGS MENU") input = self.buttons.wait_for([B.KEY_UP, B.KEY_DOWN, B.KEY_PRESS], check_release=True, release_keys=[B.KEY_PRESS]) if input == B.KEY_UP: self.menu_up() @@ -198,6 +202,7 @@ class MenuView(View): # Wait for Button Input (specifically menu selection/press) while True: + print("wait for button press 12/24 WORDS MENU") input = self.buttons.wait_for([B.KEY_UP, B.KEY_DOWN, B.KEY_PRESS], check_release=True, release_keys=[B.KEY_PRESS]) if input == B.KEY_UP: self.menu_up() diff --git a/src/seedsigner/views/screensaver.py b/src/seedsigner/views/screensaver.py index 3f4afa0d..c28d4c62 100644 --- a/src/seedsigner/views/screensaver.py +++ b/src/seedsigner/views/screensaver.py @@ -6,14 +6,23 @@ from PIL import Image, ImageDraw from . import View -from seedsigner.helpers import B +from seedsigner.helpers import B, touchscreen class LogoView(View): - def __init__(self): + def __init__(self, disp, q): + print("inside logo") + # View.disp = touchscreen.touchscreen() + # View.disp.Init() + View.disp = disp dirname = os.path.dirname(__file__) logo_url = os.path.join(dirname, "../../", "seedsigner", "resources", "logo_black_240.png") self.logo = Image.open(logo_url) + View.canvas_width = View.WIDTH + View.canvas_height = View.HEIGHT + View.canvas = Image.new('RGB', (View.canvas_width, View.canvas_height)) + View.draw = ImageDraw.Draw(View.canvas) + @@ -26,7 +35,8 @@ class OpeningSplashView(LogoView): for i in range(250, -1, -25): self.logo.putalpha(255 - i) background = Image.new("RGBA", self.logo.size, (0,0,0)) - View.disp.ShowImage(Image.alpha_composite(background, self.logo), 0, 0) + # View.disp.ShowImage(Image.alpha_composite(background, self.logo), 0, 0) + View.q.put((Image.alpha_composite(background, self.logo), 0, 0)) # Display version num and hold for a few seconds font = View.ROBOTOCONDENSED_REGULAR_22 @@ -43,8 +53,8 @@ class OpeningSplashView(LogoView): class ScreensaverView(LogoView): - def __init__(self, buttons): - super().__init__() + def __init__(self, buttons, disp, q): + super().__init__(disp, q) self.buttons = buttons diff --git a/src/seedsigner/views/seed_tools_view.py b/src/seedsigner/views/seed_tools_view.py index ec4b3fb6..c599ef4b 100644 --- a/src/seedsigner/views/seed_tools_view.py +++ b/src/seedsigner/views/seed_tools_view.py @@ -18,8 +18,8 @@ class SeedToolsView(View): ALPHABET = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"] - def __init__(self) -> None: - View.__init__(self) + def __init__(self, disp, q) -> None: + View.__init__(self, disp, q) # Gather words and seed display information self.words = [] diff --git a/src/seedsigner/views/settings_tools_view.py b/src/seedsigner/views/settings_tools_view.py index b850e926..d9e12733 100644 --- a/src/seedsigner/views/settings_tools_view.py +++ b/src/seedsigner/views/settings_tools_view.py @@ -5,8 +5,8 @@ from seedsigner.models import EncodeQRDensity class SettingsToolsView(View): - def __init__(self) -> None: - View.__init__(self) + def __init__(self, disp, q) -> None: + View.__init__(self, disp, q) self.qr = QR() self.donate_image = None diff --git a/src/seedsigner/views/view.py b/src/seedsigner/views/view.py index d1ffb509..64b9c84f 100644 --- a/src/seedsigner/views/view.py +++ b/src/seedsigner/views/view.py @@ -5,7 +5,8 @@ import pathlib import spidev as SPI import time from multiprocessing import Queue -from seedsigner.helpers import B, ST7789 +from seedsigner.helpers import B, ST7789, touchscreen + ### Generic View Class to Instatiate Display @@ -78,7 +79,7 @@ class View: previous_button_width = None - def __init__(self) -> None: + def __init__(self, screen, q) -> None: # Import here to avoid circular imports from seedsigner.controller import Controller self.controller = Controller.get_instance() @@ -91,14 +92,19 @@ class View: View.canvas = Image.new('RGB', (View.canvas_width, View.canvas_height)) View.draw = ImageDraw.Draw(View.canvas) + View.q = q # 240x240 display with hardware SPI: View.bus = 0 View.device = 0 # TODO: Add `disable_hardware` option for test suite here, too? - View.disp = ST7789(SPI.SpiDev(View.bus, View.device),View.RST, View.DC, View.BL) - View.disp.Init() - + # View.disp = ST7789(SPI.SpiDev(View.bus, View.device),View.RST, View.DC, View.BL) + print("init display") + # View.disp = touchscreen.touchscreen() + # View.disp.Init() + View.disp = screen + # import code + # code.interact(local=dict(globals(), **locals())) self.queue = Queue() @@ -115,7 +121,8 @@ class View: # Always keep a copy of the current display in the canvas View.canvas.paste(image) - View.disp.ShowImage(image, 0, 0) + View.q.put((image, 0, 0)) + # View.disp.ShowImage(image, 0, 0) def disp_show_image_pan(image, start_x, start_y, end_x, end_y, rate, alpha_overlay=None):