Mercurial > libervia-desktop-kivy
comparison libervia/desktop_kivy/core/common_widgets.py @ 493:b3cedbee561d
refactoring: rename `cagou` to `libervia.desktop_kivy` + update imports and names following backend changes
author | Goffi <goffi@goffi.org> |
---|---|
date | Fri, 02 Jun 2023 18:26:16 +0200 |
parents | cagou/core/common_widgets.py@203755bbe0fe |
children | 196483685a63 |
comparison
equal
deleted
inserted
replaced
492:5114bbb5daa3 | 493:b3cedbee561d |
---|---|
1 #!/usr/bin/env python3 | |
2 | |
3 #Libervia Desktop-Kivy | |
4 # Copyright (C) 2016-2021 Jérôme Poisson (goffi@goffi.org) | |
5 | |
6 # This program is free software: you can redistribute it and/or modify | |
7 # it under the terms of the GNU Affero General Public License as published by | |
8 # the Free Software Foundation, either version 3 of the License, or | |
9 # (at your option) any later version. | |
10 | |
11 # This program is distributed in the hope that it will be useful, | |
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 # GNU Affero General Public License for more details. | |
15 | |
16 # You should have received a copy of the GNU Affero General Public License | |
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
18 | |
19 """common advanced widgets, which can be reused everywhere.""" | |
20 | |
21 from kivy.clock import Clock | |
22 from kivy import properties | |
23 from kivy.metrics import dp | |
24 from kivy.uix.scatterlayout import ScatterLayout | |
25 from kivy.uix.boxlayout import BoxLayout | |
26 from kivy.uix.label import Label | |
27 from libervia.backend.core.i18n import _ | |
28 from libervia.backend.core import log as logging | |
29 from libervia.desktop_kivy import G | |
30 from .behaviors import TouchMenuItemBehavior | |
31 | |
32 log = logging.getLogger(__name__) | |
33 | |
34 | |
35 class DelayedBoxLayout(BoxLayout): | |
36 """A BoxLayout with delayed layout, to avoid slowing down during resize""" | |
37 # XXX: thanks to Alexander Taylor for his blog post at | |
38 # https://blog.kivy.org/2019/07/a-delayed-resize-layout-in-kivy/ | |
39 | |
40 do_layout_event = properties.ObjectProperty(None, allownone=True) | |
41 layout_delay_s = properties.NumericProperty(0.2) | |
42 #: set this to X to force next X layouts to be done without delay | |
43 dont_delay_next_layouts = properties.NumericProperty(0) | |
44 | |
45 def do_layout(self, *args, **kwargs): | |
46 if self.do_layout_event is not None: | |
47 self.do_layout_event.cancel() | |
48 if self.dont_delay_next_layouts>0: | |
49 self.dont_delay_next_layouts-=1 | |
50 super().do_layout() | |
51 else: | |
52 real_do_layout = super().do_layout | |
53 self.do_layout_event = Clock.schedule_once( | |
54 lambda dt: real_do_layout(*args, **kwargs), | |
55 self.layout_delay_s) | |
56 | |
57 | |
58 class Identities(object): | |
59 | |
60 def __init__(self, entity_ids): | |
61 identities = {} | |
62 for cat, type_, name in entity_ids: | |
63 identities.setdefault(cat, {}).setdefault(type_, []).append(name) | |
64 client = identities.get('client', {}) | |
65 if 'pc' in client: | |
66 self.type = 'desktop' | |
67 elif 'phone' in client: | |
68 self.type = 'phone' | |
69 elif 'web' in client: | |
70 self.type = 'web' | |
71 elif 'console' in client: | |
72 self.type = 'console' | |
73 else: | |
74 self.type = 'desktop' | |
75 | |
76 self.identities = identities | |
77 | |
78 @property | |
79 def name(self): | |
80 first_identity = next(iter(self.identities.values())) | |
81 names = next(iter(first_identity.values())) | |
82 return names[0] | |
83 | |
84 | |
85 class ItemWidget(TouchMenuItemBehavior, BoxLayout): | |
86 name = properties.StringProperty() | |
87 base_width = properties.NumericProperty(dp(100)) | |
88 | |
89 | |
90 class DeviceWidget(ItemWidget): | |
91 | |
92 def __init__(self, main_wid, entity_jid, identities, **kw): | |
93 self.entity_jid = entity_jid | |
94 self.identities = identities | |
95 own_jid = next(iter(G.host.profiles.values())).whoami | |
96 self.own_device = entity_jid.bare == own_jid.bare | |
97 if self.own_device: | |
98 name = self.identities.name | |
99 elif self.entity_jid.node: | |
100 name = self.entity_jid.node | |
101 elif self.entity_jid == own_jid.domain: | |
102 name = _("your server") | |
103 else: | |
104 name = entity_jid | |
105 | |
106 super(DeviceWidget, self).__init__(name=name, main_wid=main_wid, **kw) | |
107 | |
108 @property | |
109 def profile(self): | |
110 return self.main_wid.profile | |
111 | |
112 def get_symbol(self): | |
113 if self.identities.type == 'desktop': | |
114 return 'desktop' | |
115 elif self.identities.type == 'phone': | |
116 return 'mobile' | |
117 elif self.identities.type == 'web': | |
118 return 'globe' | |
119 elif self.identities.type == 'console': | |
120 return 'terminal' | |
121 else: | |
122 return 'desktop' | |
123 | |
124 def do_item_action(self, touch): | |
125 pass | |
126 | |
127 | |
128 class CategorySeparator(Label): | |
129 pass | |
130 | |
131 | |
132 class ImageViewer(ScatterLayout): | |
133 source = properties.StringProperty() | |
134 | |
135 def on_touch_down(self, touch): | |
136 if touch.is_double_tap: | |
137 self.reset() | |
138 return True | |
139 return super().on_touch_down(touch) | |
140 | |
141 def reset(self): | |
142 self.rotation = 0 | |
143 self.scale = 1 | |
144 self.x = 0 | |
145 self.y = 0 | |
146 | |
147 | |
148 class ImagesGallery(BoxLayout): | |
149 """Show list of images in a Carousel, with some controls to downloads""" | |
150 sources = properties.ListProperty() | |
151 carousel = properties.ObjectProperty() | |
152 previous_slide = None | |
153 | |
154 def on_kv_post(self, __): | |
155 self.on_sources(None, self.sources) | |
156 self.previous_slide = self.carousel.current_slide | |
157 self.carousel.bind(current_slide=self.on_slide_change) | |
158 | |
159 def on_parent(self, __, parent): | |
160 # we hide the head widget to have full screen | |
161 G.host.app.show_head_widget(not bool(parent), animation=False) | |
162 | |
163 def on_sources(self, __, sources): | |
164 if not sources or not self.carousel: | |
165 return | |
166 self.carousel.clear_widgets() | |
167 for source in sources: | |
168 img = ImageViewer( | |
169 source=source, | |
170 ) | |
171 self.carousel.add_widget(img) | |
172 | |
173 def on_slide_change(self, __, slide): | |
174 if isinstance(self.previous_slide, ImageViewer): | |
175 self.previous_slide.reset() | |
176 | |
177 self.previous_slide = slide | |
178 | |
179 def key_input(self, window, key, scancode, codepoint, modifier): | |
180 if key == 27: | |
181 G.host.close_ui() | |
182 return True |