Last active
October 20, 2019 14:56
-
-
Save gottadiveintopython/1ecdd982cba3d918c7fdd7452966fc28 to your computer and use it in GitHub Desktop.
simple and fast FileChooser
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import typing | |
| from pathlib import Path | |
| from dataclasses import dataclass | |
| from kivy.lang import Builder | |
| from kivy.clock import Clock | |
| from kivy.factory import Factory | |
| from kivy.properties import ObjectProperty, BooleanProperty | |
| @dataclass | |
| class ItemData: | |
| path: Path | |
| is_selected: bool = False | |
| Builder.load_string(''' | |
| <FastFileChooser>: | |
| orientation: 'vertical' | |
| padding: dp(5) | |
| spacing: dp(5) | |
| BoxLayout: | |
| spacing: dp(5) | |
| size_hint_y: None | |
| height: self.minimum_height | |
| Button: | |
| size_hint: None, None | |
| size: sp(30), sp(30) | |
| id: button_move_to_parent | |
| text: '^' | |
| on_press: root.current_dir = root.current_dir.parent | |
| Label: | |
| text: str(root.current_dir) | |
| size_hint_y: None | |
| height: self.texture_size[1] | |
| RecycleView: | |
| id: rv | |
| viewclass: 'FastFileChooserItem' | |
| RecycleBoxLayout: | |
| orientation: 'vertical' | |
| size_hint_y: None | |
| size_hint_x: 1 | |
| height: self.minimum_height | |
| default_size_hint: 1, None | |
| default_size: 0, sp(25) | |
| <FastFileChooserItem>: | |
| spacing: dp(10) | |
| canvas: | |
| Color: | |
| rgba: | |
| ((1, 1, 0, .2) if | |
| (self.data is not None and self.data.is_selected) | |
| else (0, 0, 0, 0)) | |
| Rectangle: | |
| pos: self.pos | |
| size: self.size | |
| Label: | |
| size_hint_x: None | |
| width: sp(20) | |
| text:'>' if (root.data is not None) and root.data.path.is_dir() else '' | |
| Label: | |
| size_hint_x: None | |
| width: self.texture_size[0] | |
| text:'' if root.data is None else root.data.path.name | |
| ''') | |
| def is_root_path(path:Path) -> bool: | |
| from kivy.utils import platform | |
| abs_str = str(path.resolve()) | |
| if platform == 'win': | |
| if len(abs_str) <= 3 and abs_str[1] == ':': | |
| return True | |
| else: | |
| if abs_str == '/': | |
| return True | |
| return False | |
| class FastFileChooser(Factory.BoxLayout): | |
| multiselect = BooleanProperty(False) | |
| current_dir = ObjectProperty() | |
| def on_current_dir(self, __, new_current_dir): | |
| if not self.ids: | |
| Clock.schedule_once(lambda dt: self.on_current_dir(__, new_current_dir)) | |
| return | |
| new_current_dir = new_current_dir.resolve() | |
| try: | |
| paths = sorted( | |
| # (child for child in new_current_dir.iterdir()), | |
| (child for child in new_current_dir.iterdir() if child.is_dir() or child.is_file()), | |
| key=lambda p: p.name.lower()) | |
| except PermissionError: | |
| Factory.Popup( | |
| size_hint=(.5, .5), | |
| title='Error', | |
| content=Factory.Label( | |
| text="Access denied!") | |
| ).open() | |
| return | |
| self.current_dir = new_current_dir | |
| self.ids.button_move_to_parent.disabled = is_root_path(new_current_dir) | |
| self.ids.rv.data = ({'data': ItemData(path=path) } for index, path in enumerate(paths)) | |
| def get_selection(self) -> typing.Iterable[Path]: | |
| return (dict_['data'].path for dict_ in self.ids.rv.data if dict_['data'].is_selected) | |
| class FastFileChooserItem(Factory.ButtonBehavior, Factory.BoxLayout): | |
| data = ObjectProperty(rebind=True) | |
| @property | |
| def rv(self): | |
| return self.parent.parent | |
| @property | |
| def fc(self): | |
| return self.parent.parent.parent | |
| def on_press(self): | |
| rv = self.rv | |
| data = self.data | |
| path = data.path | |
| fc = self.fc | |
| if path.is_file(): | |
| if data.is_selected: | |
| data.is_selected = False | |
| else: | |
| if not fc.multiselect: | |
| for dict_ in rv.data: | |
| dict_['data'].is_selected = False | |
| data.is_selected = True | |
| rv.refresh_from_data() | |
| self.property('data').dispatch(self) | |
| elif path.is_dir(): | |
| fc.current_dir = path | |
| def _test(): | |
| from kivy.app import runTouchApp | |
| ffc = FastFileChooser(multiselect=False, current_dir=Path()) | |
| runTouchApp(ffc) | |
| for path in ffc.get_selection(): | |
| print(path) | |
| if __name__ == "__main__": | |
| _test() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment