class MessageLog(UIWindow): def __init__(self, rect, manager): self.text = Message("Welcome to Vibe!").html_text + "<br>" self.rect = rect self.text_box = None self.manager = manager super().__init__(self.rect, manager, ["message_log"]) self.text_box = UITextBox(self.text, self.rect, self.manager, wrap_to_height=False, layer_starting_height=1) def add_message(self, message): self.text += message.html_text + "<br>" if self.text_box: self.text_box.kill() self.text_box = UITextBox(self.text, pygame.Rect((0, 0), (self.rect.width, self.rect.height)), self.manager, wrap_to_height=False, layer_starting_height=1, container=self.get_container()) self.text_box.parse_html_into_style_data() """ got this from Snayff, not quite sure how it works sauce: https://bitbucket.org/Snayff/notquiteparadise/src/develop/scripts/engine/ui/elements/message_log.py """ if self.text_box.scroll_bar: scroll_bar = self.text_box.scroll_bar scroll_bar.scroll_wheel_down = False scroll_bar.scroll_position += (250 * 1) scroll_bar.scroll_position = min(scroll_bar.scroll_position, scroll_bar.bottom_limit - scroll_bar.sliding_button.rect.height) x_pos = scroll_bar.rect.x + scroll_bar.shadow_width + scroll_bar.border_width y_pos = scroll_bar.scroll_position + scroll_bar.rect.y + scroll_bar.shadow_width + \ scroll_bar.border_width + scroll_bar.button_height scroll_bar.sliding_button.set_position(pygame.math.Vector2(x_pos, y_pos)) scroll_bar.start_percentage = scroll_bar.scroll_position / scroll_bar.scrollable_height if not scroll_bar.has_moved_recently: scroll_bar.has_moved_recently = True def kill(self): self.text_box.kill()
class Chat(UIContainer): # region Docstring """ Class to display the game chat """ # endregion def __init__( self, size: tuple[int, int], manager: IUIManagerInterface, udp: UDP_P2P, username: str, ) -> None: # region Docstring """ Creates a `Chat` object ### Arguments `size {(int, int)}`: `summary`: the size of the chat window `manager {UIManager}`: `summary`: the UIManager that manages this element. `udp {UDP_P2P}`: `summary`: the udp object `username {str}`: `summary`: the username of this host """ # endregion super().__init__(relative_rect=Rect((Game.SIZE[0], 0), size), manager=manager) # region Element creation self.textbox = UITextBox( html_text="", relative_rect=Rect((0, 0), (size[0], size[1] - 25)), manager=manager, container=self, ) self.entryline = UITextEntryLine( relative_rect=Rect((0, size[1] - 28), (size[0] - 50, 20)), manager=manager, container=self, ) self.entryline.set_text_length_limit(100) self.enterbtn = UIButton( text="Enter", relative_rect=Rect((size[0] - 50, size[1] - 28), (50, 30)), manager=manager, container=self, ) # endregion self.record = "" self.size = size self.udp = udp self.username = username def process_event(self, event: Event) -> Union[bool, None]: # region Docstring """ Overridden method to handle the gui events ### Arguments `event {Event}`: `summary`: the fired event ### Returns `bool | None`: return if the event has been handled """ # endregion handled = super().process_event(event) if event.type != USEREVENT: return if (event.user_type == UI_TEXT_ENTRY_FINISHED and event.ui_element == self.entryline) or (event.user_type == UI_BUTTON_PRESSED and event.ui_element == self.enterbtn): self.__send() handled = True return handled def __send(self) -> None: # region Docstring """ Handles the press of the enter `UIButton`, sending the user message.\n """ # endregion if len(self.entryline.get_text().strip()) > 0: self.udp.transmission("CHA", "01", self.username, self.entryline.get_text().strip()) self.__addmsg( f"<b>(YOU): </b><br>{self.entryline.get_text().strip()}<br>") self.entryline.set_text("") def receive(self, data: Packet, addr: Tuple[str, int], time: datetime) -> None: # region Docstring """ Method that handles the received data, address and time of reception ### Arguments `data {Packet}`: `summary`: the data received `addr {Tuple[str, int]}`: `summary`: the source address and port example: (192.168.0.1, 6000) `time {datetime}`: `summary`: the time of the packet reception """ # endregion n = UDP_P2P.latency( datetime.strptime(time.strftime("%H%M%S%f"), "%H%M%S%f"), datetime.strptime(data.time + "000", "%H%M%S%f"), ) self.record += f"<b>({data.nick.strip()} - {addr[0]} - {n}ms): </b><br>{data.msg.strip()}<br>" def update(self, time_delta: float) -> None: # region Docstring """ Overridden method to update the element ### Arguments `time_delta {float}`: `summary`: the time passed between frames, measured in seconds. """ # endregion super().update(time_delta) if self.record != self.textbox.html_text: self.textbox.kill() self.textbox = UITextBox( html_text=self.record, relative_rect=Rect((0, 0), (self.size[0], self.size[1] - 25)), container=self, manager=self.ui_manager, ) def __addmsg(self, msg: str) -> None: # region Docstring """ Method to insert text in the `UITextBox` element ### Arguments `msg {str}`: `summary`: the text to insert """ # endregion self.record += msg self.textbox.kill() self.textbox = UITextBox( html_text=self.record, relative_rect=Rect((0, 0), (self.size[0], self.size[1] - 25)), container=self, manager=self.ui_manager, )
class GUIopediaWindow(pygame_gui.elements.UIWindow): def __init__(self, manager): super().__init__(pygame.Rect((200, 50), (420, 520)), manager, window_display_title='GUIopedia!', object_id="#guiopedia_window") search_bar_top_margin = 2 search_bar_bottom_margin = 2 self.search_box = pygame_gui.elements.UITextEntryLine(pygame.Rect((150, search_bar_top_margin), (240, 20)), manager=manager, container=self, parent_element=self) self.search_label = pygame_gui.elements.UILabel(pygame.Rect((90, search_bar_top_margin), (56, self.search_box.rect.height)), "Search:", manager=manager, container=self, parent_element=self) self.home_button = pygame_gui.elements.UIButton(pygame.Rect((20, search_bar_top_margin), (29, 29)), '', manager=manager, container=self, parent_element=self, object_id='#home_button') self.remaining_window_size = (self.get_container().get_size()[0], (self.get_container().get_size()[1] - (self.search_box.rect.height + search_bar_top_margin + search_bar_bottom_margin))) self.pages = {} page_path = 'data/guiopedia/' file_paths = [join(page_path, f) for f in listdir(page_path) if isfile(join(page_path, f))] for file_path in file_paths: with open(file_path, 'r') as page_file: file_id = splitext(basename(file_path))[0] file_data = "" for line in page_file: line = line.rstrip(linesep).lstrip() # kind of hacky way to add back spaces at the end of new lines that # are removed by the pyCharm HTML # editor. perhaps our HTML parser needs to handle this case # (turning new lines into spaces # but removing spaces at the start of rendered lines?) if len(line) > 0: if line[-1] != '>': line += ' ' file_data += line self.pages[file_id] = file_data index_page = self.pages['index'] self.page_y_start_pos = (self.search_box.rect.height + search_bar_top_margin + search_bar_bottom_margin) self.page_display = UITextBox(index_page, pygame.Rect((0, self.page_y_start_pos), self.remaining_window_size), manager=manager, container=self, parent_element=self) def process_event(self, event): handled = super().process_event(event) if event.type != pygame.USEREVENT: return if event.user_type == pygame_gui.UI_TEXT_BOX_LINK_CLICKED: self.open_new_page(event.link_target) handled = True if (event.user_type == pygame_gui.UI_TEXT_ENTRY_FINISHED and event.ui_element == self.search_box): results = self.search_pages(event.text) self.create_search_results_page(results) self.open_new_page('results') handled = True if (event.user_type == pygame_gui.UI_BUTTON_PRESSED and event.ui_object_id == '#guiopedia_window.#home_button'): self.open_new_page('index') handled = True return handled def search_pages(self, search_string: str): results = {} words = search_string.split() for page in self.pages.keys(): total_occurances_of_search_words = 0 for word in words: word_occurances = self.search_text_for_occurrences_of_word(word, self.pages[page]) total_occurances_of_search_words += word_occurances if total_occurances_of_search_words > 0: results[page] = total_occurances_of_search_words sorted_results = sorted(results.items(), key=lambda item: item[1], reverse=True) return OrderedDict(sorted_results) @staticmethod def search_text_for_occurrences_of_word(word_to_search_for: str, text_to_search: str) -> int: return sum(1 for _ in re.finditer(r'\b%s\b' % re.escape(word_to_search_for), text_to_search, flags=re.IGNORECASE)) def open_new_page(self, page_link: str): self.page_display.kill() self.page_display = None if page_link in self.pages: text = self.pages[page_link] self.page_display = UITextBox(text, pygame.Rect((0, self.page_y_start_pos), self.remaining_window_size), manager=self.ui_manager, container=self, parent_element=self) def create_search_results_page(self, results): results_text = '<font size=5>Search results</font>' if len(results) == 0: results_text += '<br><br> No Results Found.' else: results_text += '<br><br>' + str(len(results)) + ' results found:' for result in results.keys(): results_text += '<br><br> - <a href=\"' + result + '\">' + result + '</a>' self.pages['results'] = results_text
class Game: def __init__(self): # Start up Pygame. pygame.init() # Title the window our game runs in. pygame.display.set_caption(config.game_name) self.options = Options() # Define the dimensions of our game's window. self.window_surface = pygame.display.set_mode(self.options.resolution) self.window_surface.blit(pygame.image.load("media/images/background.png"), (0, 0)) self.start_up = True self.enter_mines = False self.enter_busstop = False self.enter_uptown = False self.background_surface = None self.ui_manager = UIManager(self.options.resolution, PackageResource(package='media.themes', resource='theme.json')) self.text_block = None self.text_entry = None self.message_window = None self.recreate_ui() self.clock = pygame.time.Clock() self.time_delta_stack = deque([]) self.running = True def recreate_ui(self): self.ui_manager.set_window_resolution(self.options.resolution) self.ui_manager.clear_and_reset() self.background_surface = pygame.Surface(self.options.resolution) if self.start_up == True: self.image = UIImage(pygame.Rect((0, 0), self.options.resolution), title_screen_image, self.ui_manager) elif self.enter_mines == True: self.image = UIImage(pygame.Rect((0, 0), self.options.resolution), mines_image, self.ui_manager) elif self.enter_busstop == True: self.image = UIImage(pygame.Rect((0, 0), self.options.resolution), busstop_image, self.ui_manager) elif self.enter_uptown == True: self.image = UIImage(pygame.Rect((0, 0), self.options.resolution), uptown_image, self.ui_manager) else: self.background_surface.fill(self.ui_manager.get_theme().get_colour('dark_bg')) self.background_surface.blit(pygame.image.load("media/images/background.png"), (0, 0)) global response_history response = response_history response_history = response self.text_entry = UITextEntryLine(pygame.Rect((50, 550), (700, 50)), self.ui_manager, object_id = "#text_entry") self.text_block = UITextBox(response, pygame.Rect((50, 25), (700, 500)), self.ui_manager, object_id = "#text_block") def process_events(self): for event in pygame.event.get(): if event.type == pygame.QUIT: self.running = False self.ui_manager.process_events(event) if event.type==pygame.KEYDOWN: if event.key== pygame.K_UP: if self.start_up == True: self.start_up = False self.recreate_ui() if self.enter_mines == True: self.enter_mines = False self.recreate_ui() if self.enter_busstop == True: self.enter_busstop = False self.recreate_ui() if self.enter_uptown == True: self.enter_uptown = False self.recreate_ui() if event.type == pygame.USEREVENT: if (event.user_type == pygame_gui.UI_TEXT_ENTRY_FINISHED and event.ui_object_id == '#text_entry'): if event.text != "": # Turn the user's input into a string. message = event.text # Begin the response message. Start with repeating the user's input. response = "<b><i>> {message}</i></b>".format(message = message) # Create a player object using the player's save data. player_data = player.Player() # Check to see if the player is in a scripted sequence. if player_data.scene is not None: # If they are... if player_data.scene == config.scene_id_newgame: # If the player has started the game for the first time. command_response = scenes.Introduction(message) response += ("<br>" * 4) + command_response else: # If they aren't... command_response = utilities.parse_message(message) response += ("<br>" * 4) + command_response # End the response with some decoration. ^_^ response += ("<br>" * 4) + ("-" * 20) + ("<br>" * 4) # Add this response to our response history, and then send the entire history to be rendered. global response_history response += response_history response_history = response # Render the response. self.text_entry.set_text("") self.text_block.kill() self.text_block = UITextBox(response, pygame.Rect((50, 25), (700, 500)), self.ui_manager, object_id = "#text_block") if command_response == "You enter the Mines.": self.enter_mines = True self.recreate_ui() if command_response == "You enter a Bus Stop.": self.enter_busstop = True self.recreate_ui() if command_response == "You enter Uptown.": self.enter_uptown = True self.recreate_ui() def run(self): while self.running: time_delta = self.clock.tick() / 1000 # Check for inputs from the player. self.process_events() # Respond to inputs. self.ui_manager.update(time_delta) # Draw the graphics. self.window_surface.blit(self.background_surface, (0, 0)) self.ui_manager.draw_ui(self.window_surface) pygame.display.update()