class SettingString(SettingItem):
    popup = ObjectProperty(None, allownone=True)
    textinput = ObjectProperty(None)

    def on_panel(self, instance, value):
        if value is None:
            return
        self.fbind('on_release', self._create_popup)

    def dismiss(self, *largs):
        if self.popup:
            self.popup.dismiss()
        app = App.get_running_app()
        if app.popup:
            app.popup = None
        self.popup = None

    def _validate(self, instance, answer):
        value = self.popup.content.ids['input'].text.strip()
        self.dismiss()
        if answer == 'yes':
            self.value = value

    def _create_popup(self, instance):
        content = InputPopup(text='', input_text=self.value)
        app = App.get_running_app()
        content.bind(on_answer=self._validate)
        self.popup = NormalPopup(title=self.title,
                                 content=content,
                                 size_hint=(None, None),
                                 size=(app.popup_x, app.button_scale * 5),
                                 auto_dismiss=True)
        app = App.get_running_app()
        app.popup = self.popup
        self.popup.open()
示例#2
0
    def add_folder(self):
        """Starts the add folder process, creates an input text popup."""

        content = InputPopup(hint='Folder Name', text='Enter A Folder Name:')
        app = App.get_running_app()
        content.bind(on_answer=self.add_folder_answer)
        self.popup = NormalPopup(title='Create Folder', content=content, size_hint=(None, None), size=(app.popup_x, app.button_scale * 5), auto_dismiss=False)
        self.popup.open()
示例#3
0
    def delete_folder(self):
        """Starts the delete folder process, creates the confirmation popup."""

        app = App.get_running_app()
        text = "Delete The Selected Folder?"
        content = ConfirmPopup(text=text, yes_text='Delete', no_text="Don't Delete", warn_yes=True)
        content.bind(on_answer=self.delete_folder_answer)
        self.popup = NormalPopup(title='Confirm Delete', content=content, size_hint=(None, None), size=(app.popup_x, app.button_scale * 4), auto_dismiss=False)
        self.popup.open()
示例#4
0
 def load_theme(self):
     content = FileBrowser(ok_text='Load',
                           file_editable=True,
                           export_mode=False,
                           file='theme.txt')
     content.bind(on_cancel=self.dismiss_popup)
     content.bind(on_ok=self.load_theme_finish)
     self.popup = NormalPopup(title="Select Theme To Load",
                              content=content,
                              size_hint=(0.9, 0.9))
     self.popup.open()
示例#5
0
 def save_theme(self):
     content = FileBrowser(ok_text='Save',
                           file_editable=True,
                           export_mode=True,
                           file='theme.txt')
     content.bind(on_cancel=self.dismiss_popup)
     content.bind(on_ok=self.save_theme_check)
     self.popup = NormalPopup(title="Select File To Save Theme To",
                              content=content,
                              size_hint=(0.9, 0.9))
     self.popup.open()
示例#6
0
 def filechooser_popup(self):
     content = FileBrowser(ok_text='Export',
                           directory_select=False,
                           file_editable=True,
                           export_mode=True,
                           file='collage.jpg')
     content.bind(on_cancel=self.dismiss_popup)
     content.bind(on_ok=self.export_check)
     self.popup = NormalPopup(title="Select File To Export To",
                              content=content,
                              size_hint=(0.9, 0.9))
     self.popup.open()
 def _create_popup(self, instance):
     content = InputPopup(text='', input_text=self.value)
     app = App.get_running_app()
     content.bind(on_answer=self._validate)
     self.popup = NormalPopup(title=self.title,
                              content=content,
                              size_hint=(None, None),
                              size=(app.popup_x, app.button_scale * 5),
                              auto_dismiss=True)
     app = App.get_running_app()
     app.popup = self.popup
     self.popup.open()
示例#8
0
    def export_finish(self):
        app = App.get_running_app()
        content = MessagePopup(text='Exporting Collage')
        if len(self.images) > 8:
            message = 'Exporting Collage, This May Take Several Minutes, Please Wait...'
        else:
            message = 'Exporting Collage, Please Wait...'
        self.popup = NormalPopup(title=message,
                                 content=content,
                                 size_hint=(None, None),
                                 size=(app.popup_x, app.button_scale * 4))
        self.popup.open()

        #Wait a cycle so the popup can display
        Clock.schedule_once(self.export_process)
 def filechooser_popup(self):
     app = App.get_running_app()
     content = FileBrowser(ok_text='Export', path=app.last_browse_folder, file_editable=True, export_mode=True, file='collage.jpg')
     content.bind(on_cancel=self.dismiss_popup)
     content.bind(on_ok=self.export_check)
     self.popup = NormalPopup(title="Select File To Export To", content=content, size_hint=(0.9, 0.9))
     self.popup.open()
 def filechooser_popup(self):
     content = FileBrowser(ok_text='Add', directory_select=True)
     content.bind(on_cancel=self.filepopup_dismiss)
     content.bind(on_ok=self.add_directory)
     self.filepopup = filepopup = NormalPopup(title=self.title,
                                              content=content,
                                              size_hint=(0.9, 0.9))
     filepopup.open()
 def save_crashlog(self):
     app = App.get_running_app()
     app.dismiss_popup()
     from filebrowser import FileBrowser
     content = FileBrowser(ok_text='Save', directory_select=True)
     content.bind(on_cancel=app.dismiss_popup)
     content.bind(on_ok=self.save_crashlog_finish)
     app.popup = NormalPopup(title="Select A Location To Save Crashlog",
                             content=content)
     app.popup.open()
 def filechooser_popup(self):
     app = App.get_running_app()
     content = FileBrowser(ok_text='Add',
                           path=app.last_browse_folder,
                           directory_select=True)
     content.bind(on_cancel=self.filepopup_dismiss)
     content.bind(on_ok=self.add_directory)
     self.filepopup = filepopup = NormalPopup(title=self.title,
                                              content=content,
                                              size_hint=(0.9, 0.9))
     filepopup.open()
示例#13
0
 def save_theme_check(self, *_):
     path = self.popup.content.path
     file = self.popup.content.file
     self.dismiss_popup()
     self.filename = os.path.join(path, file)
     if os.path.isfile(self.filename):
         app = App.get_running_app()
         content = ConfirmPopup(text='Overwrite the file "' +
                                self.filename + '"?',
                                yes_text='Overwrite',
                                no_text="Cancel",
                                warn_yes=True)
         content.bind(on_answer=self.save_theme_finish)
         self.popup = NormalPopup(title='Confirm Overwrite',
                                  content=content,
                                  size_hint=(None, None),
                                  size=(app.popup_x, app.button_scale * 4),
                                  auto_dismiss=False)
         self.popup.open()
     else:
         self.save_theme_finish()
 def export_check(self, *_):
     popup = self.popup
     if popup:
         path = popup.content.path
         app = App.get_running_app()
         app.last_browse_folder = path
         file = popup.content.file
         self.dismiss_popup()
         if not file.lower().endswith('.jpg'):
             file = file+'.jpg'
         self.filename = os.path.join(path, file)
         if os.path.isfile(self.filename):
             content = ConfirmPopup(text='Overwrite the file "'+self.filename+'"?', yes_text='Overwrite', no_text="Cancel", warn_yes=True)
             content.bind(on_answer=self.export_overwrite_answer)
             self.popup = NormalPopup(title='Confirm Overwrite', content=content, size_hint=(None, None), size=(app.popup_x, app.button_scale * 4), auto_dismiss=False)
             self.popup.open()
         else:
             self.export_finish()
 def _create_popup(self, *_):
     app = App.get_running_app()
     if app.database_scanning:
         return
     content = BoxLayout(orientation='vertical')
     popup_width = min(0.95 * Window.width, dp(500))
     self.popup = popup = NormalPopup(title=self.title,
                                      content=content,
                                      size_hint=(None, 0.9),
                                      width=popup_width)
     if not self.value:
         content.add_widget(
             ShortLabel(
                 height=app.button_scale * 3,
                 text=
                 "You must set at least one database directory.\n\nThis is a folder where your photos are stored.\nNew photos will be imported to a database folder."
             ))
         content.add_widget(BoxLayout())
     else:
         folders = filter(None, self.value.split(';'))
         folderdata = []
         for folder in folders:
             folderdata.append({'text': folder})
         self.folderlist = folderlist = FolderSettingsList(size_hint=(1,
                                                                      .8),
                                                           id='folderlist')
         folderlist.data = folderdata
         content.add_widget(folderlist)
     buttons = BoxLayout(orientation='horizontal',
                         size_hint=(1, None),
                         height=app.button_scale)
     addbutton = NormalButton(text='+')
     addbutton.bind(on_release=self.add_path)
     removebutton = NormalButton(text='-')
     removebutton.bind(on_release=self.remove_path)
     okbutton = WideButton(text='OK')
     okbutton.bind(on_release=self._dismiss)
     buttons.add_widget(addbutton)
     buttons.add_widget(removebutton)
     buttons.add_widget(okbutton)
     content.add_widget(buttons)
     popup.open()
示例#16
0
class CollageScreen(Screen):
    sort_reverse_button = StringProperty('normal')
    images = []
    collage_background = ListProperty([0, 0, 0, 1])
    resolution = StringProperty('Medium')
    aspect = NumericProperty(1.3333)
    aspect_text = StringProperty('4:3')
    filename = StringProperty('')
    export_scale = 1

    #Widget holder variables
    sort_dropdown = ObjectProperty()  #Holder for the sort method dropdown menu
    popup = None  #Holder for the screen's popup dialog
    resolution_select = ObjectProperty()
    color_select = ObjectProperty()
    aspect_select = ObjectProperty()
    add_remove = ObjectProperty()

    #Variables relating to the photo list view on the left
    selected = StringProperty(
        '')  #The current folder/album/tag being displayed
    type = StringProperty('None')  #'Folder', 'Album', 'Tag'
    target = StringProperty(
    )  #The identifier of the album/folder/tag that is being viewed
    photos = []  #Photoinfo of all photos in the album
    sort_method = StringProperty('Name')  #Current album sort method
    sort_reverse = BooleanProperty(False)

    def deselect_images(self):
        collage = self.ids['collageHolder']
        for image in collage.children:
            image.selected = False

    def delete_selected(self):
        collage = self.ids['collageHolder']
        for image in collage.children:
            if image.selected:
                collage.remove_widget(image)

    def clear_collage(self):
        collage = self.ids['collageHolder']
        collage.clear_widgets()
        self.images = []
        self.collage_background = [0, 0, 0, 1]

    def add_all(self):
        #adds all photos to the collage using a fimonacci spiral pattern
        collage = self.ids['collageHolder']
        size = (1 / (len(self.photos)**0.5))  #average scale of photo
        photos = list(self.photos)
        random.shuffle(photos)

        tau = (1 + 5**0.5) / 2
        inc = (2 - tau) * 2 * math.pi
        theta = 0

        max_x = 0
        max_y = 0
        coords = []
        offset_scale = .5
        app = App.get_running_app()
        app.message("Added " + str(len(photos)) + " images.")
        #Generate basis coordinates and determine min/max
        for index in range(0, len(photos)):
            offset = (random.random() * offset_scale) - (
                .5 * offset_scale)  #random angle variation
            r = index**0.5
            theta = theta + inc + offset
            pos_x = 0.5 + r * math.cos(theta)
            if abs(pos_x) > max_x:
                max_x = abs(pos_x)
            pos_y = 0.5 + r * math.sin(theta)
            if abs(pos_y) > max_y:
                max_y = abs(pos_y)
            coords.append((pos_x, pos_y))

        #add photos to collage
        for index, photo in enumerate(photos):
            rand_angle = random.randint(-33, 33)
            pos_x, pos_y = coords[index]
            #scale points down by max size
            pos_x = pos_x / max_x
            pos_y = pos_y / max_y
            #scale points down to prevent photos overlapping edges
            pos_x = pos_x * (1 - (size / 2))
            pos_y = pos_y * (1 - (size / 2))
            #convert to kivy's coordinate system
            pos_x = (pos_x + 1) / 2
            pos_y = (pos_y + 1) / 2
            #offset points to correct for photo size
            pos_x = pos_x - (size / 2)
            pos_y = pos_y - (size / 2)
            position = (collage.width * pos_x, collage.height * pos_y)

            #forces lowmem mode if more than a certain number of photos
            if len(photos) > 8:
                lowmem = True
            else:
                lowmem = False
            self.add_collage_image(collage,
                                   photo[0],
                                   position,
                                   size=size,
                                   angle=rand_angle,
                                   lowmem=lowmem)

    def export(self):
        self.deselect_images()
        self.filechooser_popup()

    def filechooser_popup(self):
        content = FileBrowser(ok_text='Export',
                              directory_select=False,
                              file_editable=True,
                              export_mode=True,
                              file='collage.jpg')
        content.bind(on_cancel=self.dismiss_popup)
        content.bind(on_ok=self.export_check)
        self.popup = NormalPopup(title="Select File To Export To",
                                 content=content,
                                 size_hint=(0.9, 0.9))
        self.popup.open()

    def export_check(self, *_):
        path = self.popup.content.path
        file = self.popup.content.file
        self.dismiss_popup()
        if not file.lower().endswith('.jpg'):
            file = file + '.jpg'
        self.filename = os.path.join(path, file)
        if os.path.isfile(self.filename):
            app = App.get_running_app()
            content = ConfirmPopup(text='Overwrite the file "' +
                                   self.filename + '"?',
                                   yes_text='Overwrite',
                                   no_text="Cancel",
                                   warn_yes=True)
            content.bind(on_answer=self.export_overwrite_answer)
            self.popup = NormalPopup(title='Confirm Overwrite',
                                     content=content,
                                     size_hint=(None, None),
                                     size=(app.popup_x, app.button_scale * 4),
                                     auto_dismiss=False)
            self.popup.open()
        else:
            self.export_finish()

    def export_overwrite_answer(self, instance, answer):
        del instance
        if answer == 'yes':
            self.dismiss_popup()
            self.export_finish()

    def export_finish(self):
        app = App.get_running_app()
        content = MessagePopup(text='Exporting Collage')
        if len(self.images) > 8:
            message = 'Exporting Collage, This May Take Several Minutes, Please Wait...'
        else:
            message = 'Exporting Collage, Please Wait...'
        self.popup = NormalPopup(title=message,
                                 content=content,
                                 size_hint=(None, None),
                                 size=(app.popup_x, app.button_scale * 4))
        self.popup.open()

        #Wait a cycle so the popup can display
        Clock.schedule_once(self.export_process)

    def export_process(self, *_):
        if self.resolution == 'High':
            self.export_scale = 4
        elif self.resolution == 'Low':
            self.export_scale = 1
        else:
            self.export_scale = 2

        #wait for full sized images to load
        check_images = []
        if self.export_scale > 1:
            for image in self.images:
                async_image = image.children[0].children[0]
                if not async_image.is_full_size:
                    async_image.loadfullsize = True
                    async_image._load_fullsize()
                    check_images.append(async_image)
        while check_images:
            for image in check_images:
                if image.is_full_size:
                    check_images.remove(image)

        #wait a cycle so kivy can finish displaying the textures
        Clock.schedule_once(self.export_collage_as_image)

    def export_collage_as_image(self, *_):
        collage = self.ids['collageHolder']
        exported = self.export_scaled_jpg(collage,
                                          self.filename,
                                          image_scale=self.export_scale)
        app = App.get_running_app()
        self.dismiss_popup()
        if exported is True:
            app.message("Exported " + self.filename)
        else:
            app.message('Export error: ' + exported)

    def export_scaled_jpg(self, widget, filename, image_scale=1):
        from kivy.graphics import (Translate, Fbo, ClearColor, ClearBuffers,
                                   Scale)
        re_size = (widget.width * image_scale, widget.height * image_scale)

        if widget.parent is not None:
            canvas_parent_index = widget.parent.canvas.indexof(widget.canvas)
            if canvas_parent_index > -1:
                widget.parent.canvas.remove(widget.canvas)

        try:
            fbo = Fbo(size=re_size, with_stencilbuffer=True)
            with fbo:
                ClearColor(0, 0, 0, 0)
                ClearBuffers()
                Scale(image_scale, -image_scale, image_scale)
                Translate(-widget.x, -widget.y - widget.height, 0)

            fbo.add(widget.canvas)
            fbo.draw()
            from io import BytesIO
            image_bytes = BytesIO()
            fbo.texture.save(image_bytes, flipped=False, fmt='png')
            image_bytes.seek(0)
            from PIL import Image
            image = Image.open(image_bytes)
            image = image.convert('RGB')
            image.save(filename)
            exported = True
        except Exception as ex:
            exported = str(ex)
        try:
            fbo.remove(widget.canvas)
        except:
            pass

        if widget.parent is not None and canvas_parent_index > -1:
            widget.parent.canvas.insert(canvas_parent_index, widget.canvas)
        return exported

    def change_transform(self, transform_mode):
        for container in self.images:
            if transform_mode == 'rotscale':
                container.do_rotation = True
                container.do_scale = True
                container.do_translation = False
            elif transform_mode == 'rotate':
                container.do_rotation = True
                container.do_scale = False
                container.do_translation = False
            elif transform_mode == 'scale':
                container.do_rotation = False
                container.do_scale = True
                container.do_translation = False
            else:
                container.do_rotation = True
                container.do_scale = True
                container.do_translation = True

    def on_sort_reverse(self, *_):
        """Updates the sort reverse button's state variable, since kivy doesnt just use True/False for button states."""

        app = App.get_running_app()
        self.sort_reverse_button = 'down' if to_bool(
            app.config.get('Sorting', 'album_sort_reverse')) else 'normal'

    def drop_widget(self, fullpath, position, dropped_type='file', aspect=1):
        """Called when a widget is dropped.  Determine photo dragged, and where it needs to go."""

        collage = self.ids['collageHolder']
        position = collage.to_widget(*position)
        self.add_collage_image(collage, fullpath, position, aspect=aspect)

    def add_collage_image(self,
                          collage,
                          fullpath,
                          position,
                          size=0.5,
                          angle=0,
                          lowmem=False,
                          aspect=1):
        if not lowmem:
            if len(self.images) > 8:
                lowmem = True
        if collage.collide_point(*position):
            self.deselect_images()
            app = App.get_running_app()
            photoinfo = app.database_exists(fullpath)
            file = os.path.join(photoinfo[2], photoinfo[0])
            orientation = photoinfo[13]
            if orientation == 3 or orientation == 4:
                angle_offset = 180
            elif orientation == 5 or orientation == 6:
                angle_offset = 270
            elif orientation == 7 or orientation == 8:
                angle_offset = 90
            else:
                angle_offset = 0
            if orientation in [2, 4, 5, 7]:
                mirror = True
            else:
                mirror = False
            width = collage.width
            image_holder = ScatterImage(owner=self,
                                        source=file,
                                        rotation=angle + angle_offset,
                                        mirror=mirror,
                                        image_angle=0,
                                        photoinfo=photoinfo,
                                        lowmem=lowmem,
                                        aspect=aspect)
            image_holder.scale = size
            image_holder.selected = True
            if aspect < 1:
                image_holder.width = width * aspect
                image_holder.height = width
            else:
                image_holder.width = width
                image_holder.height = width / aspect
            self.images.append(image_holder)
            image_holder.pos = (position[0] - (width * size / 2),
                                position[1] - (width * size / 2))
            collage.add_widget(image_holder)

    def show_selected(self):
        """Scrolls the treeview to the currently selected folder"""

        database = self.ids['albumContainer']
        database_interior = self.ids['album']
        selected = self.selected
        data = database.data
        current_folder = None
        for i, node in enumerate(data):
            if node['target'] == selected and node['type'] == self.type:
                current_folder = node
                break
        if current_folder is not None:
            database_interior.selected = current_folder
            database.scroll_to_selected()

    def text_input_active(self):
        """Detects if any text input fields are currently active (being typed in).
        Returns: True or False
        """

        input_active = False
        for widget in self.walk(restrict=True):
            if widget.__class__.__name__ == 'NormalInput' or widget.__class__.__name__ == 'FloatInput' or widget.__class__.__name__ == 'IntegerInput':
                if widget.focus:
                    input_active = True
                    break
        return input_active

    def has_popup(self):
        """Detects if the current screen has a popup active.
        Returns: True or False
        """

        if self.popup:
            if self.popup.open:
                return True
        return False

    def dismiss_popup(self, *_):
        """Close a currently open popup for this screen."""

        if self.popup:
            self.popup.dismiss()
            self.popup = None

    def dismiss_extra(self):
        """Deactivates running processes if applicable.
        Returns: True if something was deactivated, False if not.
        """

        return False

    def key(self, key):
        """Handles keyboard shortcuts, performs the actions needed.
        Argument:
            key: The name of the key command to perform.
        """

        if self.text_input_active():
            pass
        else:
            if not self.popup or (not self.popup.open):
                #normal keypresses
                pass
            elif self.popup and self.popup.open:
                if key == 'enter':
                    self.popup.content.dispatch('on_answer', 'yes')

    def scroll_photolist(self):
        """Scroll the right-side photo list to the current active photo."""

        photolist = self.ids['albumContainer']
        self.show_selected()
        photolist.scroll_to_selected()

    def refresh_all(self):
        self.refresh_photolist()
        self.refresh_photoview()

    def update_selected(self):
        pass

    def refresh_photolist(self):
        """Reloads and sorts the photo list"""

        app = App.get_running_app()

        #Get photo list
        self.photos = []
        if self.type == 'Album':
            for albuminfo in app.albums:
                if albuminfo['name'] == self.target:
                    photo_paths = albuminfo['photos']
                    for fullpath in photo_paths:
                        photoinfo = app.database_exists(fullpath)
                        if photoinfo:
                            self.photos.append(photoinfo)
        elif self.type == 'Tag':
            self.photos = app.database_get_tag(self.target)
        else:
            self.photos = app.database_get_folder(self.target)

        #Remove video files
        temp_photos = []
        for photo in self.photos:
            source = os.path.join(photo[2], photo[0])
            isvideo = os.path.splitext(source)[1].lower() in movietypes
            if not isvideo:
                temp_photos.append(photo)
        self.photos = temp_photos

        #Sort photos
        if self.sort_method == 'Imported':
            sorted_photos = sorted(self.photos,
                                   key=lambda x: x[6],
                                   reverse=self.sort_reverse)
        elif self.sort_method == 'Modified':
            sorted_photos = sorted(self.photos,
                                   key=lambda x: x[7],
                                   reverse=self.sort_reverse)
        elif self.sort_method == 'Owner':
            sorted_photos = sorted(self.photos,
                                   key=lambda x: x[11],
                                   reverse=self.sort_reverse)
        elif self.sort_method == 'Name':
            sorted_photos = sorted(self.photos,
                                   key=lambda x: os.path.basename(x[0]),
                                   reverse=self.sort_reverse)
        else:
            sorted_photos = sorted(self.photos,
                                   key=lambda x: x[0],
                                   reverse=self.sort_reverse)
        self.photos = sorted_photos

    def refresh_photoview(self):
        #refresh recycleview
        photolist = self.ids['albumContainer']
        photodatas = []
        for photo in self.photos:
            source = os.path.join(photo[2], photo[0])
            filename = os.path.basename(photo[0])
            photodata = {
                'text': filename,
                'fullpath': photo[0],
                'temporary': True,
                'photoinfo': photo,
                'folder': self.selected,
                'database_folder': photo[2],
                'filename': filename,
                'target': self.selected,
                'type': self.type,
                'owner': self,
                'video': False,
                'photo_orientation': photo[13],
                'source': source,
                'title': photo[10],
                'selected': False,
                'selectable': True,
                'dragable': True
            }
            photodatas.append(photodata)
        photolist.data = photodatas

    def clear_photolist(self):
        photolist = self.ids['albumContainer']
        photolist.data = []

    def resort_method(self, method):
        """Sets the album sort method.
        Argument:
            method: String, the sort method to use
        """

        self.sort_method = method
        app = App.get_running_app()
        app.config.set('Sorting', 'album_sort', method)
        self.refresh_all()
        Clock.schedule_once(lambda *dt: self.scroll_photolist())

    def resort_reverse(self, reverse):
        """Sets the album sort reverse.
        Argument:
            reverse: String, if 'down', reverse will be enabled, disabled on any other string.
        """

        app = App.get_running_app()
        sort_reverse = True if reverse == 'down' else False
        app.config.set('Sorting', 'album_sort_reverse', sort_reverse)
        self.sort_reverse = sort_reverse
        self.refresh_all()
        Clock.schedule_once(lambda *dt: self.scroll_photolist())

    def on_leave(self):
        """Called when the screen is left.  Clean up some things."""

        self.clear_collage()
        self.clear_photolist()

    def on_enter(self):
        """Called when the screen is entered.  Set up variables and widgets, and prepare to view images."""

        app = App.get_running_app()
        self.ids['leftpanel'].width = app.left_panel_width()
        self.ids['moveButton'].state = 'down'
        self.ids['rotateButton'].state = 'normal'
        self.color_select = ColorDropDown(owner=self)
        self.resolution_select = ResolutionDropDown(owner=self)
        self.aspect_select = ExportAspectRatioDropDown(owner=self)
        self.add_remove = AddRemoveDropDown(owner=self)

        #import variables
        self.target = app.target
        self.type = app.type

        #set up sort buttons
        self.sort_dropdown = AlbumSortDropDown()
        self.sort_dropdown.bind(
            on_select=lambda instance, x: self.resort_method(x))
        self.sort_method = app.config.get('Sorting', 'album_sort')
        self.sort_reverse = to_bool(
            app.config.get('Sorting', 'album_sort_reverse'))

        #refresh views
        self.refresh_photolist()
        self.refresh_photoview()
示例#17
0
class FileBrowser(FloatLayout):
    __events__ = ('on_cancel', 'on_ok')
    path = StringProperty()
    file = StringProperty()
    files = ListProperty()
    folder_files = ListProperty()
    filename = StringProperty()
    root = StringProperty()
    allow_no_file = BooleanProperty(False)
    clickfade_object = ObjectProperty(allownone=True)

    popup = ObjectProperty(None, allownone=True)
    remember = None
    can_delete_folder = BooleanProperty(False)

    multiselect = BooleanProperty(False)
    new_folder = StringProperty('')
    start_in = StringProperty()
    directory_select = BooleanProperty(False)
    file_editable = BooleanProperty(False)
    filters = ListProperty()
    target_selected = BooleanProperty(False)
    export_mode = BooleanProperty(False)
    autoselect = BooleanProperty(False)

    header_text = StringProperty('Select A File')
    cancel_text = StringProperty('Cancel')
    ok_text = StringProperty('OK')

    def __init__(self, **kwargs):
        if not self.start_in:
            self.start_in = '/'
        Clock.schedule_once(self.refresh_locations)
        self.clickfade_object = ClickFade()
        super(FileBrowser, self).__init__(**kwargs)

    def clickfade(self, widget):
        try:
            self.remove_widget(self.clickfade_object)
        except:
            pass
        self.clickfade_object.size = widget.size
        self.clickfade_object.pos = widget.to_window(*widget.pos)
        self.clickfade_object.begin()
        self.add_widget(self.clickfade_object)

    def toggle_select(self):
        file_list = self.ids['files']
        if self.multiselect:
            file_list.toggle_select()

    def get_selected(self):
        file_list = self.ids['files']
        selected = file_list.selects
        return selected

    def dismiss_popup(self, *_):
        """If this dialog has a popup, closes it and removes it."""

        if self.popup:
            self.popup.dismiss()
            self.popup = None

    def add_folder(self):
        """Starts the add folder process, creates an input text popup."""

        content = InputPopup(hint='Folder Name', text='Enter A Folder Name:')
        app = App.get_running_app()
        content.bind(on_answer=self.add_folder_answer)
        self.popup = NormalPopup(title='Create Folder', content=content, size_hint=(None, None), size=(app.popup_x, app.button_scale * 5), auto_dismiss=False)
        self.popup.open()

    def add_folder_answer(self, instance, answer):
        """Tells the app to rename the folder if the dialog is confirmed.
        Arguments:
            instance: The dialog that called this function.
            answer: String, if 'yes', the folder will be created, all other answers will just close the dialog.
        """

        if answer == 'yes':
            text = instance.ids['input'].text.strip(' ')
            if text:
                app = App.get_running_app()
                folder = os.path.join(self.path, text)
                created = False
                try:
                    if not os.path.isdir(folder):
                        os.makedirs(folder)
                        created = True
                except:
                    pass
                if created:
                    app.message("Created the folder '"+folder+"'")
                    self.path = folder
                    self.refresh_folder()
                else:
                    app.message("Could Not Create Folder.")
        self.dismiss_popup()

    def delete_folder(self):
        """Starts the delete folder process, creates the confirmation popup."""

        app = App.get_running_app()
        text = "Delete The Selected Folder?"
        content = ConfirmPopup(text=text, yes_text='Delete', no_text="Don't Delete", warn_yes=True)
        content.bind(on_answer=self.delete_folder_answer)
        self.popup = NormalPopup(title='Confirm Delete', content=content, size_hint=(None, None), size=(app.popup_x, app.button_scale * 4), auto_dismiss=False)
        self.popup.open()

    def delete_folder_answer(self, instance, answer):
        """Tells the app to delete the folder if the dialog is confirmed.
        Arguments:
            instance: The dialog that called this function.
            answer: String, if 'yes', the folder will be deleted, all other answers will just close the dialog.
        """

        del instance
        if answer == 'yes':
            app = App.get_running_app()
            try:
                os.rmdir(self.path)
                app.message("Deleted Folder: \""+self.path+"\"")
                self.go_up()
            except:
                app.message("Could Not Delete Folder...")
        self.dismiss_popup()

    def reset_folder_position(self, *_):
        filelist = self.ids['fileList']
        filelist.scroll_y = 1

    def refresh_locations(self, *_):
        locations_list = self.ids['locationsList']
        locations = get_drives()
        self.root = locations[0][0]
        data = []
        for location in locations:
            data.append({
                'text': location[1],
                'fullpath': location[0],
                'path': location[0],
                'type': 'folder',
                'is_folder': True,
                'owner': self,
                'selectable': False
            })
        locations_list.data = data
        if not self.path:
            self.path = locations[0][0]
        self.refresh_folder()

    def refresh_folder(self, *_):
        file_list = self.ids['fileList']
        files = self.ids['files']
        files.selects = []
        data = []
        files = []
        dirs = []

        walk = os.walk
        for root, list_dirs, list_files in walk(self.path, topdown=True):
            dirs = list_dirs[:]
            list_dirs.clear()
            files = list_files

        self.folder_files = files
        if dirs or files:
            self.can_delete_folder = False
        else:
            self.can_delete_folder = True
        dirs = sorted(dirs, key=lambda s: s.lower())
        for directory in dirs:
            fullpath = os.path.join(self.path, directory)
            data.append({
                'text': directory,
                'fullpath': fullpath,
                'path': fullpath + os.path.sep,
                'type': 'folder',
                'file': '',
                'owner': self,
                'is_folder': True,
                'selected': False,
                'multiselect': self.multiselect,
                'selectable': self.directory_select,
                'file_size': '',
                'modified': ''
            })
        if not self.directory_select:
            if self.filters:
                filtered_files = []
                for item in self.filters:
                    filtered_files += fnmatch.filter(files, item)
                files = filtered_files
            #files = sorted(files, key=lambda s: s.lower())
            files = sort_nicely(files)
            for file in files:
                fullpath = os.path.join(self.path, file)
                file_size = int(os.path.getsize(fullpath))
                modified = int(os.path.getmtime(fullpath))
                data.append({
                    'text': file,
                    'fullpath': fullpath,
                    'path': self.path,
                    'type': file,
                    'file': file,
                    'owner': self,
                    'is_folder': False,
                    'selected': False,
                    'multiselect': self.multiselect,
                    'selectable': True,
                    'file_size': format_size(file_size),
                    'modified': datetime.datetime.fromtimestamp(modified).strftime('%Y-%m-%d, %I:%M%p')
                })

        file_list.data = data
        if not self.directory_select:
            if self.export_mode:
                if not self.file:
                    self.target_selected = False
                else:
                    self.target_selected = True
            else:
                self.file = ''
                self.filename = ''
                self.target_selected = False
        else:
            self.file = ''
            self.filename = ''
            self.target_selected = True

        self.reset_folder_position()
        if self.autoselect:
            self.toggle_select()

    def go_up(self, *_):
        up_path = os.path.realpath(os.path.join(self.path, '..'))
        if not up_path.endswith(os.path.sep):
            up_path += os.path.sep
        if up_path == self.path:
            up_path = self.root
        self.path = up_path
        self.refresh_folder()

    def double_click(self, instance):
        if self.target_selected and not self.export_mode:
            self.dispatch('on_ok')

    def click_node(self, node):
        self.clickfade(node)
        item = node.data
        if item['type'] == 'folder':
            self.path = item['path']
            self.refresh_folder()

    def select_item(self, item):
        if item:
            if not self.directory_select and item['type'] != 'folder':
                self.filename = item['fullpath']
                self.file = item['file']
                self.target_selected = True
        else:
            if not self.directory_select:
                self.target_selected = False
            if not self.export_mode:
                self.filename = ''
                self.file = ''

    def select_items(self, items):
        self.files = []
        for item in items:
            if 'file' in item:
                self.files.append(item['file'])

    def on_cancel(self):
        pass

    def on_ok(self):
        pass
示例#18
0
class ThemeScreen(Screen):
    """Screen layout of the album viewer."""
    popup = None  #Holder for the screen's popup dialog
    theme_backup = {}
    filename = ''
    preset_drop = ObjectProperty()

    def back(self, *_):
        app = App.get_running_app()
        app.show_database()
        return True

    def rescale_screen(self):
        app = App.get_running_app()
        self.ids['leftpanel'].width = app.left_panel_width()

    def drop_widget(self, fullpath, position, dropped_type='file', aspect=1):
        """Dummy function.  Here because the app can possibly call this function for any screen."""
        pass

    def text_input_active(self):
        """Detects if any text input fields are currently active (being typed in).
        Returns: True or False
        """

        input_active = False
        for widget in self.walk(restrict=True):
            if widget.__class__.__name__ == 'NormalInput' or widget.__class__.__name__ == 'FloatInput' or widget.__class__.__name__ == 'IntegerInput':
                if widget.focus:
                    input_active = True
                    break
        return input_active

    def has_popup(self):
        """Detects if the current screen has a popup active.
        Returns: True or False
        """

        if self.popup:
            if self.popup.open:
                return True
        return False

    def dismiss_popup(self, *_):
        """Close a currently open popup for this screen."""

        if self.popup:
            self.popup.dismiss()
            self.popup = None

    def dismiss_extra(self):
        """Close any running processes."""

        return False

    def key(self, key):
        """Handles keyboard shortcuts, performs the actions needed.
        Argument:
            key: The name of the key command to perform.
        """

        if self.text_input_active():
            pass
        else:
            if not self.popup or (not self.popup.open):
                pass
            elif self.popup and self.popup.open:
                if key == 'enter':
                    self.popup.content.dispatch('on_answer', 'yes')

    def on_leave(self):
        """Called when the screen is left.  Clean up some things."""

        app = App.get_running_app()

    def on_enter(self):
        """Called when the screen is entered.  Set up variables and widgets."""

        app = App.get_running_app()
        self.ids['leftpanel'].width = app.left_panel_width()

        #back up theme
        self.theme_backup = app.theme_to_data(app.theme)

        #Set up preset menu
        self.preset_drop = NormalDropDown()
        for preset in themes:
            menu_button = MenuButton(text=preset['name'])
            menu_button.bind(on_release=self.set_preset)
            self.preset_drop.add_widget(menu_button)

    def set_preset(self, instance):
        """Sets the current dialog preset settings to one of the presets stored in the app.
        Argument:
            index: Integer, the index of the preset to set.
        """

        self.preset_drop.dismiss()
        app = App.get_running_app()
        for preset in themes:
            if preset['name'] == instance.text:
                app.data_to_theme(preset)
                self.reload_colors()
                app.message('Reset Theme To: ' + instance.text)
                break

    def load_theme(self):
        content = FileBrowser(ok_text='Load',
                              file_editable=True,
                              export_mode=False,
                              file='theme.txt')
        content.bind(on_cancel=self.dismiss_popup)
        content.bind(on_ok=self.load_theme_finish)
        self.popup = NormalPopup(title="Select Theme To Load",
                                 content=content,
                                 size_hint=(0.9, 0.9))
        self.popup.open()

    def load_theme_finish(self, *_):
        path = self.popup.content.path
        file = self.popup.content.file
        self.dismiss_popup()
        self.filename = os.path.join(path, file)
        app = App.get_running_app()
        theme_file = self.filename
        loaded, data = app.load_theme_data(theme_file)
        if not loaded:
            app.message('Could Not Load Theme: ' + str(data))
            return
        else:
            app.message('Loaded Theme: ' + theme_file)
        self.theme_backup = data
        app.data_to_theme(data)
        self.reload_colors()

    def save_theme(self):
        content = FileBrowser(ok_text='Save',
                              file_editable=True,
                              export_mode=True,
                              file='theme.txt')
        content.bind(on_cancel=self.dismiss_popup)
        content.bind(on_ok=self.save_theme_check)
        self.popup = NormalPopup(title="Select File To Save Theme To",
                                 content=content,
                                 size_hint=(0.9, 0.9))
        self.popup.open()

    def save_theme_check(self, *_):
        path = self.popup.content.path
        file = self.popup.content.file
        self.dismiss_popup()
        self.filename = os.path.join(path, file)
        if os.path.isfile(self.filename):
            app = App.get_running_app()
            content = ConfirmPopup(text='Overwrite the file "' +
                                   self.filename + '"?',
                                   yes_text='Overwrite',
                                   no_text="Cancel",
                                   warn_yes=True)
            content.bind(on_answer=self.save_theme_finish)
            self.popup = NormalPopup(title='Confirm Overwrite',
                                     content=content,
                                     size_hint=(None, None),
                                     size=(app.popup_x, app.button_scale * 4),
                                     auto_dismiss=False)
            self.popup.open()
        else:
            self.save_theme_finish()

    def save_theme_finish(self, instance=None, answer='yes'):
        self.dismiss_popup()
        if answer != 'yes':
            return

        app = App.get_running_app()
        theme_file = self.filename
        data = app.theme_to_data(app.theme)
        saved = app.save_theme_data(theme_file, data)
        if saved is True:
            app.message('Saved Theme')
        else:
            app.message('Could Not Save Theme: ' + str(saved))

    def reset_theme(self):
        app = App.get_running_app()
        app.data_to_theme(self.theme_backup)
        self.reload_colors()

    def reload_colors(self):
        color_element_holder = self.ids['colorElementHolder']
        for widget in color_element_holder.children:
            try:
                widget.on_color_property()
                if widget.expanded:
                    widget.toggle_expanded()
            except:
                pass

    def theme_default(self, *_):
        app = App.get_running_app()
        app.theme_default()
        self.reload_colors()
class FileBrowser(BoxLayout):
    __events__ = ('on_cancel', 'on_ok')
    path = StringProperty()
    file = StringProperty()
    filename = StringProperty()
    root = StringProperty()

    popup = ObjectProperty(None, allownone=True)

    allow_new = BooleanProperty(True)
    allow_delete = BooleanProperty(True)
    new_folder = StringProperty('')
    start_in = StringProperty()
    directory_select = BooleanProperty(False)
    file_editable = BooleanProperty(False)
    filters = ListProperty()
    target_selected = BooleanProperty(False)
    export_mode = BooleanProperty(False)

    header_text = StringProperty('Select A File')
    cancel_text = StringProperty('Cancel')
    ok_text = StringProperty('OK')

    def __init__(self, **kwargs):
        if not self.start_in:
            self.start_in = '/'
        Clock.schedule_once(self.refresh_locations)
        super(FileBrowser, self).__init__(**kwargs)

    def dismiss_popup(self):
        """If this dialog has a popup, closes it and removes it."""

        if self.popup:
            self.popup.dismiss()
            self.popup = None

    def add_folder(self):
        """Starts the add folder process, creates an input text popup."""

        content = InputPopup(hint='Folder Name', text='Enter A Folder Name:')
        app = App.get_running_app()
        content.bind(on_answer=self.add_folder_answer)
        self.popup = NormalPopup(title='Create Folder',
                                 content=content,
                                 size_hint=(None, None),
                                 size=(app.popup_x, app.button_scale * 5),
                                 auto_dismiss=False)
        self.popup.open()

    def add_folder_answer(self, instance, answer):
        """Tells the app to rename the folder if the dialog is confirmed.
        Arguments:
            instance: The dialog that called this function.
            answer: String, if 'yes', the folder will be created, all other answers will just close the dialog.
        """

        if answer == 'yes':
            text = instance.ids['input'].text.strip(' ')
            if text:
                app = App.get_running_app()
                folder = os.path.join(self.path, text)
                created = False
                try:
                    if not os.path.isdir(folder):
                        os.makedirs(folder)
                        created = True
                except:
                    pass
                if created:
                    app.message("Created the folder '" + folder + "'")
                    self.path = folder
                    self.refresh_folder()
                else:
                    app.message("Could Not Create Folder.")
        self.dismiss_popup()

    def delete_folder(self):
        """Starts the delete folder process, creates the confirmation popup."""

        app = App.get_running_app()
        if not os.listdir(self.path):
            text = "Delete The Selected Folder?"
            content = ConfirmPopup(text=text,
                                   yes_text='Delete',
                                   no_text="Don't Delete",
                                   warn_yes=True)
            content.bind(on_answer=self.delete_folder_answer)
            self.popup = NormalPopup(title='Confirm Delete',
                                     content=content,
                                     size_hint=(None, None),
                                     size=(app.popup_x, app.button_scale * 4),
                                     auto_dismiss=False)
            self.popup.open()
        else:
            app.popup_message(text='Could not delete, Folder is not empty',
                              title='Warning')

    def delete_folder_answer(self, instance, answer):
        """Tells the app to delete the folder if the dialog is confirmed.
        Arguments:
            instance: The dialog that called this function.
            answer: String, if 'yes', the folder will be deleted, all other answers will just close the dialog.
        """

        del instance
        if answer == 'yes':
            app = App.get_running_app()
            try:
                os.rmdir(self.path)
                app.message("Deleted Folder: \"" + self.path + "\"")
                self.go_up()
            except:
                app.message("Could Not Delete Folder...")
        self.dismiss_popup()

    def refresh_locations(self, *_):
        locations_list = self.ids['locationsList']
        locations = get_drives()
        self.root = locations[0][0]
        data = []
        for location in locations:
            data.append({
                'text': location[1],
                'fullpath': location[0],
                'path': location[0],
                'type': 'folder',
                'owner': self
            })
        locations_list.data = data
        if not self.path:
            self.path = locations[0][0]
        self.refresh_folder()

    def refresh_folder(self, *_):
        file_list = self.ids['fileList']
        data = []
        files = []
        dirs = []
        try:
            directory_elements = os.listdir(self.path)
        except:
            directory_elements = []
        for file in directory_elements:
            fullpath = os.path.join(self.path, file)
            if os.path.isfile(fullpath):
                files.append(file)
            elif os.path.isdir(fullpath):
                dirs.append(file)
        dirs = sorted(dirs, key=lambda s: s.lower())
        for directory in dirs:
            fullpath = os.path.join(self.path, directory)
            data.append({
                'text': directory,
                'fullpath': fullpath,
                'path': fullpath + os.path.sep,
                'type': 'folder',
                'owner': self,
                'selected': False
            })
        if not self.directory_select:
            if self.filters:
                filtered_files = []
                for item in self.filters:
                    filtered_files += fnmatch.filter(files, item)
                files = filtered_files
            files = sorted(files, key=lambda s: s.lower())
            for file in files:
                data.append({
                    'text': file,
                    'fullpath': os.path.join(self.path, file),
                    'path': self.path,
                    'type': file,
                    'file': file,
                    'owner': self,
                    'selected': False
                })

        file_list.data = data
        if not self.directory_select:
            if self.export_mode:
                if not self.file:
                    self.target_selected = False
                else:
                    self.target_selected = True
            else:
                self.file = ''
                self.target_selected = False
        else:
            self.filename = self.path
            self.target_selected = True

    def go_up(self, *_):
        up_path = os.path.realpath(os.path.join(self.path, '..'))
        if not up_path.endswith(os.path.sep):
            up_path += os.path.sep
        if up_path == self.path:
            up_path = self.root
        self.path = up_path
        self.refresh_folder()

    def select(self, button):
        if button.type == 'folder':
            self.path = button.path
            self.refresh_folder()
            if self.directory_select:
                self.filename = button.fullpath
                self.target_selected = True
            elif self.export_mode:
                self.target_selected = True
            else:
                self.filename = ''
                self.target_selected = False
        else:
            self.filename = button.fullpath
            self.file = button.file
            self.target_selected = True

    def on_cancel(self):
        pass

    def on_ok(self):
        pass