Ugly workaround for double input processing issue + initial work on themes

This commit is contained in:
Admar Schoonen 2023-04-11 17:39:41 +02:00
parent c7b874fe15
commit 395c52f9a6
1 changed files with 165 additions and 37 deletions

202
clock.py
View File

@ -7,6 +7,7 @@ import traceback
import copy
import os
from kivy.config import Config
from kivy.properties import ListProperty
import time
def is_arm():
@ -67,6 +68,13 @@ Builder.load_string('''
on_pos: self.update_display()
on_size: self.update_display()
canvas:
Color:
rgb: root.color_background
Rectangle:
size: self.size
pos: self.pos
FloatLayout
id: face
size_hint: None, None
@ -74,7 +82,7 @@ Builder.load_string('''
size: 0.9*min(root.size), 0.9*min(root.size)
canvas:
Color:
rgb: 0.1, 0.1, 0.1
rgb: root.color_shade
Ellipse:
size: self.size
pos: self.pos
@ -116,7 +124,7 @@ Builder.load_string('''
size: 0.8*min(root.size), 0.7*min(root.size)
canvas:
Color:
rgb: 0.1, 0.1, 0.1
rgb: root.color_shade
Rectangle:
size: self.size
pos: self.pos
@ -130,6 +138,7 @@ Builder.load_string('''
valign: "middle"
font_size: root.height*0.05
text_size: self.size
color: root.color_font
Slider:
id: volume_slider
min: 0
@ -144,17 +153,22 @@ Builder.load_string('''
valign: "middle"
font_size: root.height*0.05
text_size: self.size
color: root.color_font
Button:
id: settings_menu_wake_up_sound_select_button
on_press: root.settings_menu_wake_up_sound_select_button_cb()
font_size: root.height*0.05
text: str(app.alarm_settings.sound_selected)
color: root.color_font
background_normal: ''
background_color: root.color_button
Label:
text:"Wake up brightness"
halign: "left"
valign: "middle"
font_size: root.height*0.05
text_size: self.size
color: root.color_font
Slider:
id: wake_up_bightness_slider
min: 0
@ -169,6 +183,7 @@ Builder.load_string('''
valign: "middle"
font_size: root.height*0.05
text_size: self.size
color: root.color_font
Slider:
id: reading_light_brightness_slider
min: 1
@ -183,6 +198,7 @@ Builder.load_string('''
valign: "middle"
font_size: root.height*0.05
text_size: self.size
color: root.color_font
Slider:
id: display_brightness_slider
min: 0
@ -198,7 +214,7 @@ Builder.load_string('''
size: 0.8*min(root.size), 0.8*min(root.size)
canvas:
Color:
rgb: 0.1, 0.1, 0.1
rgb: root.color_shade
Rectangle:
size: self.size
pos: self.pos
@ -208,6 +224,7 @@ Builder.load_string('''
Label:
text: "Select wake up sound"
font_size: root.height*0.05
color: root.color_font
GridLayout:
cols: 2
CheckBox:
@ -220,6 +237,7 @@ Builder.load_string('''
valign: "middle"
text_size: self.size
font_size: root.height*0.05
color: root.color_font
active: True
CheckBox:
group: "settings_menu_wake_up_sound"
@ -231,11 +249,15 @@ Builder.load_string('''
valign: "middle"
text_size: self.size
font_size: root.height*0.05
color: root.color_font
Button:
id: settings_menu_wake_up_sound_Ok_button
on_press: root.settings_menu_wake_up_sound_Ok_button_cb()
text: "Ok"
font_size: root.height*0.05
color: root.color_font
background_normal: ''
background_color: root.color_button
''')
Position = collections.namedtuple('Position', 'x y')
@ -288,6 +310,7 @@ class TouchEvent():
def __init__(self, x=None):
self.time = time.time()
self.touch = copy.copy(x)
self.processed = False
class MyClockWidget(FloatLayout):
grabbed = ""
@ -308,9 +331,12 @@ class MyClockWidget(FloatLayout):
# Ugly workaround for issue with Kivy and Raspberry Pi 3 + touch screen
# For each type of touch event, handling of the event is ignored until the last event is more than touch_delay_time seconds old
touch_delay_time = 0.1
last_touch_down_event = None
last_touch_move_event = None
last_touch_up_event = None
touch_down_event_prev = None
touch_move_event_prev = None
touch_up_event_prev = None
touch_down_event_curr = None
touch_move_event_curr = None
touch_up_event_curr = None
# view can be one of the following strings:
# - "clock"
@ -318,6 +344,12 @@ class MyClockWidget(FloatLayout):
# - "settings_menu"
# - "settings_menu_wake_up_sound"
view = "clock"
view_active_since = time.time()
# ugly workaround for issue where input is processed twice (specifically:
# pressing Ok in wake up sound view switches to settings view but also
# adjusts display brightness slider)
time_to_ignore_inputs_after_view_change = 0.1
# we need a dirty hack to sensure that radio button is always in sync with selected setting
settings_menu_wake_up_sound_select_button_cb_hack = False
@ -340,6 +372,54 @@ class MyClockWidget(FloatLayout):
else:
backlight = None
color_background = ListProperty([0, 0, 0])
color_shade = ListProperty([.1, .1, .1])
color_clock_hands_hours = ListProperty([.9, .9, .9])
color_clock_hands_minutes = ListProperty([.8, .8, .8])
color_clock_hands_seconds = ListProperty([.7, .7, .7])
color_alarm_hands_hours = ListProperty([.9, .0, .0])
color_alarm_hands_minutes = ListProperty([.8, .0, .0])
color_alarm_hands_seconds = ListProperty([.7, .0, .0])
color_font = ListProperty([1, 1, 1])
color_numbers = ListProperty([1, 1, 1])
color_button = ListProperty([.2, .2, .2, 1])
icon_light_off = 'icons/dark/light_off.png'
icon_light_reading = 'icons/dark/light_reading.png'
icon_light_sunrise = 'icons/dark/light_sunrise.png'
icon_light_on = 'icons/dark/light_on.png'
icon_media_playing = 'icons/dark/white_media_playing.png'
icon_media_stopped = 'icons/dark/media_stopped.png'
icon_alarm_on = 'icons/dark/alarm_on.png'
icon_alarm_off = 'icons/dark/alarm_off.png'
icon_settings_visible = 'icons/dark/settings_visible.png'
icon_settings_not_visible = 'icons/dark/settings_not_visible.png'
"""
color_background = ListProperty([1, 1, 1])
color_shade = ListProperty([.9, .9, .9])
color_clock_hands_hours = ListProperty([.1, .1, .1])
color_clock_hands_minutes = ListProperty([.2, .2, .2])
color_clock_hands_seconds = ListProperty([.3, .3, .3])
color_alarm_hands_hours = ListProperty([.9, .0, .0])
color_alarm_hands_minutes = ListProperty([.8, .0, .0])
color_alarm_hands_seconds = ListProperty([.7, .0, .0])
color_font = ListProperty([0, 0, 0])
color_numbers = ListProperty([0, 0, 0])
color_button = ListProperty([.8, .8, .8, 1])
icon_light_off = 'icons/light/light_off.png'
icon_light_reading = 'icons/light/light_reading.png'
icon_light_sunrise = 'icons/light/light_sunrise.png'
icon_light_on = 'icons/light/light_on.png'
icon_media_playing = 'icons/light/media_playing.png'
icon_media_stopped = 'icons/light/media_stopped.png'
icon_alarm_on = 'icons/light/alarm_on.png'
icon_alarm_off = 'icons/light/alarm_off.png'
icon_settings_visible = 'icons/light/settings_visible.png'
icon_settings_not_visible = 'icons/light/settings_not_visible.png'
"""
def play_sound(self, source):
alarm_settings = App.get_running_app().alarm_settings
@ -354,6 +434,7 @@ class MyClockWidget(FloatLayout):
self.player.play()
alarm_settings.alarm_playing = True
def stop_sound(self):
self.player.stop()
alarm_settings = App.get_running_app().alarm_settings
@ -399,6 +480,7 @@ class MyClockWidget(FloatLayout):
self.face_numbers.append(Label(
text=str(i + offset),
font_size=float(Config.get('graphics', 'height'))*0.05,
color=self.color_numbers,
pos_hint={
# pos_hint is a fraction in range (0, 1)
"center_x": 0.5 + 0.45*math.sin(2 * math.pi * i/12),
@ -440,16 +522,16 @@ class MyClockWidget(FloatLayout):
def update_light_button(self):
if (self.light_state == "off"):
source = 'light_off.png'
source = self.icon_light_off
rgb = [1.0, 1.0, 1.0]
elif (self.light_state == "reading"):
source = 'light_reading.png'
source = self.icon_light_reading
rgb = [1.0, 1.0, 1.0]
elif (self.light_state == "sunrise"):
source = 'light_sunrise.png'
source = self.light_sunrise
rgb = [1.0, 1.0, 1.0]
elif (self.light_state == "on"):
source = 'light_on.png'
source = self.light_on
rgb = [1.0, 1.0, 1.0]
light_button = self.ids["light_button"]
@ -462,10 +544,10 @@ class MyClockWidget(FloatLayout):
alarm_settings = App.get_running_app().alarm_settings
if alarm_settings.alarm_playing:
source = 'media_playing.png'
source = self.icon_media_playing
rgb = [1.0, 1.0, 1.0]
else:
source = 'media_stopped.png'
source = self.icon_media_stopped
rgb = [1.0, 1.0, 1.0]
play_button = self.ids["play_button"]
@ -478,10 +560,10 @@ class MyClockWidget(FloatLayout):
alarm_settings = App.get_running_app().alarm_settings
if (self.view == "set_alarm") or alarm_settings.alarm_activated:
source = 'alarm_on.png'
source = self.icon_alarm_on
rgb = [1.0, 1.0, 1.0]
else:
source = 'alarm_off.png'
source = self.icon_alarm_off
rgb = [1.0, 1.0, 1.0]
set_alarm_button = self.ids["set_alarm_button"]
@ -495,10 +577,10 @@ class MyClockWidget(FloatLayout):
alarm_settings = App.get_running_app().alarm_settings
if (self.view.startswith("settings_menu")):
source = 'settings_visible.png'
source = self.icon_settings_visible
rgb = [1.0, 1.0, 1.0]
else:
source = 'settings_not_visible.png'
source = self.icon_settings_not_visible
rgb = [1.0, 1.0, 1.0]
settings_button = self.ids["settings_button"]
@ -647,11 +729,9 @@ class MyClockWidget(FloatLayout):
if self.view == "set_alarm":
if self.grabbed != "" or self.set_alarm_timeout_counter < 1 * update_rate or \
self.set_alarm_timeout_counter % update_rate <= update_rate / 2 or alarm_settings.alarm_modified == False:
self.draw_list_curr_frame.append(["Color", hands.canvas, 0.9, 0.0, 0.0])
# Line(points=[hands.center_x, hands.center_y, hours_hand.x, hours_hand.y], width=3, cap="round")
self.draw_list_curr_frame.append(["Color", hands.canvas, self.color_alarm_hands_hours[0], self.color_alarm_hands_hours[1], self.color_alarm_hands_hours[2]])
self.draw_list_curr_frame.append(["Line", hands.canvas, [hands.center_x, hands.center_y, hours_hand.x, hours_hand.y], 3, "round"])
self.draw_list_curr_frame.append(["Color", hands.canvas, 0.8, 0.0, 0.0])
#Line(points=[hands.center_x, hands.center_y, minutes_hand.x, minutes_hand.y], width=2, cap="round")
self.draw_list_curr_frame.append(["Color", hands.canvas, self.color_alarm_hands_minutes[0], self.color_alarm_hands_minutes[1], self.color_alarm_hands_minutes[2]])
self.draw_list_curr_frame.append(["Line", hands.canvas, [hands.center_x, hands.center_y, minutes_hand.x, minutes_hand.y], 2, "round"])
if self.grabbed == "":
@ -660,19 +740,17 @@ class MyClockWidget(FloatLayout):
if self.set_alarm_timeout_counter >= 4.5 * update_rate:
self.view = "clock"
self.set_alarm_timeout_counter = 0
self.view_active_since = time.time()
if alarm_settings.alarm_modified:
alarm_settings.alarm_activated = True
alarm_settings.alarm_modified = False
else:
self.draw_list_curr_frame.append(["Color", hands.canvas, 0.9, 0.9, 0.9])
# Line(points=[hands.center_x, hands.center_y, hours_hand.x, hours_hand.y], width=3, cap="round")
self.draw_list_curr_frame.append(["Color", hands.canvas, self.color_clock_hands_hours[0], self.color_clock_hands_hours[1], self.color_clock_hands_hours[2]])
self.draw_list_curr_frame.append(["Line", hands.canvas, [hands.center_x, hands.center_y, hours_hand.x, hours_hand.y], 3, "round"])
self.draw_list_curr_frame.append(["Color", hands.canvas, 0.8, 0.8, 0.8])
# Line(points=[hands.center_x, hands.center_y, minutes_hand.x, minutes_hand.y], width=2, cap="round")
self.draw_list_curr_frame.append(["Color", hands.canvas, self.color_clock_hands_minutes[0], self.color_clock_hands_minutes[1], self.color_clock_hands_minutes[2]])
self.draw_list_curr_frame.append(["Line", hands.canvas, [hands.center_x, hands.center_y, minutes_hand.x, minutes_hand.y], 2, "round"])
self.draw_list_curr_frame.append(["Color", hands.canvas, 0.7, 0.7, 0.7])
# Line(points=[hands.center_x, hands.center_y, seconds_hand.x, seconds_hand.y], width=1, cap="round")
self.draw_list_curr_frame.append(["Color", hands.canvas, self.color_clock_hands_seconds[0], self.color_clock_hands_seconds[1], self.color_clock_hands_seconds[2]])
self.draw_list_curr_frame.append(["Line", hands.canvas, [hands.center_x, hands.center_y, seconds_hand.x, seconds_hand.y], 1, "round"])
def update_settings(self):
@ -704,17 +782,26 @@ class MyClockWidget(FloatLayout):
def process_touch_events(self):
t = time.time()
if (self.last_touch_down_event is not None) and (t - self.last_touch_down_event.time > self.touch_delay_time):
self.touch_down_function(self.last_touch_down_event.touch)
self.last_touch_down_event = None
if (self.touch_down_event_curr is not None) and (self.touch_down_event_curr.processed == False) and \
(t - self.touch_down_event_curr.time > self.touch_delay_time):
self.touch_down_function(self.touch_down_event_curr.touch)
self.touch_down_event_curr.processed = True
self.touch_down_event_prev = copy.copy(self.touch_down_event_curr)
self.touch_down_event_curr = None
if (self.last_touch_move_event is not None) and (t - self.last_touch_move_event.time > self.touch_delay_time):
self.touch_move_function(self.last_touch_move_event.touch)
self.last_touch_move_event = None
if (self.touch_move_event_curr is not None) and (self.touch_move_event_curr.processed == False) and \
(t - self.touch_move_event_curr.time > self.touch_delay_time):
self.touch_move_function(self.touch_move_event_curr.touch)
self.touch_move_event_curr.processed = True
self.touch_move_event_prev = copy.copy(self.touch_move_event_curr)
self.touch_move_event_curr = None
if (self.last_touch_up_event is not None) and (t - self.last_touch_up_event.time > self.touch_delay_time):
self.touch_up_function(self.last_touch_up_event.touch)
self.last_touch_up_event = None
if (self.touch_up_event_curr is not None) and (self.touch_up_event_curr.processed == False) and \
(t - self.touch_up_event_curr.time > self.touch_delay_time):
self.touch_up_function(self.touch_up_event_curr.touch)
self.touch_up_event_curr.processed = True
self.touch_up_event_prev = copy.copy(self.touch_up_event_curr)
self.touch_up_event_curr = None
def update_display(self, *args):
self.process_touch_events()
@ -752,12 +839,14 @@ class MyClockWidget(FloatLayout):
self.ids["settings_menu_wake_up_sound_NpoRadio1"].active = True
self.view = "settings_menu_wake_up_sound"
self.view_active_since = time.time()
def settings_menu_wake_up_sound_Ok_button_cb(self):
alarm_settings = App.get_running_app().alarm_settings
self.ids["settings_menu_wake_up_sound_select_button"].text = alarm_settings.sound_selected
self.view = "settings_menu"
self.view_active_since = time.time()
def settings_menu_wake_up_sound_cb(self, instance, value, sound):
alarm_settings = App.get_running_app().alarm_settings
@ -857,17 +946,21 @@ class MyClockWidget(FloatLayout):
if self.view == "set_alarm":
self.view = "clock"
self.view_active_since = time.time()
alarm_settings.alarm_activated = False
else:
self.view = "set_alarm"
self.view_active_since = time.time()
alarm_settings.alarm_activated = True
def on_settings_button_pressed(self):
print("settings button pressed from view " + self.view)
if self.view != "settings_menu":
self.view = "settings_menu"
self.view_active_since = time.time()
else:
self.view = "clock"
self.view_active_since = time.time()
print("view updated to " + self.view)
def touch_up_function(self, touch):
@ -1037,29 +1130,64 @@ class MyClockWidget(FloatLayout):
self.grabbed = ""
elif self.view == "settings_menu":
pass
elif self.view == "settings_menu_wake_up_sound":
pass
elif self.view == "clock":
self.stop_sound()
super(MyClockWidget, self).on_touch_down(touch)
def on_touch_down(self, touch, after=False):
t = time.time()
if t - self.view_active_since <= self.time_to_ignore_inputs_after_view_change:
return True
if self.touch_down_event_prev is None:
print("touch down at " + str(t) + " on " + str(touch.spos) + ", after: " + str(after) + ", prev event: None")
else:
print("touch down at " + str(t) + " on " + str(touch.spos) + ", after: " + str(after) + ", prev event at " + str(self.touch_down_event_prev.time) + " on " + str(self.touch_down_event_prev.touch.spos))
if after:
self.last_touch_down_event = TouchEvent(touch)
self.touch_down_event_curr = TouchEvent(touch)
return True
else:
Clock.schedule_once(lambda dt: self.on_touch_down(touch, True))
return super(MyClockWidget, self).on_touch_down(touch)
def on_touch_move(self, touch, after=False):
t = time.time()
if t - self.view_active_since <= self.time_to_ignore_inputs_after_view_change:
return True
if self.touch_move_event_prev is None:
print("touch move at " + str(t) + " on " + str(touch.spos) + ", after: " + str(after) + ", prev event: None")
else:
print("touch move at " + str(t) + " on " + str(touch.spos) + ", after: " + str(after) + ", prev event at " + str(self.touch_move_event_prev.time) + " on " + str(self.touch_move_event_prev.touch.spos))
if after:
# Do not delay processing of move events
self.touch_move_function(touch)
return True
else:
Clock.schedule_once(lambda dt: self.on_touch_move(touch, True))
return super(MyClockWidget, self).on_touch_move(touch)
def on_touch_up(self, touch, after=False):
t = time.time()
if t - self.view_active_since <= self.time_to_ignore_inputs_after_view_change:
return True
if self.touch_up_event_prev is None:
print("touch up at " + str(t) + " on " + str(touch.spos) + ", after: " + str(after) + ", prev event: None")
else:
print("touch up at " + str(t) + " on " + str(touch.spos) + ", after: " + str(after) + ", prev event at " + str(self.touch_up_event_prev.time) + " on " + str(self.touch_up_event_prev.touch.spos))
if after:
self.last_touch_up_event = TouchEvent(touch)
self.touch_up_event_curr = TouchEvent(touch)
return True
else:
Clock.schedule_once(lambda dt: self.on_touch_up(touch, True))
return super(MyClockWidget, self).on_touch_up(touch)