def test_show_hide_rendering(self, _init_pygame, default_ui_manager, _display_surface_return_none): resolution = (400, 400) empty_surface = pygame.Surface(resolution) empty_surface.fill(pygame.Color(0, 0, 0)) surface = empty_surface.copy() manager = pygame_gui.UIManager(resolution) button = UIButton(relative_rect=pygame.Rect(25, 25, 375, 150), text="Test Button", manager=manager, visible=0) manager.update(0.01) manager.draw_ui(surface) assert compare_surfaces(empty_surface, surface) surface.fill(pygame.Color(0, 0, 0)) button.show() manager.update(0.01) manager.draw_ui(surface) assert not compare_surfaces(empty_surface, surface) surface.fill(pygame.Color(0, 0, 0)) button.hide() manager.update(0.01) manager.draw_ui(surface) assert compare_surfaces(empty_surface, surface)
def test_hide(self, _init_pygame, default_ui_manager, _display_surface_return_none): button = UIButton(relative_rect=pygame.Rect(100, 100, 150, 30), text="Test Button", manager=default_ui_manager) assert button.visible == 1 button.hide() assert button.visible == 0
def test_hide_and_show_of_disabled_button(self, _init_pygame, _display_surface_return_none): manager = UIManager((800, 600)) button = UIButton(relative_rect=pygame.Rect(100, 100, 100, 100), text="button test", manager=manager, starting_height=1) button.disable() button.hide() button.show() assert button.drawable_shape.active_state.state_id == 'disabled'
def test_hover_of_hidden_elements(self, _init_pygame, _display_surface_return_none): manager = UIManager((800, 600)) button1 = UIButton(relative_rect=pygame.Rect(100, 100, 100, 100), text="Lower button test", manager=manager, starting_height=1) button2 = UIButton(relative_rect=pygame.Rect(100, 100, 100, 100), text="Higher button test", manager=manager, starting_height=2) # override of default manager _update_mouse_position method to simulate hovering over the button manager._update_mouse_position = update_mouse_position_override_factory(manager, 150, 150) assert button1.hovered is False assert button2.hovered is False manager.update(0.01) assert button1.hovered is False assert button2.hovered is True button2.hide() assert button1.hovered is False assert button2.hovered is False manager.update(0.01) assert button1.hovered is True assert button2.hovered is False
class UIClosedDropDownState: """ The closed state of the drop down just displays the currently chosen option and a button that will switch the menu to the expanded state. :param drop_down_menu_ui: The UIDropDownElement this state belongs to. :param selected_option: The currently selected option. :param base_position_rect: Position and dimensions rectangle. :param open_button_width: Width of open button. :param expand_direction: Direction of expansion, 'up' or 'down'. :param manager: The UI Manager for the whole UI. :param container: The container the element is within. :param object_ids: The object IDs for the drop down UI element. :param element_ids: The element IDs for the drop down UI element. :param visible: Whether the element is visible by default. Warning - container visibility may override this. """ def __init__(self, drop_down_menu_ui: 'UIDropDownMenu', selected_option: str, base_position_rect: Union[pygame.Rect, None], open_button_width: int, expand_direction: Union[str, None], manager: IUIManagerInterface, container: IContainerLikeInterface, object_ids: Union[List[Union[str, None]], None], element_ids: Union[List[str], None], visible: int = 1): self.drop_down_menu_ui = drop_down_menu_ui self.selected_option_button = None self.open_button = None self.selected_option = selected_option self.base_position_rect = base_position_rect self.expand_direction = expand_direction self.ui_manager = manager self.ui_container = container self.element_ids = element_ids self.object_ids = object_ids self.open_button_width = open_button_width self.should_transition = False self.target_state = 'expanded' self.visible = visible self.active_buttons = [] def disable(self): """ Disables the closed state so that it is no longer interactive. """ self.selected_option_button.disable() if self.open_button is not None: self.open_button.disable() self.drop_down_menu_ui.drawable_shape.set_active_state('disabled') def enable(self): """ Re-enables the closed state so we can once again interact with it. """ self.selected_option_button.enable() if self.open_button is not None: self.open_button.enable() self.drop_down_menu_ui.drawable_shape.set_active_state('normal') def rebuild(self): """ Rebuild the closed state from theming parameters and dimensions. """ theming_parameters = { 'normal_bg': self.drop_down_menu_ui.background_colour, 'normal_border': self.drop_down_menu_ui.border_colour, 'disabled_bg': self.drop_down_menu_ui.disabled_background_colour, 'disabled_border': self.drop_down_menu_ui.disabled_border_colour, 'border_width': self.drop_down_menu_ui.border_width, 'shadow_width': self.drop_down_menu_ui.shadow_width, 'shape_corner_radius': self.drop_down_menu_ui.shape_corner_radius } if self.drop_down_menu_ui.shape == 'rectangle': self.drop_down_menu_ui.drawable_shape = RectDrawableShape( self.drop_down_menu_ui.rect, theming_parameters, ['normal', 'disabled'], self.ui_manager) elif self.drop_down_menu_ui.shape == 'rounded_rectangle': shape_rect = self.drop_down_menu_ui.rect self.drop_down_menu_ui.drawable_shape = RoundedRectangleShape( shape_rect, theming_parameters, ['normal', 'disabled'], self.ui_manager) self.drop_down_menu_ui.set_image( self.drop_down_menu_ui.drawable_shape.get_fresh_surface()) # extra if self.open_button is not None: expand_button_symbol = '▼' if self.expand_direction is not None: if self.expand_direction == 'up': expand_button_symbol = '▲' elif self.expand_direction == 'down': expand_button_symbol = '▼' self.open_button.set_text(expand_button_symbol) def start(self, should_rebuild: bool = True): """ Called each time we enter the closed state. It creates the necessary elements, the selected option and the open button. """ if should_rebuild: self.rebuild() self.should_transition = False border_and_shadow = (self.drop_down_menu_ui.shadow_width + self.drop_down_menu_ui.border_width) self.active_buttons = [] self.selected_option_button = UIButton( pygame.Rect( (border_and_shadow, border_and_shadow), (self.base_position_rect.width - self.open_button_width, self.base_position_rect.height)), self.selected_option, self.ui_manager, self.ui_container, starting_height=2, parent_element=self.drop_down_menu_ui, object_id='#selected_option', visible=self.visible) self.drop_down_menu_ui.join_focus_sets(self.selected_option_button) self.active_buttons.append(self.selected_option_button) if self.open_button_width > 0: open_button_x = (border_and_shadow + self.base_position_rect.width - self.open_button_width) expand_button_symbol = '▼' if self.expand_direction is not None: if self.expand_direction == 'up': expand_button_symbol = '▲' elif self.expand_direction == 'down': expand_button_symbol = '▼' self.open_button = UIButton(pygame.Rect( (open_button_x, border_and_shadow), (self.open_button_width, self.base_position_rect.height)), expand_button_symbol, self.ui_manager, self.ui_container, starting_height=2, parent_element=self.drop_down_menu_ui, object_id='#expand_button', visible=self.visible) self.drop_down_menu_ui.join_focus_sets(self.open_button) self.active_buttons.append(self.open_button) def finish(self): """ Called when we leave the closed state. Kills the open button and the selected option button. """ self.selected_option_button.kill() if self.open_button is not None: self.open_button.kill() def process_event(self, event: pygame.event.Event) -> bool: """ Processes events for the closed state of the drop down. :param event: The event to process. :return: Return True if we want to consume this event so it is not passed on to the rest of the UI. """ if event.type == UI_BUTTON_PRESSED and event.ui_element in self.active_buttons: self.should_transition = True return False def update_position(self): """ Update the position of all the button elements in the closed drop down state. Used when the position of the drop down has been altered directly, rather than when it has been moved as a consequence of it's container being moved. """ # update the base position rect border_and_shadow = (self.drop_down_menu_ui.shadow_width + self.drop_down_menu_ui.border_width) self.base_position_rect.x = self.drop_down_menu_ui.relative_rect.x + border_and_shadow self.base_position_rect.y = self.drop_down_menu_ui.relative_rect.y + border_and_shadow # update all the ui elements that depend on the base position self.selected_option_button.set_relative_position( (border_and_shadow, border_and_shadow)) if self.open_button is not None: open_button_x = (border_and_shadow + self.base_position_rect.width - self.open_button_width) self.open_button.set_relative_position( (open_button_x, self.base_position_rect.y)) def update_dimensions(self): """ Update the dimensions of all the button elements in the closed drop down state. Used when the dimensions of the drop down have been altered. """ # update the base position rect border_and_shadow = (self.drop_down_menu_ui.shadow_width + self.drop_down_menu_ui.border_width) self.base_position_rect.width = ( self.drop_down_menu_ui.relative_rect.width - (2 * border_and_shadow)) self.base_position_rect.height = ( self.drop_down_menu_ui.relative_rect.height - (2 * border_and_shadow)) # update all the ui elements that depend on the base position rect self.selected_option_button.set_dimensions( (self.base_position_rect.width - self.open_button_width, self.base_position_rect.height)) if self.open_button is not None: open_button_x = (border_and_shadow + self.base_position_rect.width - self.open_button_width) self.open_button.set_dimensions( (self.open_button_width, self.base_position_rect.height)) self.open_button.set_relative_position( (open_button_x, border_and_shadow)) def on_fresh_drawable_shape_ready(self): """ Called by an element's drawable shape when it has a new image surface ready for use, normally after a rebuilding/redrawing of some kind. In this case the result is to set the UI element's image to the new surface. """ self.drop_down_menu_ui.set_image( self.drop_down_menu_ui.drawable_shape.get_fresh_surface()) def show(self): """ Show selected_option_button and open_button. """ self.visible = 1 if self.open_button is not None: self.open_button.show() if self.selected_option_button is not None: self.selected_option_button.show() def hide(self): """ Hide selected_option_button and open_button. """ self.visible = 0 if self.open_button is not None: self.open_button.hide() if self.selected_option_button is not None: self.selected_option_button.hide()
class UIHorizontalSlider(UIElement): """ A horizontal slider is intended to help users adjust values within a range, for example a volume control. :param relative_rect: A rectangle describing the position and dimensions of the element. :param start_value: The value to start the slider at. :param value_range: The full range of values. :param manager: The UIManager that manages this element. :param container: The container that this element is within. If set to None will be the root window's container. :param parent_element: The element this element 'belongs to' in the theming hierarchy. :param object_id: A custom defined ID for fine tuning of theming. :param anchors: A dictionary describing what this element's relative_rect is relative to. :param visible: Whether the element is visible by default. Warning - container visibility may override this. :param click_increment: the amount to increment by when clicking one of the arrow buttons. """ def __init__(self, relative_rect: pygame.Rect, start_value: Union[float, int], value_range: Tuple[Union[float, int], Union[float, int]], manager: IUIManagerInterface, container: Union[IContainerLikeInterface, None] = None, parent_element: UIElement = None, object_id: Union[ObjectID, str, None] = None, anchors: Dict[str, str] = None, visible: int = 1, click_increment: Union[float, int] = 1): super().__init__(relative_rect, manager, container, layer_thickness=2, starting_height=1, anchors=anchors, visible=visible) self._create_valid_ids(container=container, parent_element=parent_element, object_id=object_id, element_id='horizontal_slider') self.default_button_width = 20 self.arrow_button_width = self.default_button_width self.sliding_button_width = self.default_button_width self.current_percentage = 0.5 self.left_limit_position = 0.0 self.starting_grab_x_difference = 0 if (isinstance(start_value, int) and isinstance(value_range[0], int) and isinstance(value_range[1], int)): self.use_integers_for_value = True else: self.use_integers_for_value = False self.value_range = value_range value_range_length = self.value_range[1] - self.value_range[0] self.current_value = self.value_range[0] + (self.current_percentage * value_range_length) if self.use_integers_for_value: self.current_value = int(self.current_value) self.grabbed_slider = False self.has_moved_recently = False self.has_been_moved_by_user_recently = False self.background_colour = None self.border_colour = None self.disabled_border_colour = None self.disabled_background_colour = None self.border_width = None self.shadow_width = None self.drawable_shape = None self.shape = 'rectangle' self.shape_corner_radius = None self.background_rect = None # type: Optional[pygame.Rect] self.scrollable_width = None self.right_limit_position = None self.scroll_position = None self.left_button = None self.right_button = None self.sliding_button = None self.enable_arrow_buttons = True self.button_container = None self.button_held_repeat_time = 0.2 self.button_held_repeat_acc = 0.0 self.increment = click_increment self.rebuild_from_changed_theme_data() sliding_x_pos = int(self.background_rect.width / 2 - self.sliding_button_width / 2) self.sliding_button = UIButton(pygame.Rect( (sliding_x_pos, 0), (self.sliding_button_width, self.background_rect.height)), '', self.ui_manager, container=self.button_container, starting_height=1, parent_element=self, object_id=ObjectID( object_id='#sliding_button', class_id='None'), anchors={ 'left': 'left', 'right': 'left', 'top': 'top', 'bottom': 'bottom' }, visible=self.visible) self.sliding_button.set_hold_range((self.background_rect.width, 100)) self.set_current_value(start_value) def rebuild(self): """ Rebuild anything that might need rebuilding. """ border_and_shadow = self.border_width + self.shadow_width self.background_rect = pygame.Rect( (border_and_shadow + self.relative_rect.x, border_and_shadow + self.relative_rect.y), (self.relative_rect.width - (2 * border_and_shadow), self.relative_rect.height - (2 * border_and_shadow))) theming_parameters = { 'normal_bg': self.background_colour, 'normal_border': self.border_colour, 'disabled_bg': self.disabled_background_colour, 'disabled_border': self.disabled_border_colour, 'border_width': self.border_width, 'shadow_width': self.shadow_width, 'shape_corner_radius': self.shape_corner_radius } if self.shape == 'rectangle': self.drawable_shape = RectDrawableShape(self.rect, theming_parameters, ['normal', 'disabled'], self.ui_manager) elif self.shape == 'rounded_rectangle': self.drawable_shape = RoundedRectangleShape( self.rect, theming_parameters, ['normal', 'disabled'], self.ui_manager) self.set_image(self.drawable_shape.get_fresh_surface()) if self.button_container is None: self.button_container = UIContainer( self.background_rect, manager=self.ui_manager, container=self.ui_container, anchors=self.anchors, object_id='#horiz_scrollbar_buttons_container', visible=self.visible) else: self.button_container.set_dimensions(self.background_rect.size) self.button_container.set_relative_position( self.background_rect.topleft) # Things below here depend on theme data so need to be updated on a rebuild if self.enable_arrow_buttons: self.arrow_button_width = self.default_button_width if self.left_button is None: self.left_button = UIButton(pygame.Rect( (0, 0), (self.arrow_button_width, self.background_rect.height)), '◀', self.ui_manager, container=self.button_container, starting_height=1, parent_element=self, object_id=ObjectID( "#left_button", "@arrow_button"), anchors={ 'left': 'left', 'right': 'left', 'top': 'top', 'bottom': 'bottom' }, visible=self.visible) if self.right_button is None: self.right_button = UIButton(pygame.Rect( (-self.arrow_button_width, 0), (self.arrow_button_width, self.background_rect.height)), '▶', self.ui_manager, container=self.button_container, starting_height=1, parent_element=self, object_id=ObjectID( "#right_button", "@arrow_button"), anchors={ 'left': 'right', 'right': 'right', 'top': 'top', 'bottom': 'bottom' }, visible=self.visible) else: self.arrow_button_width = 0 if self.left_button is not None: self.left_button.kill() self.left_button = None if self.right_button is not None: self.right_button.kill() self.right_button = None self.scrollable_width = (self.background_rect.width - self.sliding_button_width - (2 * self.arrow_button_width)) self.right_limit_position = self.scrollable_width self.scroll_position = self.scrollable_width / 2 if self.sliding_button is not None: sliding_x_pos = int((self.background_rect.width / 2) - (self.sliding_button_width / 2)) self.sliding_button.set_relative_position((sliding_x_pos, 0)) self.sliding_button.set_dimensions( (self.sliding_button_width, self.background_rect.height)) self.sliding_button.set_hold_range( (self.background_rect.width, 100)) self.set_current_value(self.current_value, False) def kill(self): """ Overrides the normal sprite kill() method to also kill the button elements that help make up the slider. """ self.button_container.kill() super().kill() def update(self, time_delta: float): """ Takes care of actually moving the slider based on interactions reported by the buttons or based on movement of the mouse if we are gripping the slider itself. :param time_delta: the time in seconds between calls to update. """ super().update(time_delta) if not (self.alive() and self.is_enabled): return moved_this_frame = False moved_this_frame = self._update_arrow_buttons(moved_this_frame, time_delta) mouse_x, mouse_y = self.ui_manager.get_mouse_position() if self.sliding_button.held and self.sliding_button.in_hold_range( (mouse_x, mouse_y)): if not self.grabbed_slider: self.grabbed_slider = True real_scroll_pos = self.sliding_button.rect.left self.starting_grab_x_difference = mouse_x - real_scroll_pos real_scroll_pos = self.sliding_button.rect.left current_grab_difference = mouse_x - real_scroll_pos adjustment_required = current_grab_difference - self.starting_grab_x_difference self.scroll_position = self.scroll_position + adjustment_required self.scroll_position = min( max(self.scroll_position, self.left_limit_position), self.right_limit_position) x_pos = (self.scroll_position + self.arrow_button_width) y_pos = 0 self.sliding_button.set_relative_position((x_pos, y_pos)) moved_this_frame = True elif not self.sliding_button.held: self.grabbed_slider = False if moved_this_frame: self.current_percentage = self.scroll_position / self.scrollable_width self.current_value = self.value_range[0] + ( self.current_percentage * (self.value_range[1] - self.value_range[0])) if self.use_integers_for_value: self.current_value = int(self.current_value) if not self.has_moved_recently: self.has_moved_recently = True if not self.has_been_moved_by_user_recently: self.has_been_moved_by_user_recently = True # old event - to be removed in 0.8.0 event_data = { 'user_type': OldType(UI_HORIZONTAL_SLIDER_MOVED), 'value': self.current_value, 'ui_element': self, 'ui_object_id': self.most_specific_combined_id } pygame.event.post(pygame.event.Event(pygame.USEREVENT, event_data)) # new event event_data = { 'value': self.current_value, 'ui_element': self, 'ui_object_id': self.most_specific_combined_id } pygame.event.post( pygame.event.Event(UI_HORIZONTAL_SLIDER_MOVED, event_data)) def _update_arrow_buttons(self, moved_this_frame, time_delta): if self.left_button is not None and ( self.left_button.held and self.scroll_position > self.left_limit_position): if self.button_held_repeat_acc > self.button_held_repeat_time: self.scroll_position -= (250.0 * time_delta) self.scroll_position = max(self.scroll_position, self.left_limit_position) x_pos = (self.scroll_position + self.arrow_button_width) y_pos = 0 self.sliding_button.set_relative_position((x_pos, y_pos)) moved_this_frame = True else: self.button_held_repeat_acc += time_delta elif self.right_button is not None and ( self.right_button.held and self.scroll_position < self.right_limit_position): if self.button_held_repeat_acc > self.button_held_repeat_time: self.scroll_position += (250.0 * time_delta) self.scroll_position = min(self.scroll_position, self.right_limit_position) x_pos = (self.scroll_position + self.arrow_button_width) y_pos = 0 self.sliding_button.set_relative_position((x_pos, y_pos)) moved_this_frame = True else: self.button_held_repeat_acc += time_delta else: self.button_held_repeat_acc = 0.0 return moved_this_frame def process_event(self, event: pygame.event.Event) -> bool: processed_event = False if event.type == UI_BUTTON_PRESSED: if (event.ui_element in [self.left_button, self.right_button] and self.button_held_repeat_acc < self.button_held_repeat_time and (self.value_range[0] <= self.get_current_value() <= self.value_range[1])): old_value = self.get_current_value() new_value = (old_value - self.increment if event.ui_element == self.left_button else old_value + self.increment) self.set_current_value(new_value, False) processed_event = True event_data = { 'value': self.current_value, 'ui_element': self, 'ui_object_id': self.most_specific_combined_id } pygame.event.post( pygame.event.Event(UI_HORIZONTAL_SLIDER_MOVED, event_data)) return processed_event def get_current_value(self) -> Union[float, int]: """ Gets the current value the slider is set to. :return: The current value recorded by the slider. """ self.has_moved_recently = False self.has_been_moved_by_user_recently = False return self.current_value def set_current_value(self, value: Union[float, int], warn: bool = True): """ Sets the value of the slider, which will move the position of the slider to match. Will issue a warning if the value set is not in the value range. :param value: The value to set. :param warn: set to false to suppress the default warning, instead the value will be clamped. """ if self.use_integers_for_value: value = int(value) min_value = min(self.value_range[0], self.value_range[1]) max_value = max(self.value_range[0], self.value_range[1]) if value < min_value or value > max_value: if warn: warnings.warn('value not in range', UserWarning) return else: self.current_value = max(min(value, max_value), min_value) else: self.current_value = value value_range_size = (self.value_range[1] - self.value_range[0]) if value_range_size != 0: self.current_percentage = (float(self.current_value) - self.value_range[0]) / value_range_size self.scroll_position = self.scrollable_width * self.current_percentage x_pos = (self.scroll_position + self.arrow_button_width) y_pos = 0 self.sliding_button.set_relative_position((x_pos, y_pos)) self.has_moved_recently = True def rebuild_from_changed_theme_data(self): """ Called by the UIManager to check the theming data and rebuild whatever needs rebuilding for this element when the theme data has changed. """ super().rebuild_from_changed_theme_data() has_any_changed = False if self._check_misc_theme_data_changed( attribute_name='shape', default_value='rectangle', casting_func=str, allowed_values=['rectangle', 'rounded_rectangle']): has_any_changed = True if self._check_shape_theming_changed(defaults={ 'border_width': 1, 'shadow_width': 2, 'shape_corner_radius': 2 }): has_any_changed = True background_colour = self.ui_theme.get_colour_or_gradient( 'dark_bg', self.combined_element_ids) if background_colour != self.background_colour: self.background_colour = background_colour has_any_changed = True border_colour = self.ui_theme.get_colour_or_gradient( 'normal_border', self.combined_element_ids) if border_colour != self.border_colour: self.border_colour = border_colour has_any_changed = True disabled_background_colour = self.ui_theme.get_colour_or_gradient( 'disabled_dark_bg', self.combined_element_ids) if disabled_background_colour != self.disabled_background_colour: self.disabled_background_colour = disabled_background_colour has_any_changed = True disabled_border_colour = self.ui_theme.get_colour_or_gradient( 'disabled_border', self.combined_element_ids) if disabled_border_colour != self.disabled_border_colour: self.disabled_border_colour = disabled_border_colour has_any_changed = True def parse_to_bool(str_data: str): return bool(int(str_data)) if self._check_misc_theme_data_changed( attribute_name='enable_arrow_buttons', default_value=True, casting_func=parse_to_bool): has_any_changed = True if self._check_misc_theme_data_changed( attribute_name='sliding_button_width', default_value=self.default_button_width, casting_func=int): has_any_changed = True if has_any_changed: self.rebuild() def set_position(self, position: Union[pygame.math.Vector2, Tuple[int, int], Tuple[float, float]]): """ Sets the absolute screen position of this slider, updating all subordinate button elements at the same time. :param position: The absolute screen position to set. """ super().set_position(position) border_and_shadow = self.border_width + self.shadow_width self.background_rect.x = border_and_shadow + self.relative_rect.x self.background_rect.y = border_and_shadow + self.relative_rect.y self.button_container.set_relative_position( self.background_rect.topleft) def set_relative_position(self, position: Union[pygame.math.Vector2, Tuple[int, int], Tuple[float, float]]): """ Sets the relative screen position of this slider, updating all subordinate button elements at the same time. :param position: The relative screen position to set. """ super().set_relative_position(position) border_and_shadow = self.border_width + self.shadow_width self.background_rect.x = border_and_shadow + self.relative_rect.x self.background_rect.y = border_and_shadow + self.relative_rect.y self.button_container.set_relative_position( self.background_rect.topleft) def set_dimensions(self, dimensions: Union[pygame.math.Vector2, Tuple[int, int], Tuple[float, float]]): """ Method to directly set the dimensions of an element. :param dimensions: The new dimensions to set. """ super().set_dimensions(dimensions) border_and_shadow = self.border_width + self.shadow_width self.background_rect.width = self.relative_rect.width - ( 2 * border_and_shadow) self.background_rect.height = self.relative_rect.height - ( 2 * border_and_shadow) self.button_container.set_dimensions(self.background_rect.size) # sort out sliding button parameters self.scrollable_width = (self.background_rect.width - self.sliding_button_width - (2 * self.arrow_button_width)) self.right_limit_position = self.scrollable_width self.scroll_position = self.scrollable_width * self.current_percentage slider_x_pos = self.scroll_position + self.arrow_button_width slider_y_pos = 0 self.sliding_button.set_dimensions( (self.sliding_button_width, self.background_rect.height)) self.sliding_button.set_relative_position((slider_x_pos, slider_y_pos)) def disable(self): """ Disable the slider. It should not be interactive and will use the disabled theme colours. """ if self.is_enabled: self.is_enabled = False self.sliding_button.disable() if self.left_button: self.left_button.disable() if self.right_button: self.right_button.disable() self.drawable_shape.set_active_state('disabled') def enable(self): """ Enable the slider. It should become interactive and will use the normal theme colours. """ if not self.is_enabled: self.is_enabled = True self.sliding_button.enable() if self.left_button: self.left_button.enable() if self.right_button: self.right_button.enable() self.drawable_shape.set_active_state('normal') def show(self): """ In addition to the base UIElement.show() - show the sliding button and show the button_container which will propagate and show the left and right buttons. """ super().show() self.sliding_button.show() if self.button_container is not None: self.button_container.show() def hide(self): """ In addition to the base UIElement.hide() - hide the sliding button and hide the button_container which will propagate and hide the left and right buttons. """ super().hide() self.sliding_button.hide() if self.button_container is not None: self.button_container.hide()