def test_hide(self, _init_pygame, default_ui_manager, _display_surface_return_none): selection_list = UISelectionList( relative_rect=pygame.Rect(0, 0, 50, 80), item_list=[ 'item 1', 'item 2', 'item 3', 'item 4', 'item 5', 'item 6', 'item 7', 'item 8', 'item 9', 'item 10', 'item 11', 'item 12', 'item 13', 'item 14', 'item 15', 'item 16' ], manager=default_ui_manager, allow_multi_select=True) assert selection_list.visible == 1 assert selection_list.list_and_scroll_bar_container.visible == 1 assert selection_list.item_list_container.visible == 1 assert selection_list.scroll_bar.visible == 1 assert selection_list.scroll_bar.button_container.visible == 1 assert selection_list.scroll_bar.bottom_button.visible == 1 assert selection_list.scroll_bar.top_button.visible == 1 assert selection_list.scroll_bar.sliding_button.visible == 1 selection_list.hide() assert selection_list.visible == 0 assert selection_list.list_and_scroll_bar_container.visible == 0 assert selection_list.item_list_container.visible == 0 assert selection_list.scroll_bar.visible == 0 assert selection_list.scroll_bar.button_container.visible == 0 assert selection_list.scroll_bar.bottom_button.visible == 0 assert selection_list.scroll_bar.top_button.visible == 0 assert selection_list.scroll_bar.sliding_button.visible == 0
def test_kill(self, _init_pygame, default_ui_manager: IUIManagerInterface, _display_surface_return_none): selection_list = UISelectionList( relative_rect=pygame.Rect(0, 0, 50, 80), item_list=[ 'item 1', 'item 2', 'item 3', 'item 4', 'item 5', 'item 6', 'item 7', 'item 8', 'item 9', 'item 10', 'item 11', 'item 12', 'item 13', 'item 14', 'item 15', 'item 16' ], manager=default_ui_manager, allow_multi_select=True) assert len(default_ui_manager.get_root_container().elements) == 2 assert len(default_ui_manager.get_sprite_group().sprites()) == 13 selection_list_sprites = [ default_ui_manager.get_root_container(), selection_list, selection_list.list_and_scroll_bar_container, selection_list.item_list_container, selection_list.scroll_bar, selection_list.scroll_bar.button_container, *selection_list.item_list_container.elements, selection_list.scroll_bar.top_button, selection_list.scroll_bar.bottom_button, selection_list.scroll_bar.sliding_button ] assert default_ui_manager.get_sprite_group().sprites( ) == selection_list_sprites selection_list.kill() assert len(default_ui_manager.get_root_container().elements) == 0 assert len(default_ui_manager.get_sprite_group().sprites()) == 1 empty_ui_sprites = [default_ui_manager.get_root_container()] assert default_ui_manager.get_sprite_group().sprites( ) == empty_ui_sprites
def test_update(self, _init_pygame, default_ui_manager, _display_surface_return_none: None): selection_list = UISelectionList( relative_rect=pygame.Rect(50, 50, 150, 80), item_list=[ 'item 1', 'item 2', 'item 3', 'item 4', 'item 5', 'item 6', 'item 7', 'item 8', 'item 9', 'item 10', 'item 11', 'item 12', 'item 13', 'item 14', 'item 15', 'item 16' ], manager=default_ui_manager, allow_multi_select=True) assert selection_list.scroll_bar is not None visible_items = [ item['text'] for item in selection_list.item_list if item['button_element'] is not None ] assert visible_items == ['item 1', 'item 2', 'item 3', 'item 4'] # scroll the list a bit selection_list.scroll_bar.has_moved_recently = True selection_list.scroll_bar.start_percentage = 0.3 selection_list.update(time_delta=0.05) visible_items = [ item['text'] for item in selection_list.item_list if item['button_element'] is not None ] assert visible_items == [ 'item 5', 'item 6', 'item 7', 'item 8', 'item 9' ]
def test_default_selection_changes(self, _init_pygame, default_ui_manager, default_display_surface, _display_surface_return_none): """ Test that the default selection parameter does not permanently fix the list selection. """ resolution = (400, 400) manager = UIManager(resolution) lst = [f'item {i}' for i in range(0, 20)] default = 10 new_selection = 5 # Test single selection list single_list = UISelectionList(relative_rect=pygame.Rect( 100, 100, 400, 400), item_list=lst, default_selection=lst[default], manager=manager) event_data = { 'ui_element': single_list.item_list_container.elements[new_selection] } select_event = pygame.event.Event(pygame_gui.UI_BUTTON_PRESSED, event_data) single_list.process_event(select_event) assert lst[new_selection] == single_list.get_single_selection() # Test multi-selection list default = [lst[10], lst[17]] selections = [4, 10, 15] multi_list = UISelectionList(relative_rect=pygame.Rect( 100, 100, 400, 400), item_list=lst, default_selection=default, allow_multi_select=True, manager=manager) for selection in selections: event_data = { 'ui_element': multi_list.item_list_container.elements[selection] } select_event = pygame.event.Event(pygame_gui.UI_BUTTON_PRESSED, event_data) multi_list.process_event(select_event) final_vals = multi_list.get_multi_selection() assert len(final_vals) == 3 assert lst[10] not in final_vals assert lst[4] in final_vals assert lst[15] in final_vals assert lst[17] in final_vals
def test_enable(self, _init_pygame: None, default_ui_manager: UIManager, _display_surface_return_none: None): selection_list = UISelectionList( relative_rect=pygame.Rect(50, 50, 150, 400), item_list=['green', 'eggs', 'and', 'ham'], manager=default_ui_manager) assert selection_list.get_single_selection() is None selection_list.disable() selection_list.enable() assert selection_list.is_enabled is True assert selection_list.item_list_container.is_enabled is True # process a mouse button down event list_button = selection_list.item_list_container.elements[0] list_button.process_event( pygame.event.Event(pygame.MOUSEBUTTONDOWN, { 'button': 1, 'pos': list_button.rect.center })) # process a mouse button up event list_button.process_event( pygame.event.Event(pygame.MOUSEBUTTONUP, { 'button': 1, 'pos': list_button.rect.center })) for event in pygame.event.get(): default_ui_manager.process_events(event) assert selection_list.get_single_selection() == 'green'
def setup(self): super().setup() buttons, self.button_mapping = self.button_list( [('Back', (Action.PRE_GAME, (self.campaign, ))), ('Buy', (self.buy, ())), ('Sell', (self.sell, ())), ('Equip', (self.equip, ()))], (0.15, 0.8), (100, 25)) self.draw_money_display() self.buy_button = buttons[1] self.sell_button = buttons[2] self.equip_button = buttons[3] self.update_buttons() shop_items = self.level.shop_items shop_item_strings = [ f'{item.name} ({item.cost}ξ)' for item in shop_items ] self.create_text('Shop', 24, bottomleft=(0.5, 0.25)) shop_list = UISelectionList(relative_rect=self.proportional_rect( (0.5, 0.25), (0.35, 0.25)), item_list=shop_item_strings, manager=self.manager) for shop_item, list_item in zip(shop_items, shop_list.item_list): button = list_item["button_element"] self.button_mapping[button] = (self.item_selected, (shop_list, shop_item, button)) self.create_text('Owned', 24, bottomleft=(0.5, 0.6)) self.draw_owned_item_list()
def test_show_hide_rendering(self, _init_pygame, default_ui_manager, _display_surface_return_none): resolution = (400, 400) empty_surface = pygame.Surface(resolution) empty_surface.fill(pygame.Color(0, 0, 0)) surface = empty_surface.copy() manager = UIManager(resolution) selection_list = UISelectionList( relative_rect=pygame.Rect(100, 100, 400, 400), item_list=[ 'item 1', 'item 2', 'item 3', 'item 4', 'item 5', 'item 6', 'item 7', 'item 8', 'item 9', 'item 10', 'item 11', 'item 12', 'item 13', 'item 14', 'item 15', 'item 16' ], manager=manager, allow_multi_select=True, visible=0) manager.update(0.01) manager.draw_ui(surface) assert compare_surfaces(empty_surface, surface) surface.fill(pygame.Color(0, 0, 0)) selection_list.show() manager.update(0.01) manager.draw_ui(surface) assert not compare_surfaces(empty_surface, surface) surface.fill(pygame.Color(0, 0, 0)) selection_list.hide() manager.update(0.01) manager.draw_ui(surface) assert compare_surfaces(empty_surface, surface)
def test_default_selection_sets_correctly(self): """ Test that the default selection parameter ACTUALLY sets the values. """ resolution = (400, 400) manager = UIManager(resolution) lst = [f'item {i}' for i in range(20)] selection = 'item 10' # Single-selection list default. single_list = UISelectionList(relative_rect=pygame.Rect( 100, 100, 400, 400), item_list=lst, default_selection=selection, manager=manager) assert selection == single_list.get_single_selection() # Multi-selection list defaults. selection = ['item 3', 'item 10', 'item 15'] multi_list = UISelectionList(relative_rect=pygame.Rect( 100, 100, 400, 400), item_list=lst, default_selection=selection, allow_multi_select=True, manager=manager) assert selection == multi_list.get_multi_selection()
def test_rebuild_from_changed_theme_data_bad_values( self, _init_pygame, _display_surface_return_none): manager = UIManager((800, 600), os.path.join("tests", "data", "themes", "ui_selection_list_bad_values.json")) selection_list = UISelectionList( relative_rect=pygame.Rect(0, 0, 50, 80), item_list=[ 'item 1', 'item 2', 'item 3', 'item 4', 'item 5', 'item 6', 'item 7', 'item 8', 'item 9', 'item 10', 'item 11', 'item 12', 'item 13', 'item 14', 'item 15', 'item 16' ], manager=manager, allow_multi_select=True) assert selection_list.image is not None
def test_get_multi_selection(self, _init_pygame, default_ui_manager, _display_surface_return_none): selection_list = UISelectionList( relative_rect=pygame.Rect(50, 50, 150, 400), item_list=['green', 'eggs', 'and', 'ham'], manager=default_ui_manager, allow_multi_select=True) assert selection_list.get_multi_selection() == [] event_data = { 'user_type': pygame_gui.UI_BUTTON_PRESSED, 'ui_element': selection_list.item_list_container.elements[0] } press_list_item_event = pygame.event.Event(pygame.USEREVENT, event_data) default_ui_manager.process_events(press_list_item_event) assert selection_list.get_multi_selection() == ['green'] event_data = { 'user_type': pygame_gui.UI_BUTTON_PRESSED, 'ui_element': selection_list.item_list_container.elements[1] } press_list_item_event = pygame.event.Event(pygame.USEREVENT, event_data) default_ui_manager.process_events(press_list_item_event) assert selection_list.get_multi_selection() == ['green', 'eggs'] single_selection_list = UISelectionList( relative_rect=pygame.Rect(50, 50, 150, 400), item_list=['green', 'eggs', 'and', 'ham'], manager=default_ui_manager) with pytest.raises( RuntimeError, match='Requesting multi selection, from single-selection list' ): single_selection_list.get_multi_selection()
def setup(self): super().setup() # current_level = active_player().level # current_level.screen = self campaign_strings = list() campaigns = sorted(Campaign.all_instances()) for key, campaign in campaigns: num_levels = len(campaign.levels) levels_str = 'levels' if num_levels > 1 else 'level' campaign_strings.append(f'{campaign.name} ({num_levels} {levels_str})') # self.create_text('Shop', 24, bottomleft=(0.5, 0.25)) campaign_list = UISelectionList(relative_rect=self.proportional_rect((0.5, 0.25), (0.35, 0.25)), item_list=campaign_strings, manager=self.manager) buttons, self.button_mapping = self.button_list( [('Play Campaign', (self.start_campaign, ())), ('Back', (Action.MAIN_MENU, None))], (0.15, 300), (100, 25)) for (key, campaign), list_item in zip(campaigns, campaign_list.item_list): button = list_item["button_element"] self.button_mapping[button] = (self.campaign_selected, (campaign_list, campaign, button))
def draw_owned_item_list(self): if self.owned_list is not None: # Reset self.owned_list.kill() for button in self.owned_list_buttons: del self.button_mapping[button] self.owned_list_buttons.clear() owned_items = self.player.owned_weapons + self.player.owned_shields owned_item_strings = [ f'{item.name} ({item.cost}ξ)' for item in owned_items ] self.owned_list = UISelectionList(relative_rect=self.proportional_rect( (0.5, 0.6), (0.35, 0.25)), item_list=owned_item_strings, manager=self.manager) for owned_item, list_item in zip(owned_items, self.owned_list.item_list): button = list_item["button_element"] self.button_mapping[button] = (self.item_selected, (self.owned_list, owned_item, button)) self.owned_list_buttons.add(button)
def test_set_item_list(self, _init_pygame, default_ui_manager, _display_surface_return_none: None): selection_list = UISelectionList( relative_rect=pygame.Rect(50, 50, 150, 80), item_list=[ 'item 1', 'item 2', 'item 3', 'item 4', 'item 5', 'item 6', 'item 7', 'item 8', 'item 9', 'item 10', 'item 11', 'item 12', 'item 13', 'item 14', 'item 15', 'item 16' ], manager=default_ui_manager, allow_multi_select=True) assert selection_list.scroll_bar is not None visible_items = [ item['text'] for item in selection_list.item_list if item['button_element'] is not None ] assert visible_items == ['item 1', 'item 2', 'item 3', 'item 4'] selection_list.set_item_list([ 'new item 1', 'new item 2', 'new item 3', 'new item 4', 'new item 5', 'new item 6', 'new item 7', 'new item 8', 'new item 9', 'new item 10', 'new item 11', 'new item 12', 'new item 13', 'new item 14', 'new item 15' ]) assert selection_list.scroll_bar is not None visible_items = [ item['text'] for item in selection_list.item_list if item['button_element'] is not None ] assert visible_items == [ 'new item 1', 'new item 2', 'new item 3', 'new item 4' ] selection_list.set_item_list(['another item 1', 'another item 2']) assert selection_list.scroll_bar is None visible_items = [ item['text'] for item in selection_list.item_list if item['button_element'] is not None ] assert visible_items == ['another item 1', 'another item 2']
def test_get_single_selection(self, _init_pygame, default_ui_manager, _display_surface_return_none): selection_list = UISelectionList( relative_rect=pygame.Rect(50, 50, 150, 400), item_list=['green', 'eggs', 'and', 'ham'], manager=default_ui_manager) assert selection_list.get_single_selection() is None event_data = { 'ui_element': selection_list.item_list_container.elements[0] } press_list_item_event = pygame.event.Event( pygame_gui.UI_BUTTON_PRESSED, event_data) default_ui_manager.process_events(press_list_item_event) assert selection_list.get_single_selection() == 'green' selection_list.item_list[1]['selected'] = True with pytest.raises( RuntimeError, match= 'More than one item selected in single-selection, selection list' ): selection_list.get_single_selection() multi_selection_list = UISelectionList( relative_rect=pygame.Rect(50, 50, 150, 400), item_list=['green', 'eggs', 'and', 'ham'], manager=default_ui_manager, allow_multi_select=True) with pytest.raises( RuntimeError, match='Requesting single selection, from multi-selection list' ): multi_selection_list.get_single_selection()
class MapSettingsWindow(UIWindow): def on_fall_add_btn_click(self): map_settings.settings.falls.append( EnemiesFall([ EnemiesGroup([0] * len(enemy.enemies_definitions), 1.0, [0.5, 1.0]) ], 100)) self.current_selected_group = 0 self.update_settings() def on_fall_remove_btn_click(self): if len(map_settings.settings.falls) > 1: map_settings.settings.falls.remove( map_settings.settings.falls[self.current_selected_fall]) self.current_selected_fall = 0 self.current_selected_group = 0 self.update_settings() def on_fall_list_item_select(self): for i in range(0, len(self.falls_ui_list.item_list)): if self.falls_ui_list.item_list[i]['selected']: self.current_selected_fall = i self.current_selected_group = 0 self.update_groups_list() self.update_fall_panel() return def on_group_add_btn_click(self): map_settings.settings.falls[self.current_selected_fall].groups.append( EnemiesGroup([0] * len(enemy.enemies_definitions), 1.0, [0.5, 1.0])) self.update_groups_list() self.update_group_panel() self.update_enemies_panel() def on_group_remove_btn_click(self): curr_fall = map_settings.settings.falls[self.current_selected_fall] if len(curr_fall.groups) > 1: curr_fall.groups.remove( curr_fall.groups[self.current_selected_group]) self.current_selected_group = 0 self.update_groups_list() def on_fall_gold_text_changed(self, e): if len(map_settings.settings.falls) > 0: if len(e.text) > 0 and e.text.isnumeric(): map_settings.settings.falls[ self.current_selected_fall].gold_reward = int(e.text) else: map_settings.settings.falls[ self.current_selected_fall].gold_reward = 0 self.update_fall_panel() def on_start_gold_text_changed(self, e): if len(e.text) > 0 and e.text.isnumeric(): map_settings.settings.start_gold = int(e.text) else: map_settings.settings.start_gold = 0 self.update_general_panel() def on_start_mana_text_changed(self, e): if len(e.text) > 0 and e.text.isnumeric(): map_settings.settings.start_mana = int(e.text) else: map_settings.settings.start_mana = 0 self.update_general_panel() def on_group_list_item_select(self, e): for i in range(0, len(self.groups_ui_list.item_list)): if self.groups_ui_list.item_list[i]['selected']: self.current_selected_group = i self.update_group_panel() self.update_enemies_panel() return def on_group_spawn_delay_changed(self, e): if len(map_settings.settings.falls) > 0: if len(map_settings.settings.falls[ self.current_selected_fall].groups) > 0: curr_group = map_settings.settings.falls[ self.current_selected_fall].groups[ self.current_selected_group] if len(e.text) > 0 and utils.is_float(e.text): curr_group.spawn_delay = float(e.text) else: curr_group.spawn_delay = 0.0 self.update_group_panel() def on_group_spawn_interval_left_changed(self, e): if len(map_settings.settings.falls) > 0: if len(map_settings.settings.falls[ self.current_selected_fall].groups) > 0: curr_group = map_settings.settings.falls[ self.current_selected_fall].groups[ self.current_selected_group] if len(e.text) > 0 and utils.is_float(e.text): curr_group.interval[0] = float(e.text) else: curr_group.interval[0] = 0.0 self.update_group_panel() def on_group_spawn_interval_right_changed(self, e): if len(map_settings.settings.falls) > 0: if len(map_settings.settings.falls[ self.current_selected_fall].groups) > 0: curr_group = map_settings.settings.falls[ self.current_selected_fall].groups[ self.current_selected_group] if len(e.text) > 0 and utils.is_float(e.text): curr_group.interval[1] = float(e.text) else: curr_group.interval[1] = 0.0 self.update_group_panel() def on_change_enemy_count(self, e, i): if len(map_settings.settings.falls) > 0: if len(map_settings.settings.falls[ self.current_selected_fall].groups) > 0: curr_group = map_settings.settings.falls[ self.current_selected_fall].groups[ self.current_selected_group] if len(e.text) > 0 and e.text.isnumeric(): curr_group.enemies_counts[i] = int(e.text) else: curr_group.enemies_counts[i] = 0 self.update_enemies_panel() def on_max_tower_text_changed(self, e): if len(e.text) > 0 and e.text.isnumeric(): map_settings.settings.max_tower = math_utils.clamp( int(e.text), 0, len(tower.tower_definitions)) else: map_settings.settings.max_tower = len(tower.tower_definitions) self.update_general_panel() def on_max_spell_text_changed(self, e): if len(e.text) > 0 and e.text.isnumeric(): map_settings.settings.max_spell = math_utils.clamp( int(e.text), 0, len(spell.spells_definitions)) else: map_settings.settings.max_spell = len(spell.spells_definitions) self.update_general_panel() def __init__(self): windowWidth = 1340 windowHeight = 600 super().__init__(pygame.Rect( SCREEN_WIDTH * 0.5 - windowWidth * 0.5, SCREEN_HEIGHT * 0.5 - windowHeight * 0.5, windowWidth, windowHeight, ), ui_manager, window_display_title="Settings", resizable=False) UILabel(pygame.Rect(0, 0, 80, 30), "General", ui_manager, container=self) general_panel = UIPanel(pygame.Rect(10, 30, 250, 600 - 100), starting_layer_height=4, manager=ui_manager, container=self, object_id="#thicker_panel") UILabel(pygame.Rect(10, 10, 80, 30), "Start Gold", ui_manager, container=general_panel) self.start_gold_text_line = UITextEntryLine( pygame.Rect(100, 10, 60, 20), manager=ui_manager, container=general_panel, #object_id='#file_path_text_line', anchors={ 'left': 'left', 'right': 'left', 'top': 'top', 'bottom': 'bottom' }) register_ui_callback(self.start_gold_text_line, pygame_gui.UI_TEXT_ENTRY_CHANGED, lambda e: self.on_start_gold_text_changed(e)) UILabel(pygame.Rect(10, 40, 80, 30), "Start Mana", ui_manager, container=general_panel) self.start_mana_text_line = UITextEntryLine( pygame.Rect(100, 40, 60, 20), manager=ui_manager, container=general_panel, #object_id='#file_path_text_line', anchors={ 'left': 'left', 'right': 'left', 'top': 'top', 'bottom': 'bottom' }) register_ui_callback(self.start_mana_text_line, pygame_gui.UI_TEXT_ENTRY_CHANGED, lambda e: self.on_start_mana_text_changed(e)) UILabel(pygame.Rect(10, 70, 80, 30), "Max Tower", ui_manager, container=general_panel) self.max_tower_text_line = UITextEntryLine( pygame.Rect(100, 70, 60, 20), manager=ui_manager, container=general_panel, #object_id='#file_path_text_line', anchors={ 'left': 'left', 'right': 'left', 'top': 'top', 'bottom': 'bottom' }) register_ui_callback(self.max_tower_text_line, pygame_gui.UI_TEXT_ENTRY_CHANGED, lambda e: self.on_max_tower_text_changed(e)) UILabel(pygame.Rect(10, 100, 80, 30), "Max Spell", ui_manager, container=general_panel) self.max_spell_text_line = UITextEntryLine( pygame.Rect(100, 100, 60, 20), manager=ui_manager, container=general_panel, #object_id='#file_path_text_line', anchors={ 'left': 'left', 'right': 'left', 'top': 'top', 'bottom': 'bottom' }) register_ui_callback(self.max_spell_text_line, pygame_gui.UI_TEXT_ENTRY_CHANGED, lambda e: self.on_max_spell_text_changed(e)) # ---------------------------- falls UILabel(pygame.Rect(250, 0, 80, 30), "Falls", ui_manager, container=self) self.falls_list = ["Dummy", "Dummy"] self.current_selected_fall = 0 self.falls_ui_list = UISelectionList( pygame.Rect(270, 30, 250, 220), item_list=self.falls_list, manager=ui_manager, container=self, object_id="#thicker_panel", ) register_ui_callback(self.falls_ui_list, pygame_gui.UI_SELECTION_LIST_NEW_SELECTION, lambda e: self.on_fall_list_item_select()) self.fall_add_btn = UIButton(pygame.Rect(270, 250, 125, 30), "Add Fall", ui_manager, container=self) self.fall_remove_btn = UIButton(pygame.Rect(395, 250, 125, 30), "Remove Fall", ui_manager, container=self) register_ui_callback(self.fall_add_btn, pygame_gui.UI_BUTTON_PRESSED, lambda e: self.on_fall_add_btn_click()) register_ui_callback(self.fall_remove_btn, pygame_gui.UI_BUTTON_PRESSED, lambda e: self.on_fall_remove_btn_click()) UILabel(pygame.Rect(262, 290, 120, 30), "Fall Settings", ui_manager, container=self) self.fall_settings_panel = UIPanel(pygame.Rect(270, 320, 250, 210), starting_layer_height=4, object_id="#thicker_panel", manager=ui_manager, container=self) # gold reward UILabel(pygame.Rect(5, 10, 100, 30), "Gold Reward", ui_manager, container=self.fall_settings_panel) self.fall_gold_reward = UITextEntryLine( pygame.Rect(105, 10, 60, 20), manager=ui_manager, container=self.fall_settings_panel, ) register_ui_callback(self.fall_gold_reward, pygame_gui.UI_TEXT_ENTRY_CHANGED, lambda e: self.on_fall_gold_text_changed(e)) # ---------------------------- groups UILabel(pygame.Rect(515, 0, 80, 30), "Groups", ui_manager, container=self) self.groups_list = [] self.current_selected_group = 0 self.groups_ui_list = UISelectionList( pygame.Rect(530, 30, 380, 220), item_list=self.groups_list, manager=ui_manager, container=self, object_id="#thicker_panel", ) register_ui_callback(self.groups_ui_list, pygame_gui.UI_SELECTION_LIST_NEW_SELECTION, lambda e: self.on_group_list_item_select(e)) self.group_add_btn = UIButton(pygame.Rect(530, 250, 380 * 0.5, 30), "Add Group", ui_manager, container=self) self.group_remove_btn = UIButton(pygame.Rect(530 + 380 * 0.5, 250, 380 * 0.5, 30), "Remove Group", ui_manager, container=self) register_ui_callback(self.group_add_btn, pygame_gui.UI_BUTTON_PRESSED, lambda e: self.on_group_add_btn_click()) register_ui_callback(self.group_remove_btn, pygame_gui.UI_BUTTON_PRESSED, lambda e: self.on_group_remove_btn_click()) UILabel(pygame.Rect(530, 290, 120, 30), "Group Settings", ui_manager, container=self) group_settings_panel = UIPanel(pygame.Rect(530, 320, 380, 210), starting_layer_height=4, object_id="#thicker_panel", manager=ui_manager, container=self) UILabel(pygame.Rect(5, 10, 100, 30), "Spawn After", ui_manager, container=group_settings_panel) self.group_spawn_mode_dropdown = UIDropDownMenu( ["End Of Previous Group Spawn", "Previous Group Destruction"], "End Of Previous Group Spawn", pygame.Rect(105, 15, 250, 20), ui_manager, container=group_settings_panel) # spawn delay UILabel(pygame.Rect(5, 45, 100, 30), "Spawn Delay", ui_manager, container=group_settings_panel) self.spawn_delay_entry_line = UITextEntryLine( pygame.Rect(105, 45, 40, 20), manager=ui_manager, container=group_settings_panel) UILabel(pygame.Rect(150, 45, 60, 30), "seconds", ui_manager, container=group_settings_panel) register_ui_callback(self.spawn_delay_entry_line, pygame_gui.UI_TEXT_ENTRY_CHANGED, lambda e: self.on_group_spawn_delay_changed(e)) # interval UILabel(pygame.Rect(-2, 80, 100, 30), "Interval:", ui_manager, container=group_settings_panel) UILabel(pygame.Rect(2, 115, 50, 30), "From", ui_manager, container=group_settings_panel) self.interval_from_entry_line = UITextEntryLine( pygame.Rect(50, 115, 40, 20), manager=ui_manager, container=group_settings_panel) UILabel(pygame.Rect(95, 115, 20, 30), "To", ui_manager, container=group_settings_panel) self.interval_to_entry_line = UITextEntryLine( pygame.Rect(120, 115, 40, 20), manager=ui_manager, container=group_settings_panel) UILabel(pygame.Rect(165, 115, 60, 30), "seconds", ui_manager, container=group_settings_panel) register_ui_callback( self.interval_from_entry_line, pygame_gui.UI_TEXT_ENTRY_CHANGED, lambda e: self.on_group_spawn_interval_left_changed(e)) register_ui_callback( self.interval_to_entry_line, pygame_gui.UI_TEXT_ENTRY_CHANGED, lambda e: self.on_group_spawn_interval_right_changed(e)) # ---------------------------- enemies self.enemies_label = UILabel(pygame.Rect(910, 0, 80, 30), "Enemies", ui_manager, container=self) self.enemies_view_panel = UIPanel(relative_rect=pygame.Rect( 920, 30, 385, 505), starting_layer_height=4, object_id="#thicker_panel", manager=ui_manager, container=self) #self.enemies_view_panel.hide() #self.enemies_label.hide() #250, 600 - 100 self.enemy_container = UIScrollingContainer( pygame.Rect(0, 0, 380, 500), ui_manager, container=self.enemies_view_panel, object_id="#enemy_scrolling_container", starting_height=4) item_height = 165 self.enemy_container.set_scrollable_area_dimensions( (360, 5 + len(enemy.enemies_definitions) * item_height + 10)) """ for n in range(0, 24): UIButton( pygame.Rect(5, 5 + 50 * n, 370, 45), "hi", ui_manager, self.enemy_container ) """ self.enemies_counts_entry_lines = [] for n in range(0, len(enemy.enemies_definitions)): enemy_panel = UIPanel(relative_rect=pygame.Rect( 5, 5 + item_height * n, 350, item_height), starting_layer_height=4, manager=ui_manager, container=self.enemy_container, object_id="#thicker_panel") enemy_stats_panel = UIPanel(relative_rect=pygame.Rect( 10, 35, 325, 80), starting_layer_height=4, manager=ui_manager, container=enemy_panel) UITextBox( "<b>" + enemy.enemies_definitions[n].name + "</b>", pygame.Rect(5, 5, 340, 30), ui_manager, container=enemy_panel, object_id="#no_border_textbox", ) definition = enemy.enemies_definitions[n] preview_sprite_path = ENEMIES_PATH + definition.sprites_directory + "/" + definition.preview_sprite + ".png" image_size = (720 * 0.15, 480 * 0.15) UIImage(relative_rect=pygame.Rect(5, 5, image_size[0], image_size[1]), image_surface=resource_cache.get_resource( preview_sprite_path, resource_cache.SurfaceType, alpha=True), manager=ui_manager, container=enemy_stats_panel) UITextBox("<font color=#00FF00><b>Health: </b></font>" + str(definition.health) + "<br><br>" "<font color=#BB0000><b>Damage: </b></font>" + str(definition.damages) + "</br></br>" + "<font color=#4488FF><b>Speed: </b></font>" + str(definition.speed), pygame.Rect(5 + image_size[0] + 5, 5, 120, 140), ui_manager, container=enemy_stats_panel, object_id="#no_border_textbox") UITextBox("Count: ", pygame.Rect(5, item_height - 45, 80, 30), ui_manager, container=enemy_panel, object_id="#no_border_textbox") self.enemies_counts_entry_lines.append( UITextEntryLine( pygame.Rect(65, item_height - 45, 50, 25), manager=ui_manager, container=enemy_panel, )) register_ui_callback( self.enemies_counts_entry_lines[n], pygame_gui.UI_TEXT_ENTRY_CHANGED, lambda e, i=n: self.on_change_enemy_count(e, i)) self.set_blocking(True) self.update_settings() def update_falls_list(self): self.falls_list = [] for i in range(0, len(map_settings.settings.falls)): self.falls_list.append("Fall " + str(i + 1)) self.falls_ui_list.set_item_list(self.falls_list) if len(self.falls_list) > 0: # self.falls_ui_list.item_list[self.current_selected_fall]['selected'] = True curr_fall = map_settings.settings.falls[self.current_selected_fall] self.fall_gold_reward.set_text(str(curr_fall.gold_reward)) def update_groups_list(self): if len(self.falls_list) > 0: curr_fall = map_settings.settings.falls[self.current_selected_fall] # there is always at least 1 group per fall self.groups_list = [] for i in range(0, len(curr_fall.groups)): self.groups_list.append("Group " + str(i + 1)) self.groups_ui_list.set_item_list(self.groups_list) def update_group_panel(self): curr_fall = map_settings.settings.falls[self.current_selected_fall] if len(self.falls_list) > 0 and len(curr_fall.groups) > 0: curr_group = curr_fall.groups[self.current_selected_group] self.group_spawn_mode_dropdown.selected_option = curr_group.spawn_mode self.spawn_delay_entry_line.set_text(str(curr_group.spawn_delay)) self.interval_from_entry_line.set_text(str(curr_group.interval[0])) self.interval_to_entry_line.set_text(str(curr_group.interval[1])) def update_fall_panel(self): self.fall_gold_reward.set_text( str(map_settings.settings.falls[ self.current_selected_fall].gold_reward)) def update_general_panel(self): self.start_gold_text_line.set_text( str(map_settings.settings.start_gold)) self.start_mana_text_line.set_text( str(map_settings.settings.start_mana)) self.max_tower_text_line.set_text(str(map_settings.settings.max_tower)) self.max_spell_text_line.set_text(str(map_settings.settings.max_spell)) def update_enemies_panel(self): curr_group = map_settings.settings.falls[ self.current_selected_fall].groups[self.current_selected_group] for n in range(0, len(self.enemies_counts_entry_lines)): self.enemies_counts_entry_lines[n].set_text( str(curr_group.enemies_counts[n])) def update_settings(self): self.update_general_panel() self.update_falls_list() self.update_groups_list()
def test_default_selection_exceptions(self): """ Test that all exceptions throw appropriately: 1. ValueError if a list of strings/string tuples is passed to a single-selection list. 2. TypeError is a completely invalid type (like an object) is passed. 3. ValueError if ANY of the requested default values are not actually present in the item list. """ resolution = (400, 400) manager = UIManager(resolution) lst = [f'item {n}' for n in range(20)] # Test Case 1 test_case_1_throws = False try: UISelectionList(relative_rect=pygame.Rect(100, 100, 400, 400), item_list=lst, default_selection=['item 1', 'item 2'], manager=manager) except ValueError as e: assert 'Multiple default values' in str(e) test_case_1_throws = True assert test_case_1_throws is True # Test Case 2 test_case_2_throws = False try: UISelectionList(relative_rect=pygame.Rect(100, 100, 400, 400), item_list=lst, default_selection=4, manager=manager) except TypeError as e: assert 'is not a string or (str, str) tuple.' in str(e) test_case_2_throws = True assert test_case_2_throws is True # Test Case 3 for single-selection lists test_case_3_single_throws = False try: UISelectionList(relative_rect=pygame.Rect(100, 100, 400, 400), item_list=lst, default_selection='I am not in the list', manager=manager) except ValueError as e: assert 'not found in selection list' in str(e) test_case_3_single_throws = True assert test_case_3_single_throws is True # Test Case 4 for multi-select lists. test_case_3_multiple_throws = False try: UISelectionList( relative_rect=pygame.Rect(100, 100, 400, 400), item_list=lst, default_selection=['item 1', 'I am not in the list'], allow_multi_select=True, manager=manager) except ValueError as e: assert 'not found in selection list' in str(e) test_case_3_multiple_throws = True assert test_case_3_multiple_throws is True
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()
def __init__(self, path, title, confirm_callback, save): super().__init__( pygame.Rect(SCREEN_WIDTH / 2 - 440 / 2, SCREEN_HEIGHT / 2 - 500 / 2, 440, 500), ui_manager, window_display_title=title, resizable=True ) # set initial path self.path = path self.current_file_list = [] self.confirm_callback = confirm_callback self.save = save # set minimum dimensions minimum_dimensions = (300, 300) self.set_minimum_dimensions(minimum_dimensions) # file browser panel file_selection_rect = pygame.Rect( 10, 20, self.get_container().get_size()[0] - 20, self.get_container().get_size()[1] - 70 ) self.update_file_list() self.file_selection_list = UISelectionList( relative_rect=file_selection_rect, item_list=self.current_file_list, manager=ui_manager, container=self, object_id='#file_display_list', anchors= { 'left': 'left', 'right': 'right', 'top': 'top', 'bottom': 'bottom' } ) register_ui_callback( self.file_selection_list, pygame_gui.UI_SELECTION_LIST_NEW_SELECTION, lambda e: self.file_name_text_line.set_text(e.text) ) # text entry line to write file name text_line_rect = pygame.Rect(10, -40, self.get_container().get_size()[0] - 110, 25) self.file_name_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': 'bottom', 'bottom': 'bottom' } ) if not save: self.file_name_text_line.disable() # confirm button confirm_btn_rect = pygame.Rect(-90, -40, 80, 30) self.confirm_btn = UIButton( relative_rect=confirm_btn_rect, text="OK", manager=self.ui_manager, container=self, anchors= { 'left': 'right', 'right': 'right', 'top': 'bottom', 'bottom': 'bottom' } ) register_ui_callback( self.confirm_btn, pygame_gui.UI_BUTTON_PRESSED, lambda e: ( self.on_confirm_btn_click() ) ) self.set_blocking(True)
def test_creation(self, _init_pygame, default_ui_manager, _display_surface_return_none): UISelectionList(relative_rect=pygame.Rect(50, 50, 150, 400), item_list=['green', 'eggs', 'and', 'ham'], manager=default_ui_manager)
def test_process_event(self, _init_pygame, default_ui_manager, _display_surface_return_none: None): selection_list = UISelectionList( relative_rect=pygame.Rect(50, 50, 150, 80), item_list=[ 'item 1', 'item 2', 'item 3', 'item 4', 'item 5', 'item 6', 'item 7', 'item 8', 'item 9', 'item 10', 'item 11', 'item 12', 'item 13', 'item 14', 'item 15', 'item 16' ], manager=default_ui_manager, allow_multi_select=True, allow_double_clicks=True) event_data = { 'ui_element': selection_list.item_list_container.elements[0] } select_event = pygame.event.Event(pygame_gui.UI_BUTTON_PRESSED, event_data) selection_list.process_event(select_event) confirm_event_fired = False event_text = None for event in pygame.event.get(): if (event.type == pygame_gui.UI_SELECTION_LIST_NEW_SELECTION and event.ui_element == selection_list): confirm_event_fired = True event_text = event.text assert confirm_event_fired assert event_text == 'item 1' event_data = { 'ui_element': selection_list.item_list_container.elements[0] } unselect_event = pygame.event.Event(pygame_gui.UI_BUTTON_PRESSED, event_data) selection_list.process_event(unselect_event) confirm_event_fired = False event_text = None for event in pygame.event.get(): if (event.type == pygame_gui.UI_SELECTION_LIST_DROPPED_SELECTION and event.ui_element == selection_list): confirm_event_fired = True event_text = event.text assert confirm_event_fired assert event_text == 'item 1' event_data = { 'ui_element': selection_list.item_list_container.elements[0] } double_clicked_event = pygame.event.Event( pygame_gui.UI_BUTTON_DOUBLE_CLICKED, event_data) selection_list.process_event(double_clicked_event) confirm_event_fired = False event_text = None for event in pygame.event.get(): if (event.type == pygame_gui.UI_SELECTION_LIST_DOUBLE_CLICKED_SELECTION and event.ui_element == selection_list): confirm_event_fired = True event_text = event.text assert confirm_event_fired assert event_text == 'item 1' single_selection_list = UISelectionList( relative_rect=pygame.Rect(50, 50, 150, 80), item_list=[ 'item 1', 'item 2', 'item 3', 'item 4', 'item 5', 'item 6', 'item 7', 'item 8', 'item 9', 'item 10', 'item 11', 'item 12', 'item 13', 'item 14', 'item 15', 'item 16' ], manager=default_ui_manager, allow_multi_select=False, allow_double_clicks=True) event_data = { 'ui_element': single_selection_list.item_list_container.elements[0] } select_event = pygame.event.Event(pygame_gui.UI_BUTTON_PRESSED, event_data) single_selection_list.process_event(select_event) event_data = { 'ui_element': single_selection_list.item_list_container.elements[1] } select_another_event = pygame.event.Event(pygame_gui.UI_BUTTON_PRESSED, event_data) single_selection_list.process_event(select_another_event) dropped_event_text = None select_event_text = None for event in pygame.event.get(): if (event.type == pygame_gui.UI_SELECTION_LIST_NEW_SELECTION and event.ui_element == single_selection_list): select_event_text = event.text if (event.type == pygame_gui.UI_SELECTION_LIST_DROPPED_SELECTION and event.ui_element == single_selection_list): dropped_event_text = event.text assert select_event_text == 'item 2' and dropped_event_text == 'item 1'
chat_textBox = pygame_gui.elements.UITextBox(relative_rect=pygame.Rect( 10, 60, 350, 400), html_text=html, manager=manager) chat_entryText = pygame_gui.elements.UITextEntryLine(relative_rect=pygame.Rect( 10, 460, 350, 200), manager=manager) button_online = pygame_gui.elements.UIButton(relative_rect=pygame.Rect( 385, 100, 90, 30), text='Online', manager=manager) lista = UISelectionList(relative_rect=pygame.Rect(405, 200, 150, 146), item_list=agenda, manager=manager) screen.fill(grey) clock = pygame.time.Clock() manager.draw_ui(screen) pygame.display.flip() chat_context = None running = True while running: time_delta = clock.tick(60) / 1000.0 screen.blit(text, textRect)
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 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='#selected_option') expand_button_symbol = '▼' options_list_object_id = '#drop_down_options_list' options_list_object_ids = self.drop_down_menu_ui.object_ids[:] options_list_object_ids.append(options_list_object_id) options_list_element_ids = self.drop_down_menu_ui.element_ids[:] options_list_element_ids.append('selection_list') list_shadow_width_str = self.ui_manager.get_theme().get_misc_data( options_list_object_ids, options_list_element_ids, 'shadow_width') list_border_width_str = self.ui_manager.get_theme().get_misc_data( options_list_object_ids, options_list_element_ids, 'border_width') if list_shadow_width_str is not None: try: options_list_shadow_width = int(list_shadow_width_str) except ValueError: options_list_shadow_width = 2 else: options_list_shadow_width = 2 if list_border_width_str is not None: try: options_list_border_width = int(list_border_width_str) except ValueError: options_list_border_width = 1 else: options_list_border_width = 1 options_list_border_and_shadow = options_list_shadow_width + options_list_border_width self.options_list_height = ((20 * 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') 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, 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.rebuild()
def test_set_position(self, _init_pygame, default_ui_manager, _display_surface_return_none): test_container = UIContainer(relative_rect=pygame.Rect( 10, 10, 300, 300), manager=default_ui_manager) selection_list = UISelectionList( relative_rect=pygame.Rect(0, 0, 50, 50), item_list=[ 'item 1', 'item 2', 'item 3', 'item 4', 'item 5', 'item 6', 'item 7', 'item 8', 'item 9', 'item 10', 'item 11', 'item 12', 'item 13', 'item 14', 'item 15', 'item 16' ], manager=default_ui_manager, container=test_container, allow_multi_select=True, anchors={ 'left': 'left', 'right': 'left', 'top': 'top', 'bottom': 'top' }) selection_list.set_position((20, 20)) assert selection_list.relative_rect.topleft == (10, 10) assert selection_list.relative_rect.size == (50, 50) assert selection_list.relative_rect.bottomright == (60, 60) selection_list = UISelectionList( relative_rect=pygame.Rect(0, 0, 50, 50), item_list=[ 'item 1', 'item 2', 'item 3', 'item 4', 'item 5', 'item 6', 'item 7', 'item 8', 'item 9', 'item 10', 'item 11', 'item 12', 'item 13', 'item 14', 'item 15', 'item 16' ], manager=default_ui_manager, container=test_container, allow_multi_select=True, anchors={ 'left': 'right', 'right': 'right', 'top': 'top', 'bottom': 'top' }) selection_list.set_position((280, 120)) assert selection_list.relative_rect.topleft == (-30, 110) assert selection_list.relative_rect.size == (50, 50) assert selection_list.relative_rect.bottomright == (20, 160) selection_list = UISelectionList( relative_rect=pygame.Rect(0, 0, 50, 50), item_list=[ 'item 1', 'item 2', 'item 3', 'item 4', 'item 5', 'item 6', 'item 7', 'item 8', 'item 9', 'item 10', 'item 11', 'item 12', 'item 13', 'item 14', 'item 15', 'item 16' ], manager=default_ui_manager, container=test_container, allow_multi_select=True, anchors={ 'left': 'right', 'right': 'right', 'top': 'bottom', 'bottom': 'bottom' }) selection_list.set_position((230, 230)) assert selection_list.relative_rect.topleft == (-80, -80) assert selection_list.relative_rect.size == (50, 50) assert selection_list.relative_rect.bottomright == (-30, -30) selection_list = UISelectionList( relative_rect=pygame.Rect(0, 0, 50, 50), item_list=[ 'item 1', 'item 2', 'item 3', 'item 4', 'item 5', 'item 6', 'item 7', 'item 8', 'item 9', 'item 10', 'item 11', 'item 12', 'item 13', 'item 14', 'item 15', 'item 16' ], manager=default_ui_manager, container=test_container, allow_multi_select=True, anchors={ 'left': 'left', 'right': 'left', 'top': 'bottom', 'bottom': 'bottom' }) selection_list.set_position((130, 230)) assert selection_list.relative_rect.topleft == (120, -80) assert selection_list.relative_rect.size == (50, 50) assert selection_list.relative_rect.bottomright == (170, -30) selection_list = UISelectionList( relative_rect=pygame.Rect(0, 0, 50, 50), item_list=[ 'item 1', 'item 2', 'item 3', 'item 4', 'item 5', 'item 6', 'item 7', 'item 8', 'item 9', 'item 10', 'item 11', 'item 12', 'item 13', 'item 14', 'item 15', 'item 16' ], manager=default_ui_manager, container=test_container, allow_multi_select=True, anchors={ 'left': 'left', 'right': 'right', 'top': 'top', 'bottom': 'bottom' }) assert selection_list.relative_right_margin == 250 assert selection_list.relative_bottom_margin == 250 selection_list.set_position((20, 20)) assert selection_list.relative_rect.topleft == (10, 10) assert selection_list.relative_rect.size == (50, 50) assert selection_list.relative_rect.bottomright == (60, 60) assert selection_list.relative_right_margin == 240 assert selection_list.relative_bottom_margin == 240
class UIExpandedDropDownState: """ The expanded state of the drop down displays the currently chosen option, all the available options and a button to close the menu and return to the closed state. Picking an option will also close the menu. :param drop_down_menu_ui: The UIDropDownElement this state belongs to. :param options_list: The list of options in this drop down. :param selected_option: The currently selected option. :param base_position_rect: Position and dimensions rectangle. :param close_button_width: Width of close button. :param expand_direction: Direction of expansion, 'up' or 'down'. :param manager: The UI Manager for the whole UI. :param container: The container the element is within. :param object_ids: The object IDs for the drop down UI element. :param element_ids: The element IDs for the drop down UI element. """ def __init__(self, drop_down_menu_ui: 'UIDropDownMenu', options_list: List[str], selected_option: str, base_position_rect: Union[pygame.Rect, None], close_button_width: int, expand_direction: Union[str, None], manager: IUIManagerInterface, container: IContainerLikeInterface, object_ids: Union[List[Union[str, None]], None], element_ids: Union[List[str], None]): self.drop_down_menu_ui = drop_down_menu_ui self.options_list = options_list self.selected_option = selected_option self.base_position_rect = base_position_rect self.expand_direction = expand_direction self.ui_manager = manager self.ui_container = container self.element_ids = element_ids self.object_ids = object_ids # sizing variables self.options_list_height = 0 self.option_list_y_pos = 0 self.close_button_width = close_button_width # UI elements self.selected_option_button = None self.close_button = None self.options_selection_list = None # state transitioning self.should_transition = False self.target_state = 'closed' self.active_buttons = [] def rebuild(self): """ Rebuild the state from theming parameters and dimensions. """ theming_parameters = { 'normal_bg': self.drop_down_menu_ui.background_colour, 'normal_border': self.drop_down_menu_ui.border_colour, 'border_width': self.drop_down_menu_ui.border_width, 'shadow_width': self.drop_down_menu_ui.shadow_width, 'shape_corner_radius': self.drop_down_menu_ui.shape_corner_radius } shape_rect = self.drop_down_menu_ui.relative_rect if self.drop_down_menu_ui.shape == 'rectangle': self.drop_down_menu_ui.drawable_shape = RectDrawableShape( shape_rect, theming_parameters, ['normal'], self.ui_manager) elif self.drop_down_menu_ui.shape == 'rounded_rectangle': self.drop_down_menu_ui.drawable_shape = RoundedRectangleShape( shape_rect, theming_parameters, ['normal'], self.ui_manager) self.on_fresh_drawable_shape_ready() # extra if self.close_button is not None: expand_button_symbol = '▼' if self.expand_direction is not None: if self.expand_direction == 'up': expand_button_symbol = '▲' elif self.expand_direction == 'down': expand_button_symbol = '▼' self.close_button.set_text(expand_button_symbol) 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 _calculate_options_list_sizes(self, final_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 def finish(self): """ cleans everything up upon exiting the expanded menu state. """ self.options_selection_list.kill() self.selected_option_button.kill() if self.close_button is not None: self.close_button.kill() def process_event(self, event: pygame.event.Event) -> bool: """ Processes events for the closed state of the drop down. :param event: The event to process. :return: Return True if we want to consume this event so it is not passed on to the rest of the UI. """ if event.type == UI_BUTTON_PRESSED and event.ui_element in self.active_buttons: self.should_transition = True if (event.type == UI_SELECTION_LIST_NEW_SELECTION and event.ui_element == self.options_selection_list): selection = self.options_selection_list.get_single_selection() self.drop_down_menu_ui.selected_option = selection self.should_transition = True # old event - to be removed in 0.8.0 event_data = { 'user_type': OldType(UI_DROP_DOWN_MENU_CHANGED), 'text': self.drop_down_menu_ui.selected_option, 'ui_element': self.drop_down_menu_ui, 'ui_object_id': self.drop_down_menu_ui.most_specific_combined_id } pygame.event.post(pygame.event.Event(pygame.USEREVENT, event_data)) # new event event_data = { 'text': self.drop_down_menu_ui.selected_option, 'ui_element': self.drop_down_menu_ui, 'ui_object_id': self.drop_down_menu_ui.most_specific_combined_id } pygame.event.post( pygame.event.Event(UI_DROP_DOWN_MENU_CHANGED, event_data)) return False # don't consume any events def update_position(self): """ Update the position of all the button elements in the open drop down state. Used when the position of the drop down has been altered directly, rather than when it has been moved as a consequence of it's container being moved. """ # update the base position rect border_and_shadow = (self.drop_down_menu_ui.shadow_width + self.drop_down_menu_ui.border_width) self.base_position_rect.x = self.drop_down_menu_ui.relative_rect.x + border_and_shadow self.base_position_rect.y = self.drop_down_menu_ui.relative_rect.y + border_and_shadow # update all the ui elements that depend on the base position self.selected_option_button.set_relative_position( (border_and_shadow, border_and_shadow)) list_post = (self.drop_down_menu_ui.relative_rect.left, self.option_list_y_pos) self.options_selection_list.set_relative_position(list_post) if self.close_button is not None: close_button_x = (border_and_shadow + self.base_position_rect.width - self.close_button_width) self.close_button.set_relative_position( [close_button_x, border_and_shadow]) def update_dimensions(self): """ Update the dimensions of all the button elements in the closed drop down state. Used when the dimensions of the drop down have been altered. """ # update the base position rect border_and_shadow = (self.drop_down_menu_ui.shadow_width + self.drop_down_menu_ui.border_width) self.base_position_rect.width = ( self.drop_down_menu_ui.relative_rect.width - (2 * border_and_shadow)) self.base_position_rect.height = ( self.drop_down_menu_ui.relative_rect.height - (2 * border_and_shadow)) if self.expand_direction is not None: if self.expand_direction == 'up': 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': 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 # update all the ui elements that depend on the base position rect self.selected_option_button.set_dimensions( (self.base_position_rect.width - self.close_button_width, self.base_position_rect.height)) self.options_selection_list.set_dimensions( ((self.drop_down_menu_ui.relative_rect.width - self.close_button_width), self.options_list_height)) list_pos = (self.drop_down_menu_ui.relative_rect.left, self.option_list_y_pos) self.options_selection_list.set_relative_position(list_pos) if self.close_button is not None: close_button_x = (border_and_shadow + self.base_position_rect.width - self.close_button_width) self.close_button.set_dimensions( (self.close_button_width, self.base_position_rect.height)) self.close_button.set_relative_position( (close_button_x, border_and_shadow)) def on_fresh_drawable_shape_ready(self): """ Called by an element's drawable shape when it has a new image surface ready for use, normally after a rebuilding/redrawing of some kind. In this case the result is to set the UI element's image to the new surface. """ self.drop_down_menu_ui.set_image( self.drop_down_menu_ui.drawable_shape.get_fresh_surface()) def hide(self): """ Transition from expanded state to closed state. """ self.should_transition = True
def test_set_dimensions(self, _init_pygame, default_ui_manager, _display_surface_return_none): test_container = UIContainer(relative_rect=pygame.Rect( 10, 10, 300, 300), manager=default_ui_manager) selection_list = UISelectionList( relative_rect=pygame.Rect(30, 30, 50, 50), item_list=[ 'item 1', 'item 2', 'item 3', 'item 4', 'item 5', 'item 6', 'item 7', 'item 8', 'item 9', 'item 10', 'item 11', 'item 12', 'item 13', 'item 14', 'item 15', 'item 16' ], manager=default_ui_manager, container=test_container, allow_multi_select=True, anchors={ 'left': 'left', 'right': 'left', 'top': 'top', 'bottom': 'top' }) assert selection_list.relative_right_margin is None assert selection_list.relative_bottom_margin is None selection_list.set_dimensions((20, 20)) assert selection_list.relative_rect.topleft == (30, 30) assert selection_list.relative_rect.size == (20, 20) assert selection_list.relative_rect.bottomright == (50, 50) assert selection_list.rect.topleft == (40, 40) assert selection_list.rect.size == (20, 20) assert selection_list.rect.bottomright == (60, 60) assert selection_list.relative_right_margin is None assert selection_list.relative_bottom_margin is None selection_list = UISelectionList( relative_rect=pygame.Rect(-60, 10, 50, 50), item_list=[ 'item 1', 'item 2', 'item 3', 'item 4', 'item 5', 'item 6', 'item 7', 'item 8', 'item 9', 'item 10', 'item 11', 'item 12', 'item 13', 'item 14', 'item 15', 'item 16' ], manager=default_ui_manager, container=test_container, allow_multi_select=True, anchors={ 'left': 'right', 'right': 'right', 'top': 'top', 'bottom': 'top' }) assert selection_list.relative_right_margin == 10 assert selection_list.relative_bottom_margin is None selection_list.set_dimensions((60, 60)) assert selection_list.relative_rect.topleft == (-60, 10) assert selection_list.relative_rect.size == (60, 60) assert selection_list.relative_rect.bottomright == (0, 70) assert selection_list.rect.topleft == (250, 20) assert selection_list.rect.size == (60, 60) assert selection_list.rect.bottomright == (310, 80) assert selection_list.relative_right_margin == 0 assert selection_list.relative_bottom_margin is None selection_list = UISelectionList( relative_rect=pygame.Rect(-70, -70, 50, 50), item_list=[ 'item 1', 'item 2', 'item 3', 'item 4', 'item 5', 'item 6', 'item 7', 'item 8', 'item 9', 'item 10', 'item 11', 'item 12', 'item 13', 'item 14', 'item 15', 'item 16' ], manager=default_ui_manager, container=test_container, allow_multi_select=True, anchors={ 'left': 'right', 'right': 'right', 'top': 'bottom', 'bottom': 'bottom' }) assert selection_list.relative_right_margin == 20 assert selection_list.relative_bottom_margin == 20 selection_list.set_dimensions((30, 30)) assert selection_list.relative_rect.topleft == (-70, -70) assert selection_list.relative_rect.size == (30, 30) assert selection_list.relative_rect.bottomright == (-40, -40) assert selection_list.rect.topleft == (240, 240) assert selection_list.rect.size == (30, 30) assert selection_list.rect.bottomright == (270, 270) assert selection_list.relative_right_margin == 40 assert selection_list.relative_bottom_margin == 40 selection_list = UISelectionList( relative_rect=pygame.Rect(50, -50, 50, 50), item_list=[ 'item 1', 'item 2', 'item 3', 'item 4', 'item 5', 'item 6', 'item 7', 'item 8', 'item 9', 'item 10', 'item 11', 'item 12', 'item 13', 'item 14', 'item 15', 'item 16' ], manager=default_ui_manager, container=test_container, allow_multi_select=True, anchors={ 'left': 'left', 'right': 'left', 'top': 'bottom', 'bottom': 'bottom' }) assert selection_list.relative_right_margin is None assert selection_list.relative_bottom_margin == 0 selection_list.set_dimensions((100, 100)) assert selection_list.relative_rect.topleft == (50, -50) assert selection_list.relative_rect.size == (100, 100) assert selection_list.relative_rect.bottomright == (150, 50) assert selection_list.rect.topleft == (60, 260) assert selection_list.rect.size == (100, 100) assert selection_list.rect.bottomright == (160, 360) assert selection_list.relative_right_margin is None assert selection_list.relative_bottom_margin == -50 selection_list = UISelectionList( relative_rect=pygame.Rect(10, 10, 50, 50), item_list=[ 'item 1', 'item 2', 'item 3', 'item 4', 'item 5', 'item 6', 'item 7', 'item 8', 'item 9', 'item 10', 'item 11', 'item 12', 'item 13', 'item 14', 'item 15', 'item 16' ], manager=default_ui_manager, container=test_container, allow_multi_select=True, anchors={ 'left': 'left', 'right': 'right', 'top': 'top', 'bottom': 'bottom' }) assert selection_list.relative_right_margin == 240 assert selection_list.relative_bottom_margin == 240 selection_list.set_dimensions((90, 90)) assert selection_list.relative_rect.topleft == (10, 10) assert selection_list.relative_rect.size == (90, 90) assert selection_list.relative_rect.bottomright == (100, 100) assert selection_list.rect.topleft == (20, 20) assert selection_list.rect.size == (90, 90) assert selection_list.rect.bottomright == (110, 110) assert selection_list.relative_right_margin == 200 assert selection_list.relative_bottom_margin == 200