Added new design and minor improvements
This commit is contained in:
parent
d3f46c820e
commit
30eb1e4cdd
10 changed files with 181 additions and 28 deletions
|
@ -15,6 +15,7 @@ class CalendarEvent (object):
|
||||||
self.highlight = None
|
self.highlight = None
|
||||||
|
|
||||||
self.calendar_name = None
|
self.calendar_name = None
|
||||||
|
self.calendar_url = None
|
||||||
|
|
||||||
self.location = None
|
self.location = None
|
||||||
self.fetch_datetime = None
|
self.fetch_datetime = None
|
||||||
|
|
|
@ -10,6 +10,7 @@ class CalendarInterface (DataSourceInterface):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.events = []
|
self.events = []
|
||||||
|
self.excluded_urls = []
|
||||||
|
|
||||||
def reload(self):
|
def reload(self):
|
||||||
if self.is_available() == False:
|
if self.is_available() == False:
|
||||||
|
@ -17,6 +18,9 @@ class CalendarInterface (DataSourceInterface):
|
||||||
self.events = self.__get_events__()
|
self.events = self.__get_events__()
|
||||||
self.events = self.__sort_events__(self.events)
|
self.events = self.__sort_events__(self.events)
|
||||||
|
|
||||||
|
def exclude_calendars(self, urls=[]):
|
||||||
|
self.excluded_urls = urls
|
||||||
|
|
||||||
def __sort_events__(self, events):
|
def __sort_events__(self, events):
|
||||||
events.sort(key=lambda x: x.begin_datetime)
|
events.sort(key=lambda x: x.begin_datetime)
|
||||||
return events
|
return events
|
||||||
|
@ -72,6 +76,10 @@ class CalendarInterface (DataSourceInterface):
|
||||||
|
|
||||||
events_in_range = []
|
events_in_range = []
|
||||||
for event in self.events:
|
for event in self.events:
|
||||||
|
# Is excluded?
|
||||||
|
if event.calendar_url in self.excluded_urls:
|
||||||
|
continue
|
||||||
|
|
||||||
event_occurrence = self.__get_if_event_in_range__(
|
event_occurrence = self.__get_if_event_in_range__(
|
||||||
event, start, duration)
|
event, start, duration)
|
||||||
if event_occurrence:
|
if event_occurrence:
|
||||||
|
|
151
Calendar/DayFocusListPanel.py
Normal file
151
Calendar/DayFocusListPanel.py
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
from datetime import date, datetime, timedelta, timezone
|
||||||
|
from settings import line_thickness, general_settings
|
||||||
|
from DayHeaderDesign import DayHeaderDesign
|
||||||
|
from HourListDesign import HourListDesign
|
||||||
|
from DayRowDesign import DayRowDesign
|
||||||
|
from PanelDesign import PanelDesign
|
||||||
|
from Assets import colors
|
||||||
|
from PIL import ImageDraw
|
||||||
|
|
||||||
|
HEADER_SIZE = (1, 0.2)
|
||||||
|
HOURLIST_HEIGHT = 0.3
|
||||||
|
HOURLIST_SIZE = (1, HOURLIST_HEIGHT)
|
||||||
|
DAYLIST_YPOS = HEADER_SIZE[1] + HOURLIST_SIZE[1]
|
||||||
|
DAYLIST_HEIGHT = 1 - HEADER_SIZE[1] - HOURLIST_SIZE[1]
|
||||||
|
DAYLIST_SIZE = (1, DAYLIST_HEIGHT)
|
||||||
|
HOURS_COUNT = 6
|
||||||
|
DAYROW_MIN_FORMAT = 40 / 384
|
||||||
|
DAYROW_MAX_FORMAT = 60 / 384
|
||||||
|
PANEL_LINE_THICKNESS = line_thickness
|
||||||
|
|
||||||
|
|
||||||
|
class DayFocusListPanel (PanelDesign):
|
||||||
|
"""Shows Day-View for today and a short Day-List for
|
||||||
|
the upcoming days."""
|
||||||
|
|
||||||
|
def __init__(self, size):
|
||||||
|
super(DayFocusListPanel, self).__init__(size)
|
||||||
|
self.hours_count = HOURS_COUNT
|
||||||
|
self.__init_modules__()
|
||||||
|
|
||||||
|
def __abs_co__(self, coordinates):
|
||||||
|
return (int(coordinates[0] * self.size[0]), int(coordinates[1] * self.size[1]))
|
||||||
|
|
||||||
|
def __init_modules__(self):
|
||||||
|
self.__init_header__()
|
||||||
|
self.__init_hourlist__()
|
||||||
|
self.__init_daylist__()
|
||||||
|
|
||||||
|
def __init_header__(self):
|
||||||
|
self.__header__ = DayHeaderDesign(
|
||||||
|
self.__abs_co__(HEADER_SIZE), date.today())
|
||||||
|
self.__header__.pos = (0, 0)
|
||||||
|
|
||||||
|
def __init_hourlist__(self):
|
||||||
|
start, end = self.__get_current_hour_range__()
|
||||||
|
size = self.__abs_co__(HOURLIST_SIZE)
|
||||||
|
|
||||||
|
self.__hourlist__ = HourListDesign(size, start, end)
|
||||||
|
self.__hourlist__.pos = (0, self.__header__.size[1])
|
||||||
|
|
||||||
|
def __init_daylist__(self):
|
||||||
|
self.__daylist_rows__ = []
|
||||||
|
self.__calc_dayrow_size__()
|
||||||
|
self.__create_day_rows__()
|
||||||
|
|
||||||
|
def __calc_dayrow_size__(self):
|
||||||
|
max_area_height = DAYLIST_HEIGHT * self.size[1]
|
||||||
|
max_row_number = max_area_height / (DAYROW_MIN_FORMAT * self.size[0])
|
||||||
|
min_row_number = max_area_height / (DAYROW_MAX_FORMAT * self.size[0])
|
||||||
|
average_row_number = (max_row_number + min_row_number) / 2
|
||||||
|
self.dayrow_count = round(average_row_number)
|
||||||
|
row_height = max_area_height / self.dayrow_count
|
||||||
|
self.dayrow_size = (1, row_height / self.size[1])
|
||||||
|
|
||||||
|
def __create_day_rows__(self):
|
||||||
|
following_days = self.__get_following_days__()
|
||||||
|
for i, date in enumerate(following_days):
|
||||||
|
row = DayRowDesign(self.__abs_co__(self.dayrow_size), date)
|
||||||
|
row.pos = self.__get_day_row_pos__(i)
|
||||||
|
self.__daylist_rows__.append(row)
|
||||||
|
|
||||||
|
def __get_following_days__(self):
|
||||||
|
following_days = []
|
||||||
|
for i in range(self.dayrow_count):
|
||||||
|
following_days.append(date.today() + timedelta(days=i + 1))
|
||||||
|
return following_days
|
||||||
|
|
||||||
|
def __get_day_row_pos__(self, i):
|
||||||
|
ypos = self.size[1] * DAYLIST_YPOS
|
||||||
|
down_shift = i * self.dayrow_size[1] * self.size[1]
|
||||||
|
return (0, int(ypos + down_shift))
|
||||||
|
|
||||||
|
def __finish_panel__(self):
|
||||||
|
self.draw_design(self.__header__)
|
||||||
|
self.draw_design(self.__hourlist__)
|
||||||
|
|
||||||
|
for row in self.__daylist_rows__:
|
||||||
|
self.draw_design(row)
|
||||||
|
self.__draw_daylist_lines__()
|
||||||
|
|
||||||
|
def __draw_daylist_lines__(self):
|
||||||
|
positions = []
|
||||||
|
for i in range(len(self.__daylist_rows__)):
|
||||||
|
positions.append(self.__get_day_row_pos__(i)[1])
|
||||||
|
for ypos in positions:
|
||||||
|
line_start = (0, ypos)
|
||||||
|
line_end = (self.size[0], ypos)
|
||||||
|
ImageDraw.Draw(self.__image__).line(
|
||||||
|
[line_start, line_end], fill=colors["fg"], width=PANEL_LINE_THICKNESS)
|
||||||
|
|
||||||
|
def __get_current_hour_range__(self):
|
||||||
|
start_hour = datetime.now().hour
|
||||||
|
additional_hours = self.hours_count - 1
|
||||||
|
|
||||||
|
if start_hour + additional_hours > 23:
|
||||||
|
start_hour = 23 - additional_hours
|
||||||
|
|
||||||
|
return start_hour, start_hour + additional_hours
|
||||||
|
|
||||||
|
def add_weather(self, weather):
|
||||||
|
self.__header__.add_weather(weather)
|
||||||
|
|
||||||
|
def add_calendar(self, calendar):
|
||||||
|
allday_ev, timed_ev = self.__split_events__(
|
||||||
|
calendar.get_today_events())
|
||||||
|
self.__header__.add_events(allday_ev)
|
||||||
|
self.__hourlist__.add_events(timed_ev)
|
||||||
|
|
||||||
|
self.__add_calendar_daylist__(calendar)
|
||||||
|
|
||||||
|
def __split_events__(self, events):
|
||||||
|
allday_ev = []
|
||||||
|
timed_ev = []
|
||||||
|
|
||||||
|
for event in events:
|
||||||
|
if event.allday:
|
||||||
|
allday_ev.append(event)
|
||||||
|
elif event.multiday:
|
||||||
|
if self.__is_today__(event.begin_datetime):
|
||||||
|
timed_ev.append(event)
|
||||||
|
elif self.__is_today__(event.end_datetime):
|
||||||
|
timed_ev.append(event)
|
||||||
|
else:
|
||||||
|
allday_ev.append(event)
|
||||||
|
else:
|
||||||
|
timed_ev.append(event)
|
||||||
|
return allday_ev, timed_ev
|
||||||
|
|
||||||
|
def __is_today__(self, dt):
|
||||||
|
today = date.today()
|
||||||
|
return dt.day == today.day and \
|
||||||
|
dt.month == today.month and \
|
||||||
|
dt.year == today.year
|
||||||
|
|
||||||
|
def __add_calendar_daylist__(self, calendar):
|
||||||
|
calendar.exclude_calendars(general_settings["extra-excluded-urls"])
|
||||||
|
|
||||||
|
for row in self.__daylist_rows__:
|
||||||
|
row.add_calendar(calendar)
|
||||||
|
|
||||||
|
calendar.exclude_calendars()
|
|
@ -17,6 +17,7 @@ from settings import datetime_encoding, language, render_to_display, render_to_f
|
||||||
from MonthOvPanel import MonthOvPanel
|
from MonthOvPanel import MonthOvPanel
|
||||||
from DayListPanel import DayListPanel
|
from DayListPanel import DayListPanel
|
||||||
from DayViewPanel import DayViewPanel
|
from DayViewPanel import DayViewPanel
|
||||||
|
from DayFocusListPanel import DayFocusListPanel
|
||||||
from MonthViewPanel import MonthViewPanel
|
from MonthViewPanel import MonthViewPanel
|
||||||
from AgendaListPanel import AgendaListPanel
|
from AgendaListPanel import AgendaListPanel
|
||||||
from ImageFramePanel import ImageFramePanel
|
from ImageFramePanel import ImageFramePanel
|
||||||
|
@ -54,12 +55,14 @@ available_panels = {
|
||||||
"day-list": DayListPanel,
|
"day-list": DayListPanel,
|
||||||
"month-overview": MonthOvPanel,
|
"month-overview": MonthOvPanel,
|
||||||
"day-view": DayViewPanel,
|
"day-view": DayViewPanel,
|
||||||
|
"day-focus-list": DayFocusListPanel,
|
||||||
"agenda-list": AgendaListPanel,
|
"agenda-list": AgendaListPanel,
|
||||||
"month-view": MonthViewPanel,
|
"month-view": MonthViewPanel,
|
||||||
"image-frame": ImageFramePanel
|
"image-frame": ImageFramePanel,
|
||||||
}
|
}
|
||||||
|
|
||||||
loop_timer = LoopTimer(update_interval, run_on_hour=run_on_hour, max_loop_count=max_loop_count)
|
loop_timer = LoopTimer(
|
||||||
|
update_interval, run_on_hour=run_on_hour, max_loop_count=max_loop_count)
|
||||||
|
|
||||||
"""Main loop starts from here"""
|
"""Main loop starts from here"""
|
||||||
|
|
||||||
|
@ -117,7 +120,8 @@ def main():
|
||||||
loop_timer.end_loop()
|
loop_timer.end_loop()
|
||||||
|
|
||||||
if loop_timer.was_last_loop():
|
if loop_timer.was_last_loop():
|
||||||
debug.print_line("Maximum loop count " + str(loop_timer.loop_count) + " reached, exiting.")
|
debug.print_line("Maximum loop count " +
|
||||||
|
str(loop_timer.loop_count) + " reached, exiting.")
|
||||||
return
|
return
|
||||||
|
|
||||||
sleep_time = loop_timer.time_until_next()
|
sleep_time = loop_timer.time_until_next()
|
||||||
|
|
|
@ -51,6 +51,7 @@ class IcalEvents(CalendarInterface):
|
||||||
ical = Calendar(decode)
|
ical = Calendar(decode)
|
||||||
for event in ical.events:
|
for event in ical.events:
|
||||||
cal_event = CalendarEvent()
|
cal_event = CalendarEvent()
|
||||||
|
cal_event.calendar_url = calendar
|
||||||
|
|
||||||
cal_event.fetch_datetime = datetime.now(timezone.utc)
|
cal_event.fetch_datetime = datetime.now(timezone.utc)
|
||||||
cal_event.begin_datetime = event.begin.datetime
|
cal_event.begin_datetime = event.begin.datetime
|
||||||
|
|
|
@ -44,18 +44,3 @@ class ImageFramePanel (PanelDesign):
|
||||||
overlay = ImageDesign(self.size, self.overlay_path)
|
overlay = ImageDesign(self.size, self.overlay_path)
|
||||||
overlay.__finish_image__()
|
overlay.__finish_image__()
|
||||||
self.__image__.alpha_composite(overlay.__image__)
|
self.__image__.alpha_composite(overlay.__image__)
|
||||||
|
|
||||||
def add_weather(self, weather):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def add_calendar(self, calendar):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def add_rssfeed(self, rss):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def add_crypto(self, crypto):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def add_tasks(self, tasks):
|
|
||||||
pass
|
|
||||||
|
|
|
@ -12,19 +12,19 @@ class PanelDesign (DesignEntity):
|
||||||
self.start_timestamp = datetime.now()
|
self.start_timestamp = datetime.now()
|
||||||
|
|
||||||
def add_weather(self, weather):
|
def add_weather(self, weather):
|
||||||
raise NotImplementedError("Function needs to be implemented")
|
pass
|
||||||
|
|
||||||
def add_calendar(self, calendar):
|
def add_calendar(self, calendar):
|
||||||
raise NotImplementedError("Function needs to be implemented")
|
pass
|
||||||
|
|
||||||
def add_rssfeed(self, rss):
|
def add_rssfeed(self, rss):
|
||||||
raise NotImplementedError("Function needs to be implemented")
|
pass
|
||||||
|
|
||||||
def add_tasks(self, tasks):
|
def add_tasks(self, tasks):
|
||||||
raise NotImplementedError("Function needs to be implemented")
|
pass
|
||||||
|
|
||||||
def add_crypto(self, crypto):
|
def add_crypto(self, crypto):
|
||||||
raise NotImplementedError("Function needs to be implemented")
|
pass
|
||||||
|
|
||||||
def __finish_panel__(self):
|
def __finish_panel__(self):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -30,13 +30,14 @@ run_on_hour = True # If True, updates calendar every full hour, ignoring differ
|
||||||
font_size = 14 # does not affect every text
|
font_size = 14 # does not affect every text
|
||||||
font_boldness = "semibold" # extralight, light, regular, semibold, bold, extrabold
|
font_boldness = "semibold" # extralight, light, regular, semibold, bold, extrabold
|
||||||
line_thickness = 1 # 1-3 Thickness advised
|
line_thickness = 1 # 1-3 Thickness advised
|
||||||
choosen_design = "month-overview" # month-overview, day-list, day-view, agenda-list, month-view, image-frame
|
choosen_design = "month-overview" # month-overview, day-list, day-view, day-focus-list, agenda-list, month-view, image-frame
|
||||||
general_settings = { # General settings that designs may use
|
general_settings = { # General settings that designs may use
|
||||||
"info-area" : "rss", # empty, events, rss, crypto
|
"info-area" : "rss", # empty, events, rss, crypto
|
||||||
"highlight-event-days" : True,
|
"highlight-event-days" : True,
|
||||||
"weather-info" : True,
|
"weather-info" : True,
|
||||||
"image-folder" : "",
|
"image-folder" : "",
|
||||||
"overlay-image" : "" # Size must be 384x640px with default display
|
"overlay-image" : "", # Size must be 384x640px with default display
|
||||||
|
"extra-excluded-urls" : []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
BIN
Gallery/day-focus-list_example.png
Normal file
BIN
Gallery/day-focus-list_example.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
|
@ -15,13 +15,14 @@ This software fully supports the 3-Colour **and** 2-Colour version of the 7.5" E
|
||||||
* **Added Support for the 2-Colour E-Paper Display as well!** (Late September 2018)
|
* **Added Support for the 2-Colour E-Paper Display as well!** (Late September 2018)
|
||||||
* **Added Support for Raspbian Stretch lite.** (Late September 2018)
|
* **Added Support for Raspbian Stretch lite.** (Late September 2018)
|
||||||
|
|
||||||
<img src="https://github.com/mgfcf/E-Paper-Calendar/blob/master/Gallery/day-list_example.png" width="270"><img src="https://github.com/mgfcf/E-Paper-Calendar/blob/master/Gallery/month-overview_example.png" width="270"><img src="https://github.com/mgfcf/E-Paper-Calendar/blob/master/Gallery/agenda-list_example.png" width="270"><img src="https://github.com/mgfcf/E-Paper-Calendar/blob/master/Gallery/day-view_example.png" width="270"><img src="https://github.com/mgfcf/E-Paper-Calendar/blob/master/Gallery/image-frame_example.png" width="270">
|
<img src="https://github.com/mgfcf/E-Paper-Calendar/blob/master/Gallery/day-list_example.png" width="270"><img src="https://github.com/mgfcf/E-Paper-Calendar/blob/master/Gallery/month-overview_example.png" width="270"><img src="https://github.com/mgfcf/E-Paper-Calendar/blob/master/Gallery/agenda-list_example.png" width="270"><img src="https://github.com/mgfcf/E-Paper-Calendar/blob/master/Gallery/day-view_example.png" width="270"><img src="https://github.com/mgfcf/E-Paper-Calendar/blob/master/Gallery/day-focus-list_example.png" width="270"><img src="https://github.com/mgfcf/E-Paper-Calendar/blob/master/Gallery/image-frame_example.png" width="270">
|
||||||
|
|
||||||
1.: Day-List Panel 
|
1.: Day-List Panel 
|
||||||
2.: Month-Overview Panel 
|
2.: Month-Overview Panel 
|
||||||
3.: Agenda-List Panel<br>
|
3.: Agenda-List Panel<br>
|
||||||
4.: Day-View Panel 
|
4.: Day-View Panel 
|
||||||
5.: Image-Frame Panel
|
5.: Day-Focus-List Panel 
|
||||||
|
6.: Image-Frame Panel
|
||||||
|
|
||||||
## Main features
|
## Main features
|
||||||
* Display a calendar with one of multiple designes
|
* Display a calendar with one of multiple designes
|
||||||
|
@ -98,6 +99,7 @@ Once the packages are installed, navigate to the home directory, open 'E-Paper-M
|
||||||
| `"weather-info"` | If set to `False`, weather info areas disappear and make room for events/rss/etc. (depends on the design). |
|
| `"weather-info"` | If set to `False`, weather info areas disappear and make room for events/rss/etc. (depends on the design). |
|
||||||
| `"image-folder"` | Set a relative or absolute path to a folder containing images that you want to see fullscreen with the `"image-frame"` design activated. |
|
| `"image-folder"` | Set a relative or absolute path to a folder containing images that you want to see fullscreen with the `"image-frame"` design activated. |
|
||||||
| `"overlay-image"` | Set a relative or absolute path to an image with the same size as the screen (default: 384x640px) to show some static information over every image shown in the `"image-frame"` design. If the overlay image is contained within the `"image-folder"`, it will not be included into the slideshow. |
|
| `"overlay-image"` | Set a relative or absolute path to an image with the same size as the screen (default: 384x640px) to show some static information over every image shown in the `"image-frame"` design. If the overlay image is contained within the `"image-folder"`, it will not be included into the slideshow. |
|
||||||
|
| `"extra-excluded-urls"` | A list of calendar urls that may be excluded in some panels in certain areas. |
|
||||||
|
|
||||||
### Debug
|
### Debug
|
||||||
| Parameter | Description |
|
| Parameter | Description |
|
||||||
|
|
Loading…
Reference in a new issue