Kaynağa Gözat

Optimized screen draw. Only update needed rects

Ander 11 yıl önce
ebeveyn
işleme
00b50c5202

+ 0 - 42
mopidy_touchscreen/dynamic_background.py

@@ -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

+ 3 - 0
mopidy_touchscreen/library_screen.py

@@ -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

+ 4 - 0
mopidy_touchscreen/list_view.py

@@ -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:

+ 3 - 0
mopidy_touchscreen/main_screen.py

@@ -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:

+ 3 - 0
mopidy_touchscreen/menu_screen.py

@@ -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(

+ 3 - 0
mopidy_touchscreen/playlist_screen.py

@@ -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)
 

+ 12 - 4
mopidy_touchscreen/screen_manager.py

@@ -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)

+ 38 - 8
mopidy_touchscreen/screen_objects.py

@@ -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])

+ 1 - 1
mopidy_touchscreen/touch_screen.py

@@ -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

+ 3 - 0
mopidy_touchscreen/tracklist.py

@@ -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)