Optimized screen draw. Only update needed rects

This commit is contained in:
Ander
2014-11-14 11:18:59 +01:00
parent 08da4995f1
commit 00b50c5202
10 changed files with 70 additions and 55 deletions

View File

@@ -1,42 +0,0 @@
import logging
import random
logger = logging.getLogger(__name__)
class DynamicBackground():
def __init__(self):
self.current = get_valid_color()
self.target = get_valid_color()
def draw_background(self, surface):
same = True
for x in range(0, 3):
if self.current[x] > self.target[x]:
self.current[x] -= 1
elif self.current[x] < self.target[x]:
self.current[x] += 1
if self.current != self.target:
same = False
if same:
self.target = get_valid_color()
surface.fill(self.current)
# Returns an array with 3 integers in range of 0-255
# The sum of the three integers will be lower than 255*2
# (510) to avoid very bright colors
# White text should be seen ok with this background color
def get_valid_color():
color = [0, 0, 0]
total = 0
for i in range(0, 3):
color[i] = random.randint(0, 255)
total += color[i]
extra = total - 510
if extra > 0:
i = random.randint(0, 2)
color[i] -= extra
return color

View File

@@ -22,6 +22,9 @@ class LibraryScreen():
self.library_strings = None self.library_strings = None
self.lookup_uri(None) self.lookup_uri(None)
def get_dirty_area(self):
return self.list_view.get_dirty_area()
def go_inside_directory(self, uri): def go_inside_directory(self, uri):
self.directory_list.append(self.current_directory) self.directory_list.append(self.current_directory)
self.current_directory = uri self.current_directory = uri

View File

@@ -21,8 +21,12 @@ class ListView():
self.set_list([]) self.set_list([])
self.selected = [] self.selected = []
def get_dirty_area(self):
return self.screen_objects.get_dirty_area()
# Sets the list for the lisview. It should be an iterable of strings # Sets the list for the lisview. It should be an iterable of strings
def set_list(self, item_list): def set_list(self, item_list):
self.screen_objects.clear()
self.list = item_list self.list = item_list
self.list_size = len(item_list) self.list_size = len(item_list)
if self.max_rows < self.list_size: if self.max_rows < self.list_size:

View File

@@ -108,6 +108,9 @@ class MainScreen():
else: else:
self.load_image() self.load_image()
def get_dirty_area(self):
return self.touch_text_manager.get_dirty_area()
def get_artist_string(self): def get_artist_string(self):
artists_string = '' artists_string = ''
for artist in self.artists: for artist in self.artists:

View File

@@ -50,6 +50,9 @@ class MenuScreen():
def update(self, screen): def update(self, screen):
self.screen_objects.render(screen) self.screen_objects.render(screen)
def get_dirty_area(self):
self.screen_objects.get_dirty_area()
def touch_event(self, event): def touch_event(self, event):
if event.type == InputManager.click: if event.type == InputManager.click:
clicked = self.screen_objects.get_touch_objects_in_pos( clicked = self.screen_objects.get_touch_objects_in_pos(

View File

@@ -13,6 +13,9 @@ class PlaylistScreen():
self.playlists = [] self.playlists = []
self.playlists_loaded() self.playlists_loaded()
def get_dirty_area(self):
return self.list_view.get_dirty_area()
def update(self, screen): def update(self, screen):
self.list_view.render(screen) self.list_view.render(screen)

View File

@@ -6,7 +6,6 @@ import mopidy.core
import pygame import pygame
from pkg_resources import Requirement, resource_filename from pkg_resources import Requirement, resource_filename
from .dynamic_background import DynamicBackground
from .library_screen import LibraryScreen from .library_screen import LibraryScreen
from .main_screen import MainScreen from .main_screen import MainScreen
from .menu_screen import MenuScreen from .menu_screen import MenuScreen
@@ -24,7 +23,6 @@ class ScreenManager():
self.core = core self.core = core
self.backend = backend self.backend = backend
self.fonts = {} self.fonts = {}
self.background = DynamicBackground()
self.current_screen = 0 self.current_screen = 0
self.base_size = self.size[1] / 8 self.base_size = self.size[1] / 8
font = resource_filename(Requirement.parse("mopidy-touchscreen"), font = resource_filename(Requirement.parse("mopidy-touchscreen"),
@@ -44,6 +42,7 @@ class ScreenManager():
self.top_bar_objects = ScreenObjectsManager() self.top_bar_objects = ScreenObjectsManager()
self.down_bar_objects = ScreenObjectsManager() self.down_bar_objects = ScreenObjectsManager()
self.selected_zone = self.top_bar_objects self.selected_zone = self.top_bar_objects
self.dirty_area = []
# Top bar # Top bar
self.top_bar = pygame.Surface((self.size[0], self.base_size), self.top_bar = pygame.Surface((self.size[0], self.base_size),
@@ -135,7 +134,7 @@ class ScreenManager():
def update(self): def update(self):
surface = pygame.Surface(self.size) surface = pygame.Surface(self.size)
self.background.draw_background(surface) surface.fill([200,200,200])
self.screens[self.current_screen].update(surface) self.screens[self.current_screen].update(surface)
surface.blit(self.top_bar, (0, 0)) surface.blit(self.top_bar, (0, 0))
surface.blit(self.down_bar, (0, self.base_size * 7)) surface.blit(self.down_bar, (0, self.base_size * 7))
@@ -148,6 +147,14 @@ class ScreenManager():
self.screens[0].track_started(track.track) self.screens[0].track_started(track.track)
self.screens[1].track_started(track) self.screens[1].track_started(track)
def get_dirty_area(self):
self.dirty_area = self.dirty_area + self.top_bar_objects.get_dirty_area()
self.dirty_area = self.dirty_area + self.down_bar_objects.get_dirty_area()
self.dirty_area = self.dirty_area + self.screens[self.current_screen].get_dirty_area()
dirty_area = self.dirty_area
self.dirty_area = []
return dirty_area
def track_playback_ended(self, tl_track, time_position): def track_playback_ended(self, tl_track, time_position):
self.screens[0].track_playback_ended(tl_track, time_position) self.screens[0].track_playback_ended(tl_track, time_position)
@@ -261,6 +268,7 @@ class ScreenManager():
self.current_screen = new_screen self.current_screen = new_screen
self.down_bar_objects.get_touch_object( self.down_bar_objects.get_touch_object(
"menu_" + str(new_screen)).set_active(True) "menu_" + str(new_screen)).set_active(True)
self.dirty_area.append(pygame.Rect(0,0,self.size[0],self.size[1]))
def playlists_loaded(self): def playlists_loaded(self):
self.screens[3].playlists_loaded() self.screens[3].playlists_loaded()

View File

@@ -15,9 +15,19 @@ class ScreenObjectsManager():
self.text_objects = {} self.text_objects = {}
self.selected = None self.selected = None
self.selected_key = None self.selected_key = None
self.dirty_area = []
def clear(self):
for key in self.touch_objects:
self.dirty_area.append(self.touch_objects[key].rect_in_pos)
for key in self.text_objects:
self.dirty_area.append(self.text_objects[key].rect_in_pos)
self.touch_objects = {}
self.text_objects = {}
def set_object(self, key, add_object): def set_object(self, key, add_object):
self.text_objects[key] = add_object self.text_objects[key] = add_object
self.dirty_area.append(add_object.rect_in_pos)
def get_object(self, key): def get_object(self, key):
return self.text_objects[key] return self.text_objects[key]
@@ -30,12 +40,19 @@ class ScreenObjectsManager():
def render(self, surface): def render(self, surface):
for key in self.text_objects: for key in self.text_objects:
self.text_objects[key].update() if self.text_objects[key].update():
self.dirty_area.append(self.text_objects[key].rect_in_pos)
self.text_objects[key].render(surface) self.text_objects[key].render(surface)
for key in self.touch_objects: for key in self.touch_objects:
self.touch_objects[key].update() if self.touch_objects[key].update():
self.dirty_area.append(self.touch_objects[key].rect_in_pos)
self.touch_objects[key].render(surface) self.touch_objects[key].render(surface)
def get_dirty_area(self):
dirty_area = self.dirty_area
self.dirty_area = []
return dirty_area
def get_touch_objects_in_pos(self, pos): def get_touch_objects_in_pos(self, pos):
touched_objects = [] touched_objects = []
for key in self.touch_objects: for key in self.touch_objects:
@@ -192,6 +209,7 @@ class BaseItem():
def __init__(self, pos, size): def __init__(self, pos, size):
self.pos = pos self.pos = pos
self.size = size self.size = size
self.dirty = True
self.rect = pygame.Rect(0, 0, self.size[0], self.size[1]) self.rect = pygame.Rect(0, 0, self.size[0], self.size[1])
self.rect_in_pos = pygame.Rect(self.pos[0], self.pos[1], self.size[0], self.rect_in_pos = pygame.Rect(self.pos[0], self.pos[1], self.size[0],
self.size[1]) self.size[1])
@@ -199,8 +217,13 @@ class BaseItem():
def get_right_pos(self): def get_right_pos(self):
return self.pos[0] + self.size[0] return self.pos[0] + self.size[0]
# Returns if must be redraw
def update(self): def update(self):
pass if self.dirty:
self.dirty = False
return True
else:
return False
class TextItem(BaseItem): class TextItem(BaseItem):
@@ -237,6 +260,9 @@ class TextItem(BaseItem):
self.step = -self.size[0] self.step = -self.size[0]
else: else:
self.step = self.step + 4 self.step = self.step + 4
return True
else:
return BaseItem.update(self)
def render(self, surface): def render(self, surface):
if self.fit_horizontal: if self.fit_horizontal:
@@ -246,6 +272,7 @@ class TextItem(BaseItem):
def set_text(self, text, change_size): def set_text(self, text, change_size):
self.dirty = True
if change_size: if change_size:
TextItem.__init__(self, self.font, text, self.pos, None) TextItem.__init__(self, self.font, text, self.pos, None)
else: else:
@@ -262,9 +289,11 @@ class TouchObject(BaseItem):
return self.rect_in_pos.collidepoint(pos) return self.rect_in_pos.collidepoint(pos)
def set_active(self, active): def set_active(self, active):
self.dirty = True
self.active = active self.active = active
def set_selected(self, selected): def set_selected(self, selected):
self.dirty = True
self.selected = selected self.selected = selected
@@ -278,9 +307,10 @@ class TouchAndTextItem(TouchObject, TextItem):
self.selected_box = self.font.render(text, True, self.selected_color) self.selected_box = self.font.render(text, True, self.selected_color)
def update(self): def update(self):
TextItem.update(self) return TextItem.update(self)
def set_text(self, text, change_size): def set_text(self, text, change_size):
self.dirty = True
TextItem.set_text(self, text, change_size) TextItem.set_text(self, text, change_size)
self.active_box = self.font.render(text, True, self.active_color) self.active_box = self.font.render(text, True, self.active_color)
self.selected_box = self.font.render(text, True, self.selected_color) self.selected_box = self.font.render(text, True, self.selected_color)
@@ -316,8 +346,6 @@ class Progressbar(TouchObject):
self.text.pos = (self.pos[0] + self.size[0] / 2 - self.text.size[0] / self.text.pos = (self.pos[0] + self.size[0] / 2 - self.text.size[0] /
2, self.text.pos[1]) 2, self.text.pos[1])
def update(self):
pass
def render(self, surface): def render(self, surface):
surface.blit(self.surface, self.pos) surface.blit(self.surface, self.pos)
@@ -325,6 +353,7 @@ class Progressbar(TouchObject):
def set_value(self, value): def set_value(self, value):
if value != self.value: if value != self.value:
self.dirty = True
self.value = value self.value = value
if self.value_text: if self.value_text:
self.set_text(str(self.value)) self.set_text(str(self.value))
@@ -376,6 +405,7 @@ class ScrollBar(TouchObject):
return 0 return 0
def set_item(self, current_item): def set_item(self, current_item):
self.dirty = True
self.current_item = current_item self.current_item = current_item
self.bar_pos = float(self.current_item) / float(self.max) * float( self.bar_pos = float(self.current_item) / float(self.max) * float(
self.size[1]) self.size[1])

View File

@@ -51,7 +51,7 @@ class TouchScreen(pykka.ThreadingActor, core.CoreListener):
while self.running: while self.running:
clock.tick(15) clock.tick(15)
screen.blit(self.screen_manager.update(), (0, 0)) screen.blit(self.screen_manager.update(), (0, 0))
pygame.display.flip() pygame.display.update(self.screen_manager.get_dirty_area())
for event in pygame.event.get(): for event in pygame.event.get():
if event.type == pygame.QUIT: if event.type == pygame.QUIT:
self.running = False self.running = False

View File

@@ -14,6 +14,9 @@ class Tracklist():
self.tracks_strings = [] self.tracks_strings = []
self.update_list() self.update_list()
def get_dirty_area(self):
return self.list_view.get_dirty_area()
def update(self, screen): def update(self, screen):
self.list_view.render(screen) self.list_view.render(screen)