You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

187 lines
6.9 KiB

# -*- coding: utf-8 -*-
import os
from functools import partial
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.popup import Popup
from kivy.properties import StringProperty, ObjectProperty, NumericProperty, BooleanProperty
from kivy.garden.magnet import Magnet
from kivy.clock import Clock
from kivy.logger import Logger
from kivy.config import Config
from PIL import Image
from kivy.graphics.opengl import GL_MAX_TEXTURE_SIZE, glGetIntegerv
from kivy.factory import Factory
class Slide(BoxLayout):
app = ObjectProperty(None)
img_src = StringProperty(None)
thumb_src = StringProperty(None)
artist = StringProperty('')
title = StringProperty('')
year = StringProperty('')
real_size = ObjectProperty(None)
texture_size = ObjectProperty(None)
info_panel = BooleanProperty(False)
def get_slide_info(self):
return {'img_src': self.img_src,
'thumb_src': self.thumb_src,
'artist': self.artist,
'title': self.title,
'year': self.year,
'texture_size': self.texture_size
}
def update_texture_size(self):
im = Image.open(os.path.join(self.app.tempdir, self.img_src))
self.texture_size = im.size
return im.size
def on_img_src(self, *args):
Logger.debug('Editor: img_src updated for {title}'.format(title=self.title))
max_texture_size = glGetIntegerv(GL_MAX_TEXTURE_SIZE)[0]
try:
im = Image.open(self.img_src)
if max(im.size) > max_texture_size:
Logger.debug('Application : image too big for max texture size ! Resizing...')
size = self.app.resize(im.size, (max_texture_size, max_texture_size))
im.thumbnail(size, Image.ANTIALIAS)
im.save(self.img_src)
except IOError:
Logger.debug('Editor: {img_src} is not a valid filename.'.format(img_src=self.img_src))
def show_info_panel(self):
if self.info_panel:
self.info_panel = False
self.remove_widget(self.children[0])
elif not self.info_panel:
self.info_panel = True
info_panel = Factory.SlideInfo(id='info_panel')
info_panel.artist.text = self.artist
info_panel.title.text = self.title
info_panel.year.text = self.year
self.add_widget(info_panel)
class SlideInfoDialog(Popup):
slide = ObjectProperty(None)
app = ObjectProperty(None)
def on_validate(self):
if self.slide.parent:
# Update with the index of DraggableSlide in grid_layout.
self.app.update_presentation('update', self.slide.parent.parent.children.index(self.slide.parent), None)
else:
self.slide.update_texture_size()
self.app.add_slide(self.slide)
self.dismiss()
# Class based on @tshirtman drag'n drop example.
class DraggableSlide(Magnet):
img = ObjectProperty(None, allownone=True)
app = ObjectProperty(None)
old_index = NumericProperty(None)
new_index = NumericProperty(None)
no_slides = NumericProperty(None)
def on_img(self, *args):
self.clear_widgets()
if self.img:
Clock.schedule_once(lambda *x: self.add_widget(self.img), 0)
def create_clock(self, touch, *args):
callback = partial(self.single_tap, touch)
Clock.schedule_once(callback, Config.getint('postproc', 'double_tap_time') / 1000)
touch.ud['event'] = callback
def delete_clock(self, touch, *args):
# TODO: Fix touch_up passing through when popup dismissed.
try:
Clock.unschedule(touch.ud['event'])
except KeyError:
Logger.exception(
'Application: Touch up passed through and unscheduled clock event could not be unscheduled. A bug...')
def on_touch_down(self, touch, *args):
if self.collide_point(*touch.pos):
if touch.is_touch:
self.create_clock(touch)
if touch.is_double_tap:
self.delete_clock(touch)
popup = SlideInfoDialog(slide=self.img)
popup.open()
return super(DraggableSlide, self).on_touch_down(touch)
def single_tap(self, touch, *args):
if self.collide_point(*touch.pos):
grid_layout = self.app.root.current_screen.slides_view.grid_layout
# Get position of current slide and number of slides
for index, value in enumerate(grid_layout.children):
if self == value:
self.old_index = index
self.no_slides = len(grid_layout.children)
touch.grab(self)
self.remove_widget(self.img)
self.app.root.current_screen.add_widget(self.img)
self.center = touch.pos
self.img.center = touch.pos
return True
return super(DraggableSlide, self).on_touch_down(touch)
def on_touch_move(self, touch, *args):
grid_layout = self.app.root.current_screen.slides_view.grid_layout
if touch.grab_current == self:
self.img.center = touch.pos
if grid_layout.collide_point(*touch.pos):
grid_layout.remove_widget(self)
for i, c in enumerate(grid_layout.children):
if c.collide_point(*touch.pos):
grid_layout.add_widget(self, i)
self.new_index = i
break
else:
grid_layout.add_widget(self)
# Remove slide if dropped out of grid_layout.
else:
if self.parent == grid_layout:
grid_layout.remove_widget(self)
self.center = touch.pos
def on_touch_up(self, touch, *args):
grid_layout = self.app.root.current_screen.slides_view.grid_layout
if self.collide_point(*touch.pos):
self.delete_clock(touch)
if touch.grab_current == self:
if any(touch.dpos) == 0:
if grid_layout.collide_point(*touch.pos):
grid_layout.remove_widget(self)
grid_layout.add_widget(self, self.old_index)
else:
grid_layout.add_widget(self)
# Delete entry in app.presentation if DraggableSlide removed.
elif len(grid_layout.children) < self.no_slides:
self.app.update_presentation('rm', self.old_index, self.new_index)
# Move entry in app.presentation accordingly to DraggableSlide move.
elif any(touch.dpos) > 0 and self.old_index != self.new_index and self.new_index is not None:
self.app.update_presentation('mv', self.old_index, self.new_index)
self.app.root.current_screen.remove_widget(self.img)
self.add_widget(self.img)
touch.ungrab(self)
return True
return super(DraggableSlide, self).on_touch_up(touch, *args)