def onClickMapEditor(filename): from ev3sim.visual.manager import ScreenObjectManager ScreenObjectManager.instance.pushScreen( ScreenObjectManager.SCREEN_RESCUE_EDIT, batch_file=find_abs(f"{filename}.sim", batch_locations()), )
def clickSimBots(self, preset): abs_path = find_abs(preset, allowed_areas=preset_locations()) with open(abs_path, "r") as f: preset_config = yaml.safe_load(f) sim_path = find_abs(preset_config["sim_location"], allowed_areas=batch_locations()) ScreenObjectManager.instance.pushScreen( ScreenObjectManager.SCREEN_BOTS, batch_file=sim_path, )
def clickSimSettings(self, preset): import importlib abs_path = find_abs(preset, allowed_areas=preset_locations()) with open(abs_path, "r") as f: preset_config = yaml.safe_load(f) sim_path = find_abs(preset_config["sim_location"], allowed_areas=batch_locations()) mname, cname = preset_config["visual_settings"].rsplit(".", 1) klass = getattr(importlib.import_module(mname), cname) ScreenObjectManager.instance.pushScreen( ScreenObjectManager.SCREEN_SETTINGS, file=sim_path, settings=klass, allows_filename_change=False, extension="sim", )
def generateObjects(self): # First, find all batch files. if not self.in_error: self.available_batches = [] error_batches = [] for rel_dir in batch_locations(): # Only show custom sims. if not rel_dir.startswith("workspace/custom/"): continue try: actual_dir = find_abs_directory(rel_dir) except: continue for batch in BatchValidator.all_valid_in_dir(actual_dir): # Show the dir name. try: with open(os.path.join(actual_dir, batch), "r") as f: config = yaml.safe_load(f) if not config.get("hidden", False): rest = rel_dir directory = "" while not directory: rest, directory = os.path.split(rest) self.available_batches.append( (directory, os.path.join(actual_dir, batch), actual_dir, batch)) except Exception as e: sentry_sdk.capture_exception(e) error_batches.append(os.path.join(actual_dir, batch)) if self.first_launch and error_batches: self.first_launch = False self.in_error = True self.addErrorDialog( 'A problem occured loading the following batches:<br><br><font color="#cc0000">' + "<br>".join(batch for batch in error_batches) + "</font>") return for i, batch in enumerate(self.available_batches): if i == self.batch_index: try: with open(batch[1], "r") as f: config = yaml.safe_load(f) # Update batch information preset_path = find_abs(config["preset_file"], allowed_areas=["workspace"]) with open(preset_path, "r") as f: preset_config = yaml.safe_load(f) preset_preview = find_abs(preset_config["preview_path"], allowed_areas=["workspace"]) self.preview_image_source = pygame.image.load( preset_preview) except Exception as e: sentry_sdk.capture_exception(e) self.setBatchIndex(-1) self.addErrorDialog( '<font color="#cc0000">The task you have selected has some internal errors EV3Sim cannot resolve.</font><br><br>' + "This can be caused by moving/renaming a bot as well as a few other things.<br><br>" + "If you'd like to fix this, then try manually editing the sim file in a text editor or contact the developers." ) return # Draw Background self.bg = pygame_gui.elements.UIPanel( relative_rect=pygame.Rect(0, 0, *self._size), starting_layer_height=-1, manager=self, object_id=pygame_gui.core.ObjectID("background"), ) self._all_objs.append(self.bg) # Scrolling container old_y = getattr(getattr(self, "scrolling_container", None), "cur_y", 0) self.scrolling_container = CustomScroll( relative_rect=pygame.Rect(0, 0, self._size[0], 5 * self._size[1]), manager=self, object_id=pygame_gui.core.ObjectID("scroll_container"), ) picture_width = 360 self.scrolling_container.elems_size = picture_width * 0.4 self.scrolling_container.span_elems = 4 self.scrolling_container.num_elems = len(self.available_batches) scrolling_size = (self._size[0] / 4 + self._size[0] / 5, self._size[1] * 0.95 - min(self._size[1] / 6, 90) + 20) # Setting dimensions and positions on a UIScrollingContainer seems buggy. This works. self.scrolling_container.set_dimensions(scrolling_size) self.scrolling_container.set_position(scrolling_size) self.scrolling_container.cur_y = old_y self.scrolling_container.set_scroll(old_y) self._all_objs.append(self.scrolling_container) # The batch buttons button_size = self._size[0] / 4, 60 info_size = self._size[0] / 4 - 20, 15 batch_rect = lambda i: (self._size[0] / 10, self._size[1] / 10 + i * button_size[1] * 1.5) info_rect = lambda b_r: ( b_r[0] + button_size[0] - info_size[0] - 10, b_r[1] + button_size[1] - info_size[1] - 5, ) self.batch_buttons = [] for i, (show, batch, actual_dir, filename) in enumerate(self.available_batches): self.batch_buttons.append( pygame_gui.elements.UIButton( relative_rect=pygame.Rect(*batch_rect(i), *button_size), text=show, manager=self, container=self.scrolling_container, object_id=pygame_gui.core.ObjectID(show + "-" + str(i), "list_button"), )) self.addButtonEvent(show + "-" + str(i), self.setBatchIndex, i) self._all_objs.extend(self.batch_buttons) # Remove remove_size = self._size[0] / 8, min(self._size[1] / 6, 90) remove_icon_size = remove_size[1] * 0.6, remove_size[1] * 0.6 remove_batch_pos = (self._size[0] / 3 - 2 * remove_size[0] - 15, self._size[1] * 0.95 - remove_size[1]) self.remove_batch = pygame_gui.elements.UIButton( relative_rect=pygame.Rect(*remove_batch_pos, *remove_size), text="", manager=self, object_id=pygame_gui.core.ObjectID("remove_batch", "cancel-changes"), ) self.addButtonEvent("remove_batch", self.clickRemove) if not self.remove_enable: self.remove_batch.disable() remove_batch_path = find_abs("ui/bin.png", allowed_areas=asset_locations()) self.remove_icon = pygame_gui.elements.UIImage( relative_rect=pygame.Rect( *self.iconPos(remove_batch_pos, remove_size, remove_icon_size), *remove_icon_size), image_surface=pygame.image.load(remove_batch_path), manager=self, object_id=pygame_gui.core.ObjectID("remove_batch-icon"), ) self._all_objs.append(self.remove_batch) self._all_objs.append(self.remove_icon) preview_size = self._size[0] / 4, self._size[1] / 4 preview_size = ( min(preview_size[0], (preview_size[1] * 4) // 3), min(preview_size[1], (preview_size[0] * 3) // 4), ) preview_image_pos = (self._size[0] * 0.9 - preview_size[0], self._size[1] * 0.1) self.preview_image = pygame_gui.elements.UIImage( relative_rect=pygame.Rect(*preview_image_pos, *preview_size), image_surface=pygame.Surface(self._size), manager=self, object_id=pygame_gui.core.ObjectID("preview-image"), ) self._all_objs.append(self.preview_image) code_size = preview_size[0] * 0.4, preview_size[1] * 0.4 code_button_pos = ( self._size[0] * 0.9 - code_size[0] - 10, self._size[1] * 0.1 + preview_size[1] + 10, ) code_icon_size = code_size[1] * 0.6, code_size[1] * 0.6 self.code_button = pygame_gui.elements.UIButton( relative_rect=pygame.Rect(*code_button_pos, *code_size), text="", manager=self, object_id=pygame_gui.core.ObjectID("bot-code", "settings_buttons"), ) self.addButtonEvent("bot-code", self.clickCode) if not self.code_enable: self.code_button.disable() code_icon_path = find_abs("ui/code.png", allowed_areas=asset_locations()) self.code_icon = pygame_gui.elements.UIImage( relative_rect=pygame.Rect( *self.iconPos(code_button_pos, code_size, code_icon_size), *code_icon_size), image_surface=pygame.image.load(code_icon_path), manager=self, object_id=pygame_gui.core.ObjectID("code-icon"), ) self._all_objs.append(self.code_button) self._all_objs.append(self.code_icon) bots_button_pos = ( self._size[0] * 0.9 - preview_size[0] + 10, self._size[1] * 0.1 + preview_size[1] + 10, ) self.bots_button = pygame_gui.elements.UIButton( relative_rect=pygame.Rect(*bots_button_pos, *code_size), text="", manager=self, object_id=pygame_gui.core.ObjectID("bot-bots", "settings_buttons"), ) self.addButtonEvent("bot-bots", self.clickBots) if not self.bots_enable: self.bots_button.disable() bots_icon_path = find_abs("ui/bot.png", allowed_areas=asset_locations()) self.bots_icon = pygame_gui.elements.UIImage( relative_rect=pygame.Rect( *self.iconPos(bots_button_pos, code_size, code_icon_size), *code_icon_size), image_surface=pygame.image.load(bots_icon_path), manager=self, object_id=pygame_gui.core.ObjectID("bots-icon"), ) self._all_objs.append(self.bots_button) self._all_objs.append(self.bots_icon) start_size = self._size[0] / 4, min(self._size[1] / 4, 120) start_icon_size = start_size[1] * 0.6, start_size[1] * 0.6 start_button_pos = (self._size[0] * 0.9 - start_size[0], self._size[1] * 0.9 - start_size[1]) self.start_button = pygame_gui.elements.UIButton( relative_rect=pygame.Rect(*start_button_pos, *start_size), text="", manager=self, object_id=pygame_gui.core.ObjectID("start-sim", "action_button"), ) self.addButtonEvent("start-sim", self.clickStart) if not self.start_enable: self.start_button.disable() start_icon_path = find_abs("ui/start_sim.png", allowed_areas=asset_locations()) self.start_icon = pygame_gui.elements.UIImage( relative_rect=pygame.Rect( *self.iconPos(start_button_pos, start_size, start_icon_size), *start_icon_size), image_surface=pygame.image.load(start_icon_path), manager=self, object_id=pygame_gui.core.ObjectID("start-sim-icon"), ) self._all_objs.append(self.start_button) self._all_objs.append(self.start_icon) self.changeSelectedTheming() super().generateObjects()
def playSim(self, preset): abs_path = find_abs(preset, allowed_areas=preset_locations()) with open(abs_path, "r") as f: preset_config = yaml.safe_load(f) sim_path = find_abs(preset_config["sim_location"], allowed_areas=batch_locations()) with open(sim_path, "r") as f: sim_config = yaml.safe_load(f) to_remove = [] for index in range(len(sim_config["bots"])): # Try loading this bot. try: with open( os.path.join( find_abs(sim_config["bots"][index], bot_locations()), "config.bot"), "r") as f: bot_config = yaml.safe_load(f) if not BotValidator.validate_json(bot_config): to_remove.append(index) if bot_config.get("type", "python") == "python": fname = bot_config.get("script", "code.py") else: fname = bot_config.get("script", "program.ev3") if not os.path.exists( os.path.join( find_abs(sim_config["bots"][index], bot_locations()), fname)): def action(): with open( os.path.join( find_abs(sim_config["bots"][index], bot_locations()), fname), "w") as f: f.write("# Put your code here!\n") ScreenObjectManager.instance.forceCloseError( f"Your bot {sim_config['bots'][index]} does not contain the file {fname}. You may have renamed or deleted it by accident. In order to use this bot, you need to add this file back. Click \"Add {fname}\" to create this file, or do it manually.", (f"Add {fname}", action), ) return except: to_remove.append(index) if to_remove: for index in to_remove[::-1]: del sim_config["bots"][index] with open(sim_path, "w") as f: f.write(yaml.dump(sim_config)) if not sim_config["bots"]: # We cannot play, there no are valid bots. return ScreenObjectManager.instance.pushScreen( ScreenObjectManager.SCREEN_BOTS, batch_file=sim_path, next=ScreenObjectManager.instance.SCREEN_SIM, next_kwargs={"batch": sim_path}, ) return ScreenObjectManager.instance.pushScreen( ScreenObjectManager.instance.SCREEN_SIM, batch=sim_path, )
def generateObjects(self): from ev3sim.visual.manager import ScreenObjectManager self.show_custom = False # First, check if there are any valid batches in the custom folder. for rel_dir in batch_locations(): # Only consider custom sims. if not rel_dir.startswith("workspace/custom/"): continue try: actual_dir = find_abs_directory(rel_dir) except: continue for _ in BatchValidator.all_valid_in_dir(actual_dir): self.show_custom = True break # In order to respect theme changes, objects must be built in initWithKwargs self.bg = pygame_gui.elements.UIPanel( relative_rect=pygame.Rect(0, 0, *self._size), starting_layer_height=-1, manager=self, object_id=pygame_gui.core.ObjectID("background"), ) self._all_objs.append(self.bg) self.title = pygame_gui.elements.UITextBox( relative_rect=pygame.Rect(0, 0, -1, -1), html_text="EV3<i>Sim</i>", manager=self, object_id=pygame_gui.core.ObjectID("title"), ) self.title.set_position( ((self._size[0] - self.title.rect.width) / 2, 50)) self._all_objs.append(self.title) self.button_size = ((self._size[0] / 4, self._size[1] / 10) if self.show_custom else (self._size[0] / 4, self._size[1] / 8)) settings_size = self.button_size[0] * 0.3, self.button_size[1] bot_size = settings_size settings_icon_size = settings_size[1] * 0.6, settings_size[1] * 0.6 bot_icon_size = bot_size[1] * 0.6, bot_size[1] * 0.6 settings_icon_path = find_abs("ui/settings.png", allowed_areas=asset_locations()) bot_icon_path = find_abs("ui/bot.png", allowed_areas=asset_locations()) self.soccer_button = pygame_gui.elements.UIButton( relative_rect=pygame.Rect(*self.buttonPos(0), *self.button_size), text="Soccer", manager=self, object_id=pygame_gui.core.ObjectID("soccer_button", "menu_button"), ) self.addButtonEvent("soccer_button", lambda: self.playSim("soccer.yaml")) self._all_objs.append(self.soccer_button) soccer_settings_button_pos = [ self.buttonPos(0)[0] + self.button_size[0] + 20, self.buttonPos(0)[1] ] self.soccer_settings_button = pygame_gui.elements.UIButton( relative_rect=pygame.Rect(*soccer_settings_button_pos, *settings_size), text="", manager=self, object_id=pygame_gui.core.ObjectID("soccer-settings", "settings_buttons"), ) self.addButtonEvent("soccer-settings", self.clickSimSettings, "soccer.yaml") self.soccer_settings_icon = pygame_gui.elements.UIImage( relative_rect=pygame.Rect( *self.iconPos(soccer_settings_button_pos, settings_size, settings_icon_size), *settings_icon_size), image_surface=pygame.image.load(settings_icon_path), manager=self, object_id=pygame_gui.core.ObjectID("soccer-settings-icon"), ) self._all_objs.append(self.soccer_settings_button) self._all_objs.append(self.soccer_settings_icon) soccer_bot_button_pos = [ self.buttonPos(0)[0] + self.button_size[0] + settings_size[0] + 40, self.buttonPos(0)[1], ] self.soccer_bot_button = pygame_gui.elements.UIButton( relative_rect=pygame.Rect(*soccer_bot_button_pos, *bot_size), text="", manager=self, object_id=pygame_gui.core.ObjectID("soccer-bot", "settings_buttons"), ) self.addButtonEvent("soccer-bot", self.clickSimBots, "soccer.yaml") self.soccer_bot_icon = pygame_gui.elements.UIImage( relative_rect=pygame.Rect( *self.iconPos(soccer_bot_button_pos, bot_size, bot_icon_size), *bot_icon_size), image_surface=pygame.image.load(bot_icon_path), manager=self, object_id=pygame_gui.core.ObjectID("soccer-bot-icon"), ) self._all_objs.append(self.soccer_bot_button) self._all_objs.append(self.soccer_bot_icon) self.rescue_button = pygame_gui.elements.UIButton( relative_rect=pygame.Rect(*self.buttonPos(1), *self.button_size), text="Rescue", manager=self, object_id=pygame_gui.core.ObjectID("rescue_button", "menu_button"), ) self.addButtonEvent("rescue_button", lambda: self.playSim("rescue.yaml")) self._all_objs.append(self.rescue_button) rescue_settings_button_pos = [ self.buttonPos(1)[0] + self.button_size[0] + 20, self.buttonPos(1)[1] ] self.rescue_settings_button = pygame_gui.elements.UIButton( relative_rect=pygame.Rect(*rescue_settings_button_pos, *settings_size), text="", manager=self, object_id=pygame_gui.core.ObjectID("rescue-settings", "settings_buttons"), ) self.addButtonEvent("rescue-settings", self.clickSimSettings, "rescue.yaml") self.rescue_settings_icon = pygame_gui.elements.UIImage( relative_rect=pygame.Rect( *self.iconPos(rescue_settings_button_pos, settings_size, settings_icon_size), *settings_icon_size), image_surface=pygame.image.load(settings_icon_path), manager=self, object_id=pygame_gui.core.ObjectID("rescue-settings-icon"), ) self._all_objs.append(self.rescue_settings_button) self._all_objs.append(self.rescue_settings_icon) rescue_bot_button_pos = [ self.buttonPos(1)[0] + self.button_size[0] + settings_size[0] + 40, self.buttonPos(1)[1], ] self.rescue_bot_button = pygame_gui.elements.UIButton( relative_rect=pygame.Rect(*rescue_bot_button_pos, *bot_size), text="", manager=self, object_id=pygame_gui.core.ObjectID("rescue-bot", "settings_buttons"), ) self.addButtonEvent("rescue-bot", self.clickSimBots, "rescue.yaml") self.rescue_bot_icon = pygame_gui.elements.UIImage( relative_rect=pygame.Rect( *self.iconPos(rescue_bot_button_pos, bot_size, bot_icon_size), *bot_icon_size), image_surface=pygame.image.load(bot_icon_path), manager=self, object_id=pygame_gui.core.ObjectID("rescue-bot-icon"), ) self._all_objs.append(self.rescue_bot_button) self._all_objs.append(self.rescue_bot_icon) if self.show_custom: self.custom_button = pygame_gui.elements.UIButton( relative_rect=pygame.Rect(*self.buttonPos(2), *self.button_size), text="Custom", manager=self, object_id=pygame_gui.core.ObjectID("custom_button", "menu_button"), ) self.addButtonEvent("custom_button", self.clickCustom) self._all_objs.append(self.custom_button) self.bot_button = pygame_gui.elements.UIButton( relative_rect=pygame.Rect( *self.buttonPos(3 if self.show_custom else 2), *self.button_size), text="Bots", manager=self, object_id=pygame_gui.core.ObjectID("bots_button", "menu_button"), ) self.addButtonEvent( "bots_button", lambda: ScreenObjectManager.instance.pushScreen(ScreenObjectManager .SCREEN_BOTS), ) self._all_objs.append(self.bot_button) self.settings_button = pygame_gui.elements.UIButton( relative_rect=pygame.Rect( *self.buttonPos(4 if self.show_custom else 3), *self.button_size), text="Settings", manager=self, object_id=pygame_gui.core.ObjectID("main_settings_button", "menu_button"), ) def clickSettings(): ScreenObjectManager.instance.pushScreen( ScreenObjectManager.SCREEN_SETTINGS, file=find_abs("user_config.yaml", config_locations()), settings=main_settings, ) ScreenObjectManager.instance.screens[ ScreenObjectManager.SCREEN_SETTINGS].clearEvents() self.addButtonEvent("main_settings_button", clickSettings) self._all_objs.append(self.settings_button) super().generateObjects()