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