예제 #1
0
 def swapSlides(self):
     self.remaining = 0
     self.slide_index += 1
     self.slide_index %= self.SLIDE_NUMS
     self.slide_surface_prev = pygame.image.load(
         find_abs(f"bg_slide{(self.slide_index - 1) % self.SLIDE_NUMS}.png",
                  asset_locations()))
     self.slide_surface_next = pygame.image.load(
         find_abs(f"bg_slide{self.slide_index}.png", asset_locations()))
예제 #2
0
 def setCheckboxBg(self, value, obj):
     img = pygame.image.load(
         find_abs("ui/box_check.png" if value else "ui/box_clear.png",
                  allowed_areas=asset_locations()))
     if img.get_size() != obj.rect.size:
         img = pygame.transform.smoothscale(
             img, (obj.rect.width, obj.rect.height))
     obj.set_image(img)
예제 #3
0
 def updateFlipCheckbox(self):
     img = pygame.image.load(
         find_abs(
             "ui/box_check.png" if self.getSelectedAttribute("flip", False)
             else "ui/box_clear.png",
             allowed_areas=asset_locations(),
         ))
     if img.get_size() != self.flip_image.rect.size:
         img = pygame.transform.smoothscale(
             img, (self.flip_image.rect.width, self.flip_image.rect.height))
     self.flip_image.set_image(img)
예제 #4
0
        def action():
            import yaml
            """Go through and try fixing the bots."""
            for bot in old_bots:
                dirpath = os.path.join(path, bot[:-4])
                # Folder
                if os.path.isdir(dirpath):
                    import shutil

                    shutil.rmtree(dirpath)
                os.mkdir(dirpath)
                # config.bot
                with open(os.path.join(path, bot), "r") as f:
                    config = yaml.safe_load(f)
                bot_script = config.get("script", "code.py")
                preview_image = config.get("preview_path", "preview.png")
                for keyword in ["script", "preview_path"]:
                    if keyword in config:
                        del config[keyword]
                with open(os.path.join(dirpath, "config.bot"), "w") as f:
                    f.write(yaml.dump(config))
                # code.py
                try:
                    code_path = os.path.join(
                        find_abs_directory("workspace/code/"), bot_script)
                    with open(code_path, "r") as f:
                        code = f.read()
                except:
                    code = ""
                with open(os.path.join(dirpath, "code.py"), "w") as f:
                    f.write(code)
                # preview.png
                try:
                    preview = find_abs(preview_image, asset_locations())
                    with open(preview, "rb") as f:
                        preview_data = f.read()
                except:
                    preview_data = bytes()
                with open(os.path.join(dirpath, "preview.png"), "wb") as f:
                    f.write(preview_data)
                # Remove the old bot
                os.remove(os.path.join(path, bot))
            # Additionally, we need to update all sim files to no longer use the .bot prefix
            actual_dir = find_abs_directory("workspace/sims/")
            for file in os.listdir(actual_dir):
                if os.path.isfile(os.path.join(
                        actual_dir, file)) and file.endswith(".sim"):
                    with open(os.path.join(actual_dir, file), "r") as f:
                        config = yaml.safe_load(f)
                    for x in range(len(config.get("bots", []))):
                        if config["bots"][x].endswith(".bot"):
                            config["bots"][x] = config["bots"][x][:-4]
                    with open(os.path.join(actual_dir, file), "w") as f:
                        f.write(yaml.dump(config))
예제 #5
0
    def image_path(self, value):
        from ev3sim.file_helper import find_abs

        image_path = find_abs(value, allowed_areas=asset_locations())
        if image_path != self._image_path:
            self._image_path = image_path
            self.image = pygame.image.load(self._image_path)
            try:
                self.calculatePoints()
            except:
                pass
예제 #6
0
    def generateVisual(self, size, container, manager, idx):
        self.container = container
        off = self.offset(size)

        label_size = ((size[0] - 40) / 2 - 10, 40)
        label_pos = (off[0] + 20, off[1])
        label = pygame_gui.elements.UILabel(
            relative_rect=pygame.Rect(*label_pos, *label_size),
            manager=manager,
            object_id=pygame_gui.core.ObjectID(f"{idx}-file-label",
                                               "entry-label"),
            container=container,
            text=self.title,
        )

        button_size = ((size[0] - 40) * 0.25 - 20, 44)
        button_size = [min(button_size[0], button_size[1])] * 2
        file_size = ((size[0] - 40) / 2 - button_size[0] - 30, 40)
        button_pos = (
            off[0] + 50 + label_size[0] + file_size[0],
            off[1] - 2,
        )
        file_pos = (off[0] + 40 + label_size[0], off[1])
        click = pygame_gui.elements.UIButton(
            relative_rect=pygame.Rect(*button_pos, *button_size),
            manager=manager,
            object_id=pygame_gui.core.ObjectID(f"{idx+2}-button",
                                               "file-button"),
            container=container,
            text="",
        )
        img = pygame.image.load(
            find_abs("ui/folder.png", allowed_areas=asset_locations()))
        if img.get_size() != button_size:
            img = pygame.transform.smoothscale(img, button_size)
        click_icon = pygame_gui.elements.UIImage(
            relative_rect=pygame.Rect(*button_pos, *button_size),
            manager=manager,
            object_id=pygame_gui.core.ObjectID(f"{idx+3}-image", "file-image"),
            container=container,
            image_surface=img,
        )

        self.filename = pygame_gui.elements.UILabel(
            relative_rect=pygame.Rect(*file_pos, *file_size),
            manager=manager,
            object_id=pygame_gui.core.ObjectID(f"{idx+1}-file-name",
                                               "entry-label"),
            container=container,
            text=self.current if self.current else "",
        )

        return [label, self.filename, click, click_icon]
예제 #7
0
    def initFromKwargs(self, **kwargs):
        super().initFromKwargs(**kwargs)
        from ev3sim.file_helper import find_abs

        self.font_style = kwargs.get("font_style",
                                     "fonts/OpenSans-SemiBold.ttf")
        self.font_path = find_abs(self.font_style,
                                  allowed_areas=asset_locations())
        self.font_size = kwargs.get("font_size", 30)
        self.hAlignment = kwargs.get("hAlignment", "l")
        self.vAlignment = kwargs.get("vAlignment", "t")
        self.text = kwargs.get("text", "Test")
예제 #8
0
 def updateSpawnCheckbox(self):
     tile_pos = self.getSelectedAttribute("position")
     spawn = self.previous_info["settings"]["rescue"]["BOT_SPAWN_POSITION"][
         0][0]
     img = pygame.image.load(
         find_abs(
             "ui/box_check.png" if tile_pos[0] == spawn[0]
             and tile_pos[1] == spawn[1] else "ui/box_clear.png",
             allowed_areas=asset_locations(),
         ))
     if img.get_size() != self.spawn_image.rect.size:
         img = pygame.transform.smoothscale(
             img,
             (self.spawn_image.rect.width, self.spawn_image.rect.height))
     self.spawn_image.set_image(img)
예제 #9
0
    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()
예제 #10
0
    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()
예제 #11
0
    def generateObjects(self):
        # First, find all bot files.
        if not self.in_error:
            self.available_bots = []
            error_bots = []
            for rel_dir in bot_locations():
                try:
                    actual_dir = find_abs_directory(rel_dir)
                except:
                    continue
                for bot in BotValidator.all_valid_in_dir(actual_dir):
                    try:
                        # Show everything except dir and .bot
                        with open(os.path.join(actual_dir, bot, "config.bot"),
                                  "r") as f:
                            config = yaml.safe_load(f)
                        # If we are hidden, or in edit mode with hidden_edit, then don't show.
                        if not config.get("hidden", False) and not (
                                config.get("hidden_edit", False)
                                and len(self.bot_keys) == 0):
                            self.available_bots.append(
                                (bot, os.path.join(actual_dir,
                                                   bot), rel_dir, bot))
                    except Exception as e:
                        sentry_sdk.capture_exception(e)
                        error_bots.append(os.path.join(actual_dir, bot))
            if self.first_launch and error_bots:
                self.first_launch = False
                self.in_error = True
                self.addErrorDialog(
                    'A problem occured loading the following bots:<br><br><font color="#cc0000">'
                    + "<br>".join(bot for bot in error_bots) + "</font>")
                return

        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),
            manager=self,
            object_id=pygame_gui.core.ObjectID("scroll_container"),
        )
        self.scrolling_container.num_elems = len(self.available_bots)
        scrolling_size = (self._size[0] / 4 + self._size[0] / 5,
                          self._size[1] * 0.9 - min(self._size[1] / 6, 90))
        # 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)

        button_size = self._size[0] / 4, 60
        info_size = self._size[0] / 4 - 20, 15
        bot_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.bot_buttons = []
        self.bot_descriptions = []
        for i, (show, bot, rel_dir,
                filename) in enumerate(self.available_bots):
            self.bot_buttons.append(
                pygame_gui.elements.UIButton(
                    relative_rect=pygame.Rect(*bot_rect(i), *button_size),
                    text=show,
                    manager=self,
                    container=self.scrolling_container,
                    object_id=pygame_gui.core.ObjectID(
                        show + "-" + str(i), "list_button_highlighted"
                        if i == self.bot_index else "list_button"),
                ))
            self.addButtonEvent(show + "-" + str(i), self.setBotIndex, i)
            self.bot_descriptions.append(
                pygame_gui.elements.UILabel(
                    relative_rect=pygame.Rect(*info_rect(bot_rect(i)),
                                              *info_size),
                    text=rel_dir,
                    manager=self,
                    container=self.scrolling_container,
                    object_id=pygame_gui.core.ObjectID(
                        show + "-dir-" + str(i), "button_info_selected"
                        if i == self.bot_index else "button_info"),
                ))
        self._all_objs.extend(self.bot_buttons)
        self._all_objs.extend(self.bot_descriptions)

        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),
        )
        try:
            if self.bot_index >= len(self.available_bots):
                self.bot_index = -1
            if self.bot_index == -1:
                image = pygame.Surface(preview_size)
                image.fill(pygame.Color(self.bg.background_colour))
            else:
                with open(
                        os.path.join(self.available_bots[self.bot_index][1],
                                     "config.bot"), "r") as f:
                    config = yaml.safe_load(f)
                bot_preview = os.path.join(
                    self.available_bots[self.bot_index][1],
                    config.get("preview_path", "preview.png"))
                image = pygame.image.load(bot_preview)
        except Exception as e:
            sentry_sdk.capture_exception(e)
            self.setBotIndex(-1)
            self.addErrorDialog(
                '<font color="#cc0000">The bot you have selected has some internal errors EV3Sim cannot resolve.</font><br><br>'
                +
                "If you'd like to fix this, then try manually editing the bot file in a text editor."
            )
            return
        if image.get_size() != preview_size:
            image = pygame.transform.smoothscale(
                image, [int(v) for v in preview_size])
        self.preview_image = pygame_gui.elements.UIImage(
            relative_rect=pygame.Rect(self._size[0] * 0.9 - preview_size[0],
                                      self._size[1] * 0.1, *preview_size),
            image_surface=image,
            manager=self,
            object_id=pygame_gui.core.ObjectID("preview-image"),
        )
        self._all_objs.append(self.preview_image)

        if len(self.bot_keys) == 0:
            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)

            edit_button_pos = (
                self._size[0] * 0.9 - preview_size[0],
                self._size[1] * 0.1 + preview_size[1] + 10,
            )
            self.edit_button = pygame_gui.elements.UIButton(
                relative_rect=pygame.Rect(*edit_button_pos, *code_size),
                text="",
                manager=self,
                object_id=pygame_gui.core.ObjectID("bot-edit",
                                                   "settings_buttons"),
            )
            self.addButtonEvent("bot-edit", self.clickEdit)
            if not self.edit_enable:
                self.edit_button.disable()
            edit_icon_path = find_abs("ui/edit.png",
                                      allowed_areas=asset_locations())
            self.edit_icon = pygame_gui.elements.UIImage(
                relative_rect=pygame.Rect(
                    *self.iconPos(edit_button_pos, code_size, code_icon_size),
                    *code_icon_size),
                image_surface=pygame.image.load(edit_icon_path),
                manager=self,
                object_id=pygame_gui.core.ObjectID("edit-icon"),
            )
            self._all_objs.append(self.edit_button)
            self._all_objs.append(self.edit_icon)

            new_size = self._size[0] / 8, min(self._size[1] / 6, 90)
            new_icon_size = new_size[1] * 0.6, new_size[1] * 0.6
            new_bot_pos = (bot_rect(0)[0] + button_size[0] - new_size[0],
                           self._size[1] * 0.9 - new_size[1])
            self.new_bot = pygame_gui.elements.UIButton(
                relative_rect=pygame.Rect(*new_bot_pos, *new_size),
                text="",
                manager=self,
                object_id=pygame_gui.core.ObjectID("new_bot", "action_button"),
            )
            self.addButtonEvent("new_bot", self.clickNew)
            new_bot_path = find_abs("ui/add.png",
                                    allowed_areas=asset_locations())
            self.new_icon = pygame_gui.elements.UIImage(
                relative_rect=pygame.Rect(
                    *self.iconPos(new_bot_pos, new_size, new_icon_size),
                    *new_icon_size),
                image_surface=pygame.image.load(new_bot_path),
                manager=self,
                object_id=pygame_gui.core.ObjectID("new_bot-icon"),
            )
            self._all_objs.append(self.new_bot)
            self._all_objs.append(self.new_icon)

            remove_bot_pos = (bot_rect(0)[0],
                              self._size[1] * 0.9 - new_size[1])
            self.remove_bot = pygame_gui.elements.UIButton(
                relative_rect=pygame.Rect(*remove_bot_pos, *new_size),
                text="",
                manager=self,
                object_id=pygame_gui.core.ObjectID("remove_bot",
                                                   "cancel-changes"),
            )
            self.addButtonEvent("remove_bot", self.clickRemove)
            if not self.remove_enable:
                self.remove_bot.disable()
            remove_bot_path = find_abs("ui/bin.png",
                                       allowed_areas=asset_locations())
            self.remove_icon = pygame_gui.elements.UIImage(
                relative_rect=pygame.Rect(
                    *self.iconPos(remove_bot_pos, new_size, new_icon_size),
                    *new_icon_size),
                image_surface=pygame.image.load(remove_bot_path),
                manager=self,
                object_id=pygame_gui.core.ObjectID("remove_bot-icon"),
            )
            self._all_objs.append(self.remove_bot)
            self._all_objs.append(self.remove_icon)
            super().generateObjects()
        else:
            # Bot key locations, for selecting bots in batch files.
            self.bot_loc_spots = []
            for i in range(len(self.bot_keys)):
                if i == self.key_index:
                    self.bot_loc_spots.append(
                        self.createBotImage(i, bg=pygame.Color("#80b918")))
                else:
                    self.bot_loc_spots.append(self.createBotImage(i))
                self.sizeBotImage(i, big_mode=len(self.bot_keys) == 1)
                img = self.preview_images[i]
                if img is None:
                    continue
                if img.get_size() != self.bot_loc_spots[i].rect.size:
                    img = pygame.transform.smoothscale(
                        img, (self.bot_loc_spots[i].rect.width,
                              self.bot_loc_spots[i].rect.height))
                self.bot_loc_spots[i].set_image(img)
            self._all_objs.extend(self.bot_loc_spots)

            select_size = (self._size[0] / 4 - 20) / 2, min(
                self._size[1] / 4, 120)
            select_button_pos = (self._size[0] * 0.9 - select_size[0] * 2 - 15,
                                 self._size[1] * 0.9 - select_size[1])
            self.select_button = pygame_gui.elements.UIButton(
                relative_rect=pygame.Rect(*select_button_pos, *select_size),
                text="SELECT",
                manager=self,
                object_id=pygame_gui.core.ObjectID("select-bot",
                                                   "action_button"),
            )
            self.addButtonEvent("select-bot", self.clickSelect)
            if not self.select_enable:
                self.select_button.disable()
            self._all_objs.append(self.select_button)

            done_size = (self._size[0] / 4 - 20) / 2, min(
                self._size[1] / 4, 120)
            done_button_pos = (self._size[0] * 0.9 - select_size[0] - 5,
                               self._size[1] * 0.9 - select_size[1])
            self.done_button = pygame_gui.elements.UIButton(
                relative_rect=pygame.Rect(*done_button_pos, *done_size),
                text="DONE",
                manager=self,
                object_id=pygame_gui.core.ObjectID("select-done",
                                                   "action_button"),
            )
            self.addButtonEvent("select-done", self.clickDone)
            if self.key_index == 0:
                self.done_button.disable()
            self._all_objs.append(self.done_button)
            super().generateObjects()