touchscreen!

This commit is contained in:
Sam Korn
2022-03-07 21:38:16 -07:00
parent 813b14ec8a
commit b15f0545c7
23 changed files with 701 additions and 74 deletions
+10
View File
@@ -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
+295
View File
@@ -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("<Button-1>", 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("<ButtonPress>", press)
btn_KEY_UP.bind("<ButtonRelease>", 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('<Control-c>', 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
```
+5 -3
View File
@@ -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
urtypes @ git+https://github.com/jreesun/urtypes.git@e0d0db277ec2339650343eaf7b220fffb9233241
#-e src/vendor/urtypes
+8 -2
View File
@@ -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()
+24 -10
View File
@@ -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:
+3 -1
View File
@@ -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
+94 -38
View File
@@ -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 = [
+5 -3
View File
@@ -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
+218
View File
@@ -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("<ButtonPress>", self.update_button_state)
self.btn_KEY_DOWN.bind("<ButtonPress>", self.update_button_state)
self.btn_KEY_PRESS.bind("<ButtonPress>", self.update_button_state)
self.btn_KEY_LEFT.bind("<ButtonPress>", self.update_button_state)
self.btn_KEY_RIGHT.bind("<ButtonPress>", self.update_button_state)
self.btn_KEY_1.bind("<ButtonPress>", self.update_button_state)
self.btn_KEY_2.bind("<ButtonPress>", self.update_button_state)
self.btn_KEY_3.bind("<ButtonPress>", self.update_button_state)
# self.btn_KEY_UP.bind("<ButtonRelease>", self.update_button_state)
# self.btn_KEY_DOWN.bind("<ButtonRelease>", self.update_button_state)
# self.btn_KEY_PRESS.bind("<ButtonRelease>", self.update_button_state)
# self.btn_KEY_LEFT.bind("<ButtonRelease>", self.update_button_state)
# self.btn_KEY_RIGHT.bind("<ButtonRelease>", self.update_button_state)
# self.btn_KEY_1.bind("<ButtonRelease>", self.update_button_state)
# self.btn_KEY_2.bind("<ButtonRelease>", self.update_button_state)
# self.btn_KEY_3.bind("<ButtonRelease>", 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!")
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 847 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

+7 -2
View File
@@ -10,8 +10,8 @@ import re
class MenuView(View):
def __init__(self) -> 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()
+15 -5
View File
@@ -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
+2 -2
View File
@@ -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 = []
+2 -2
View File
@@ -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
+13 -6
View File
@@ -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):