Rename to Fractal Viewer, add Sierpinsky Carpet, use arcade 3.2.0

instead
of development
This commit is contained in:
csd4ni3l
2025-05-24 09:24:22 +02:00
parent c295fec105
commit 51c0c6ef05
13 changed files with 280 additions and 109 deletions

View File

@@ -17,9 +17,9 @@ jobs:
- name: Setup Python - name: Setup Python
uses: actions/setup-python@v5 uses: actions/setup-python@v5
with: with:
python-version: '3.11' python-version: "3.11"
architecture: 'x64' architecture: "x64"
cache: 'pip' cache: "pip"
cache-dependency-path: | cache-dependency-path: |
**/requirements*.txt **/requirements*.txt
@@ -37,24 +37,24 @@ jobs:
include-data-dir: assets=assets include-data-dir: assets=assets
include-data-files: CREDITS=CREDITS include-data-files: CREDITS=CREDITS
mode: standalone mode: standalone
output-file: MandelBrotViewer output-file: FractalViewer
- name: Zip Build Output - name: Zip Build Output
shell: bash shell: bash
run: | run: |
mkdir -p zip_output mkdir -p zip_output
if [ "${{ runner.os }}" = "Windows" ]; then if [ "${{ runner.os }}" = "Windows" ]; then
powershell.exe -Command "Compress-Archive -Path 'build/run.dist/*' -DestinationPath 'zip_output/MandelBrotViewer-${{ runner.os }}.zip'" powershell.exe -Command "Compress-Archive -Path 'build/run.dist/*' -DestinationPath 'zip_output/FractalViewer-${{ runner.os }}.zip'"
else else
cd build/run.dist cd build/run.dist
zip -r "../../zip_output/MandelBrotViewer-${{ runner.os }}.zip" . zip -r "../../zip_output/FractalViewer-${{ runner.os }}.zip" .
fi fi
- name: Upload Zipped Build Artifact - name: Upload Zipped Build Artifact
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: MandelBrotViewer-${{ runner.os }}.zip name: FractalViewer-${{ runner.os }}.zip
path: zip_output/MandelBrotViewer-${{ runner.os }}.zip path: zip_output/FractalViewer-${{ runner.os }}.zip
release: release:
name: Create GitHub Release name: Create GitHub Release
needs: build needs: build
@@ -63,31 +63,31 @@ jobs:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Download All Zipped Builds - name: Download All Zipped Builds
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
with: with:
path: downloads path: downloads
- name: Delete Old Release (if exists) - name: Delete Old Release (if exists)
continue-on-error: true continue-on-error: true
run: gh release delete latest -y run: gh release delete latest -y
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Delete Git tag (if exists) - name: Delete Git tag (if exists)
continue-on-error: true continue-on-error: true
run: | run: |
git push origin :refs/tags/latest git push origin :refs/tags/latest
git tag -d latest git tag -d latest
- name: Recreate Git tag at HEAD - name: Recreate Git tag at HEAD
run: | run: |
git tag latest git tag latest
git push origin latest git push origin latest
- name: Create the new release - name: Create the new release
run: gh release create latest downloads/**/MandelBrotViewer-*.zip --title "Latest Build" --notes "Most recent multi-platform builds of MandelBrotViewer" run: gh release create latest downloads/**/FractalViewer-*.zip --title "Latest Build" --notes "Most recent multi-platform builds of FractalViewer"
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1 +1,3 @@
Mandelbrot viewer in Python using compute shaders and the Arcade and Pyglet modules. Fractal viewer in Python using compute shaders and the Arcade and Pyglet modules.
Currently supports Sierpinsky Carpet and Mandelbrot.

95
game/mandelbrot.py Normal file
View File

@@ -0,0 +1,95 @@
import arcade, arcade.gui, pyglet, json
from PIL import Image
from game.shader import create_mandelbrot_shader
from utils.constants import menu_background_color, button_style, initial_real_min, initial_real_max, initial_imag_min, initial_imag_max
from utils.preload import button_texture, button_hovered_texture
class MandelbrotViewer(arcade.gui.UIView):
def __init__(self, pypresence_client):
super().__init__()
self.pypresence_client = pypresence_client
self.real_min = initial_real_min
self.real_max = initial_real_max
self.imag_min = initial_imag_min
self.imag_max = initial_imag_max
with open("settings.json", "r") as file:
self.settings_dict = json.load(file)
self.max_iter = self.settings_dict.get("mandelbrot_max_iter", 200)
self.zoom = 1.0
def on_show_view(self):
super().on_show_view()
self.shader_program, self.mandelbrot_image = create_mandelbrot_shader(self.window.width, self.window.height, self.settings_dict.get("mandelbrot_precision", "Single").lower())
self.mandelbrot_sprite = pyglet.sprite.Sprite(img=self.mandelbrot_image)
self.create_image()
self.pypresence_client.update(state='Viewing Mandelbrot', details=f'Zoom: {self.zoom}\nMax Iterations: {self.max_iter}', start=self.pypresence_client.start_time)
self.setup_ui()
def main_exit(self):
from menus.main import Main
self.window.show_view(Main(self.pypresence_client))
def setup_ui(self):
self.anchor = self.add_widget(arcade.gui.UIAnchorLayout(size_hint=(1, 1)))
self.info_box = self.anchor.add(arcade.gui.UIBoxLayout(space_between=10, vertical=False), anchor_x="center", anchor_y="top")
self.zoom_label = self.info_box.add(arcade.gui.UILabel(text=f"Zoom: {self.zoom}", font_name="Protest Strike", font_size=16))
self.max_iter_label = self.info_box.add(arcade.gui.UILabel(text=f"Max Iterations: {self.max_iter}", font_name="Protest Strike", font_size=16))
self.back_button = arcade.gui.UITextureButton(texture=button_texture, texture_hovered=button_hovered_texture, text='<--', style=button_style, width=100, height=50)
self.back_button.on_click = lambda event: self.main_exit()
self.anchor.add(self.back_button, anchor_x="left", anchor_y="top", align_x=5, align_y=-5)
def zoom_at(self, center_x, center_y, zoom_factor):
center_real = self.real_min + (center_x / self.width) * (self.real_max - self.real_min)
center_imag = self.imag_min + (center_y / self.height) * (self.imag_max - self.imag_min)
new_real_range = (self.real_max - self.real_min) / zoom_factor
new_imag_range = (self.imag_max - self.imag_min) / zoom_factor
self.real_min = center_real - new_real_range / 2
self.real_max = center_real + new_real_range / 2
self.imag_min = center_imag - new_imag_range / 2
self.imag_max = center_imag + new_imag_range / 2
def create_image(self):
with self.shader_program:
self.shader_program['u_maxIter'] = self.max_iter
self.shader_program['u_resolution'] = (self.window.width, self.window.height)
self.shader_program['u_real_range'] = (self.real_min, self.real_max)
self.shader_program['u_imag_range'] = (self.imag_min, self.imag_max)
self.shader_program.dispatch(self.mandelbrot_image.width, self.mandelbrot_image.height, 1, barrier=pyglet.gl.GL_ALL_BARRIER_BITS)
def on_mouse_press(self, x: int, y: int, button: int, modifiers: int) -> bool | None:
super().on_mouse_press(x, y, button, modifiers)
if button == arcade.MOUSE_BUTTON_LEFT:
zoom = self.settings_dict.get("mandelbrot_zoom_increase", 2)
elif button == arcade.MOUSE_BUTTON_RIGHT:
zoom = 1 / self.settings_dict.get("mandelbrot_zoom_increase", 2)
else:
return
self.zoom *= zoom
self.zoom_label.text = f"Zoom: {self.zoom}"
self.zoom_at(self.window.mouse.data["x"], self.window.mouse.data["y"], zoom)
self.create_image()
self.pypresence_client.update(state='Viewing Mandelbrot', details=f'Zoom: {self.zoom}\nMax Iterations: {self.max_iter}', start=self.pypresence_client.start_time)
def on_draw(self):
self.window.clear()
self.mandelbrot_sprite.draw()
self.ui.draw()

View File

@@ -1,95 +1,42 @@
import arcade, arcade.gui, pyglet, json import arcade, arcade.gui
from PIL import Image from utils.constants import button_style
from game.shader import create_mandelbrot_shader
from utils.constants import menu_background_color, button_style, initial_real_min, initial_real_max, initial_imag_min, initial_imag_max
from utils.preload import button_texture, button_hovered_texture from utils.preload import button_texture, button_hovered_texture
class Game(arcade.gui.UIView): class FractalChooser(arcade.gui.UIView):
def __init__(self, pypresence_client): def __init__(self, pypresence_client):
super().__init__() super().__init__()
self.pypresence_client = pypresence_client self.pypresence_client = pypresence_client
self.real_min = initial_real_min
self.real_max = initial_real_max
self.imag_min = initial_imag_min
self.imag_max = initial_imag_max
with open("settings.json", "r") as file:
self.settings_dict = json.load(file)
self.max_iter = self.settings_dict.get("max_iter", 200)
self.zoom = 1.0
def on_show_view(self): def on_show_view(self):
super().on_show_view() super().on_show_view()
self.shader_program, self.mandelbrot_image = create_mandelbrot_shader(self.window.width, self.window.height, self.settings_dict.get("precision", "Single").lower())
self.mandelbrot_sprite = pyglet.sprite.Sprite(img=self.mandelbrot_image)
self.create_image()
self.pypresence_client.update(state='Viewing Mandelbrot', details=f'Zoom: {self.zoom}\nMax Iterations: {self.max_iter}', start=self.pypresence_client.start_time)
self.setup_ui()
def main_exit(self):
from menus.main import Main
self.window.show_view(Main(self.pypresence_client))
def setup_ui(self):
self.anchor = self.add_widget(arcade.gui.UIAnchorLayout(size_hint=(1, 1))) self.anchor = self.add_widget(arcade.gui.UIAnchorLayout(size_hint=(1, 1)))
self.info_box = self.anchor.add(arcade.gui.UIBoxLayout(space_between=10, vertical=False), anchor_x="center", anchor_y="top") self.grid = self.add_widget(arcade.gui.UIGridLayout(row_count=3, column_count=3, horizontal_spacing=10, vertical_spacing=10))
self.zoom_label = self.info_box.add(arcade.gui.UILabel(text=f"Zoom: {self.zoom}", font_name="Protest Strike", font_size=16)) self.anchor.add(self.grid, anchor_x="center", anchor_y="center")
self.max_iter_label = self.info_box.add(arcade.gui.UILabel(text=f"Max Iterations: {self.max_iter}", font_name="Protest Strike", font_size=16))
self.title_label = self.anchor.add(arcade.gui.UILabel(text="Choose a fractal to view.", font_name="Protest Strike", font_size=32), anchor_x="center", anchor_y="top", align_y=-50)
self.back_button = arcade.gui.UITextureButton(texture=button_texture, texture_hovered=button_hovered_texture, text='<--', style=button_style, width=100, height=50) self.back_button = arcade.gui.UITextureButton(texture=button_texture, texture_hovered=button_hovered_texture, text='<--', style=button_style, width=100, height=50)
self.back_button.on_click = lambda event: self.main_exit() self.back_button.on_click = lambda event: self.main_exit()
self.anchor.add(self.back_button, anchor_x="left", anchor_y="top", align_x=5, align_y=-5) self.anchor.add(self.back_button, anchor_x="left", anchor_y="top", align_x=5, align_y=-5)
def zoom_at(self, center_x, center_y, zoom_factor): self.mandelbrot_button = self.grid.add(arcade.gui.UITextureButton(texture=button_texture, texture_hovered=button_hovered_texture, text='Mandelbrot', style=button_style, width=200, height=200), row=0, column=0)
center_real = self.real_min + (center_x / self.width) * (self.real_max - self.real_min) self.mandelbrot_button.on_click = lambda event: self.mandelbrot()
center_imag = self.imag_min + (center_y / self.height) * (self.imag_max - self.imag_min)
new_real_range = (self.real_max - self.real_min) / zoom_factor self.sierpinsky_carpet_button = self.grid.add(arcade.gui.UITextureButton(texture=button_texture, texture_hovered=button_hovered_texture, text='Sierpinsky Carpet', style=button_style, width=200, height=200), row=0, column=1)
new_imag_range = (self.imag_max - self.imag_min) / zoom_factor self.sierpinsky_carpet_button.on_click = lambda event: self.sierpinsky_carpet()
self.real_min = center_real - new_real_range / 2 def main_exit(self):
self.real_max = center_real + new_real_range / 2 from menus.main import Main
self.imag_min = center_imag - new_imag_range / 2 self.window.show_view(Main(self.pypresence_client))
self.imag_max = center_imag + new_imag_range / 2
def create_image(self): def mandelbrot(self):
with self.shader_program: from game.mandelbrot import MandelbrotViewer
self.shader_program['u_maxIter'] = self.max_iter self.window.show_view(MandelbrotViewer(self.pypresence_client))
self.shader_program['u_resolution'] = (self.window.width, self.window.height)
self.shader_program['u_real_range'] = (self.real_min, self.real_max)
self.shader_program['u_imag_range'] = (self.imag_min, self.imag_max)
self.shader_program.dispatch(self.mandelbrot_image.width, self.mandelbrot_image.height, 1, barrier=pyglet.gl.GL_ALL_BARRIER_BITS)
def on_mouse_press(self, x: int, y: int, button: int, modifiers: int) -> bool | None: def sierpinsky_carpet(self):
super().on_mouse_press(x, y, button, modifiers) from game.sierpinsky_carpet import SierpinskyCarpetViewer
self.window.show_view(SierpinskyCarpetViewer(self.pypresence_client))
if button == arcade.MOUSE_BUTTON_LEFT:
zoom = self.settings_dict.get("zoom_increase", 2)
elif button == arcade.MOUSE_BUTTON_RIGHT:
zoom = 1 / self.settings_dict.get("zoom_increase", 2)
else:
return
self.zoom *= zoom
self.zoom_label.text = f"Zoom: {self.zoom}"
self.zoom_at(self.window.mouse.data["x"], self.window.mouse.data["y"], zoom)
self.create_image()
self.pypresence_client.update(state='Viewing Mandelbrot', details=f'Zoom: {self.zoom}\nMax Iterations: {self.max_iter}', start=self.pypresence_client.start_time)
def on_draw(self):
self.window.clear()
self.mandelbrot_sprite.draw()
self.ui.draw()

View File

@@ -50,6 +50,43 @@ void main() {
} }
""" """
sierpinsky_carpet_compute_source = """#version 430 core
uniform int u_depth;
uniform int u_zoom;
layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(location = 0, rgba32f) uniform image2D img_output;
void main() {
ivec2 coord = ivec2(gl_GlobalInvocationID.xy);
bool isHole = false;
for (int i = 0; i < u_depth; ++i) {
if (coord.x % 3 == 1 && coord.y % 3 == 1) {
isHole = true;
break;
}
coord /= 3;
}
vec4 color = isHole ? vec4(0, 0, 0, 1) : vec4(1, 1, 1, 1);
imageStore(img_output, ivec2(gl_GlobalInvocationID.xy), color);
}
"""
def create_sierpinsky_carpet_shader(width, height, precision="single"):
shader_source = sierpinsky_carpet_compute_source
shader_program = pyglet.graphics.shader.ComputeShaderProgram(shader_source)
sierpinsky_carpet_image = pyglet.image.Texture.create(width, height, internalformat=pyglet.gl.GL_RGBA32F)
uniform_location = shader_program['img_output']
sierpinsky_carpet_image.bind_image_texture(unit=uniform_location)
return shader_program, sierpinsky_carpet_image
def create_mandelbrot_shader(width, height, precision="single"): def create_mandelbrot_shader(width, height, precision="single"):
shader_source = mandelbrot_compute_source shader_source = mandelbrot_compute_source

81
game/sierpinsky_carpet.py Normal file
View File

@@ -0,0 +1,81 @@
import arcade, arcade.gui, pyglet, json
from PIL import Image
from game.shader import create_sierpinsky_carpet_shader
from utils.constants import menu_background_color, button_style
from utils.preload import button_texture, button_hovered_texture
class SierpinskyCarpetViewer(arcade.gui.UIView):
def __init__(self, pypresence_client):
super().__init__()
self.pypresence_client = pypresence_client
with open("settings.json", "r") as file:
self.settings_dict = json.load(file)
self.depth = self.settings_dict.get("sierpinsky_depth", 10)
self.zoom = 1.0
self.click_center = (self.width / 2, self.height / 2)
def on_show_view(self):
super().on_show_view()
self.shader_program, self.sierpinsky_carpet_image = create_sierpinsky_carpet_shader(self.window.width, self.window.height, self.settings_dict.get("precision", "Single").lower())
self.sierpinsky_carpet_sprite = pyglet.sprite.Sprite(img=self.sierpinsky_carpet_image)
self.create_image()
self.pypresence_client.update(state='Viewing Sierpinsky Carpet', details=f'Zoom: {self.zoom}\nDepth: {self.depth}', start=self.pypresence_client.start_time)
self.setup_ui()
def main_exit(self):
from menus.main import Main
self.window.show_view(Main(self.pypresence_client))
def setup_ui(self):
self.anchor = self.add_widget(arcade.gui.UIAnchorLayout(size_hint=(1, 1)))
self.info_box = self.anchor.add(arcade.gui.UIBoxLayout(space_between=10, vertical=False), anchor_x="center", anchor_y="top")
self.zoom_label = self.info_box.add(arcade.gui.UILabel(text=f"Zoom: {self.zoom}", font_name="Protest Strike", font_size=16))
self.depth_label = self.info_box.add(arcade.gui.UILabel(text=f"Depth: {self.depth}", font_name="Protest Strike", font_size=16))
self.back_button = arcade.gui.UITextureButton(texture=button_texture, texture_hovered=button_hovered_texture, text='<--', style=button_style, width=100, height=50)
self.back_button.on_click = lambda event: self.main_exit()
self.anchor.add(self.back_button, anchor_x="left", anchor_y="top", align_x=5, align_y=-5)
def create_image(self):
with self.shader_program:
self.shader_program['u_depth'] = self.depth
#self.shader_program['u_zoom'] = int(self.zoom)
#self.shader_program['u_resolution'] = self.window.size
#self.shader_program['u_center'] = self.click_center
self.shader_program.dispatch(self.sierpinsky_carpet_image.width, self.sierpinsky_carpet_image.height, 1, barrier=pyglet.gl.GL_ALL_BARRIER_BITS)
def on_mouse_press(self, x: int, y: int, button: int, modifiers: int) -> bool | None:
super().on_mouse_press(x, y, button, modifiers)
if button == arcade.MOUSE_BUTTON_LEFT:
zoom = self.settings_dict.get("sierpinsky_zoom_increase", 2)
elif button == arcade.MOUSE_BUTTON_RIGHT:
zoom = 1 / self.settings_dict.get("sierpinsky_zoom_increase", 2)
else:
return
self.zoom *= zoom
self.click_center = (x, y)
self.zoom_label.text = f"Zoom: {self.zoom}"
self.create_image()
self.pypresence_client.update(state='Viewing Sierpinsky Carpet', details=f'Zoom: {self.zoom}\nMax Iterations: {self.depth}', start=self.pypresence_client.start_time)
def on_draw(self):
self.window.clear()
self.sierpinsky_carpet_sprite.draw()
self.ui.draw()

View File

@@ -1,4 +1,5 @@
import arcade, arcade.gui, asyncio, pypresence, time, copy, json import arcade, arcade.gui, asyncio, pypresence, time, copy, json
from game.play import FractalChooser
from utils.preload import button_texture, button_hovered_texture from utils.preload import button_texture, button_hovered_texture
from utils.constants import big_button_style, discord_presence_id from utils.constants import big_button_style, discord_presence_id
from utils.utils import FakePyPresence from utils.utils import FakePyPresence
@@ -50,7 +51,7 @@ class Main(arcade.gui.UIView):
def on_show_view(self): def on_show_view(self):
super().on_show_view() super().on_show_view()
self.title_label = self.box.add(arcade.gui.UILabel(text="Mandelbrot Viewer", font_name="Protest Strike", font_size=48)) self.title_label = self.box.add(arcade.gui.UILabel(text="Fractal Viewer", font_name="Protest Strike", font_size=48))
self.play_button = self.box.add(arcade.gui.UITextureButton(text="Play", texture=button_texture, texture_hovered=button_hovered_texture, width=self.window.width / 2, height=150, style=big_button_style)) self.play_button = self.box.add(arcade.gui.UITextureButton(text="Play", texture=button_texture, texture_hovered=button_hovered_texture, width=self.window.width / 2, height=150, style=big_button_style))
self.play_button.on_click = lambda event: self.play() self.play_button.on_click = lambda event: self.play()
@@ -59,8 +60,8 @@ class Main(arcade.gui.UIView):
self.settings_button.on_click = lambda event: self.settings() self.settings_button.on_click = lambda event: self.settings()
def play(self): def play(self):
from game.play import Game from game.play import FractalChooser
self.window.show_view(Game(self.pypresence_client)) self.window.show_view(FractalChooser(self.pypresence_client))
def settings(self): def settings(self):
from menus.settings import Settings from menus.settings import Settings

View File

@@ -1,10 +1,10 @@
[project] [project]
name = "MandelbrotViewer" name = "FractalViewer"
version = "0.1.0" version = "0.1.0"
description = "Mandelbrot viewer in Python using compute shaders and the Arcade and Pyglet modules." description = "Fractal viewer in Python using compute shaders and the Arcade and Pyglet modules."
readme = "README.md" readme = "README.md"
requires-python = ">=3.11" requires-python = ">=3.11"
dependencies = ["arcade", "pypresence>=4.3.0"] dependencies = [
"arcade==3.2.0",
[tool.uv.sources] "pypresence>=4.3.0",
arcade = { git = "https://github.com/pythonarcade/arcade.git", rev = "development" } ]

View File

@@ -1,3 +1,3 @@
Pillow Pillow
git+https://github.com/pythonarcade/arcade.git@development arcade==3.2.0
pypresence pypresence

2
run.py
View File

@@ -64,7 +64,7 @@ else:
with open("settings.json", "w") as file: with open("settings.json", "w") as file:
file.write(json.dumps(settings)) file.write(json.dumps(settings))
window = arcade.Window(width=resolution[0], height=resolution[1], title='Mandelbrot Viewer', samples=antialiasing, antialiasing=antialiasing > 0, fullscreen=fullscreen, vsync=vsync, resizable=False, style=style) window = arcade.Window(width=resolution[0], height=resolution[1], title='Fractal Viewer', samples=antialiasing, antialiasing=antialiasing > 0, fullscreen=fullscreen, vsync=vsync, resizable=False, style=style)
if vsync: if vsync:
window.set_vsync(True) window.set_vsync(True)

View File

@@ -27,9 +27,13 @@ slider_style = {'normal': slider_default_style, 'hover': slider_hover_style, 'pr
settings = { settings = {
"Mandelbrot": { "Mandelbrot": {
"Float Precision": {"type": "option", "options": ["Single", "Double"], "config_key": "precision", "default": "Single"}, "Float Precision": {"type": "option", "options": ["Single", "Double"], "config_key": "mandelbrot_precision", "default": "Single"},
"Zoom Increase Per Click": {"type": "slider", "min": 2, "max": 100, "config_key": "zoom_increase", "default": 2}, "Zoom Increase Per Click": {"type": "slider", "min": 2, "max": 100, "config_key": "mandelbrot_zoom_increase", "default": 2},
"Max Iterations": {"type": "slider", "min": 100, "max": 10000, "config_key": "max_iter", "default": 200} "Max Iterations": {"type": "slider", "min": 100, "max": 10000, "config_key": "mandelbrot_max_iter", "default": 200}
},
"Sierpinsky Carpet": {
"Zoom Increase Per Click": {"type": "slider", "min": 2, "max": 100, "config_key": "sierpinsky_zoom_increase", "default": 2},
"Depth": {"type": "slider", "min": 2, "max": 10000, "config_key": "sierpinsky_depth", "default": 10}
}, },
"Graphics": { "Graphics": {
"Window Mode": {"type": "option", "options": ["Windowed", "Fullscreen", "Borderless"], "config_key": "window_mode", "default": "Windowed"}, "Window Mode": {"type": "option", "options": ["Windowed", "Fullscreen", "Borderless"], "config_key": "window_mode", "default": "Windowed"},

View File

@@ -52,7 +52,7 @@ class ErrorView(arcade.gui.UIView):
def on_show_view(self): def on_show_view(self):
super().on_show_view() super().on_show_view()
self.window.set_caption('Mandelbrot Viewer - Error') self.window.set_caption('Fractal Viewer - Error')
self.window.set_mouse_visible(True) self.window.set_mouse_visible(True)
self.window.set_exclusive_mouse(False) self.window.set_exclusive_mouse(False)
arcade.set_background_color(menu_background_color) arcade.set_background_color(menu_background_color)

12
uv.lock generated
View File

@@ -4,14 +4,18 @@ requires-python = ">=3.11"
[[package]] [[package]]
name = "arcade" name = "arcade"
version = "3.1.0" version = "3.2.0"
source = { git = "https://github.com/pythonarcade/arcade.git?rev=development#a17e95502bc0c7cd0527445e62bff84a49183c43" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "pillow" }, { name = "pillow" },
{ name = "pyglet" }, { name = "pyglet" },
{ name = "pymunk" }, { name = "pymunk" },
{ name = "pytiled-parser" }, { name = "pytiled-parser" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/e5/39/87eaffdfc50ec9d4b4573652ef8b80cca0592e5ccafb5fc5bc8612b1445d/arcade-3.2.0.tar.gz", hash = "sha256:1c2c56181560665f6542157b9ab316b9551274a9ee8468bae017ed5b8fee18fd", size = 41941030, upload_time = "2025-05-09T20:16:20.112Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/40/9a/ac86f5cbccfe5455a28308fcf2d7179af8d9c3087ad4eb45706c2a7b089b/arcade-3.2.0-py3-none-any.whl", hash = "sha256:7bb47cf643b43272e4300d8a5ca5f1b1e9e131b0f3f1d3fad013cb29528d3062", size = 42635264, upload_time = "2025-05-09T20:16:15.98Z" },
]
[[package]] [[package]]
name = "attrs" name = "attrs"
@@ -68,7 +72,7 @@ wheels = [
] ]
[[package]] [[package]]
name = "mandelbrotviewer" name = "fractalviewer"
version = "0.1.0" version = "0.1.0"
source = { virtual = "." } source = { virtual = "." }
dependencies = [ dependencies = [
@@ -78,7 +82,7 @@ dependencies = [
[package.metadata] [package.metadata]
requires-dist = [ requires-dist = [
{ name = "arcade", git = "https://github.com/pythonarcade/arcade.git?rev=development" }, { name = "arcade", specifier = "==3.2.0" },
{ name = "pypresence", specifier = ">=4.3.0" }, { name = "pypresence", specifier = ">=4.3.0" },
] ]