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
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