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)
Esempio n. 5
0
    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()
Esempio n. 6
0
    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'
            })
Esempio n. 7
0
    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)
Esempio n. 14
0
    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()