diff --git a/clock.py b/clock.py index e70afe9..9573160 100644 --- a/clock.py +++ b/clock.py @@ -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)