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.lookup_uri(None)
def get_dirty_area(self):
return self.list_view.get_dirty_area()
def go_inside_directory(self, uri):
self.directory_list.append(self.current_directory)
self.current_directory = uri

View File

@@ -21,8 +21,12 @@ class ListView():
self.set_list([])
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
def set_list(self, item_list):
self.screen_objects.clear()
self.list = item_list
self.list_size = len(item_list)
if self.max_rows < self.list_size:

View File

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

View File

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

View File

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

View File

@@ -6,7 +6,6 @@ import mopidy.core
import pygame
from pkg_resources import Requirement, resource_filename
from .dynamic_background import DynamicBackground
from .library_screen import LibraryScreen
from .main_screen import MainScreen
from .menu_screen import MenuScreen
@@ -24,7 +23,6 @@ class ScreenManager():
self.core = core
self.backend = backend
self.fonts = {}
self.background = DynamicBackground()
self.current_screen = 0
self.base_size = self.size[1] / 8
font = resource_filename(Requirement.parse("mopidy-touchscreen"),
@@ -44,6 +42,7 @@ class ScreenManager():
self.top_bar_objects = ScreenObjectsManager()
self.down_bar_objects = ScreenObjectsManager()
self.selected_zone = self.top_bar_objects
self.dirty_area = []
# Top bar
self.top_bar = pygame.Surface((self.size[0], self.base_size),
@@ -135,7 +134,7 @@ class ScreenManager():
def update(self):
surface = pygame.Surface(self.size)
self.background.draw_background(surface)
surface.fill([200,200,200])
self.screens[self.current_screen].update(surface)
surface.blit(self.top_bar, (0, 0))
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[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):
self.screens[0].track_playback_ended(tl_track, time_position)
@@ -261,6 +268,7 @@ class ScreenManager():
self.current_screen = new_screen
self.down_bar_objects.get_touch_object(
"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):
self.screens[3].playlists_loaded()
@@ -286,4 +294,4 @@ class ScreenManager():
pos = self.down_bar_objects.selected.pos
self.selected_zone = self.top_bar_objects
self.down_bar_objects.set_selected(None)
self.change_selection(event, pos)
self.change_selection(event, pos)

View File

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

View File

@@ -51,7 +51,7 @@ class TouchScreen(pykka.ThreadingActor, core.CoreListener):
while self.running:
clock.tick(15)
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():
if event.type == pygame.QUIT:
self.running = False

View File

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