1
+ # SPDX-FileCopyrightText: 2022 Tim Cocks
2
+ #
3
+ # SPDX-License-Identifier: MIT
1
4
5
+ """
6
+ `tab_layout`
7
+ ================================================================================
8
+
9
+ A layout that organizes pages into tabs.
10
+
11
+
12
+ * Author(s): Tim Cocks
13
+
14
+ Implementation Notes
15
+ --------------------
16
+
17
+ **Hardware:**
18
+
19
+ **Software and Dependencies:**
20
+
21
+ * Adafruit CircuitPython firmware for the supported boards:
22
+ https://github.com/adafruit/circuitpython/releases
23
+
24
+ """
2
25
try :
3
- from typing import Optional , Union
26
+ from typing import Optional , Union , Tuple
4
27
from fontio import BuiltinFont
5
28
from adafruit_bitmap_font .bdf import BDF
6
29
from adafruit_bitmap_font .pcf import PCF
7
30
except ImportError :
8
31
pass
9
32
10
- import board
11
33
import terminalio
12
34
import displayio
13
35
import adafruit_imageload
14
36
from adafruit_display_text .bitmap_label import Label
15
37
from adafruit_imageload .tilegrid_inflator import inflate_tilegrid
16
38
from adafruit_displayio_layout .layouts .page_layout import PageLayout
17
39
40
+
18
41
class TabLayout (displayio .Group ):
19
- def __init__ (self ,
20
- x : int = 0 , y : int = 0 ,
21
- display : displayio .Display = board .DISPLAY ,
22
- tab_text_scale : int = 1 ,
23
- custom_font : Optional [Union [BuiltinFont , BDF , PCF ]] = terminalio .FONT ,
24
- inactive_tab_spritesheet : Optional [str ] = None ,
25
- active_tab_spritesheet : Optional [str ] = None ,
26
- active_tab_text_color : Optional [int , tuple [int , int , int ]] = 0x999999 ,
27
- inactive_tab_text_color : Optional [int , tuple [int , int , int ]] = 0xfffff ,
28
- inactive_tab_transparent_indexes : Optional [Union [int , tuple [int , int ]]] = None ,
29
- active_tab_transparent_indexes : Optional [Union [int , tuple [int , int ]]] = None ,
30
- tab_count : int = None ,
31
- ):
42
+ """
43
+ A layout that organizes children into a grid table structure.
44
+
45
+ :param int x: x location the layout should be placed. Pixel coordinates.
46
+ :param int y: y location the layout should be placed. Pixel coordinates.
47
+ :param displayio.Display display: The Display object to show the tab layout on.
48
+ :param int tab_text_scale: Size of the text shown in the tabs.
49
+ Whole numbers 1 and greater are valid
50
+ :param Optional[Union[BuiltinFont, BDF, PCF]] custom_font: A pre-loaded font object to use
51
+ for the tab labels
52
+ :param str inactive_tab_spritesheet: Filepath of the spritesheet to show for inactive tabs.
53
+ :param str active_tab_spritesheet: Filepath of the spritesheet to show for the active tab.
54
+ :param Optional[int, tuple[int, int, int]] active_tab_text_color: Hex or tuple color to use
55
+ for the active tab label
56
+ :param Optional[int, tuple[int, int, int]] inactive_tab_text_color: Hex or tuple color to
57
+ use for inactive tab labels
58
+ :param Optional[Union[int, tuple[int, int]]] inactive_tab_transparent_indexes: single index
59
+ or tuple of multiple indexes to be made transparent in the inactive tab sprite palette.
60
+ :param Optional[Union[int, tuple[int, int]]] active_tab_transparent_indexes: single index
61
+ or tuple of multiple indexes to be made transparent in the active tab sprite palette.
62
+ :param int tab_count: How many tabs to draw in the layout. Positive whole numbers are valid.
63
+ """
64
+
65
+ # pylint: disable=too-many-instance-attributes, too-many-arguments, invalid-name, too-many-branches
32
66
67
+ def __init__ (
68
+ self ,
69
+ x : int = 0 ,
70
+ y : int = 0 ,
71
+ display : Optional [displayio .Display ] = None ,
72
+ tab_text_scale : int = 1 ,
73
+ custom_font : Optional [Union [BuiltinFont , BDF , PCF ]] = terminalio .FONT ,
74
+ inactive_tab_spritesheet : Optional [str ] = None ,
75
+ active_tab_spritesheet : Optional [str ] = None ,
76
+ active_tab_text_color : Optional [Union [int , Tuple [int , int , int ]]] = 0x999999 ,
77
+ inactive_tab_text_color : Optional [Union [int , Tuple [int , int , int ]]] = 0xFFFFF ,
78
+ inactive_tab_transparent_indexes : Optional [Union [int , Tuple [int , int ]]] = None ,
79
+ active_tab_transparent_indexes : Optional [Union [int , Tuple [int , int ]]] = None ,
80
+ tab_count : int = None ,
81
+ ):
82
+
83
+ if display is None :
84
+ # pylint: disable=import-outside-toplevel
85
+ import board
86
+
87
+ if hasattr (board , "DISPLAY" ):
88
+ display = board .DISPLAY
33
89
if inactive_tab_spritesheet is None :
34
90
raise AttributeError ("Must pass active_tab_spritesheet" )
35
91
if active_tab_spritesheet is None :
@@ -39,8 +95,12 @@ def __init__(self,
39
95
40
96
super ().__init__ (x = x , y = y )
41
97
self .tab_count = tab_count
42
- self ._active_bmp , self ._active_palette = adafruit_imageload .load (active_tab_spritesheet )
43
- self ._inactive_bmp , self ._inactive_palette = adafruit_imageload .load (inactive_tab_spritesheet )
98
+ self ._active_bmp , self ._active_palette = adafruit_imageload .load (
99
+ active_tab_spritesheet
100
+ )
101
+ self ._inactive_bmp , self ._inactive_palette = adafruit_imageload .load (
102
+ inactive_tab_spritesheet
103
+ )
44
104
45
105
if isinstance (active_tab_transparent_indexes , int ):
46
106
self ._active_palette .make_transparent (active_tab_transparent_indexes )
@@ -56,7 +116,9 @@ def __init__(self,
56
116
for index in inactive_tab_transparent_indexes :
57
117
self ._inactive_palette .make_transparent (index )
58
118
else :
59
- raise AttributeError ("inactive_tab_transparent_indexes must be int or tuple" )
119
+ raise AttributeError (
120
+ "inactive_tab_transparent_indexes must be int or tuple"
121
+ )
60
122
61
123
self .tab_height = self ._active_bmp .height
62
124
self .display = display
@@ -72,25 +134,35 @@ def __init__(self,
72
134
self .append (self .page_layout )
73
135
74
136
def _draw_tabs (self ):
75
- for i , page_dict in enumerate (self .page_layout ._page_content_list ):
137
+ for i , page_dict in enumerate (self .page_layout .page_content_list ):
76
138
if i not in self .tab_dict :
77
139
print (f"creating tab { i } " )
78
140
_new_tab_group = displayio .Group ()
79
- _tab_tilegrid = inflate_tilegrid (bmp_obj = self ._inactive_bmp , bmp_palette = self ._inactive_palette ,
80
- target_size = ((self .display .width // self .tab_count ) // (
81
- self ._active_bmp .width // 3 ), 3 ))
141
+ _tab_tilegrid = inflate_tilegrid (
142
+ bmp_obj = self ._inactive_bmp ,
143
+ bmp_palette = self ._inactive_palette ,
144
+ target_size = (
145
+ (self .display .width // self .tab_count )
146
+ // (self ._active_bmp .width // 3 ),
147
+ 3 ,
148
+ ),
149
+ )
82
150
83
151
_tab_tilegrid .x = (self .display .width // self .tab_count ) * i
84
152
_new_tab_group .append (_tab_tilegrid )
85
153
86
- _tab_label = Label (self .custom_font , text = page_dict ["page_name" ],
87
- color = self .inactive_tab_text_color , scale = self .tab_text_scale )
154
+ _tab_label = Label (
155
+ self .custom_font ,
156
+ text = page_dict ["page_name" ],
157
+ color = self .inactive_tab_text_color ,
158
+ scale = self .tab_text_scale ,
159
+ )
88
160
89
161
_tab_label .anchor_point = (0.5 , 0.5 )
90
162
_tab_label .anchored_position = (
91
- _tab_tilegrid .x +
92
- ((_tab_tilegrid .width * _tab_tilegrid .tile_width ) // 2 ),
93
- (_tab_tilegrid .height * _tab_tilegrid .tile_height ) // 2
163
+ _tab_tilegrid .x
164
+ + ((_tab_tilegrid .width * _tab_tilegrid .tile_width ) // 2 ),
165
+ (_tab_tilegrid .height * _tab_tilegrid .tile_height ) // 2 ,
94
166
)
95
167
_new_tab_group .append (_tab_label )
96
168
@@ -113,10 +185,15 @@ def _update_active_tab(self):
113
185
self .tab_group [i ][1 ].color = self .inactive_tab_text_color
114
186
115
187
def add_content (self , tab_content , tab_name ):
188
+ """Add a child to the tab layout.
189
+
190
+ :param tab_content: the content for the tab typically a Group
191
+ :param tab_name: the name of this tab, will be shown inside the tab
192
+
193
+ :return: None"""
116
194
self .page_layout .add_content (tab_content , tab_name )
117
195
self ._draw_tabs ()
118
196
119
-
120
197
def show_page (self , page_name = None , page_index = None ):
121
198
"""
122
199
Show the specified page, and hide all other pages.
@@ -129,7 +206,6 @@ def show_page(self, page_name=None, page_index=None):
129
206
self .page_layout .show_page (page_name = page_name , page_index = page_index )
130
207
self ._update_active_tab ()
131
208
132
-
133
209
@property
134
210
def showing_page_index (self ):
135
211
"""
@@ -140,7 +216,8 @@ def showing_page_index(self):
140
216
141
217
@showing_page_index .setter
142
218
def showing_page_index (self , new_index ):
143
- self .show_page (page_index = new_index )
219
+ if self .showing_page_index != new_index :
220
+ self .show_page (page_index = new_index )
144
221
145
222
@property
146
223
def showing_page_name (self ):
@@ -180,3 +257,21 @@ def previous_page(self, loop=True):
180
257
"""
181
258
self .page_layout .previous_page (loop = loop )
182
259
self ._update_active_tab ()
260
+
261
+ def handle_touch_events (self , touch_event ):
262
+ """
263
+ Check if the touch event is on the tabs and if so change to the touched tab.
264
+
265
+ :param tuple touch_event: tuple containing x and y coordinates of the
266
+ touch event in indexes 0 and 1.
267
+ :return: None
268
+ """
269
+
270
+ if touch_event :
271
+ if 0 <= touch_event [1 ] <= self .tab_height :
272
+
273
+ touched_tab_index = touch_event [0 ] // (
274
+ self .display .width // self .tab_count
275
+ )
276
+ print (f"{ touch_event [0 ]} - { touched_tab_index } " )
277
+ self .showing_page_index = touched_tab_index
0 commit comments