def __init__(self, rect: pygame.Rect, manager: IUIManagerInterface, action_long_desc: str, *, window_title: str = 'Confirm', action_short_name: str = 'OK', blocking: bool = True, object_id: Union[ObjectID, str] = ObjectID('#confirmation_dialog', None), visible: int = 1): super().__init__(rect, manager, window_display_title=window_title, object_id=object_id, resizable=True, visible=visible) minimum_dimensions = (260, 200) if rect.width < minimum_dimensions[0] or rect.height < minimum_dimensions[1]: warn_string = ("Initial size: " + str(rect.size) + " is less than minimum dimensions: " + str(minimum_dimensions)) warnings.warn(warn_string, UserWarning) self.set_minimum_dimensions(minimum_dimensions) self.confirm_button = UIButton(relative_rect=pygame.Rect(-220, -40, 100, 30), text=action_short_name, manager=self.ui_manager, container=self, object_id='#confirm_button', anchors={'left': 'right', 'right': 'right', 'top': 'bottom', 'bottom': 'bottom'}) self.cancel_button = UIButton(relative_rect=pygame.Rect(-110, -40, 100, 30), text='Cancel', manager=self.ui_manager, container=self, object_id='#cancel_button', anchors={'left': 'right', 'right': 'right', 'top': 'bottom', 'bottom': 'bottom'}) text_width = self.get_container().get_size()[0] - 10 text_height = self.get_container().get_size()[1] - 50 self.confirmation_text = UITextBox(html_text=action_long_desc, relative_rect=pygame.Rect(5, 5, text_width, text_height), manager=self.ui_manager, container=self, anchors={'left': 'left', 'right': 'right', 'top': 'top', 'bottom': 'bottom'}) self.set_blocking(blocking)
def update(self, time_delta: float): """ A method called every update cycle of our application. Designed to be overridden by derived classes but also has a little functionality to make sure the panel's layer 'thickness' is accurate and to handle window resizing. :param time_delta: time passed in seconds between one call to this method and the next. """ super().update(time_delta) if self.scroll_bar is not None and self.scroll_bar.check_has_moved_recently( ): list_height_adjustment = min( self.scroll_bar.start_percentage * self.total_height_of_list, self.lowest_list_pos) for index, item in enumerate(self.item_list): new_height = int((index * self.list_item_height) - list_height_adjustment) if (-self.list_item_height <= new_height <= self.item_list_container.relative_rect.height): if item['button_element'] is not None: item['button_element'].set_relative_position( (0, new_height)) else: button_rect = pygame.Rect( 0, new_height, self.item_list_container.relative_rect.width, self.list_item_height) button = UIButton( relative_rect=button_rect, text=item['text'], manager=self.ui_manager, parent_element=self, container=self.item_list_container, object_id=ObjectID( object_id=item['object_id'], class_id='@selection_list_item'), allow_double_clicks=self.allow_double_clicks, anchors={ 'left': 'left', 'right': 'right', 'top': 'top', 'bottom': 'top' }) self.join_focus_sets(button) item['button_element'] = button if item['selected']: item['button_element'].select() else: if item['button_element'] is not None: item['button_element'].kill() item['button_element'] = None
def __init__(self, rect: pygame.Rect, html_message: str, manager: IUIManagerInterface, *, window_title: str = 'pygame-gui.message_window_title_bar', object_id: Union[ObjectID, str] = ObjectID('#message_window', None), visible: int = 1): super().__init__(rect, manager, window_display_title=window_title, object_id=object_id, resizable=True, visible=visible) minimum_dimensions = (250, 160) if rect.width < minimum_dimensions[0] or rect.height < minimum_dimensions[1]: warn_string = ("Initial size: " + str(rect.size) + " is less than minimum dimensions: " + str(minimum_dimensions)) warnings.warn(warn_string, UserWarning) self.set_minimum_dimensions(minimum_dimensions) self.dismiss_button = None self.text_block = None button_size = (-1, 24) button_spacing = 10 button_vertical_space = (button_spacing * 2) + button_size[1] dismiss_button_rect = pygame.Rect((0, 0), button_size) dismiss_button_rect.bottomright = (-button_spacing, -button_spacing) self.dismiss_button = UIButton(relative_rect=dismiss_button_rect, text="pygame-gui.Dismiss", manager=manager, container=self, tool_tip_text="Click to get rid of this message.", object_id='#dismiss_button', anchors={"left": "right", "top": "bottom", "right": "right", "bottom": "bottom"} ) text_block_rect = pygame.Rect(0, 0, self.get_container().get_size()[0], self.get_container().get_size()[1] - button_vertical_space) self.text_block = UITextBox(html_message, text_block_rect, manager=manager, container=self, anchors={"left": "left", "top": "top", "right": "right", "bottom": "bottom"} )
def __init__(self, rect: pygame.Rect, manager: IUIManagerInterface, *, initial_colour: pygame.Color = pygame.Color(0, 0, 0, 255), window_title: str = "pygame-gui.colour_picker_title_bar", object_id: Union[ObjectID, str] = ObjectID('#colour_picker_dialog', None), visible: int = 1): super().__init__(rect, manager, window_display_title=window_title, object_id=object_id, resizable=True, visible=visible) minimum_dimensions = (390, 390) if rect.width < minimum_dimensions[ 0] or rect.height < minimum_dimensions[1]: warn_string = ("Initial size: " + str(rect.size) + " is less than minimum dimensions: " + str(minimum_dimensions)) warnings.warn(warn_string, UserWarning) self.set_minimum_dimensions(minimum_dimensions) self.current_colour = initial_colour self.cancel_button = UIButton(relative_rect=pygame.Rect( -10, -40, -1, 30), text='pygame-gui.Cancel', manager=self.ui_manager, container=self, object_id='#cancel_button', anchors={ 'left': 'right', 'right': 'right', 'top': 'bottom', 'bottom': 'bottom' }) self.ok_button = UIButton(relative_rect=pygame.Rect(-10, -40, -1, 30), text='pygame-gui.OK', manager=self.ui_manager, container=self, object_id='#ok_button', anchors={ 'left': 'right', 'right': 'right', 'top': 'bottom', 'bottom': 'bottom', 'right_target': self.cancel_button }) default_sizes = { 'element_spacing': 20, 'channel_spacing': 11, 'channel_height': 29 } current_colour_surface = pygame.surface.Surface((64, 64), flags=pygame.SRCALPHA, depth=32) current_colour_surface.fill(self.current_colour) self.current_colour_image = UIImage( pygame.Rect(default_sizes['element_spacing'], -100, 64, 64), image_surface=current_colour_surface, manager=self.ui_manager, container=self, anchors={ 'left': 'left', 'right': 'left', 'top': 'bottom', 'bottom': 'bottom' }) mini_colour_surf = pygame.surface.Surface((2, 2), flags=pygame.SRCALPHA, depth=32) mini_colour_surf.fill(pygame.Color(0, 0, 0, 255), pygame.Rect(0, 0, 1, 2)) mini_colour_surf.fill(pygame.Color(255, 255, 255, 255), pygame.Rect(1, 1, 1, 1)) hue_colour = pygame.Color(255, 255, 255, 255) hue_colour.hsva = (int(self.current_colour.hsva[0]), 100, 100, 100) mini_colour_surf.fill(hue_colour, pygame.Rect(1, 0, 1, 1)) self.sat_value_square = UIImage( pygame.Rect(default_sizes['element_spacing'], default_sizes['element_spacing'], 200, 200), image_surface=pygame.transform.smoothscale(mini_colour_surf, (200, 200)), manager=self.ui_manager, container=self) self.hue_channel = None self.sat_channel = None self.value_channel = None self.red_channel = None self.green_channel = None self.blue_channel = None self._setup_channels(default_sizes)
def start(self, should_rebuild: bool = True): """ Called each time we enter the expanded state. It creates the necessary elements, the selected option, all the other available options and the close button. """ 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.close_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=ObjectID('#selected_option', None)) self.drop_down_menu_ui.join_focus_sets(self.selected_option_button) self.active_buttons.append(self.selected_option_button) expand_button_symbol = '▼' list_object_id = '#drop_down_options_list' list_object_ids = self.drop_down_menu_ui.object_ids[:] list_object_ids.append(list_object_id) list_class_ids = self.drop_down_menu_ui.class_ids[:] list_class_ids.append(None) list_element_ids = self.drop_down_menu_ui.element_ids[:] list_element_ids.append('selection_list') final_ids = self.ui_manager.get_theme().build_all_combined_ids( list_element_ids, list_class_ids, list_object_ids) self._calculate_options_list_sizes(final_ids) if self.expand_direction is not None: if self.expand_direction == 'up': expand_button_symbol = '▲' if self.drop_down_menu_ui.expansion_height_limit is None: self.drop_down_menu_ui.expansion_height_limit = self.base_position_rect.top self.options_list_height = min( self.options_list_height, self.drop_down_menu_ui.expansion_height_limit) self.option_list_y_pos = self.base_position_rect.top - self.options_list_height elif self.expand_direction == 'down': expand_button_symbol = '▼' if self.drop_down_menu_ui.expansion_height_limit is None: height_limit = (self.drop_down_menu_ui.ui_container. relative_rect.height - self.base_position_rect.bottom) self.drop_down_menu_ui.expansion_height_limit = height_limit self.options_list_height = min( self.options_list_height, self.drop_down_menu_ui.expansion_height_limit) self.option_list_y_pos = self.base_position_rect.bottom if self.close_button_width > 0: close_button_x = (border_and_shadow + self.base_position_rect.width - self.close_button_width) self.close_button = UIButton(pygame.Rect( (close_button_x, border_and_shadow), (self.close_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') self.drop_down_menu_ui.join_focus_sets(self.close_button) self.active_buttons.append(self.close_button) list_rect = pygame.Rect(self.drop_down_menu_ui.relative_rect.left, self.option_list_y_pos, (self.drop_down_menu_ui.relative_rect.width - self.close_button_width), self.options_list_height) self.options_selection_list = UISelectionList( list_rect, starting_height=3, item_list=self.options_list, allow_double_clicks=False, manager=self.ui_manager, parent_element=self.drop_down_menu_ui, container=self.drop_down_menu_ui.ui_container, anchors=self.drop_down_menu_ui.anchors, object_id='#drop_down_options_list') self.drop_down_menu_ui.join_focus_sets(self.options_selection_list) if should_rebuild: self.rebuild()
def __init__(self, rect: pygame.Rect, manager: IUIManagerInterface, window_title: str = 'File Dialog', initial_file_path: Union[str, None] = None, object_id: Union[ObjectID, str] = ObjectID('#file_dialog', None), allow_existing_files_only: bool = False, allow_picking_directories: bool = False, visible: int = 1): super().__init__(rect, manager, window_display_title=window_title, object_id=object_id, resizable=True, visible=visible) minimum_dimensions = (260, 300) if rect.width < minimum_dimensions[ 0] or rect.height < minimum_dimensions[1]: warn_string = ("Initial size: " + str(rect.size) + " is less than minimum dimensions: " + str(minimum_dimensions)) warnings.warn(warn_string, UserWarning) self.set_minimum_dimensions(minimum_dimensions) self.allow_existing_files_only = allow_existing_files_only self.allow_picking_directories = allow_picking_directories self.delete_confirmation_dialog = None # type: Union[UIConfirmationDialog, None] self.current_file_path = None # type: Union[Path, None] if initial_file_path is not None: pathed_initial_file_path = Path(initial_file_path) if pathed_initial_file_path.exists( ) and not pathed_initial_file_path.is_file(): self.current_directory_path = str( pathed_initial_file_path.resolve()) if self.allow_picking_directories: self.current_file_path = self.current_directory_path elif pathed_initial_file_path.exists( ) and pathed_initial_file_path.is_file(): self.current_file_path = pathed_initial_file_path.resolve() self.current_directory_path = str( pathed_initial_file_path.parent.resolve()) elif pathed_initial_file_path.parent.exists(): self.current_directory_path = str( pathed_initial_file_path.parent.resolve()) self.current_file_path = ( Path(initial_file_path).parent.resolve() / Path(initial_file_path).name) else: self.current_directory_path = str(Path('.').resolve()) self.last_valid_directory_path = self.current_directory_path self.current_file_list = None # type: Union[List[str], None] self.update_current_file_list() self.ok_button = UIButton(relative_rect=pygame.Rect( -220, -40, 100, 30), text='OK', manager=self.ui_manager, container=self, object_id='#ok_button', anchors={ 'left': 'right', 'right': 'right', 'top': 'bottom', 'bottom': 'bottom' }) if not self._validate_file_path(self.current_file_path): self.ok_button.disable() self.cancel_button = UIButton(relative_rect=pygame.Rect( -110, -40, 100, 30), text='Cancel', manager=self.ui_manager, container=self, object_id='#cancel_button', anchors={ 'left': 'right', 'right': 'right', 'top': 'bottom', 'bottom': 'bottom' }) self.home_button = UIButton(relative_rect=pygame.Rect(10, 10, 20, 20), text='⌂', tool_tip_text='Home Directory', manager=self.ui_manager, container=self, object_id='#home_icon_button', anchors={ 'left': 'left', 'right': 'left', 'top': 'top', 'bottom': 'top' }) self.delete_button = UIButton(relative_rect=pygame.Rect( 32, 10, 20, 20), text='⌧', tool_tip_text='Delete', manager=self.ui_manager, container=self, object_id='#delete_icon_button', anchors={ 'left': 'left', 'right': 'left', 'top': 'top', 'bottom': 'top' }) if not self._validate_path_exists_and_of_allowed_type( self.current_file_path, allow_directories=False): self.delete_button.disable() self.parent_directory_button = UIButton( relative_rect=pygame.Rect(54, 10, 20, 20), text='↑', tool_tip_text='Parent Directory', manager=self.ui_manager, container=self, object_id='#parent_icon_button', anchors={ 'left': 'left', 'right': 'left', 'top': 'top', 'bottom': 'top' }) self.refresh_button = UIButton(relative_rect=pygame.Rect( 76, 10, 20, 20), text='⇪', tool_tip_text='Refresh Directory', manager=self.ui_manager, container=self, object_id='#refresh_icon_button', anchors={ 'left': 'left', 'right': 'left', 'top': 'top', 'bottom': 'top' }) text_line_rect = pygame.Rect(10, 40, self.get_container().get_size()[0] - 20, 25) self.file_path_text_line = UITextEntryLine( relative_rect=text_line_rect, manager=self.ui_manager, container=self, object_id='#file_path_text_line', anchors={ 'left': 'left', 'right': 'right', 'top': 'top', 'bottom': 'top' }) if self.current_file_path is not None: self.file_path_text_line.set_text(str(self.current_file_path)) self._highlight_file_name_for_editing() else: self.file_path_text_line.set_text(str(self.current_directory_path)) file_selection_rect = pygame.Rect( 10, 80, self.get_container().get_size()[0] - 20, self.get_container().get_size()[1] - 130) self.file_selection_list = UISelectionList( relative_rect=file_selection_rect, item_list=self.current_file_list, manager=self.ui_manager, container=self, object_id='#file_display_list', anchors={ 'left': 'left', 'right': 'right', 'top': 'top', 'bottom': 'bottom' })
def __init__(self, relative_rect: pygame.Rect, starting_layer_height: int, manager: IUIManagerInterface, *, element_id: str = 'panel', margins: Dict[str, int] = None, container: Union[IContainerLikeInterface, None] = None, parent_element: UIElement = None, object_id: Union[ObjectID, str, None] = None, anchors: Dict[str, str] = None, visible: int = 1): super().__init__(relative_rect, manager, container, starting_height=starting_layer_height, layer_thickness=1, anchors=anchors, visible=visible) self._create_valid_ids(container=container, parent_element=parent_element, object_id=object_id, element_id=element_id) self.background_colour = None self.border_colour = None self.background_image = None self.border_width = 1 self.shadow_width = 2 self.shape_corner_radius = 0 self.shape = 'rectangle' self.rebuild_from_changed_theme_data() if margins is None: self.container_margins = { 'left': self.shadow_width + self.border_width, 'right': self.shadow_width + self.border_width, 'top': self.shadow_width + self.border_width, 'bottom': self.shadow_width + self.border_width } else: self.container_margins = margins container_rect = pygame.Rect( self.relative_rect.left + self.container_margins['left'], self.relative_rect.top + self.container_margins['top'], self.relative_rect.width - (self.container_margins['left'] + self.container_margins['right']), self.relative_rect.height - (self.container_margins['top'] + self.container_margins['bottom'])) self.panel_container = UIContainer( container_rect, manager, starting_height=starting_layer_height, container=container, parent_element=self, object_id=ObjectID(object_id='#panel_container', class_id=None), anchors=anchors, visible=self.visible)
def __init__(self, rect: pygame.Rect, manager: IUIManagerInterface, window_title: str = 'pygame-gui.console_title_bar', object_id: Union[ObjectID, str] = ObjectID('#console_window', None), visible: int = 1, preload_bold_log_font: bool = True): super().__init__(rect, manager, window_display_title=window_title, object_id=object_id, resizable=True, visible=visible) self.default_log_prefix = '> ' self.log_prefix = self.default_log_prefix self.should_logged_commands_escape_html = True self.logged_commands_above = [] self.current_logged_command = None self.logged_commands_below = [] self.command_entry = UITextEntryLine(relative_rect=pygame.rect.Rect( (2, -32), (self.get_container().get_size()[0] - 4, 30)), manager=self.ui_manager, container=self, object_id='#command_entry', anchors={ 'left': 'left', 'right': 'right', 'top': 'bottom', 'bottom': 'bottom' }) self.log = UITextBox(html_text="", relative_rect=pygame.rect.Rect( (2, 2), (self.get_container().get_size()[0] - 4, self.get_container().get_size()[1] - 36)), manager=manager, container=self, object_id='#log', anchors={ 'left': 'left', 'right': 'right', 'top': 'top', 'bottom': 'bottom' }) if preload_bold_log_font: # Would be better to load this font during UIManager setup, but this is probably # second best place. We can't know if someone will use the console window in advance # but if they do and use the default bold output setup for it, it would be a good idea # to load the bold font at th the same time th other UI stuff is loaded. log_font_info = self.ui_theme.get_font_info( self.log.combined_element_ids) font_dict = self.ui_manager.get_theme().get_font_dictionary() bold_font_id = font_dict.create_font_id(log_font_info['size'], log_font_info['name'], bold=True, italic=False) if not font_dict.check_font_preloaded(bold_font_id): font_dict.preload_font(log_font_info['size'], log_font_info['name'], bold=True)
def __init__(self, relative_rect: pygame.Rect, manager: IUIManagerInterface, *, starting_height: int = 1, container: Union[IContainerLikeInterface, None] = None, parent_element: Union[UIElement, None] = None, object_id: Union[ObjectID, str, None] = None, anchors: Union[Dict[str, str], None] = None, visible: int = 1): super().__init__(relative_rect, manager, container, starting_height=starting_height, layer_thickness=2, anchors=anchors, visible=visible) self._create_valid_ids(container=container, parent_element=parent_element, object_id=object_id, element_id='scrolling_container') # self.parent_element = parent_element self.scroll_bar_width = 0 self.scroll_bar_height = 0 self.need_to_sort_out_scrollbars = False self.vert_scroll_bar = None # type: Union[UIVerticalScrollBar, None] self.horiz_scroll_bar = None # type: Union[UIHorizontalScrollBar, None] self.set_image(self.ui_manager.get_universal_empty_surface()) # this contains the scroll bars and the 'view' container self._root_container = UIContainer(relative_rect=relative_rect, manager=manager, starting_height=starting_height, container=container, parent_element=parent_element, object_id=ObjectID(object_id='#root_container', class_id=None), anchors=anchors, visible=self.visible) # This container is the view on to the scrollable container it's size is determined by # the size of the root container and whether there are any scroll bars or not. view_rect = pygame.Rect(0, 0, relative_rect.width, relative_rect.height) self._view_container = UIContainer(relative_rect=view_rect, manager=manager, starting_height=0, container=self._root_container, parent_element=parent_element, object_id=ObjectID(object_id='#view_container', class_id=None), anchors={'left': 'left', 'right': 'right', 'top': 'top', 'bottom': 'bottom'}) # This container is what we actually put other stuff in. # It is aligned to the top left corner but that isn't that important for a container that # can be much larger than it's view scrollable_rect = pygame.Rect(0, 0, relative_rect.width, relative_rect.height) self.scrollable_container = UIContainer(relative_rect=scrollable_rect, manager=manager, starting_height=0, container=self._view_container, parent_element=parent_element, object_id=ObjectID( object_id='#scrollable_container', class_id=None), anchors={'left': 'left', 'right': 'left', 'top': 'top', 'bottom': 'top'}) self.scrolling_height = 0 self.scrolling_width = 0 self.scrolling_bottom = 0 self.scrolling_right = 0 self._calculate_scrolling_dimensions()
def set_item_list(self, new_item_list: Union[List[str], List[Tuple[str, str]]]): """ Set a new string list (or tuple of strings & ids list) as the item list for this selection list. This will change what is displayed in the list. Tuples should be arranged like so: (list_text, object_ID) - list_text: displayed in the UI - object_ID: used for theming and events :param new_item_list: The new list to switch to. Can be a list of strings or tuples. """ self._raw_item_list = new_item_list self.item_list = [] # type: List[Dict] for new_item in new_item_list: if isinstance(new_item, str): new_item_list_item = { 'text': new_item, 'button_element': None, 'selected': False, 'object_id': '#item_list_item' } elif isinstance(new_item, tuple): new_item_list_item = { 'text': new_item[0], 'button_element': None, 'selected': False, 'object_id': new_item[1] } else: raise ValueError('Invalid item list') self.item_list.append(new_item_list_item) self.total_height_of_list = self.list_item_height * len(self.item_list) self.lowest_list_pos = ( self.total_height_of_list - self.list_and_scroll_bar_container.relative_rect.height) inner_visible_area_height = self.list_and_scroll_bar_container.relative_rect.height if self.total_height_of_list > inner_visible_area_height: # we need a scroll bar self.current_scroll_bar_width = self.scroll_bar_width percentage_visible = inner_visible_area_height / max( self.total_height_of_list, 1) if self.scroll_bar is not None: self.scroll_bar.reset_scroll_position() self.scroll_bar.set_visible_percentage(percentage_visible) self.scroll_bar.start_percentage = 0 else: self.scroll_bar = UIVerticalScrollBar( pygame.Rect(-self.scroll_bar_width, 0, self.scroll_bar_width, inner_visible_area_height), visible_percentage=percentage_visible, manager=self.ui_manager, parent_element=self, container=self.list_and_scroll_bar_container, anchors={ 'left': 'right', 'right': 'right', 'top': 'top', 'bottom': 'bottom' }) self.join_focus_sets(self.scroll_bar) else: if self.scroll_bar is not None: self.scroll_bar.kill() self.scroll_bar = None self.current_scroll_bar_width = 0 # create button list container if self.item_list_container is not None: self.item_list_container.clear() if (self.item_list_container.relative_rect.width != (self.list_and_scroll_bar_container.relative_rect.width - self.current_scroll_bar_width)): container_dimensions = ( self.list_and_scroll_bar_container.relative_rect.width - self.current_scroll_bar_width, self.list_and_scroll_bar_container.relative_rect.height) self.item_list_container.set_dimensions(container_dimensions) else: self.item_list_container = UIContainer( pygame.Rect( 0, 0, self.list_and_scroll_bar_container.relative_rect.width - self.current_scroll_bar_width, self.list_and_scroll_bar_container.relative_rect.height), manager=self.ui_manager, starting_height=0, parent_element=self, container=self.list_and_scroll_bar_container, object_id='#item_list_container', anchors={ 'left': 'left', 'right': 'right', 'top': 'top', 'bottom': 'bottom' }) self.join_focus_sets(self.item_list_container) item_y_height = 0 for item in self.item_list: if item_y_height <= self.item_list_container.relative_rect.height: button_rect = pygame.Rect( 0, item_y_height, self.item_list_container.relative_rect.width, self.list_item_height) item['button_element'] = UIButton( relative_rect=button_rect, text=item['text'], manager=self.ui_manager, parent_element=self, container=self.item_list_container, object_id=ObjectID(object_id=item['object_id'], class_id='@selection_list_item'), allow_double_clicks=self.allow_double_clicks, anchors={ 'left': 'left', 'right': 'right', 'top': 'top', 'bottom': 'top' }) self.join_focus_sets(item['button_element']) item_y_height += self.list_item_height else: break
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='#vert_scrollbar_buttons_container', visible=self.visible) self.join_focus_sets(self.button_container) else: self.button_container.set_dimensions(self.background_rect.size) self.button_container.set_relative_position( self.background_rect.topleft) if self.enable_arrow_buttons: self.arrow_button_height = self.button_height if self.top_button is None: self.top_button = UIButton(pygame.Rect( (0, 0), (self.background_rect.width, self.arrow_button_height)), '▲', self.ui_manager, container=self.button_container, starting_height=1, parent_element=self, object_id=ObjectID( "#top_button", "@arrow_button"), anchors={ 'left': 'left', 'right': 'right', 'top': 'top', 'bottom': 'top' }) self.join_focus_sets(self.top_button) if self.bottom_button is None: self.bottom_button = UIButton(pygame.Rect( (0, -self.arrow_button_height), (self.background_rect.width, self.arrow_button_height)), '▼', self.ui_manager, container=self.button_container, starting_height=1, parent_element=self, object_id=ObjectID( "#bottom_button", "@arrow_button"), anchors={ 'left': 'left', 'right': 'right', 'top': 'bottom', 'bottom': 'bottom' }) self.join_focus_sets(self.bottom_button) else: self.arrow_button_height = 0 if self.top_button is not None: self.top_button.kill() self.top_button = None if self.bottom_button is not None: self.bottom_button.kill() self.bottom_button = None self.scrollable_height = self.background_rect.height - ( 2 * self.arrow_button_height) self.bottom_limit = self.scrollable_height scroll_bar_height = max( 5, int(self.scrollable_height * self.visible_percentage)) self.scroll_position = min(max(self.scroll_position, self.top_limit), self.bottom_limit - scroll_bar_height) x_pos = 0 y_pos = (self.scroll_position + self.arrow_button_height) self.sliding_rect_position = pygame.math.Vector2(x_pos, y_pos) if self.sliding_button is not None: self.sliding_button.set_relative_position( self.sliding_rect_position) self.sliding_button.set_dimensions( (self.background_rect.width, scroll_bar_height)) self.sliding_button.set_hold_range( (100, self.background_rect.height))
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 start(self): """ Called each time we enter the expanded state. It creates the necessary elements, the selected option, all the other available options and the close button. """ self.should_transition = False self.selected_option_button = UIButton(pygame.Rect(self.base_position_rect.topleft, (self.base_position_rect.width - self.close_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=ObjectID('#selected_option', None)) self.drop_down_menu_ui.join_focus_sets(self.selected_option_button) expand_button_symbol = '▼' list_object_id = '#drop_down_options_list' list_object_ids = self.drop_down_menu_ui.object_ids[:] list_object_ids.append(list_object_id) list_class_ids = self.drop_down_menu_ui.class_ids[:] list_class_ids.append(None) list_element_ids = self.drop_down_menu_ui.element_ids[:] list_element_ids.append('selection_list') final_ids = self.ui_manager.get_theme().build_all_combined_ids(list_element_ids, list_class_ids, list_object_ids) try: list_shadow_width = int( self.ui_manager.get_theme().get_misc_data('shadow_width', final_ids)) except (LookupError, ValueError): list_shadow_width = 2 try: list_border_width = int( self.ui_manager.get_theme().get_misc_data('border_width', final_ids)) except (LookupError, ValueError): list_border_width = 1 try: list_item_height = int( self.ui_manager.get_theme().get_misc_data('list_item_height', final_ids)) except (LookupError, ValueError): list_item_height = 20 options_list_border_and_shadow = list_shadow_width + list_border_width self.options_list_height = ((list_item_height * len(self.options_list)) + (2 * options_list_border_and_shadow)) self.option_list_y_pos = 0 if self.expand_direction is not None: if self.expand_direction == 'up': expand_button_symbol = '▲' if self.drop_down_menu_ui.expansion_height_limit is None: self.drop_down_menu_ui.expansion_height_limit = self.base_position_rect.top self.options_list_height = min(self.options_list_height, self.drop_down_menu_ui.expansion_height_limit) self.option_list_y_pos = self.base_position_rect.top - self.options_list_height elif self.expand_direction == 'down': expand_button_symbol = '▼' if self.drop_down_menu_ui.expansion_height_limit is None: height_limit = (self.drop_down_menu_ui.ui_container.relative_rect.height - self.base_position_rect.bottom) self.drop_down_menu_ui.expansion_height_limit = height_limit self.options_list_height = min(self.options_list_height, self.drop_down_menu_ui.expansion_height_limit) self.option_list_y_pos = self.base_position_rect.bottom close_button_x = (self.base_position_rect.x + self.base_position_rect.width - self.close_button_width) self.close_button = UIButton(pygame.Rect((close_button_x, self.base_position_rect.y), (self.close_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') self.drop_down_menu_ui.join_focus_sets(self.close_button) list_rect = pygame.Rect(self.drop_down_menu_ui.relative_rect.left, self.option_list_y_pos, (self.drop_down_menu_ui.relative_rect.width - self.close_button_width), self.options_list_height) self.options_selection_list = UISelectionList(list_rect, starting_height=2, item_list=self.options_list, allow_double_clicks=False, manager=self.ui_manager, parent_element=self.drop_down_menu_ui, container=self.ui_container, object_id='#drop_down_options_list') self.drop_down_menu_ui.join_focus_sets(self.options_selection_list) self.rebuild()