Recover files

This commit is contained in:
Ander
2015-04-09 01:21:50 +02:00
parent c2b3a16cd3
commit 660258f044
26 changed files with 687 additions and 595 deletions

3
.gitignore vendored
View File

@@ -3,8 +3,9 @@
*.swp
*~
.coverage
.idea/
.tox/
MANIFEST
build/
dist/
.idea/
xunit-*.xml

View File

@@ -1,6 +1,6 @@
****************************
******************
Mopidy-Touchscreen
****************************
******************
.. image:: https://img.shields.io/pypi/v/Mopidy-Touchscreen.svg?style=flat
:target: https://pypi.python.org/pypi/Mopidy-Touchscreen/
@@ -10,25 +10,28 @@ Mopidy-Touchscreen
:target: https://pypi.python.org/pypi/Mopidy-Touchscreen/
:alt: Number of PyPI downloads
.. image:: https://img.shields.io/travis/9and3r/mopidy-touchscreen/master.png?style=flat
.. image:: https://img.shields.io/travis/9and3r/mopidy-touchscreen/develop.svg?style=flat
:target: https://travis-ci.org/9and3r/mopidy-touchscreen
:alt: Travis CI build status
.. image:: https://img.shields.io/coveralls/9and3r/mopidy-touchscreen/master.svg?style=flat
:target: https://coveralls.io/r/9and3r/mopidy-touchscreen?branch=master
.. image:: https://img.shields.io/coveralls/9and3r/mopidy-touchscreen/develop.svg?style=flat
:target: https://coveralls.io/r/9and3r/mopidy-touchscreen?branch=develop
:alt: Test coverage
Extension for displaying track info and controlling Mopidy from a touch screen using `PyGame <http://www.pygame.org/>`_/SDL.
Extension for displaying track info and controlling Mopidy from a touch screen
using `PyGame <http://www.pygame.org/>`_/SDL.
Cover images are downloaded from `last.fm <http://www.last.fm/api>`_
Dependencies
============
- ``Mopidy`` >= 0.18
- ``Mopidy`` >= 1.0
- ``Pykka`` >= 1.1
- ``pygame``
Installation
============
@@ -55,13 +58,24 @@ Mopidy-Touchscreen to your Mopidy configuration file::
cache_dir = $XDG_CACHE_DIR/mopidy/touchscreen
The following configuration values are available:
- ``touchscreen/enabled``: If the Touchscreen extension should be enabled or not.
- ``touchscreen/screen_width``: The width of the resolution you want to use in pixels.
- ``touchscreen/screen_height``: The width of the resolution you want to use in pixels.
- ``touchscreen/cursor``: If the mouse cursor should be shown. (If you use a touchscreen it should be false)
- ``touchscreen/fullscreen``: If you want to be shown as a window or in fullscreen.
- ``touchscreen/screen_width``: The folder to be used as cache. Defaults to ``$XDG_CACHE_DIR/mopidy/touchscreen``, which usually means
- ``touchscreen/enabled``: If the Touchscreen extension should be enabled or
not.
- ``touchscreen/screen_width``: The width of the resolution you want to use in
pixels.
- ``touchscreen/screen_height``: The width of the resolution you want to use in
pixels.
- ``touchscreen/cursor``: If the mouse cursor should be shown. (If you use a
touchscreen it should be false)
- ``touchscreen/fullscreen``: If you want to be shown as a window or in
fullscreen.
- ``touchscreen/screen_width``: The folder to be used as cache. Defaults to
``$XDG_CACHE_DIR/mopidy/touchscreen``, which usually means
``~/.cache/mopidy/touchscreen``
@@ -84,30 +98,31 @@ Add to the config the next variables::
sdl_fbdev = /dev/fb1
sdl_mousdrv = TSLIB
sdl_mousedev = event0
This is just an example. It may work but each LCD Shield seems to have its own configuration.
To find your values find an example of using pygame with your LCD Shield and it should be something like this in the code::
os.environ["SDL_FBDEV"] = "/dev/fb1"
os.environ["SDL_MOUSEDRV"] = "TSLIB"
os.environ["SDL_MOUSEDEV"] = "event0"
Run mopidy with root privileges
Run Mopidy with root privileges
```````````````````````````````
You can use ``sudo mopidy``.
In case you are using musicbox edit ``/etc/init.d/mopidy`` file. Change ``DAEMON_USER=mopidy`` to ``DAEMON_USER=root``
Do not forget that this is a workaround and that mopidy will run with root privileges.
Help
====
You can use `mopidy discuss <https://discuss.mopidy.com/>`_
or send an email to `9and3r@gmail.com <mailto:9and3r@gmail.com>`_
Features
========
@@ -132,16 +147,19 @@ Planned
* Use keyboard or GPIO buttons instead of touchscreen
Screenshots
===========
.. image:: http://i60.tinypic.com/qqsait.jpg
Video
=====
`Example video running the extension <https://www.youtube.com/watch?v=KuYoIb8Q2LI>`_
Project resources
=================
@@ -153,25 +171,26 @@ Project resources
Changelog
=========
v0.3.2
----------------------------------------
v0.4.0 (UNRELEASED)
-------------------
- Require Mopidy v1.0
- Update to work with changed core playback API in Mopidy 1.0
v0.3.2 (2015-01-09)
-------------------
- Bug Fixes
- UI changes
- Smoth text scrolling
- Search albums, artist or songs (Not fully implemented. Basic functionality)
v0.2.1
----------------------------------------
v0.2.1 (2014-08-02)
-------------------
- Font will be included on installation
v0.2.0
----------------------------------------
v0.2.0 (2014-08-02)
-------------------
- First working version
v0.1.0 (UNRELEASED)
----------------------------------------
- Initial release.

View File

@@ -40,8 +40,8 @@ Or, if available, install the Debian/Ubuntu package from `apt.mopidy.com
<http://apt.mopidy.com/>`_.
Configuration
=============
Basic Configuration
===================
Before starting Mopidy, you must add configuration for
Mopidy-Touchscreen to your Mopidy configuration file::
@@ -62,10 +62,54 @@ The following configuration values are available:
- ``touchscreen/cursor``: If the mouse cursor should be shown. (If you use a touchscreen it should be false)
- ``touchscreen/fullscreen``: If you want to be shown as a window or in fullscreen.
- ``touchscreen/screen_width``: The folder to be used as cache. Defaults to ``$XDG_CACHE_DIR/mopidy/touchscreen``, which usually means
``~/.cache/mopidy/spotify``
``~/.cache/mopidy/touchscreen``
How to Setup
============
Use the basic configuration to setup as most standard screens works fine without further configuration.
Raspberry Pi and LCD Shields
----------------------------
If you are using a LCD Shield in Raspberry Pi you need to config your LCD and run mopidy with root privileges:
Configure your LCD Shield
`````````````````````````
Add to the config the next variables::
[touchscreen]
sdl_fbdev = /dev/fb1
sdl_mousdrv = TSLIB
sdl_mousedev = event0
This is just an example. It may work but each LCD Shield seems to have its own configuration.
To find your values find an example of using pygame with your LCD Shield and it should be something like this in the code::
os.environ["SDL_FBDEV"] = "/dev/fb1"
os.environ["SDL_MOUSEDRV"] = "TSLIB"
os.environ["SDL_MOUSEDEV"] = "event0"
Run mopidy with root privileges
```````````````````````````````
You can use ``sudo mopidy``.
In case you are using musicbox edit ``/etc/init.d/mopidy`` file. Change ``DAEMON_USER=mopidy`` to ``DAEMON_USER=root``
Do not forget that this is a workaround and that mopidy will run with root privileges.
Help
====
You can use `mopidy discuss <https://discuss.mopidy.com/>`_
or send an email to `9and3r@gmail.com <mailto:9and3r@gmail.com>`_
Features
=============
========
Working
-------
@@ -109,10 +153,18 @@ Project resources
Changelog
=========
v0.3.2
----------------------------------------
- Bug Fixes
- UI changes
- Smoth text scrolling
- Search albums, artist or songs (Not fully implemented. Basic functionality)
v0.2.1
----------------------------------------
-Font will be included on instalation
- Font will be included on installation
v0.2.0
----------------------------------------

View File

@@ -1,16 +1,13 @@
from __future__ import unicode_literals
import logging
import os
from mopidy import config, ext
from .touch_screen import TouchScreen
__version__ = '0.3.2'
# TODO: If you need to log, use loggers named after the current Python module
logger = logging.getLogger(__name__)
__version__ = '0.4.0'
class Extension(ext.Extension):

View File

@@ -1,61 +0,0 @@
import random
change_speed = 2
import pygame
class DynamicBackground():
def __init__(self, size):
self.size = size
self.current = get_valid_color()
self.target = get_valid_color()
self.surface = None
def draw_background(self, surface):
same = True
for x in range(0, 3):
if abs(self.current[x]-self.target[x]) < change_speed:
self.current[x] = self.target[x]
else:
if self.current[x] > self.target[x]:
self.current[x] -= change_speed
elif self.current[x] < self.target[x]:
self.current[x] += change_speed
if self.current != self.target:
same = False
#if same:
# self.target = get_valid_color()
surface.fill(self.current)
if self.surface is not None:
surface.blit(self.surface,(0,0))
def set_target_color(self, color, surface):
self.target = [color[0], color[1], color[2]]
#irudi = pygame.Surface(surface.get_size())
#pygame.transform.laplacian(surface, irudi)
irudi = surface
target = pygame.Surface(self.size)
pygame.transform.smoothscale(irudi, self.size, target)
target.set_alpha(80)
self.surface = target
# 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

@@ -0,0 +1,4 @@
# flake8: noqa
from dynamic_background import DynamicBackground
from list_view import ListView
from screen_objects import *

View File

@@ -0,0 +1,106 @@
import random
import pygame
change_speed = 2
class DynamicBackground():
def __init__(self, size):
self.current = get_valid_color()
self.target = get_valid_color()
self.auto_mode = True
self.image_loaded = False
self.size = size
self.surface = pygame.Surface(self.size).convert()
self.target_current_same = False
def draw_background(self):
if self.image_loaded:
return self.surface.copy()
else:
if not self.target_current_same:
for x in range(0, 3):
if abs(self.current[x]-self.target[x]) < change_speed:
self.current[x] = self.target[x]
self.target_current_same = True
else:
self.target_current_same = False
if self.current[x] > self.target[x]:
self.current[x] -= change_speed
elif self.current[x] < self.target[x]:
self.current[x] += change_speed
if self.auto_mode and self.target_current_same:
self.target = get_valid_color()
self.target_current_same = False
self.surface.fill(self.current)
return self.surface.copy()
def set_target_color(self, color, image):
if color is not None:
self.auto_mode = False
self.target_current_same = False
self.target = get_similar_valid_color(color)
else:
self.auto_mode = True
self.target = get_valid_color()
self.target_current_same = False
if image is not None:
image_size = get_aspect_scale_size(image, self.size)
target = pygame.transform.smoothscale(image, image_size)
target.set_alpha(150)
self.image_loaded = True
self.surface.fill((0, 0, 0))
pos = ((self.size[0] - image_size[0])/2,
(self.size[1] - image_size[1])/2)
self.surface.blit(target, pos)
else:
self.image_loaded = False
# It will return the same color if sum is less than 510
# Otherwise a darker color will be returned
# White text should be seen ok with this background color
def get_similar_valid_color(color):
sum = color[0] + color[1] + color[2]
new_color = [0, 0, 0]
if sum > 510:
rest = (sum - 510)/3 + 1
for x in range(0, 3):
new_color[x] = color[x] - rest
return new_color
else:
return color
# 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
def get_aspect_scale_size(img, (bx, by)):
size = img.get_size()
aspect_x = bx / float(size[0])
aspect_y = by / float(size[1])
if aspect_x > aspect_y:
aspect = aspect_x
else:
aspect = aspect_y
new_size = (int(aspect*size[0]), int(aspect*size[1]))
return new_size

View File

@@ -1,8 +1,9 @@
import logging
from .screen_objects import ScreenObjectsManager, ScrollBar, \
from screen_objects import ScreenObjectsManager, ScrollBar, \
TouchAndTextItem
from .input_manager import InputManager
from ..input import InputManager
logger = logging.getLogger(__name__)
@@ -19,10 +20,12 @@ class ListView():
self.list_size = 0
self.list = []
self.scrollbar = False
self.selected = None
self.active = []
self.set_list([])
self.selected = []
# 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):
self.screen_objects.clear()
self.list = item_list
@@ -38,6 +41,10 @@ class ListView():
scroll_bar)
else:
self.scrollbar = False
if self.list_size > 0:
self.selected = 0
else:
self.selected = None
self.load_new_item_position(0)
# Will load items currently displaying in item_pos
@@ -55,12 +62,12 @@ class ListView():
width = self.size[0]
while i < self.list_size and z < self.max_rows:
item = TouchAndTextItem(self.font, self.list[i], (
self.pos[0], self.pos[1] + self.base_size * z),
(width, -1))
self.pos[0],
self.pos[1] + self.base_size * z), (width, -1))
self.screen_objects.set_touch_object(str(i), item)
i += 1
z += 1
self.reload_selected()
def render(self, surface):
self.screen_objects.render(surface)
@@ -73,12 +80,22 @@ class ListView():
if objects is not None:
for key in objects:
if key == "scrollbar":
direction = self.screen_objects.get_touch_object(
key).touch(touch_event.current_pos)
direction = \
self.screen_objects.get_touch_object(
key).touch(touch_event.current_pos)
if direction != 0:
self.move_to(direction)
else:
return int(key)
elif (touch_event.type == InputManager.key and
self.selected is not None):
if touch_event.direction == InputManager.enter:
if self.selected is not None:
return self.selected
elif touch_event.direction == InputManager.up:
self.set_selected(self.selected-1)
elif touch_event.direction == InputManager.down:
self.set_selected(self.selected+1)
elif touch_event.type == InputManager.swipe:
if touch_event.direction == InputManager.up:
self.move_to(-1)
@@ -106,22 +123,58 @@ class ListView():
self.screen_objects.get_touch_object(
"scrollbar").set_item(
self.current_item)
self.set_selected(self.selected)
self.set_active(self.active)
# Set selected items
def set_selected(self, selected):
for number in self.selected:
# Set active items
def set_active(self, active):
for number in self.active:
try:
self.screen_objects.get_touch_object(
str(number)).set_active(
False)
except KeyError:
pass
for number in selected:
for number in active:
try:
self.screen_objects.get_touch_object(
str(number)).set_active(
True)
except KeyError:
pass
self.selected = selected
self.active = active
def set_selected(self, selected):
if selected > -1 and selected < len(self.list):
if self.selected is not None:
try:
self.screen_objects.get_touch_object(
str(self.selected)).set_selected(
False)
except KeyError:
pass
if selected is not None:
try:
self.screen_objects.get_touch_object(
str(selected)).set_selected(
True)
except KeyError:
pass
self.selected = selected
self.set_selected_on_screen()
def set_selected_on_screen(self):
if self.current_item + self.max_rows <= self.selected:
self.move_to(1)
self.set_selected_on_screen()
elif self.current_item > self.selected:
self.move_to(-1)
self.set_selected_on_screen()
def reload_selected(self):
if self.selected is not None:
try:
self.screen_objects.get_touch_object(
str(self.selected)).set_selected(
True)
except KeyError:
pass

View File

@@ -1,8 +1,7 @@
import logging
import math
import pygame
from .input_manager import InputManager
import pygame
logger = logging.getLogger(__name__)
@@ -31,7 +30,6 @@ class ScreenObjectsManager():
def get_touch_object(self, key):
return self.touch_objects[key]
def render(self, surface):
for key in self.text_objects:
self.text_objects[key].update()
@@ -67,134 +65,6 @@ class ScreenObjectsManager():
self.selected = None
self.selected_key = None
def change_selected(self, direction, pos):
if pos is None:
pos = self.selected.pos
if direction == InputManager.right:
bests = self.find_nearest_objects(
self.find_in_quadrant(False, True, pos), True, pos)
best_key = self.find_best_object(bests, False, True, pos)
elif direction == InputManager.left:
bests = self.find_nearest_objects(
self.find_in_quadrant(False, False, pos), True, pos)
best_key = self.find_best_object(bests, False, False, pos)
elif direction == InputManager.down:
bests = self.find_nearest_objects(
self.find_in_quadrant(True, True, pos), False, pos)
best_key = self.find_best_object(bests, True, True, pos)
elif direction == InputManager.up:
bests = self.find_nearest_objects(
self.find_in_quadrant(True, False, pos), False, pos)
best_key = self.find_best_object(bests, True, False, pos)
if best_key is None:
return False
else:
self.set_selected(best_key)
return True
# Find touch objects on specified quadrant
# The quadrant is the normal math one with x and y
# x is positive on the bottom as pygame x
# The quadrant origin (0,0) is the selected pos
def find_in_quadrant(self, vertical, positive, pos):
objects = {}
if vertical:
if positive:
for key in self.touch_objects:
current = self.touch_objects[key]
if current.pos[1] > pos[1]:
objects[key] = current
else:
for key in self.touch_objects:
current = self.touch_objects[key]
if current.pos[1] < pos[1]:
objects[key] = current
else:
if positive:
for key in self.touch_objects:
current = self.touch_objects[key]
if current.pos[0] > pos[0]:
objects[key] = current
else:
for key in self.touch_objects:
current = self.touch_objects[key]
if current.pos[0] < pos[0]:
objects[key] = current
return objects
# Find the objects that are nearest
def find_nearest_objects(self, objects, vertical, pos):
best_pos = None
min_value = None
best_objects = {}
if vertical:
for key in objects:
if min_value is None:
best_pos = objects[key].pos[1]
min_value = abs(objects[key].pos[1] - pos[1])
elif abs(objects[key].pos[1] - pos[1]) < min_value:
min_value = abs(objects[key].pos[1] - pos[1])
best_pos = objects[key].pos[1]
for key in objects:
if objects[key].pos[1] == best_pos:
best_objects[key] = objects[key]
return best_objects
else:
for key in objects:
if min_value is None:
best_pos = objects[key].pos[0]
min_value = abs(objects[key].pos[0] - pos[0])
elif abs(objects[key].pos[0] - pos[0]) < min_value:
min_value = abs(objects[key].pos[0] - pos[0])
best_pos = objects[key].pos[0]
for key in objects:
if objects[key].pos[0] == best_pos:
best_objects[key] = objects[key]
return best_objects
def find_best_object(self, objects, vertical, positive, pos):
best_key = None
best_pos = None
if vertical:
if positive:
for key in objects:
if best_pos is None:
best_pos = objects[key].pos[1]
best_key = key
elif objects[key].pos[1] >= pos[1] and \
objects[key].pos[1] < best_pos:
best_pos = objects[key].pos[1]
best_key = key
else:
for key in objects:
if best_pos is None:
best_pos = objects[key].pos[1]
best_key = key
elif objects[key].pos[1] <= pos[1] and \
objects[key].pos[1] > best_pos:
best_pos = objects[key].pos[1]
best_key = key
else:
if positive:
for key in objects:
if best_pos is None:
best_pos = objects[key].pos[0]
best_key = key
elif objects[key].pos[0] >= pos[0] and \
objects[key].pos[0] < best_pos:
best_pos = objects[key].pos[0]
best_key = key
else:
for key in objects:
if best_pos is None:
best_pos = objects[key].pos[0]
best_key = key
elif objects[key].pos[0] <= pos[0] and \
objects[key].pos[0] > best_pos:
best_pos = objects[key].pos[0]
best_key = key
return best_key
class BaseItem():
def __init__(self, pos, size):
@@ -208,20 +78,20 @@ class BaseItem():
def get_right_pos(self):
return self.pos[0] + self.size[0]
def update(self):
pass
class TextItem(BaseItem):
scroll_speed = 2
scroll_speed = 5
def __init__(self, font, text, pos, size, center=False):
self.font = font
self.text = text
self.color = (255, 255, 255)
self.box = self.font.render(text, True, self.color)
self.box = self.box.convert_alpha()
if size is not None:
if size[1] == -1:
height = self.font.size(text)[1]
@@ -235,6 +105,8 @@ class TextItem(BaseItem):
size[0]:
self.fit_horizontal = False
self.step = 0
self.step_2 = None
self.scroll_white_gap = self.font.get_height() * 4
else:
self.fit_horizontal = True
if self.pos[1] + self.box.get_rect().height > pos[1] + \
@@ -249,26 +121,43 @@ class TextItem(BaseItem):
self.center = center
if self.center:
if self.fit_horizontal:
self.margin = (self.size[0]-self.box.get_rect().width)/2
self.margin = (self.size[0] -
self.box.get_rect().width)/2
def update(self):
if not self.fit_horizontal:
if self.step > self.box.get_rect().width:
self.step = -self.size[0]
self.step += TextItem.scroll_speed
if self.step_2 is None:
if (self.box.get_rect().width - self.step +
self.scroll_white_gap) < self.size[0]:
self.step_2 = \
self.box.get_rect().width - \
self.step + self.scroll_white_gap
else:
self.step = self.step + TextItem.scroll_speed
self.step_2 -= TextItem.scroll_speed
if self.step_2 < 0:
self.step = 0 - self.step_2
self.step_2 = None
return True
else:
return BaseItem.update(self)
def render(self, surface):
if self.fit_horizontal:
surface.blit(self.box, ((self.pos[0] + self.margin), self.pos[1]), area=self.rect)
surface.blit(
self.box, ((self.pos[0] + self.margin),
self.pos[1]), area=self.rect)
else:
surface.blit(self.box, self.pos,
area=pygame.Rect(self.step, 0, self.size[0],
self.size[1]))
if self.step_2 is not None:
surface.blit(self.box, (self.pos[0]+self.step_2,
self.pos[1]),
area=pygame.Rect(0, 0,
self.size[0] -
self.step_2,
self.size[1]))
def set_text(self, text, change_size):
if text != self.text:
@@ -285,6 +174,15 @@ class TouchObject(BaseItem):
BaseItem.__init__(self, pos, size)
self.active = False
self.selected = False
self.selected_box = pygame.Surface(size, pygame.SRCALPHA)
self.selected_box = self.selected_box.convert_alpha()
self.selected_box.fill((0, 0, 0, 128))
self.selected_box_rectangle = pygame.Surface(size, pygame.SRCALPHA)
self.selected_box_rectangle = \
self.selected_box_rectangle.convert_alpha()
pygame.draw.rect(self.selected_box_rectangle, (255, 255, 255),
self.selected_box_rectangle.get_rect(),
size[1]/10+1)
def is_pos_inside(self, pos):
return self.rect_in_pos.collidepoint(pos)
@@ -295,38 +193,49 @@ class TouchObject(BaseItem):
def set_selected(self, selected):
self.selected = selected
def render(self, surface):
if self.selected:
surface.blit(self.selected_box, self.pos)
surface.blit(self.selected_box_rectangle, self.pos)
def pre_render(self, surface):
if self.selected:
surface.blit(self.selected_box, self.pos)
def post_render(self, surface):
if self.selected:
surface.blit(self.selected_box_rectangle, self.pos)
class TouchAndTextItem(TouchObject, TextItem):
def __init__(self, font, text, pos, size, center=False):
TextItem.__init__(self, font, text, pos, size, center=center)
TouchObject.__init__(self, pos, self.size)
self.active_color = (0, 150, 255)
self.selected_color = (150, 0, 255)
self.normal_box = self.box
self.active_box = self.font.render(text, True,
self.active_color)
self.selected_box = self.font.render(text, True,
self.selected_color)
def update(self):
TextItem.update(self)
def set_text(self, text, change_size):
TextItem.set_text(self, text, change_size)
self.normal_box = self.box
self.active_box = self.font.render(text, True,
self.active_color)
self.selected_box = self.font.render(text, True,
self.selected_color)
def set_active(self, active):
TouchObject.set_active(self, active)
if self.active:
self.box = self.active_box
else:
self.box = self.normal_box
def render(self, surface):
if not self.fit_horizontal:
self.rect = pygame.Rect(self.step, 0, self.size[0],
self.size[1])
if self.selected:
surface.blit(self.selected_box, (self.pos[0]+self.margin, self.pos[1]), area=self.rect)
elif self.active:
surface.blit(self.active_box, (self.pos[0]+self.margin, self.pos[1]), area=self.rect)
else:
surface.blit(self.box, (self.pos[0]+self.margin, self.pos[1]), area=self.rect)
TouchObject.pre_render(self, surface)
TextItem.render(self, surface)
TouchObject.post_render(self, surface)
class Progressbar(TouchObject):
@@ -336,24 +245,33 @@ class Progressbar(TouchObject):
self.max = max_value
self.back_color = (0, 0, 0, 128)
self.main_color = (0, 150, 255)
self.surface = pygame.Surface(self.size, pygame.SRCALPHA)
self.surface = pygame.Surface(self.size, pygame.SRCALPHA)\
.convert_alpha()
self.surface.fill(self.back_color)
self.value_text = value_text
if value_text:
self.text = TextItem(font, str(max_value), pos, None)
self.text.pos = (
self.pos[0] + self.size[0] / 2 - self.text.size[0] /
2, self.text.pos[1])
self.text.pos = (self.pos[0]
+ self.size[0] / 2 -
self.text.size[0] /
2, self.text.pos[1])
self.text.set_text(str(self.value), True)
else:
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])
self.pos[0] + self.size[0] / 2 - self.text.size[0] /
2, self.text.pos[1])
# Rectangle
self.rectangle = pygame.Surface(size, pygame.SRCALPHA)\
.convert_alpha()
pygame.draw.rect(self.rectangle, (255, 255, 255),
self.rectangle.get_rect(),
size[1]/20+1)
def render(self, surface):
surface.blit(self.surface, self.pos)
surface.blit(self.rectangle, self.pos)
self.text.render(surface)
def set_value(self, value):
@@ -361,9 +279,10 @@ class Progressbar(TouchObject):
self.value = value
if self.value_text:
self.set_text(str(self.value))
self.text.pos = (
self.pos[0] + self.size[0] / 2 - self.text.size[0] /
2, self.text.pos[1])
self.text.pos = (self.pos[0]
+ self.size[0] / 2 -
self.text.size[0]
/ 2, self.text.pos[1])
self.surface.fill(self.back_color)
pos_pixel = value * self.size[0] / self.max
rect = pygame.Rect(0, 0, pos_pixel, self.size[1])
@@ -386,7 +305,8 @@ class ScrollBar(TouchObject):
self.max = max_value
self.items_on_screen = items_on_screen
self.current_item = 0
self.back_bar = pygame.Surface(self.size, pygame.SRCALPHA)
self.back_bar = pygame.Surface(self.size, pygame.SRCALPHA)\
.convert_alpha()
self.back_bar.fill((255, 255, 255, 128))
self.bar_pos = 0
if self.max < 1:
@@ -395,7 +315,7 @@ class ScrollBar(TouchObject):
self.bar_size = math.ceil(
float(self.items_on_screen) / float(self.max) * float(
self.size[1]))
self.bar = pygame.Surface((self.size[0], self.bar_size))
self.bar = pygame.Surface((self.size[0], self.bar_size)).convert()
self.bar.fill((255, 255, 255))
def render(self, surface):

View File

@@ -0,0 +1,2 @@
# flake8: noqa
from input_manager import InputManager

View File

@@ -1,8 +1,9 @@
import logging
import pygame
import RPi.GPIO as GPIO
import pygame
logger = logging.getLogger(__name__)
@@ -92,8 +93,3 @@ def enter(channel):
dict['key'] = pygame.K_RETURN
event = pygame.event.Event(type, dict)
pygame.event.post(event)

View File

@@ -93,10 +93,10 @@ class InputManager():
def mouse_up(self, event):
self.up_pos = event.pos
if abs(self.down_pos[0] - self.up_pos[
0]) < self.max_move_margin:
if abs(self.down_pos[1] - self.up_pos[
1]) < self.max_move_margin:
if abs(self.down_pos[0] -
self.up_pos[0]) < self.max_move_margin:
if abs(self.down_pos[1] -
self.up_pos[1]) < self.max_move_margin:
if time.time() - InputManager.long_click_min_time > \
self.down_time:
return InputEvent(InputManager.long_click,
@@ -106,13 +106,13 @@ class InputManager():
return InputEvent(InputManager.click,
self.down_pos,
self.up_pos, None, None)
elif abs(self.down_pos[1] - self.up_pos[
1]) > self.min_swipe_move:
elif abs(self.down_pos[1] - self.up_pos[1])\
> self.min_swipe_move:
return InputEvent(InputManager.swipe, self.down_pos,
self.up_pos, True, None)
elif self.down_pos[1] - self.up_pos[1] < self.max_move_margin:
if abs(self.down_pos[0] - self.up_pos[
0]) > self.min_swipe_move:
if abs(self.down_pos[0] - self.up_pos[0]) > \
self.min_swipe_move:
return InputEvent(InputManager.swipe, self.down_pos,
self.up_pos, False, None)

View File

@@ -1,92 +0,0 @@
import os
import socket
import mopidy
from .screen_objects import ScreenObjectsManager, TouchAndTextItem
from .input_manager import InputManager
from .base_screen import BaseScreen
class MenuScreen(BaseScreen):
def __init__(self, size, base_size, manager, fonts):
BaseScreen.__init__(self, size, base_size, manager, fonts)
self.ip = None
self.screen_objects = ScreenObjectsManager()
# Exit mopidy button
button = TouchAndTextItem(self.manager.fonts['icon'],
u"\ue611",
(0, 0), None)
self.screen_objects.set_touch_object("exit_icon", button)
button = TouchAndTextItem(self.fonts['base'],
"Exit Mopidy",
(button.get_right_pos(),
0),
None)
self.screen_objects.set_touch_object("exit", button)
# Shutdown button
button = TouchAndTextItem(self.fonts['icon'],
u"\ue60b",
(0, self.base_size * 1), None)
self.screen_objects.set_touch_object("shutdown_icon", button)
button = TouchAndTextItem(self.fonts['base'],
"Shutdown",
(button.get_right_pos(),
self.base_size * 1),
None)
self.screen_objects.set_touch_object("shutdown", button)
# Restart button
button = TouchAndTextItem(self.fonts['icon'],
u"\ue609",
(0, self.base_size * 2), None)
self.screen_objects.set_touch_object("restart_icon", button)
button = TouchAndTextItem(self.fonts['base'],
"Restart",
(button.get_right_pos(),
self.base_size * 2),
None)
self.screen_objects.set_touch_object("restart", button)
# IP addres
button = TouchAndTextItem(self.fonts['base'], "IP: ",
(0, self.base_size * 3), None)
self.screen_objects.set_touch_object("ip", button)
def update(self, screen, update_all):
self.screen_objects.render(screen)
def touch_event(self, event):
if event.type == InputManager.click:
clicked = self.screen_objects.get_touch_objects_in_pos(
event.current_pos)
for key in clicked:
if key == "exit_icon" or key == "exit":
mopidy.utils.process.exit_process()
elif key == "shutdown_icon" or key == "shutdown":
if os.system("gksu -- shutdown now -h") != 0:
os.system("shutdown now -h")
elif key == "restart_icon" or key == "restart":
if os.system("gksu -- shutdown -r now") != 0:
os.system("shutdown -r now")
elif key == "ip":
self.check_connection()
# Will check internet connection
def check_connection(self):
try:
self.manager.set_connection(False, True)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
self.ip = s.getsockname()[0]
s.close()
self.screen_objects.get_touch_object("ip").set_text(
"IP: " + self.ip, "None")
self.manager.set_connection(True, False)
except socket.error:
s.close()
self.ip = None
self.screen_objects.get_touch_object("ip").set_text(
"IP: No internet", "None")
self.manager.set_connection(False, False)

View File

@@ -1,18 +1,17 @@
import logging
import traceback
import pygame
from graphic_utils import DynamicBackground, \
ScreenObjectsManager, TouchAndTextItem
from input import InputManager
from pkg_resources import Requirement, resource_filename
from .search_screen import SearchScreen
from .library_screen import LibraryScreen
from .main_screen import MainScreen
from .menu_screen import MenuScreen
from .playlist_screen import PlaylistScreen
from .screen_objects import ScreenObjectsManager, \
TouchAndTextItem
from .input_manager import InputManager
from .tracklist import Tracklist
from .dynamic_background import DynamicBackground
import pygame
from screens import LibraryScreen, MainScreen, MenuScreen,\
PlaylistScreen, SearchScreen, Tracklist
logger = logging.getLogger(__name__)
@@ -29,41 +28,49 @@ class ScreenManager():
self.core = core
self.cache = cache
self.fonts = {}
self.background = None
self.current_screen = library_index
self.init_manager(size)
# Init variables in init
self.base_size = None
self.size = None
self.screens = None
self.track = None
self.input_manager = InputManager(size)
self.down_bar_objects = ScreenObjectsManager()
self.down_bar = None
self.init_manager(size)
def init_manager(self, size):
self.size = size
self.background = DynamicBackground(self.size)
self.current_screen = 0
self.base_size = self.size[1] / 8
font = resource_filename(
Requirement.parse("mopidy-touchscreen"),
"mopidy_touchscreen/icomoon.ttf")
self.fonts['base'] = pygame.font.SysFont("verdana",
self.fonts['base'] = pygame.font.SysFont("arial",
self.base_size)
self.fonts['icon'] = pygame.font.Font(font, self.base_size)
try:
self.screens = [
SearchScreen(size, self.base_size, self, self.fonts),
MainScreen(size, self.base_size, self, self.fonts, self.cache, self.core, self.background),
MainScreen(size, self.base_size, self, self.fonts,
self.cache, self.core, self.background),
Tracklist(size, self.base_size, self, self.fonts),
LibraryScreen(size, self.base_size, self, self.fonts),
PlaylistScreen(size, self.base_size, self, self.fonts),
PlaylistScreen(size,
self.base_size, self, self.fonts),
MenuScreen(size, self.base_size, self, self.fonts)]
except:
traceback.print_exc()
self.track = None
self.input_manager = InputManager(size)
self.down_bar_objects = ScreenObjectsManager()
self.screen_changed = True
# Menu buttons
button_size = (self.size[0] / 6, self.base_size)
# Search button
# Search button
button = TouchAndTextItem(self.fonts['icon'], u" \ue986",
(0, self.base_size * 7),
button_size, center=True)
@@ -101,14 +108,16 @@ class ScreenManager():
# Menu button
button = TouchAndTextItem(self.fonts['icon'], u" \ue60a",
(x, self.base_size * 7), button_size, center=True)
(x, self.base_size * 7),
button_size,
center=True)
self.down_bar_objects.set_touch_object("menu_5", button)
# Down bar
self.down_bar = pygame.Surface(
(self.size[0], self.size[1] - self.base_size * 7),
pygame.SRCALPHA)
self.down_bar.fill((0, 0, 0, 128))
self.down_bar.fill((0, 0, 0, 200))
self.options_changed()
self.mute_changed(self.core.playback.mute.get())
@@ -118,13 +127,10 @@ class ScreenManager():
self.change_screen(self.current_screen)
def update(self):
surface = pygame.Surface(self.size)
self.background.draw_background(surface)
self.screens[self.current_screen].update(surface,
self.screen_changed)
surface = self.background.draw_background()
self.screens[self.current_screen].update(surface)
surface.blit(self.down_bar, (0, self.base_size * 7))
self.down_bar_objects.render(surface)
self.screen_changed = False
return surface
def track_started(self, track):
@@ -133,7 +139,8 @@ class ScreenManager():
self.screens[tracklist_index].track_started(track)
def track_playback_ended(self, tl_track, time_position):
self.screens[main_screen_index].track_playback_ended(tl_track, time_position)
self.screens[main_screen_index].track_playback_ended(
tl_track, time_position)
def event(self, event):
event = self.input_manager.event(event)
@@ -143,16 +150,26 @@ class ScreenManager():
def manage_event(self, event):
if event.type == InputManager.click:
objects = self.down_bar_objects.get_touch_objects_in_pos(event.current_pos)
objects = \
self.down_bar_objects.get_touch_objects_in_pos(
event.current_pos)
return self.click_on_objects(objects, event)
else:
if event.type == InputManager.key:
if event.direction == InputManager.right:
self.change_screen(self.current_screen+1)
return True
elif event.direction == InputManager.left:
self.change_screen(self.current_screen-1)
return True
return False
def volume_changed(self, volume):
self.screens[main_screen_index].volume_changed(volume)
def playback_state_changed(self, old_state, new_state):
self.screens[main_screen_index].playback_state_changed(old_state, new_state)
self.screens[main_screen_index].playback_state_changed(
old_state, new_state)
def mute_changed(self, mute):
self.screens[main_screen_index].mute_changed(mute)
@@ -164,12 +181,12 @@ class ScreenManager():
self.screens[main_screen_index].options_changed()
def change_screen(self, new_screen):
self.screen_changed = True
self.down_bar_objects.get_touch_object(
"menu_" + str(self.current_screen)).set_active(False)
self.current_screen = new_screen
self.down_bar_objects.get_touch_object(
"menu_" + str(new_screen)).set_active(True)
if new_screen > -1 and new_screen < len(self.screens):
self.down_bar_objects.get_touch_object(
"menu_" + str(self.current_screen)).set_active(False)
self.current_screen = new_screen
self.down_bar_objects.get_touch_object(
"menu_" + str(new_screen)).set_active(True)
def click_on_objects(self, objects, event):
if objects is not None:
@@ -183,7 +200,8 @@ class ScreenManager():
self.screens[playlist_index].playlists_loaded()
def set_connection(self, connection, loading):
self.screens[main_screen_index].set_connection(connection, loading)
self.screens[main_screen_index].set_connection(connection,
loading)
def check_connection(self):
self.screens[menu_index].check_connection()

View File

@@ -0,0 +1,7 @@
# flake8: noqa
from library_screen import LibraryScreen
from main_screen import MainScreen
from menu_screen import MenuScreen
from playlist_screen import PlaylistScreen
from search_screen import SearchScreen
from tracklist import Tracklist

View File

@@ -1,6 +1,3 @@
__author__ = 'ander'
class BaseScreen():
def __init__(self, size, base_size, manager, fonts):

View File

@@ -1,29 +1,22 @@
import logging
from base_screen import BaseScreen
import mopidy.models
from .list_view import ListView
from .input_manager import InputManager
from .base_screen import BaseScreen
logger = logging.getLogger(__name__)
from ..graphic_utils import ListView
class LibraryScreen(BaseScreen):
def __init__(self, size, base_size, manager, fonts):
BaseScreen.__init__(self, size, base_size, manager, fonts)
self.list_view = ListView((0, 0), (
self.size[0], self.size[1] - self.base_size),
self.base_size,
self.fonts['base'])
self.size[0], self.size[1] -
self.base_size), self.base_size, self.fonts['base'])
self.directory_list = []
self.current_directory = None
self.library = None
self.library_strings = None
self.browse_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
@@ -44,7 +37,7 @@ class LibraryScreen(BaseScreen):
self.current_directory = directory
self.browse_uri(directory)
def update(self, screen, update_all):
def update(self, screen):
self.list_view.render(screen)
def touch_event(self, touch_event):
@@ -54,24 +47,25 @@ class LibraryScreen(BaseScreen):
if clicked == 0:
self.go_up_directory()
else:
if self.library[
clicked - 1].type == mopidy.models.Ref.TRACK:
self.play_uri(self.current_directory, clicked-1)
if self.library[clicked - 1].type\
== mopidy.models.Ref.TRACK:
self.play_uri(clicked-1)
else:
self.go_inside_directory(
self.library[clicked - 1].uri)
else:
self.go_inside_directory(
self.library[clicked].uri)
self.go_inside_directory(self.library[clicked].uri)
def play_uri(self, uri, track_pos):
def play_uri(self, track_pos):
self.manager.core.tracklist.clear()
tracks = []
for item in self.library:
if item.type == mopidy.models.Ref.TRACK:
tracks.append(self.manager.core.library.lookup(item.uri).get()[0])
tracks.append(self.manager.core.library.lookup(
item.uri).get()[0])
else:
track_pos = track_pos - 1
track_pos -= 1
self.manager.core.tracklist.add(tracks)
self.manager.core.playback.play(tl_track=self.manager.core.tracklist.tl_tracks.get()[track_pos])
self.manager.core.playback.play(
tl_track=self.manager.core.tracklist.tl_tracks.get()
[track_pos])

View File

@@ -3,24 +3,28 @@ import json
import logging
import os
import time
import mopidy.core
import urllib
import urllib2
from threading import Thread
import pygame
from .base_screen import BaseScreen
from .screen_objects import (Progressbar, ScreenObjectsManager,
TextItem,
TouchAndTextItem)
from .input_manager import InputManager
from base_screen import BaseScreen
import mopidy.core
import pygame
from ..graphic_utils import Progressbar, \
ScreenObjectsManager, TouchAndTextItem
from ..input import InputManager
logger = logging.getLogger(__name__)
class MainScreen(BaseScreen):
def __init__(self, size, base_size, manager, fonts, cache, core, background):
def __init__(self, size, base_size, manager, fonts, cache, core,
background):
BaseScreen.__init__(self, size, base_size, manager, fonts)
self.core = core
self.track = None
@@ -35,8 +39,7 @@ class MainScreen(BaseScreen):
self.track_playback_ended(None, None)
else:
self.track_started(current_track)
# Top bar
self.top_bar = pygame.Surface((self.size[0], self.base_size),
pygame.SRCALPHA)
@@ -85,7 +88,7 @@ class MainScreen(BaseScreen):
self.touch_text_manager.set_touch_object("volume", progress)
progress.set_value(self.core.playback.volume.get())
def update(self, screen, update_all):
def update(self, screen):
screen.blit(self.top_bar, (0, 0))
if self.track is not None:
self.touch_text_manager.get_touch_object(
@@ -94,10 +97,12 @@ class MainScreen(BaseScreen):
self.touch_text_manager.get_touch_object(
"time_progress").set_text(
time.strftime('%M:%S', time.gmtime(
self.core.playback.time_position.get() / 1000)) + "/" + self.track_duration)
self.core.playback.time_position.get() / 1000)) +
"/" + self.track_duration)
if self.image is not None:
screen.blit(self.image, (
self.base_size / 2, self.base_size + self.base_size / 2))
self.base_size / 2, self.base_size +
self.base_size / 2))
self.touch_text_manager.render(screen)
return screen
@@ -116,22 +121,22 @@ class MainScreen(BaseScreen):
# Track name
label = TouchAndTextItem(self.fonts['base'],
MainScreen.get_track_name(track),
(x, self.base_size * 2),
(width, -1))
MainScreen.get_track_name(track),
(x, self.base_size * 2), (width, -1))
self.touch_text_manager.set_touch_object("track_name", label)
# Album name
label = TouchAndTextItem(self.fonts['base'],
MainScreen.get_track_album_name(track),
(x, self.base_size * 3),
(width, -1))
MainScreen.get_track_album_name
(track), (x, self.base_size * 3),
(width, -1))
self.touch_text_manager.set_touch_object("album_name", label)
# Artist
label = TouchAndTextItem(self.fonts['base'], self.get_artist_string(),
(x, self.base_size * 4),
(width, -1))
label = TouchAndTextItem(self.fonts['base'],
self.get_artist_string(),
(x, self.base_size * 4),
(width, -1))
self.touch_text_manager.set_touch_object("artist_name", label)
# Previous track button
@@ -150,9 +155,8 @@ class MainScreen(BaseScreen):
# Progress
progress = Progressbar(self.fonts['base'],
time.strftime('%M:%S', time.gmtime(
0)) + "/" + time.strftime('%M:%S',
time.gmtime(
0)),
0)) + "/" + time.strftime(
'%M:%S', time.gmtime(0)),
(size_1, self.base_size * 6),
(
self.size[0] - size_1 - size_2,
@@ -220,72 +224,80 @@ class MainScreen(BaseScreen):
logger.info("Cover could not be downloaded")
# There is no cover so it will use all the screen size for the text
# There is no cover
# so it will use all the screen size for the text
width = self.size[0] - self.base_size
current = TouchAndTextItem(self.fonts['base'],
MainScreen.get_track_name(self.track),
(self.base_size / 2,
self.base_size * 2),
(width, -1))
self.touch_text_manager.set_touch_object("track_name", current)
MainScreen.get_track_name
(self.track),
(self.base_size / 2,
self.base_size * 2),
(width, -1))
self.touch_text_manager.set_touch_object("track_name",
current)
current = TouchAndTextItem(self.fonts['base'],
MainScreen.get_track_album_name(
self.track),
(self.base_size / 2,
self.base_size * 3),
(width, -1))
self.touch_text_manager.set_touch_object("album_name", current)
MainScreen.get_track_album_name
(self.track),
(self.base_size / 2,
self.base_size * 3),
(width, -1))
self.touch_text_manager.set_touch_object("album_name",
current)
current = TouchAndTextItem(self.fonts['base'],
self.get_artist_string(),
(self.base_size / 2,
self.base_size * 4),
(width, -1))
self.touch_text_manager.set_touch_object("artist_name", current)
self.get_artist_string(),
(self.base_size / 2,
self.base_size * 4),
(width, -1))
self.touch_text_manager.set_touch_object("artist_name",
current)
def track_playback_ended(self, tl_track, time_position):
if self.image is not None:
self.dirty_area.append(pygame.Rect(self.base_size / 2,
self.base_size + self.base_size / 2,
self.image.get_rect().width,
self.image.get_rect().height))
self.image = None
self.background.set_target_color(None, None)
self.image = None
self.track_duration = "00:00"
width = self.size[0] - self.base_size
current = TouchAndTextItem(self.fonts['base'], "",
(self.base_size / 2, self.base_size * 2),
(width, -1))
self.touch_text_manager.set_touch_object("track_name", current)
(self.base_size / 2,
self.base_size * 2),
(width, -1))
self.touch_text_manager.set_touch_object("track_name",
current)
current = TouchAndTextItem(self.fonts['base'], "",
(self.base_size / 2, self.base_size * 3),
(width, -1))
self.touch_text_manager.set_touch_object("album_name", current)
(self.base_size / 2,
self.base_size * 3),
(width, -1))
self.touch_text_manager.set_touch_object("album_name",
current)
current = TouchAndTextItem(self.fonts['base'], "",
(self.base_size / 2, self.base_size * 4),
(width, -1))
self.touch_text_manager.set_touch_object("artist_name", current)
(self.base_size / 2,
self.base_size * 4),
(width, -1))
self.touch_text_manager.set_touch_object("artist_name",
current)
def load_image(self):
size = self.base_size * 4
image = pygame.transform.scale(pygame.image.load(
self.get_cover_folder() +
self.get_image_file_name()).convert(),
(size, size))
self.background.set_target_color(pygame.transform.average_color(image), image)
image_original = pygame.image.load(
self.get_cover_folder() +
self.get_image_file_name())
image = pygame.transform.scale(image_original, (size, size))
image = image.convert()
self.background.set_target_color(pygame.transform.average_color(image),
image_original)
self.image = image
def touch_event(self, event):
if event.type == InputManager.click:
objects = self.touch_text_manager.get_touch_objects_in_pos(
event.current_pos)
objects = \
self.touch_text_manager.get_touch_objects_in_pos(
event.current_pos)
if objects is not None:
self.click_on_objects(objects, event)
@@ -306,13 +318,13 @@ class MainScreen(BaseScreen):
volume = 0
self.core.playback.volume = volume
self.manager.volume_changed(volume)
def click_on_objects(self, objects, event):
if objects is not None:
for key in objects:
if key == "time_progress":
value = self.touch_text_manager.get_touch_object(
key).get_pos_value(
key).get_pos_value(
event.current_pos) * 1000
self.core.playback.seek(value)
@@ -358,7 +370,7 @@ class MainScreen(BaseScreen):
value = volume.get_pos_value(pos)
self.core.playback.volume = value
self.volume_changed(value)
def volume_changed(self, volume):
if not self.core.playback.mute.get():
if volume > 80:
@@ -379,7 +391,7 @@ class MainScreen(BaseScreen):
u"\ue622", False)
self.touch_text_manager.get_touch_object("volume").set_value(
volume)
def options_changed(self):
self.touch_text_manager.get_touch_object("random").set_active(
self.core.tracklist.random.get())
@@ -396,7 +408,7 @@ class MainScreen(BaseScreen):
u"\ue623", False)
else:
self.volume_changed(self.core.playback.volume.get())
def playback_state_changed(self, old_state, new_state):
if new_state == mopidy.core.PlaybackState.PLAYING:
self.touch_text_manager.get_touch_object(
@@ -404,9 +416,10 @@ class MainScreen(BaseScreen):
else:
self.touch_text_manager.get_touch_object(
"pause_play").set_text(u"\ue615", False)
def set_connection(self, connection, loading):
internet = self.touch_text_manager.get_touch_object("internet")
internet = self.touch_text_manager.get_touch_object(
"internet")
if loading:
internet.set_text(u"\ue627", None)
internet.set_active(False)
@@ -414,7 +427,6 @@ class MainScreen(BaseScreen):
internet.set_text(u"\ue602", None)
internet.set_active(connection)
@staticmethod
def get_track_name(track):
if track.name is None:
@@ -424,8 +436,8 @@ class MainScreen(BaseScreen):
@staticmethod
def get_track_album_name(track):
if track.album is not None and track.album.name is not None and len(
track.album.name) > 0:
if track.album is not None and track.album.name is not None\
and len(track.album.name) > 0:
return track.album.name
else:
return "Unknow Album"

View File

@@ -0,0 +1,54 @@
import os
import socket
from base_screen import BaseScreen
import mopidy
from ..graphic_utils import ListView
class MenuScreen(BaseScreen):
def __init__(self, size, base_size, manager, fonts):
BaseScreen.__init__(self, size, base_size, manager, fonts)
self.ip = None
self.list = ListView((0, 0), size, base_size, fonts['base'])
self.list_items = ["Exit Mopidy", "Shutdown", "Restart", "IP: "]
self.list.set_list(self.list_items)
def update(self, screen):
self.list.render(screen)
def touch_event(self, event):
clicked = self.list.touch_event(event)
if clicked is not None:
if clicked == 0:
mopidy.utils.process.exit_process()
elif clicked == 1:
if os.system("gksu -- shutdown now -h") != 0:
os.system("sudo shutdown now -h")
elif clicked == 2:
if os.system("gksu -- shutdown -r now") != 0:
os.system("sudo shutdown -r now")
elif clicked == 3:
self.check_connection()
# Will check internet connection
def check_connection(self):
try:
self.manager.set_connection(False, True)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
self.ip = s.getsockname()[0]
s.close()
self.list_items[3] = "IP: " + self.ip
self.list.set_list(self.list_items)
self.manager.set_connection(True, False)
except socket.error:
s.close()
self.ip = None
self.list_items[2] = "IP: No internet"
self.list.set_list(self.list_items)
self.manager.set_connection(False, False)

View File

@@ -1,14 +1,15 @@
from .list_view import ListView
from .base_screen import BaseScreen
from base_screen import BaseScreen
from ..graphic_utils import ListView
class PlaylistScreen(BaseScreen):
def __init__(self, size, base_size, manager, fonts):
BaseScreen.__init__(self, size, base_size, manager, fonts)
self.list_view = ListView((0, 0), (
self.size[0], self.size[1] - self.base_size),
self.base_size,
self.fonts['base'])
self.size[0], self.size[1] -
self.base_size), self.base_size,
self.fonts['base'])
self.playlists_strings = []
self.playlists = []
self.playlists_loaded()
@@ -16,7 +17,7 @@ class PlaylistScreen(BaseScreen):
self.playlist_tracks = []
self.playlist_tracks_strings = []
def update(self, screen, update_all):
def update(self, screen):
self.list_view.render(screen)
def playlists_loaded(self):
@@ -36,21 +37,20 @@ class PlaylistScreen(BaseScreen):
self.playlist_tracks_strings.append(track.name)
self.list_view.set_list(self.playlist_tracks_strings)
def touch_event(self, touch_event):
clicked = self.list_view.touch_event(touch_event)
if clicked is not None:
if self.selected_playlist is None:
self.playlist_selected(self.playlists[clicked])
else:
if clicked==0:
if clicked == 0:
self.selected_playlist = None
self.list_view.set_list(self.playlists_strings)
else:
self.manager.core.tracklist.clear()
self.manager.core.tracklist.add(self.playlist_tracks)
self.manager.core.playback.play(tl_track=self.manager.core.tracklist.tl_tracks.get()[clicked-1])
#self.manager.core.tracklist.clear()
#self.manager.core.tracklist.add(
# uri=self.playlists[clicked].uri)
#self.manager.core.playback.play()
self.manager.core.tracklist.add(
self.playlist_tracks)
self.manager.core.playback.play(
tl_track=self.manager.core.
tracklist.tl_tracks.get()
[clicked-1])

View File

@@ -1,15 +1,11 @@
from .list_view import ListView
import logging
from base_screen import BaseScreen
import pygame
from .screen_objects import Progressbar, ScreenObjectsManager, \
TouchAndTextItem, TextItem
from .base_screen import BaseScreen
from .input_manager import InputManager
logger = logging.getLogger(__name__)
from ..graphic_utils import ListView,\
ScreenObjectsManager, TextItem, TouchAndTextItem
from ..input import InputManager
mode_track_name = 0
mode_album_name = 1
@@ -20,40 +16,43 @@ class SearchScreen(BaseScreen):
def __init__(self, size, base_size, manager, fonts):
BaseScreen.__init__(self, size, base_size, manager, fonts)
self.list_view = ListView((0, self.base_size*2), (
self.size[0], self.size[1] - 3*self.base_size),
self.base_size,
manager.fonts['base'])
self.size[0], self.size[1] -
3*self.base_size), self.base_size, manager.fonts['base'])
self.results_strings = []
self.results = []
self.screen_objects = ScreenObjectsManager()
self.query = ""
# Query text
text = TextItem(self.fonts['base'],self.query, (0, 0), (self.size[0], self.base_size), center=True)
text = TextItem(self.fonts['base'], self.query, (0, 0),
(self.size[0], self.base_size), center=True)
self.screen_objects.set_object("query", text)
# Mode buttons
button_size = (self.size[0] / 3, self.base_size)
self.mode_objects_keys = ["mode_track", "mode_album", "mode_artist"]
self.mode_objects_keys = ["mode_track", "mode_album",
"mode_artist"]
# Track button
button = TouchAndTextItem(self.fonts['base'], "Track",
(0, self.base_size),
button_size, center=True)
self.screen_objects.set_touch_object(self.mode_objects_keys[0], button)
self.screen_objects.set_touch_object(
self.mode_objects_keys[0], button)
# Album button
button = TouchAndTextItem(self.fonts['base'], "Album",
(button_size[0], self.base_size),
button_size, center=True)
self.screen_objects.set_touch_object(self.mode_objects_keys[1], button)
self.screen_objects.set_touch_object(
self.mode_objects_keys[1], button)
# Artist button
button = TouchAndTextItem(self.fonts['base'], "Artist",
(button_size[0]*2, self.base_size),
button_size, center=True)
self.screen_objects.set_touch_object(self.mode_objects_keys[2], button)
self.screen_objects.set_touch_object(
self.mode_objects_keys[2], button)
# Top Bar
self.top_bar = pygame.Surface(
@@ -65,7 +64,7 @@ class SearchScreen(BaseScreen):
self.set_mode(mode=mode_track_name)
self.set_query("")
def update(self, screen, update_all):
def update(self, screen):
screen.blit(self.top_bar, (0, 0))
self.screen_objects.render(screen)
self.list_view.render(screen)
@@ -74,12 +73,15 @@ class SearchScreen(BaseScreen):
if mode is not self.mode:
self.mode = mode
for key in self.mode_objects_keys:
self.screen_objects.get_touch_object(key).set_active(False)
self.screen_objects.get_touch_object(self.mode_objects_keys[self.mode]).set_active(True)
self.screen_objects.get_touch_object(key).\
set_active(False)
self.screen_objects.get_touch_object(
self.mode_objects_keys[self.mode]).set_active(True)
def set_query(self, query=""):
self.query = query
self.screen_objects.get_object("query").set_text(self.query, False)
self.screen_objects.get_object("query").set_text(
self.query, False)
def search(self, query=None, mode=None):
if query is not None:
@@ -92,8 +94,9 @@ class SearchScreen(BaseScreen):
search_query = {'album': [self.query]}
else:
search_query = {'artist': [self.query]}
if len(self.query)>0:
current_results = self.manager.core.library.search(search_query).get()
if len(self.query) > 0:
current_results = self.manager.core.library.search(
search_query).get()
self.results = []
self.results_strings = []
for backend in current_results:
@@ -109,8 +112,6 @@ class SearchScreen(BaseScreen):
self.results_strings.append(result.name)
self.list_view.set_list(self.results_strings)
def touch_event(self, touch_event):
if touch_event.type == InputManager.click:
clicked = self.list_view.touch_event(touch_event)
@@ -120,7 +121,8 @@ class SearchScreen(BaseScreen):
uri=self.results[clicked].uri)
self.manager.core.playback.play()
else:
clicked = self.screen_objects.get_touch_objects_in_pos(touch_event.down_pos)
clicked = self.screen_objects.get_touch_objects_in_pos(
touch_event.down_pos)
if len(clicked) > 0:
clicked = clicked[0]
if clicked == self.mode_objects_keys[0]:
@@ -130,4 +132,4 @@ class SearchScreen(BaseScreen):
if clicked == self.mode_objects_keys[2]:
self.search(mode=2)
else:
self.list_view.touch_event(touch_event)
self.list_view.touch_event(touch_event)

View File

@@ -1,6 +1,7 @@
from .list_view import ListView
from base_screen import BaseScreen
from .main_screen import MainScreen
from .base_screen import BaseScreen
from ..graphic_utils import ListView
class Tracklist(BaseScreen):
@@ -10,12 +11,15 @@ class Tracklist(BaseScreen):
self.base_size = base_size
self.manager = manager
self.list_view = ListView((0, 0), (
self.size[0], self.size[1] - self.base_size), self.base_size, self.fonts['base'])
self.size[0], self.size[1] -
self.base_size), self.base_size, self.fonts['base'])
self.tracks = []
self.tracks_strings = []
self.update_list()
self.track_started(
self.manager.core.playback.current_tl_track.get())
def update(self, screen, update_all):
def update(self, screen):
self.list_view.render(screen)
def tracklist_changed(self):
@@ -32,9 +36,8 @@ class Tracklist(BaseScreen):
def touch_event(self, touch_event):
pos = self.list_view.touch_event(touch_event)
if pos is not None:
self.manager.core.playback.change_track(self.tracks[pos],
on_error_step=1)
self.manager.core.playback.play(self.tracks[pos])
def track_started(self, track):
self.list_view.set_selected(
self.list_view.set_active(
[self.manager.core.tracklist.index(track).get()])

View File

@@ -1,11 +1,13 @@
import logging
import os
import traceback
from threading import Thread
import os
from mopidy import core, utils
import pygame
import pykka
import mopidy
from mopidy import core
from .screen_manager import ScreenManager
@@ -23,12 +25,20 @@ class TouchScreen(pykka.ThreadingActor, core.CoreListener):
self.fullscreen = config['touchscreen']['fullscreen']
self.screen_size = (config['touchscreen']['screen_width'],
config['touchscreen']['screen_height'])
os.environ["SDL_FBDEV"] = config['touchscreen']['sdl_fbdev']
os.environ["SDL_MOUSEDRV"] = config['touchscreen'][
'sdl_mousdrv']
os.environ["SDL_MOUSEDEV"] = config['touchscreen'][
'sdl_mousedev']
os.environ["SDL_AUDIODRIVER"] = config['touchscreen']['sdl_audiodriver']
if config['touchscreen']['sdl_fbdev'].lower() != "none":
os.environ["SDL_FBDEV"] = config['touchscreen']['sdl_fbdev']
if config['touchscreen']['sdl_mousdrv'].lower() != "none":
os.environ["SDL_MOUSEDRV"] = (
config['touchscreen']['sdl_mousdrv'])
if config['touchscreen']['sdl_mousedev'].lower() != "none":
os.environ["SDL_MOUSEDEV"] = config['touchscreen']['sdl_mousedev']
if config['touchscreen']['sdl_audiodriver'].lower() != "none":
os.environ["SDL_AUDIODRIVER"] = (
config['touchscreen']['sdl_audiodriver'])
os.environ["SDL_PATH_DSP"] = config['touchscreen']['sdl_path_dsp']
pygame.init()
pygame.display.set_caption("Mopidy-Touchscreen")
@@ -37,12 +47,12 @@ class TouchScreen(pykka.ThreadingActor, core.CoreListener):
self.screen_manager = ScreenManager(self.screen_size,
self.core,
self.cache_dir)
# Raspberry pi GPIO
self.gpio = config['touchscreen']['gpio']
if self.gpio:
from .gpio_inpput_manager import GPIOManager
from input import GPIOManager
pins = {}
pins['left'] = config['touchscreen']['gpio_left']
@@ -54,8 +64,8 @@ class TouchScreen(pykka.ThreadingActor, core.CoreListener):
def get_display_surface(self, size):
if self.fullscreen:
self.screen = pygame.display.set_mode(size,
pygame.FULLSCREEN)
self.screen = pygame.display.set_mode(
size, pygame.FULLSCREEN)
else:
self.screen = pygame.display.set_mode(size, pygame.RESIZABLE)
@@ -76,7 +86,7 @@ class TouchScreen(pykka.ThreadingActor, core.CoreListener):
else:
self.screen_manager.event(event)
pygame.quit()
mopidy.utils.process.exit_process()
utils.process.exit_process()
def on_start(self):
try:

View File

@@ -6,9 +6,9 @@ from setuptools import find_packages, setup
def get_version(filename):
content = open(filename).read()
metadata = dict(re.findall("__([a-z]+)__ = '([^']+)'", content))
return metadata['version']
with open(filename) as fh:
metadata = dict(re.findall("__([a-z]+)__ = '([^']+)'", fh.read()))
return metadata['version']
setup(
@@ -26,7 +26,7 @@ setup(
include_package_data=True,
install_requires=[
'setuptools',
'Mopidy >= 0.18',
'Mopidy >= 1.0',
'Pykka >= 1.1',
'pygame'
],

Binary file not shown.

View File

@@ -27,5 +27,3 @@ class ExtensionTest(unittest.TestCase):
# TODO Test the content of your config schema
# self.assertIn('username', schema)
# self.assertIn('password', schema)
# TODO Write more tests