bauiv1lib.colorpicker
Provides popup windows for choosing colors.
1# Released under the MIT License. See LICENSE for details. 2# 3"""Provides popup windows for choosing colors.""" 4 5from __future__ import annotations 6 7from typing import TYPE_CHECKING 8 9from bauiv1lib.popup import PopupWindow 10import bauiv1 as bui 11 12if TYPE_CHECKING: 13 from typing import Any, Sequence 14 15 16class ColorPicker(PopupWindow): 17 """A popup UI to select from a set of colors. 18 19 Passes the color to the delegate's color_picker_selected_color() method. 20 """ 21 22 def __init__( 23 self, 24 parent: bui.Widget, 25 position: tuple[float, float], 26 initial_color: Sequence[float] = (1.0, 1.0, 1.0), 27 delegate: Any = None, 28 scale: float | None = None, 29 offset: tuple[float, float] = (0.0, 0.0), 30 tag: Any = '', 31 ): 32 # pylint: disable=too-many-locals 33 assert bui.app.classic is not None 34 35 c_raw = bui.app.classic.get_player_colors() 36 assert len(c_raw) == 16 37 self.colors = [c_raw[0:4], c_raw[4:8], c_raw[8:12], c_raw[12:16]] 38 39 uiscale = bui.app.ui_v1.uiscale 40 if scale is None: 41 scale = ( 42 2.3 43 if uiscale is bui.UIScale.SMALL 44 else 1.65 45 if uiscale is bui.UIScale.MEDIUM 46 else 1.23 47 ) 48 self._parent = parent 49 self._position = position 50 self._scale = scale 51 self._offset = offset 52 self._delegate = delegate 53 self._transitioning_out = False 54 self._tag = tag 55 self._initial_color = initial_color 56 57 # Create our _root_widget. 58 super().__init__( 59 position=position, 60 size=(210, 240), 61 scale=scale, 62 focus_position=(10, 10), 63 focus_size=(190, 220), 64 bg_color=(0.5, 0.5, 0.5), 65 offset=offset, 66 ) 67 rows: list[list[bui.Widget]] = [] 68 closest_dist = 9999.0 69 closest = (0, 0) 70 for y in range(4): 71 row: list[bui.Widget] = [] 72 rows.append(row) 73 for x in range(4): 74 color = self.colors[y][x] 75 dist = ( 76 abs(color[0] - initial_color[0]) 77 + abs(color[1] - initial_color[1]) 78 + abs(color[2] - initial_color[2]) 79 ) 80 if dist < closest_dist: 81 closest = (x, y) 82 closest_dist = dist 83 btn = bui.buttonwidget( 84 parent=self.root_widget, 85 position=(22 + 45 * x, 185 - 45 * y), 86 size=(35, 40), 87 label='', 88 button_type='square', 89 on_activate_call=bui.WeakCall(self._select, x, y), 90 autoselect=True, 91 color=color, 92 extra_touch_border_scale=0.0, 93 ) 94 row.append(btn) 95 other_button = bui.buttonwidget( 96 parent=self.root_widget, 97 position=(105 - 60, 13), 98 color=(0.7, 0.7, 0.7), 99 text_scale=0.5, 100 textcolor=(0.8, 0.8, 0.8), 101 size=(120, 30), 102 label=bui.Lstr( 103 resource='otherText', 104 fallback_resource='coopSelectWindow.customText', 105 ), 106 autoselect=True, 107 on_activate_call=bui.WeakCall(self._select_other), 108 ) 109 110 # Custom colors are limited to pro currently. 111 assert bui.app.classic is not None 112 if not bui.app.classic.accounts.have_pro(): 113 bui.imagewidget( 114 parent=self.root_widget, 115 position=(50, 12), 116 size=(30, 30), 117 texture=bui.gettexture('lock'), 118 draw_controller=other_button, 119 ) 120 121 # If their color is close to one of our swatches, select it. 122 # Otherwise select 'other'. 123 if closest_dist < 0.03: 124 bui.containerwidget( 125 edit=self.root_widget, 126 selected_child=rows[closest[1]][closest[0]], 127 ) 128 else: 129 bui.containerwidget( 130 edit=self.root_widget, selected_child=other_button 131 ) 132 133 def get_tag(self) -> Any: 134 """Return this popup's tag.""" 135 return self._tag 136 137 def _select_other(self) -> None: 138 from bauiv1lib import purchase 139 140 # Requires pro. 141 assert bui.app.classic is not None 142 if not bui.app.classic.accounts.have_pro(): 143 purchase.PurchaseWindow(items=['pro']) 144 self._transition_out() 145 return 146 ColorPickerExact( 147 parent=self._parent, 148 position=self._position, 149 initial_color=self._initial_color, 150 delegate=self._delegate, 151 scale=self._scale, 152 offset=self._offset, 153 tag=self._tag, 154 ) 155 156 # New picker now 'owns' the delegate; we shouldn't send it any 157 # more messages. 158 self._delegate = None 159 self._transition_out() 160 161 def _select(self, x: int, y: int) -> None: 162 if self._delegate: 163 self._delegate.color_picker_selected_color(self, self.colors[y][x]) 164 bui.apptimer(0.05, self._transition_out) 165 166 def _transition_out(self) -> None: 167 if not self._transitioning_out: 168 self._transitioning_out = True 169 if self._delegate is not None: 170 self._delegate.color_picker_closing(self) 171 bui.containerwidget(edit=self.root_widget, transition='out_scale') 172 173 def on_popup_cancel(self) -> None: 174 if not self._transitioning_out: 175 bui.getsound('swish').play() 176 self._transition_out() 177 178 179class ColorPickerExact(PopupWindow): 180 """pops up a ui to select from a set of colors. 181 passes the color to the delegate's color_picker_selected_color() method""" 182 183 def __init__( 184 self, 185 parent: bui.Widget, 186 position: tuple[float, float], 187 initial_color: Sequence[float] = (1.0, 1.0, 1.0), 188 delegate: Any = None, 189 scale: float | None = None, 190 offset: tuple[float, float] = (0.0, 0.0), 191 tag: Any = '', 192 ): 193 # pylint: disable=too-many-locals 194 del parent # Unused var. 195 assert bui.app.classic is not None 196 197 c_raw = bui.app.classic.get_player_colors() 198 assert len(c_raw) == 16 199 self.colors = [c_raw[0:4], c_raw[4:8], c_raw[8:12], c_raw[12:16]] 200 201 uiscale = bui.app.ui_v1.uiscale 202 if scale is None: 203 scale = ( 204 2.3 205 if uiscale is bui.UIScale.SMALL 206 else 1.65 207 if uiscale is bui.UIScale.MEDIUM 208 else 1.23 209 ) 210 self._delegate = delegate 211 self._transitioning_out = False 212 self._tag = tag 213 self._color = list(initial_color) 214 self._last_press_time = bui.apptime() 215 self._last_press_color_name: str | None = None 216 self._last_press_increasing: bool | None = None 217 self._change_speed = 1.0 218 width = 180.0 219 height = 240.0 220 221 # Creates our _root_widget. 222 super().__init__( 223 position=position, 224 size=(width, height), 225 scale=scale, 226 focus_position=(10, 10), 227 focus_size=(width - 20, height - 20), 228 bg_color=(0.5, 0.5, 0.5), 229 offset=offset, 230 ) 231 self._swatch = bui.imagewidget( 232 parent=self.root_widget, 233 position=(width * 0.5 - 50, height - 70), 234 size=(100, 70), 235 texture=bui.gettexture('buttonSquare'), 236 color=(1, 0, 0), 237 ) 238 x = 50 239 y = height - 90 240 self._label_r: bui.Widget 241 self._label_g: bui.Widget 242 self._label_b: bui.Widget 243 for color_name, color_val in [ 244 ('r', (1, 0.15, 0.15)), 245 ('g', (0.15, 1, 0.15)), 246 ('b', (0.15, 0.15, 1)), 247 ]: 248 txt = bui.textwidget( 249 parent=self.root_widget, 250 position=(x - 10, y), 251 size=(0, 0), 252 h_align='center', 253 color=color_val, 254 v_align='center', 255 text='0.12', 256 ) 257 setattr(self, '_label_' + color_name, txt) 258 for b_label, bhval, binc in [('-', 30, False), ('+', 75, True)]: 259 bui.buttonwidget( 260 parent=self.root_widget, 261 position=(x + bhval, y - 15), 262 scale=0.8, 263 repeat=True, 264 text_scale=1.3, 265 size=(40, 40), 266 label=b_label, 267 autoselect=True, 268 enable_sound=False, 269 on_activate_call=bui.WeakCall( 270 self._color_change_press, color_name, binc 271 ), 272 ) 273 y -= 42 274 275 btn = bui.buttonwidget( 276 parent=self.root_widget, 277 position=(width * 0.5 - 40, 10), 278 size=(80, 30), 279 text_scale=0.6, 280 color=(0.6, 0.6, 0.6), 281 textcolor=(0.7, 0.7, 0.7), 282 label=bui.Lstr(resource='doneText'), 283 on_activate_call=bui.WeakCall(self._transition_out), 284 autoselect=True, 285 ) 286 bui.containerwidget(edit=self.root_widget, start_button=btn) 287 288 # Unlike the swatch picker, we stay open and constantly push our 289 # color to the delegate, so start doing that. 290 self._update_for_color() 291 292 # noinspection PyUnresolvedReferences 293 def _update_for_color(self) -> None: 294 if not self.root_widget: 295 return 296 bui.imagewidget(edit=self._swatch, color=self._color) 297 298 # We generate these procedurally, so pylint misses them. 299 # FIXME: create static attrs instead. 300 # pylint: disable=consider-using-f-string 301 bui.textwidget(edit=self._label_r, text='%.2f' % self._color[0]) 302 bui.textwidget(edit=self._label_g, text='%.2f' % self._color[1]) 303 bui.textwidget(edit=self._label_b, text='%.2f' % self._color[2]) 304 if self._delegate is not None: 305 self._delegate.color_picker_selected_color(self, self._color) 306 307 def _color_change_press(self, color_name: str, increasing: bool) -> None: 308 # If we get rapid-fire presses, eventually start moving faster. 309 current_time = bui.apptime() 310 since_last = current_time - self._last_press_time 311 if ( 312 since_last < 0.2 313 and self._last_press_color_name == color_name 314 and self._last_press_increasing == increasing 315 ): 316 self._change_speed += 0.25 317 else: 318 self._change_speed = 1.0 319 self._last_press_time = current_time 320 self._last_press_color_name = color_name 321 self._last_press_increasing = increasing 322 323 color_index = ('r', 'g', 'b').index(color_name) 324 offs = int(self._change_speed) * (0.01 if increasing else -0.01) 325 self._color[color_index] = max( 326 0.0, min(1.0, self._color[color_index] + offs) 327 ) 328 self._update_for_color() 329 330 def get_tag(self) -> Any: 331 """Return this popup's tag value.""" 332 return self._tag 333 334 def _transition_out(self) -> None: 335 if not self._transitioning_out: 336 self._transitioning_out = True 337 if self._delegate is not None: 338 self._delegate.color_picker_closing(self) 339 bui.containerwidget(edit=self.root_widget, transition='out_scale') 340 341 def on_popup_cancel(self) -> None: 342 if not self._transitioning_out: 343 bui.getsound('swish').play() 344 self._transition_out()
17class ColorPicker(PopupWindow): 18 """A popup UI to select from a set of colors. 19 20 Passes the color to the delegate's color_picker_selected_color() method. 21 """ 22 23 def __init__( 24 self, 25 parent: bui.Widget, 26 position: tuple[float, float], 27 initial_color: Sequence[float] = (1.0, 1.0, 1.0), 28 delegate: Any = None, 29 scale: float | None = None, 30 offset: tuple[float, float] = (0.0, 0.0), 31 tag: Any = '', 32 ): 33 # pylint: disable=too-many-locals 34 assert bui.app.classic is not None 35 36 c_raw = bui.app.classic.get_player_colors() 37 assert len(c_raw) == 16 38 self.colors = [c_raw[0:4], c_raw[4:8], c_raw[8:12], c_raw[12:16]] 39 40 uiscale = bui.app.ui_v1.uiscale 41 if scale is None: 42 scale = ( 43 2.3 44 if uiscale is bui.UIScale.SMALL 45 else 1.65 46 if uiscale is bui.UIScale.MEDIUM 47 else 1.23 48 ) 49 self._parent = parent 50 self._position = position 51 self._scale = scale 52 self._offset = offset 53 self._delegate = delegate 54 self._transitioning_out = False 55 self._tag = tag 56 self._initial_color = initial_color 57 58 # Create our _root_widget. 59 super().__init__( 60 position=position, 61 size=(210, 240), 62 scale=scale, 63 focus_position=(10, 10), 64 focus_size=(190, 220), 65 bg_color=(0.5, 0.5, 0.5), 66 offset=offset, 67 ) 68 rows: list[list[bui.Widget]] = [] 69 closest_dist = 9999.0 70 closest = (0, 0) 71 for y in range(4): 72 row: list[bui.Widget] = [] 73 rows.append(row) 74 for x in range(4): 75 color = self.colors[y][x] 76 dist = ( 77 abs(color[0] - initial_color[0]) 78 + abs(color[1] - initial_color[1]) 79 + abs(color[2] - initial_color[2]) 80 ) 81 if dist < closest_dist: 82 closest = (x, y) 83 closest_dist = dist 84 btn = bui.buttonwidget( 85 parent=self.root_widget, 86 position=(22 + 45 * x, 185 - 45 * y), 87 size=(35, 40), 88 label='', 89 button_type='square', 90 on_activate_call=bui.WeakCall(self._select, x, y), 91 autoselect=True, 92 color=color, 93 extra_touch_border_scale=0.0, 94 ) 95 row.append(btn) 96 other_button = bui.buttonwidget( 97 parent=self.root_widget, 98 position=(105 - 60, 13), 99 color=(0.7, 0.7, 0.7), 100 text_scale=0.5, 101 textcolor=(0.8, 0.8, 0.8), 102 size=(120, 30), 103 label=bui.Lstr( 104 resource='otherText', 105 fallback_resource='coopSelectWindow.customText', 106 ), 107 autoselect=True, 108 on_activate_call=bui.WeakCall(self._select_other), 109 ) 110 111 # Custom colors are limited to pro currently. 112 assert bui.app.classic is not None 113 if not bui.app.classic.accounts.have_pro(): 114 bui.imagewidget( 115 parent=self.root_widget, 116 position=(50, 12), 117 size=(30, 30), 118 texture=bui.gettexture('lock'), 119 draw_controller=other_button, 120 ) 121 122 # If their color is close to one of our swatches, select it. 123 # Otherwise select 'other'. 124 if closest_dist < 0.03: 125 bui.containerwidget( 126 edit=self.root_widget, 127 selected_child=rows[closest[1]][closest[0]], 128 ) 129 else: 130 bui.containerwidget( 131 edit=self.root_widget, selected_child=other_button 132 ) 133 134 def get_tag(self) -> Any: 135 """Return this popup's tag.""" 136 return self._tag 137 138 def _select_other(self) -> None: 139 from bauiv1lib import purchase 140 141 # Requires pro. 142 assert bui.app.classic is not None 143 if not bui.app.classic.accounts.have_pro(): 144 purchase.PurchaseWindow(items=['pro']) 145 self._transition_out() 146 return 147 ColorPickerExact( 148 parent=self._parent, 149 position=self._position, 150 initial_color=self._initial_color, 151 delegate=self._delegate, 152 scale=self._scale, 153 offset=self._offset, 154 tag=self._tag, 155 ) 156 157 # New picker now 'owns' the delegate; we shouldn't send it any 158 # more messages. 159 self._delegate = None 160 self._transition_out() 161 162 def _select(self, x: int, y: int) -> None: 163 if self._delegate: 164 self._delegate.color_picker_selected_color(self, self.colors[y][x]) 165 bui.apptimer(0.05, self._transition_out) 166 167 def _transition_out(self) -> None: 168 if not self._transitioning_out: 169 self._transitioning_out = True 170 if self._delegate is not None: 171 self._delegate.color_picker_closing(self) 172 bui.containerwidget(edit=self.root_widget, transition='out_scale') 173 174 def on_popup_cancel(self) -> None: 175 if not self._transitioning_out: 176 bui.getsound('swish').play() 177 self._transition_out()
A popup UI to select from a set of colors.
Passes the color to the delegate's color_picker_selected_color() method.
ColorPicker( parent: _bauiv1.Widget, position: tuple[float, float], initial_color: Sequence[float] = (1.0, 1.0, 1.0), delegate: Any = None, scale: float | None = None, offset: tuple[float, float] = (0.0, 0.0), tag: Any = '')
23 def __init__( 24 self, 25 parent: bui.Widget, 26 position: tuple[float, float], 27 initial_color: Sequence[float] = (1.0, 1.0, 1.0), 28 delegate: Any = None, 29 scale: float | None = None, 30 offset: tuple[float, float] = (0.0, 0.0), 31 tag: Any = '', 32 ): 33 # pylint: disable=too-many-locals 34 assert bui.app.classic is not None 35 36 c_raw = bui.app.classic.get_player_colors() 37 assert len(c_raw) == 16 38 self.colors = [c_raw[0:4], c_raw[4:8], c_raw[8:12], c_raw[12:16]] 39 40 uiscale = bui.app.ui_v1.uiscale 41 if scale is None: 42 scale = ( 43 2.3 44 if uiscale is bui.UIScale.SMALL 45 else 1.65 46 if uiscale is bui.UIScale.MEDIUM 47 else 1.23 48 ) 49 self._parent = parent 50 self._position = position 51 self._scale = scale 52 self._offset = offset 53 self._delegate = delegate 54 self._transitioning_out = False 55 self._tag = tag 56 self._initial_color = initial_color 57 58 # Create our _root_widget. 59 super().__init__( 60 position=position, 61 size=(210, 240), 62 scale=scale, 63 focus_position=(10, 10), 64 focus_size=(190, 220), 65 bg_color=(0.5, 0.5, 0.5), 66 offset=offset, 67 ) 68 rows: list[list[bui.Widget]] = [] 69 closest_dist = 9999.0 70 closest = (0, 0) 71 for y in range(4): 72 row: list[bui.Widget] = [] 73 rows.append(row) 74 for x in range(4): 75 color = self.colors[y][x] 76 dist = ( 77 abs(color[0] - initial_color[0]) 78 + abs(color[1] - initial_color[1]) 79 + abs(color[2] - initial_color[2]) 80 ) 81 if dist < closest_dist: 82 closest = (x, y) 83 closest_dist = dist 84 btn = bui.buttonwidget( 85 parent=self.root_widget, 86 position=(22 + 45 * x, 185 - 45 * y), 87 size=(35, 40), 88 label='', 89 button_type='square', 90 on_activate_call=bui.WeakCall(self._select, x, y), 91 autoselect=True, 92 color=color, 93 extra_touch_border_scale=0.0, 94 ) 95 row.append(btn) 96 other_button = bui.buttonwidget( 97 parent=self.root_widget, 98 position=(105 - 60, 13), 99 color=(0.7, 0.7, 0.7), 100 text_scale=0.5, 101 textcolor=(0.8, 0.8, 0.8), 102 size=(120, 30), 103 label=bui.Lstr( 104 resource='otherText', 105 fallback_resource='coopSelectWindow.customText', 106 ), 107 autoselect=True, 108 on_activate_call=bui.WeakCall(self._select_other), 109 ) 110 111 # Custom colors are limited to pro currently. 112 assert bui.app.classic is not None 113 if not bui.app.classic.accounts.have_pro(): 114 bui.imagewidget( 115 parent=self.root_widget, 116 position=(50, 12), 117 size=(30, 30), 118 texture=bui.gettexture('lock'), 119 draw_controller=other_button, 120 ) 121 122 # If their color is close to one of our swatches, select it. 123 # Otherwise select 'other'. 124 if closest_dist < 0.03: 125 bui.containerwidget( 126 edit=self.root_widget, 127 selected_child=rows[closest[1]][closest[0]], 128 ) 129 else: 130 bui.containerwidget( 131 edit=self.root_widget, selected_child=other_button 132 )
def
on_popup_cancel(self) -> None:
174 def on_popup_cancel(self) -> None: 175 if not self._transitioning_out: 176 bui.getsound('swish').play() 177 self._transition_out()
Called when the popup is canceled.
Cancels can occur due to clicking outside the window, hitting escape, etc.
Inherited Members
180class ColorPickerExact(PopupWindow): 181 """pops up a ui to select from a set of colors. 182 passes the color to the delegate's color_picker_selected_color() method""" 183 184 def __init__( 185 self, 186 parent: bui.Widget, 187 position: tuple[float, float], 188 initial_color: Sequence[float] = (1.0, 1.0, 1.0), 189 delegate: Any = None, 190 scale: float | None = None, 191 offset: tuple[float, float] = (0.0, 0.0), 192 tag: Any = '', 193 ): 194 # pylint: disable=too-many-locals 195 del parent # Unused var. 196 assert bui.app.classic is not None 197 198 c_raw = bui.app.classic.get_player_colors() 199 assert len(c_raw) == 16 200 self.colors = [c_raw[0:4], c_raw[4:8], c_raw[8:12], c_raw[12:16]] 201 202 uiscale = bui.app.ui_v1.uiscale 203 if scale is None: 204 scale = ( 205 2.3 206 if uiscale is bui.UIScale.SMALL 207 else 1.65 208 if uiscale is bui.UIScale.MEDIUM 209 else 1.23 210 ) 211 self._delegate = delegate 212 self._transitioning_out = False 213 self._tag = tag 214 self._color = list(initial_color) 215 self._last_press_time = bui.apptime() 216 self._last_press_color_name: str | None = None 217 self._last_press_increasing: bool | None = None 218 self._change_speed = 1.0 219 width = 180.0 220 height = 240.0 221 222 # Creates our _root_widget. 223 super().__init__( 224 position=position, 225 size=(width, height), 226 scale=scale, 227 focus_position=(10, 10), 228 focus_size=(width - 20, height - 20), 229 bg_color=(0.5, 0.5, 0.5), 230 offset=offset, 231 ) 232 self._swatch = bui.imagewidget( 233 parent=self.root_widget, 234 position=(width * 0.5 - 50, height - 70), 235 size=(100, 70), 236 texture=bui.gettexture('buttonSquare'), 237 color=(1, 0, 0), 238 ) 239 x = 50 240 y = height - 90 241 self._label_r: bui.Widget 242 self._label_g: bui.Widget 243 self._label_b: bui.Widget 244 for color_name, color_val in [ 245 ('r', (1, 0.15, 0.15)), 246 ('g', (0.15, 1, 0.15)), 247 ('b', (0.15, 0.15, 1)), 248 ]: 249 txt = bui.textwidget( 250 parent=self.root_widget, 251 position=(x - 10, y), 252 size=(0, 0), 253 h_align='center', 254 color=color_val, 255 v_align='center', 256 text='0.12', 257 ) 258 setattr(self, '_label_' + color_name, txt) 259 for b_label, bhval, binc in [('-', 30, False), ('+', 75, True)]: 260 bui.buttonwidget( 261 parent=self.root_widget, 262 position=(x + bhval, y - 15), 263 scale=0.8, 264 repeat=True, 265 text_scale=1.3, 266 size=(40, 40), 267 label=b_label, 268 autoselect=True, 269 enable_sound=False, 270 on_activate_call=bui.WeakCall( 271 self._color_change_press, color_name, binc 272 ), 273 ) 274 y -= 42 275 276 btn = bui.buttonwidget( 277 parent=self.root_widget, 278 position=(width * 0.5 - 40, 10), 279 size=(80, 30), 280 text_scale=0.6, 281 color=(0.6, 0.6, 0.6), 282 textcolor=(0.7, 0.7, 0.7), 283 label=bui.Lstr(resource='doneText'), 284 on_activate_call=bui.WeakCall(self._transition_out), 285 autoselect=True, 286 ) 287 bui.containerwidget(edit=self.root_widget, start_button=btn) 288 289 # Unlike the swatch picker, we stay open and constantly push our 290 # color to the delegate, so start doing that. 291 self._update_for_color() 292 293 # noinspection PyUnresolvedReferences 294 def _update_for_color(self) -> None: 295 if not self.root_widget: 296 return 297 bui.imagewidget(edit=self._swatch, color=self._color) 298 299 # We generate these procedurally, so pylint misses them. 300 # FIXME: create static attrs instead. 301 # pylint: disable=consider-using-f-string 302 bui.textwidget(edit=self._label_r, text='%.2f' % self._color[0]) 303 bui.textwidget(edit=self._label_g, text='%.2f' % self._color[1]) 304 bui.textwidget(edit=self._label_b, text='%.2f' % self._color[2]) 305 if self._delegate is not None: 306 self._delegate.color_picker_selected_color(self, self._color) 307 308 def _color_change_press(self, color_name: str, increasing: bool) -> None: 309 # If we get rapid-fire presses, eventually start moving faster. 310 current_time = bui.apptime() 311 since_last = current_time - self._last_press_time 312 if ( 313 since_last < 0.2 314 and self._last_press_color_name == color_name 315 and self._last_press_increasing == increasing 316 ): 317 self._change_speed += 0.25 318 else: 319 self._change_speed = 1.0 320 self._last_press_time = current_time 321 self._last_press_color_name = color_name 322 self._last_press_increasing = increasing 323 324 color_index = ('r', 'g', 'b').index(color_name) 325 offs = int(self._change_speed) * (0.01 if increasing else -0.01) 326 self._color[color_index] = max( 327 0.0, min(1.0, self._color[color_index] + offs) 328 ) 329 self._update_for_color() 330 331 def get_tag(self) -> Any: 332 """Return this popup's tag value.""" 333 return self._tag 334 335 def _transition_out(self) -> None: 336 if not self._transitioning_out: 337 self._transitioning_out = True 338 if self._delegate is not None: 339 self._delegate.color_picker_closing(self) 340 bui.containerwidget(edit=self.root_widget, transition='out_scale') 341 342 def on_popup_cancel(self) -> None: 343 if not self._transitioning_out: 344 bui.getsound('swish').play() 345 self._transition_out()
pops up a ui to select from a set of colors. passes the color to the delegate's color_picker_selected_color() method
ColorPickerExact( parent: _bauiv1.Widget, position: tuple[float, float], initial_color: Sequence[float] = (1.0, 1.0, 1.0), delegate: Any = None, scale: float | None = None, offset: tuple[float, float] = (0.0, 0.0), tag: Any = '')
184 def __init__( 185 self, 186 parent: bui.Widget, 187 position: tuple[float, float], 188 initial_color: Sequence[float] = (1.0, 1.0, 1.0), 189 delegate: Any = None, 190 scale: float | None = None, 191 offset: tuple[float, float] = (0.0, 0.0), 192 tag: Any = '', 193 ): 194 # pylint: disable=too-many-locals 195 del parent # Unused var. 196 assert bui.app.classic is not None 197 198 c_raw = bui.app.classic.get_player_colors() 199 assert len(c_raw) == 16 200 self.colors = [c_raw[0:4], c_raw[4:8], c_raw[8:12], c_raw[12:16]] 201 202 uiscale = bui.app.ui_v1.uiscale 203 if scale is None: 204 scale = ( 205 2.3 206 if uiscale is bui.UIScale.SMALL 207 else 1.65 208 if uiscale is bui.UIScale.MEDIUM 209 else 1.23 210 ) 211 self._delegate = delegate 212 self._transitioning_out = False 213 self._tag = tag 214 self._color = list(initial_color) 215 self._last_press_time = bui.apptime() 216 self._last_press_color_name: str | None = None 217 self._last_press_increasing: bool | None = None 218 self._change_speed = 1.0 219 width = 180.0 220 height = 240.0 221 222 # Creates our _root_widget. 223 super().__init__( 224 position=position, 225 size=(width, height), 226 scale=scale, 227 focus_position=(10, 10), 228 focus_size=(width - 20, height - 20), 229 bg_color=(0.5, 0.5, 0.5), 230 offset=offset, 231 ) 232 self._swatch = bui.imagewidget( 233 parent=self.root_widget, 234 position=(width * 0.5 - 50, height - 70), 235 size=(100, 70), 236 texture=bui.gettexture('buttonSquare'), 237 color=(1, 0, 0), 238 ) 239 x = 50 240 y = height - 90 241 self._label_r: bui.Widget 242 self._label_g: bui.Widget 243 self._label_b: bui.Widget 244 for color_name, color_val in [ 245 ('r', (1, 0.15, 0.15)), 246 ('g', (0.15, 1, 0.15)), 247 ('b', (0.15, 0.15, 1)), 248 ]: 249 txt = bui.textwidget( 250 parent=self.root_widget, 251 position=(x - 10, y), 252 size=(0, 0), 253 h_align='center', 254 color=color_val, 255 v_align='center', 256 text='0.12', 257 ) 258 setattr(self, '_label_' + color_name, txt) 259 for b_label, bhval, binc in [('-', 30, False), ('+', 75, True)]: 260 bui.buttonwidget( 261 parent=self.root_widget, 262 position=(x + bhval, y - 15), 263 scale=0.8, 264 repeat=True, 265 text_scale=1.3, 266 size=(40, 40), 267 label=b_label, 268 autoselect=True, 269 enable_sound=False, 270 on_activate_call=bui.WeakCall( 271 self._color_change_press, color_name, binc 272 ), 273 ) 274 y -= 42 275 276 btn = bui.buttonwidget( 277 parent=self.root_widget, 278 position=(width * 0.5 - 40, 10), 279 size=(80, 30), 280 text_scale=0.6, 281 color=(0.6, 0.6, 0.6), 282 textcolor=(0.7, 0.7, 0.7), 283 label=bui.Lstr(resource='doneText'), 284 on_activate_call=bui.WeakCall(self._transition_out), 285 autoselect=True, 286 ) 287 bui.containerwidget(edit=self.root_widget, start_button=btn) 288 289 # Unlike the swatch picker, we stay open and constantly push our 290 # color to the delegate, so start doing that. 291 self._update_for_color()
def
on_popup_cancel(self) -> None:
342 def on_popup_cancel(self) -> None: 343 if not self._transitioning_out: 344 bui.getsound('swish').play() 345 self._transition_out()
Called when the popup is canceled.
Cancels can occur due to clicking outside the window, hitting escape, etc.