Move GUI to Source folder to avoid conflicts
This commit is contained in:
1
source/__init__.py
Normal file
1
source/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
# do nothing, just exist to make "source" package
|
||||
347
source/classes/SpriteSelector.py
Normal file
347
source/classes/SpriteSelector.py
Normal file
@@ -0,0 +1,347 @@
|
||||
from tkinter import filedialog, messagebox, Button, Canvas, Label, LabelFrame, Frame, PhotoImage, Scrollbar, Toplevel, ALL, NSEW, LEFT, BOTTOM, X, RIGHT, TOP, HORIZONTAL, EW, NS
|
||||
from glob import glob
|
||||
import json
|
||||
import os
|
||||
import random
|
||||
import shutil
|
||||
from urllib.parse import urlparse
|
||||
from urllib.request import urlopen
|
||||
import webbrowser
|
||||
from GuiUtils import ToolTips, set_icon, BackgroundTaskProgress
|
||||
from Rom import Sprite
|
||||
from Utils import is_bundled, local_path, output_path, open_file
|
||||
|
||||
|
||||
class SpriteSelector(object):
|
||||
def __init__(self, parent, callback, adjuster=False):
|
||||
if is_bundled():
|
||||
self.deploy_icons()
|
||||
self.parent = parent
|
||||
self.window = Toplevel(parent)
|
||||
self.window.geometry("800x650")
|
||||
self.sections = []
|
||||
self.callback = callback
|
||||
self.adjuster = adjuster
|
||||
|
||||
self.window.wm_title("TAKE ANY ONE YOU WANT")
|
||||
self.window['padx'] = 5
|
||||
self.window['pady'] = 5
|
||||
self.all_sprites = []
|
||||
|
||||
def open_official_sprite_listing(_evt):
|
||||
webbrowser.open("http://alttpr.com/sprite_preview")
|
||||
|
||||
def open_unofficial_sprite_dir(_evt):
|
||||
open_file(self.unofficial_sprite_dir)
|
||||
|
||||
def open_spritesomething_listing(_evt):
|
||||
webbrowser.open("https://artheau.github.io/SpriteSomething/?mode=zelda3/link")
|
||||
|
||||
official_frametitle = Frame(self.window)
|
||||
official_title_text = Label(official_frametitle, text="Official Sprites")
|
||||
official_title_link = Label(official_frametitle, text="(open)", fg="blue", cursor="hand2")
|
||||
official_title_text.pack(side=LEFT)
|
||||
official_title_link.pack(side=LEFT)
|
||||
official_title_link.bind("<Button-1>", open_official_sprite_listing)
|
||||
|
||||
unofficial_frametitle = Frame(self.window)
|
||||
unofficial_title_text = Label(unofficial_frametitle, text="Unofficial Sprites")
|
||||
unofficial_title_link = Label(unofficial_frametitle, text="(open)", fg="blue", cursor="hand2")
|
||||
unofficial_title_text.pack(side=LEFT)
|
||||
unofficial_title_link.pack(side=LEFT)
|
||||
unofficial_title_link.bind("<Button-1>", open_unofficial_sprite_dir)
|
||||
spritesomething_title_link = Label(unofficial_frametitle, text="(SpriteSomething)", fg="blue", cursor="hand2")
|
||||
spritesomething_title_link.pack(side=LEFT)
|
||||
spritesomething_title_link.bind("<Button-1>", open_spritesomething_listing)
|
||||
|
||||
self.icon_section(official_frametitle, self.official_sprite_dir+'/*', 'Official sprites not found. Click "Update official sprites" to download them.')
|
||||
self.icon_section(unofficial_frametitle, self.unofficial_sprite_dir+'/*', 'Put sprites in the unofficial sprites folder (see open link above) to have them appear here.')
|
||||
|
||||
frame = Frame(self.window)
|
||||
frame.pack(side=BOTTOM, fill=X, pady=5)
|
||||
|
||||
button = Button(frame, text="Browse for file...", command=self.browse_for_sprite)
|
||||
button.pack(side=RIGHT, padx=(5, 0))
|
||||
|
||||
button = Button(frame, text="Update official sprites", command=self.update_official_sprites)
|
||||
button.pack(side=RIGHT, padx=(5, 0))
|
||||
|
||||
button = Button(frame, text="Default Link sprite", command=self.use_default_link_sprite)
|
||||
button.pack(side=LEFT, padx=(0, 5))
|
||||
|
||||
button = Button(frame, text="Random sprite", command=self.use_random_sprite)
|
||||
button.pack(side=LEFT, padx=(0, 5))
|
||||
|
||||
if adjuster:
|
||||
button = Button(frame, text="Current sprite from rom", command=self.use_default_sprite)
|
||||
button.pack(side=LEFT, padx=(0, 5))
|
||||
|
||||
set_icon(self.window)
|
||||
self.window.focus()
|
||||
|
||||
def icon_section(self, frame_label, path, no_results_label):
|
||||
frame = LabelFrame(self.window, labelwidget=frame_label, padx=5, pady=5)
|
||||
canvas = Canvas(frame, borderwidth=0)
|
||||
y_scrollbar = Scrollbar(frame, orient="vertical", command=canvas.yview)
|
||||
y_scrollbar.pack(side="right", fill="y")
|
||||
content_frame = Frame(canvas)
|
||||
canvas.pack(side="left", fill="both", expand=True)
|
||||
canvas.create_window((4, 4), window=content_frame, anchor="nw")
|
||||
canvas.configure(yscrollcommand=y_scrollbar.set)
|
||||
|
||||
def onFrameConfigure(canvas):
|
||||
"""Reset the scroll region to encompass the inner frame"""
|
||||
canvas.configure(scrollregion=canvas.bbox("all"))
|
||||
|
||||
content_frame.bind("<Configure>", lambda event, canvas=canvas: onFrameConfigure(canvas))
|
||||
frame.pack(side=TOP, fill=X)
|
||||
|
||||
sprites = []
|
||||
|
||||
for file in glob(output_path(path)):
|
||||
sprites.append(Sprite(file))
|
||||
|
||||
sprites.sort(key=lambda s: str.lower(s.name or "").strip())
|
||||
|
||||
i = 0
|
||||
for sprite in sprites:
|
||||
image = get_image_for_sprite(sprite)
|
||||
if image is None:
|
||||
continue
|
||||
self.all_sprites.append(sprite)
|
||||
button = Button(content_frame, image=image, command=lambda spr=sprite: self.select_sprite(spr))
|
||||
ToolTips.register(button, sprite.name + ("\nBy: %s" % sprite.author_name if sprite.author_name else ""))
|
||||
button.image = image
|
||||
button.grid(row=i // 16, column=i % 16)
|
||||
i += 1
|
||||
|
||||
if i == 0:
|
||||
label = Label(content_frame, text=no_results_label)
|
||||
label.pack()
|
||||
|
||||
def update_official_sprites(self):
|
||||
# need to wrap in try catch. We don't want errors getting the json or downloading the files to break us.
|
||||
self.window.destroy()
|
||||
self.parent.update()
|
||||
def work(task):
|
||||
resultmessage = ""
|
||||
successful = True
|
||||
|
||||
def finished():
|
||||
task.close_window()
|
||||
if successful:
|
||||
messagebox.showinfo("Sprite Updater", resultmessage)
|
||||
else:
|
||||
messagebox.showerror("Sprite Updater", resultmessage)
|
||||
SpriteSelector(self.parent, self.callback, self.adjuster)
|
||||
|
||||
try:
|
||||
task.update_status("Downloading official sprites list")
|
||||
with urlopen('https://alttpr.com/sprites') as response:
|
||||
sprites_arr = json.loads(response.read().decode("utf-8"))
|
||||
except Exception as e:
|
||||
resultmessage = "Error getting list of official sprites. Sprites not updated.\n\n%s: %s" % (type(e).__name__, e)
|
||||
successful = False
|
||||
task.queue_event(finished)
|
||||
return
|
||||
|
||||
try:
|
||||
task.update_status("Determining needed sprites")
|
||||
current_sprites = [os.path.basename(file) for file in glob(self.official_sprite_dir+'/*')]
|
||||
official_sprites = [(sprite['file'], os.path.basename(urlparse(sprite['file']).path)) for sprite in sprites_arr]
|
||||
needed_sprites = [(sprite_url, filename) for (sprite_url, filename) in official_sprites if filename not in current_sprites]
|
||||
bundled_sprites = [os.path.basename(file) for file in glob(self.local_official_sprite_dir+'/*')]
|
||||
# todo: eventually use the above list to avoid downloading any sprites that we already have cached in the bundle.
|
||||
|
||||
official_filenames = [filename for (_, filename) in official_sprites]
|
||||
obsolete_sprites = [sprite for sprite in current_sprites if sprite not in official_filenames]
|
||||
except Exception as e:
|
||||
resultmessage = "Error Determining which sprites to update. Sprites not updated.\n\n%s: %s" % (type(e).__name__, e)
|
||||
successful = False
|
||||
task.queue_event(finished)
|
||||
return
|
||||
|
||||
updated = 0
|
||||
for (sprite_url, filename) in needed_sprites:
|
||||
try:
|
||||
task.update_status("Downloading needed sprite %g/%g" % (updated + 1, len(needed_sprites)))
|
||||
target = os.path.join(self.official_sprite_dir, filename)
|
||||
with urlopen(sprite_url) as response, open(target, 'wb') as out:
|
||||
shutil.copyfileobj(response, out)
|
||||
except Exception as e:
|
||||
resultmessage = "Error downloading sprite. Not all sprites updated.\n\n%s: %s" % (type(e).__name__, e)
|
||||
successful = False
|
||||
updated += 1
|
||||
|
||||
deleted = 0
|
||||
for sprite in obsolete_sprites:
|
||||
try:
|
||||
task.update_status("Removing obsolete sprite %g/%g" % (deleted + 1, len(obsolete_sprites)))
|
||||
os.remove(os.path.join(self.official_sprite_dir, sprite))
|
||||
except Exception as e:
|
||||
resultmessage = "Error removing obsolete sprite. Not all sprites updated.\n\n%s: %s" % (type(e).__name__, e)
|
||||
successful = False
|
||||
deleted += 1
|
||||
|
||||
if successful:
|
||||
resultmessage = "official sprites updated successfully"
|
||||
|
||||
task.queue_event(finished)
|
||||
|
||||
BackgroundTaskProgress(self.parent, work, "Updating Sprites")
|
||||
|
||||
def browse_for_sprite(self):
|
||||
sprite = filedialog.askopenfilename(
|
||||
filetypes=[("All Sprite Sources", (".zspr", ".spr", ".sfc", ".smc")),
|
||||
("ZSprite files", ".zspr"),
|
||||
("Sprite files", ".spr"),
|
||||
("Rom Files", (".sfc", ".smc")),
|
||||
("All Files", "*")])
|
||||
try:
|
||||
self.callback(Sprite(sprite))
|
||||
except Exception:
|
||||
self.callback(None)
|
||||
self.window.destroy()
|
||||
|
||||
def use_default_sprite(self):
|
||||
self.callback(None, False)
|
||||
self.window.destroy()
|
||||
|
||||
def use_default_link_sprite(self):
|
||||
self.callback(Sprite.default_link_sprite(), False)
|
||||
self.window.destroy()
|
||||
|
||||
def use_random_sprite(self):
|
||||
self.callback(random.choice(self.all_sprites) if self.all_sprites else None, True)
|
||||
self.window.destroy()
|
||||
|
||||
def select_sprite(self, spritename):
|
||||
self.callback(spritename, False)
|
||||
self.window.destroy()
|
||||
|
||||
def deploy_icons(self):
|
||||
if not os.path.exists(self.unofficial_sprite_dir):
|
||||
os.makedirs(self.unofficial_sprite_dir)
|
||||
if not os.path.exists(self.official_sprite_dir):
|
||||
shutil.copytree(self.local_official_sprite_dir, self.official_sprite_dir)
|
||||
|
||||
@property
|
||||
def official_sprite_dir(self):
|
||||
if is_bundled():
|
||||
return output_path("sprites/official")
|
||||
return self.local_official_sprite_dir
|
||||
|
||||
@property
|
||||
def local_official_sprite_dir(self):
|
||||
return local_path("data/sprites/official")
|
||||
|
||||
@property
|
||||
def unofficial_sprite_dir(self):
|
||||
if is_bundled():
|
||||
return output_path("sprites/unofficial")
|
||||
return self.local_unofficial_sprite_dir
|
||||
|
||||
@property
|
||||
def local_unofficial_sprite_dir(self):
|
||||
return local_path("data/sprites/unofficial")
|
||||
|
||||
|
||||
def get_image_for_sprite(sprite):
|
||||
if not sprite.valid:
|
||||
return None
|
||||
height = 24
|
||||
width = 16
|
||||
|
||||
def draw_sprite_into_gif(add_palette_color, set_pixel_color_index):
|
||||
|
||||
def drawsprite(spr, pal_as_colors, offset):
|
||||
for y, row in enumerate(spr):
|
||||
for x, pal_index in enumerate(row):
|
||||
if pal_index:
|
||||
color = pal_as_colors[pal_index - 1]
|
||||
set_pixel_color_index(x + offset[0], y + offset[1], color)
|
||||
|
||||
add_palette_color(16, (40, 40, 40))
|
||||
shadow = [
|
||||
[0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0],
|
||||
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
|
||||
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
|
||||
[0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0],
|
||||
]
|
||||
|
||||
drawsprite(shadow, [16], (2, 17))
|
||||
|
||||
palettes = sprite.decode_palette()
|
||||
for i in range(15):
|
||||
add_palette_color(i + 1, palettes[0][i])
|
||||
|
||||
body = sprite.decode16(0x4C0)
|
||||
drawsprite(body, list(range(1, 16)), (0, 8))
|
||||
head = sprite.decode16(0x40)
|
||||
drawsprite(head, list(range(1, 16)), (0, 0))
|
||||
|
||||
def make_gif(callback):
|
||||
gif_header = b'GIF89a'
|
||||
|
||||
gif_lsd = bytearray(7)
|
||||
gif_lsd[0] = width
|
||||
gif_lsd[2] = height
|
||||
gif_lsd[4] = 0xF4 # 32 color palette follows. transparant + 15 for sprite + 1 for shadow=17 which rounds up to 32 as nearest power of 2
|
||||
gif_lsd[5] = 0 # background color is zero
|
||||
gif_lsd[6] = 0 # aspect raio not specified
|
||||
gif_gct = bytearray(3 * 32)
|
||||
|
||||
gif_gce = bytearray(8)
|
||||
gif_gce[0] = 0x21 # start of extention blocked
|
||||
gif_gce[1] = 0xF9 # identifies this as the Graphics Control extension
|
||||
gif_gce[2] = 4 # we are suppling only the 4 four bytes
|
||||
gif_gce[3] = 0x01 # this gif includes transparency
|
||||
gif_gce[4] = gif_gce[5] = 0 # animation frrame delay (unused)
|
||||
gif_gce[6] = 0 # transparent color is index 0
|
||||
gif_gce[7] = 0 # end of gif_gce
|
||||
gif_id = bytearray(10)
|
||||
gif_id[0] = 0x2c
|
||||
# byte 1,2 are image left. 3,4 are image top both are left as zerosuitsamus
|
||||
gif_id[5] = width
|
||||
gif_id[7] = height
|
||||
gif_id[9] = 0 # no local color table
|
||||
|
||||
gif_img_minimum_code_size = bytes([7]) # we choose 7 bits, so that each pixel is represented by a byte, for conviennce.
|
||||
|
||||
clear = 0x80
|
||||
stop = 0x81
|
||||
|
||||
unchunked_image_data = bytearray(height * (width + 1) + 1)
|
||||
# we technically need a Clear code once every 125 bytes, but we do it at the start of every row for simplicity
|
||||
for row in range(height):
|
||||
unchunked_image_data[row * (width + 1)] = clear
|
||||
unchunked_image_data[-1] = stop
|
||||
|
||||
def add_palette_color(index, color):
|
||||
gif_gct[3 * index] = color[0]
|
||||
gif_gct[3 * index + 1] = color[1]
|
||||
gif_gct[3 * index + 2] = color[2]
|
||||
|
||||
def set_pixel_color_index(x, y, color):
|
||||
unchunked_image_data[y * (width + 1) + x + 1] = color
|
||||
|
||||
callback(add_palette_color, set_pixel_color_index)
|
||||
|
||||
def chunk_image(img):
|
||||
for i in range(0, len(img), 255):
|
||||
chunk = img[i:i + 255]
|
||||
yield bytes([len(chunk)])
|
||||
yield chunk
|
||||
|
||||
gif_img = b''.join([gif_img_minimum_code_size] + list(chunk_image(unchunked_image_data)) + [b'\x00'])
|
||||
|
||||
gif = b''.join([gif_header, gif_lsd, gif_gct, gif_gce, gif_id, gif_img, b'\x3b'])
|
||||
|
||||
return gif
|
||||
|
||||
gif_data = make_gif(draw_sprite_into_gif)
|
||||
image = PhotoImage(data=gif_data)
|
||||
|
||||
return image.zoom(2)
|
||||
1
source/classes/__init__.py
Normal file
1
source/classes/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
# do nothing, just exist to make "source.classes" package
|
||||
108
source/classes/constants.py
Normal file
108
source/classes/constants.py
Normal file
@@ -0,0 +1,108 @@
|
||||
CUSTOMITEMS = [
|
||||
"bow", "progressivebow", "boomerang", "redmerang", "hookshot",
|
||||
"mushroom", "powder", "firerod", "icerod", "bombos",
|
||||
"ether", "quake", "lamp", "hammer", "shovel",
|
||||
|
||||
"flute", "bugnet", "book", "bottle", "somaria",
|
||||
"byrna", "cape", "mirror", "boots", "powerglove",
|
||||
"titansmitt", "progressiveglove", "flippers", "pearl", "heartpiece",
|
||||
|
||||
"heartcontainer", "sancheart", "sword1", "sword2", "sword3",
|
||||
"sword4", "progressivesword", "shield1", "shield2", "shield3",
|
||||
"progressiveshield", "mail2", "mail3", "progressivemail", "halfmagic",
|
||||
|
||||
"quartermagic", "bombsplus5", "bombsplus10", "arrowsplus5", "arrowsplus10",
|
||||
"arrow1", "arrow10", "bomb1", "bomb3", "bomb10",
|
||||
"rupee1", "rupee5", "rupee20", "rupee50", "rupee100",
|
||||
|
||||
"rupee300", "blueclock", "greenclock", "redclock", "silversupgrade",
|
||||
"generickeys", "triforcepieces", "triforcepiecesgoal", "triforce", "rupoor",
|
||||
"rupoorcost"
|
||||
]
|
||||
|
||||
CANTSTARTWITH = [
|
||||
"triforcepiecesgoal", "triforce", "rupoor",
|
||||
"rupoorcost"
|
||||
]
|
||||
|
||||
CUSTOMITEMLABELS = [
|
||||
"Bow", "Progressive Bow", "Blue Boomerang", "Red Boomerang", "Hookshot",
|
||||
"Mushroom", "Magic Powder", "Fire Rod", "Ice Rod", "Bombos",
|
||||
"Ether", "Quake", "Lamp", "Hammer", "Shovel",
|
||||
|
||||
"Ocarina", "Bug Catching Net", "Book of Mudora", "Bottle", "Cane of Somaria",
|
||||
"Cane of Byrna", "Magic Cape", "Magic Mirror", "Pegasus Boots", "Power Glove",
|
||||
"Titans Mitts", "Progressive Glove", "Flippers", "Moon Pearl", "Piece of Heart",
|
||||
|
||||
"Boss Heart Container", "Sanctuary Heart Container", "Fighter Sword", "Master Sword", "Tempered Sword",
|
||||
"Golden Sword", "Progressive Sword", "Blue Shield", "Red Shield", "Mirror Shield",
|
||||
"Progressive Shield", "Blue Mail", "Red Mail", "Progressive Armor", "Magic Upgrade (1/2)",
|
||||
|
||||
"Magic Upgrade (1/4)", "Bomb Upgrade (+5)", "Bomb Upgrade (+10)", "Arrow Upgrade (+5)", "Arrow Upgrade (+10)",
|
||||
"Single Arrow", "Arrows (10)", "Single Bomb", "Bombs (3)", "Bombs (10)",
|
||||
"Rupee (1)", "Rupees (5)", "Rupees (20)", "Rupees (50)", "Rupees (100)",
|
||||
|
||||
"Rupees (300)", "Blue Clock", "Green Clock", "Red Clock", "Silver Arrows",
|
||||
"Small Key (Universal)", "Triforce Piece", "Triforce Piece Goal", "Triforce", "Rupoor",
|
||||
"Rupoor Cost"
|
||||
]
|
||||
|
||||
SETTINGSTOPROCESS = {
|
||||
"randomizer": {
|
||||
"item": {
|
||||
"retro": "retro",
|
||||
"worldstate": "mode",
|
||||
"logiclevel": "logic",
|
||||
"goal": "goal",
|
||||
"crystals_gt": "crystals_gt",
|
||||
"crystals_ganon": "crystals_ganon",
|
||||
"weapons": "swords",
|
||||
"itempool": "difficulty",
|
||||
"itemfunction": "item_functionality",
|
||||
"timer": "timer",
|
||||
"progressives": "progressive",
|
||||
"accessibility": "accessibility",
|
||||
"sortingalgo": "algorithm"
|
||||
},
|
||||
"entrance": {
|
||||
"openpyramid": "openpyramid",
|
||||
"shuffleganon": "shuffleganon",
|
||||
"entranceshuffle": "shuffle"
|
||||
},
|
||||
"enemizer": {
|
||||
"potshuffle": "shufflepots",
|
||||
"enemyshuffle": "shuffleenemies",
|
||||
"bossshuffle": "shufflebosses",
|
||||
"enemydamage": "enemy_damage",
|
||||
"enemyhealth": "enemy_health"
|
||||
},
|
||||
"dungeon": {
|
||||
"mapshuffle": "mapshuffle",
|
||||
"compassshuffle": "compassshuffle",
|
||||
"smallkeyshuffle": "keyshuffle",
|
||||
"bigkeyshuffle": "bigkeyshuffle",
|
||||
"dungeondoorshuffle": "door_shuffle",
|
||||
"experimental": "experimental",
|
||||
"dungeon_counters": "dungeon_counters"
|
||||
},
|
||||
"multiworld": {
|
||||
"names": "names"
|
||||
},
|
||||
"gameoptions": {
|
||||
"hints": "hints",
|
||||
"nobgm": "disablemusic",
|
||||
"quickswap": "quickswap",
|
||||
"heartcolor": "heartcolor",
|
||||
"heartbeep": "heartbeep",
|
||||
"menuspeed": "fastmenu",
|
||||
"owpalettes": "ow_palettes",
|
||||
"uwpalettes": "uw_palettes"
|
||||
},
|
||||
"generation": {
|
||||
"spoiler": "create_spoiler",
|
||||
"suppressrom": "suppress_rom",
|
||||
"usestartinventory": "usestartinventory",
|
||||
"usecustompool": "custom"
|
||||
}
|
||||
}
|
||||
}
|
||||
1
source/gui/__init__.py
Normal file
1
source/gui/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
# do nothing, just exist to make "source.gui" package
|
||||
1
source/gui/about/__init__.py
Normal file
1
source/gui/about/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
# do nothing, just exist to make "source.gui.about" package
|
||||
1
source/gui/adjust/__init__.py
Normal file
1
source/gui/adjust/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
# do nothing, just exist to make "source.gui.adjust" package
|
||||
113
source/gui/adjust/overview.py
Normal file
113
source/gui/adjust/overview.py
Normal file
@@ -0,0 +1,113 @@
|
||||
from tkinter import ttk, filedialog, messagebox, IntVar, StringVar, Button, Checkbutton, Entry, Frame, Label, OptionMenu, E, W, LEFT, RIGHT, X, BOTTOM
|
||||
from AdjusterMain import adjust
|
||||
from argparse import Namespace
|
||||
from source.classes.SpriteSelector import SpriteSelector
|
||||
import source.gui.widgets as widgets
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
|
||||
def adjust_page(top, parent, settings):
|
||||
# Adjust page
|
||||
self = ttk.Frame(parent)
|
||||
|
||||
# Adjust options
|
||||
self.widgets = {}
|
||||
|
||||
# Adjust option sections
|
||||
self.frames = {}
|
||||
self.frames["checkboxes"] = Frame(self)
|
||||
self.frames["checkboxes"].pack(anchor=W)
|
||||
|
||||
self.frames["selectOptionsFrame"] = Frame(self)
|
||||
self.frames["leftAdjustFrame"] = Frame(self.frames["selectOptionsFrame"])
|
||||
self.frames["rightAdjustFrame"] = Frame(self.frames["selectOptionsFrame"])
|
||||
self.frames["bottomAdjustFrame"] = Frame(self)
|
||||
self.frames["selectOptionsFrame"].pack(fill=X)
|
||||
self.frames["leftAdjustFrame"].pack(side=LEFT)
|
||||
self.frames["rightAdjustFrame"].pack(side=RIGHT)
|
||||
self.frames["bottomAdjustFrame"].pack(fill=X)
|
||||
|
||||
with open(os.path.join("resources","app","gui","adjust","overview","widgets.json")) as widgetDefns:
|
||||
myDict = json.load(widgetDefns)
|
||||
for framename,theseWidgets in myDict.items():
|
||||
dictWidgets = widgets.make_widgets_from_dict(self, theseWidgets, self.frames[framename])
|
||||
for key in dictWidgets:
|
||||
self.widgets[key] = dictWidgets[key]
|
||||
packAttrs = {"anchor":E}
|
||||
if self.widgets[key].type == "checkbox":
|
||||
packAttrs["anchor"] = W
|
||||
self.widgets[key].pack(packAttrs)
|
||||
|
||||
# Sprite Selection
|
||||
self.spriteNameVar2 = StringVar()
|
||||
spriteDialogFrame2 = Frame(self.frames["leftAdjustFrame"])
|
||||
baseSpriteLabel2 = Label(spriteDialogFrame2, text='Sprite:')
|
||||
spriteEntry2 = Label(spriteDialogFrame2, textvariable=self.spriteNameVar2)
|
||||
self.sprite = None
|
||||
|
||||
def set_sprite(sprite_param, random_sprite=False):
|
||||
if sprite_param is None or not sprite_param.valid:
|
||||
self.sprite = None
|
||||
self.spriteNameVar2.set('(unchanged)')
|
||||
else:
|
||||
self.sprite = sprite_param
|
||||
self.spriteNameVar2.set(self.sprite.name)
|
||||
top.randomSprite.set(random_sprite)
|
||||
|
||||
def SpriteSelectAdjuster():
|
||||
SpriteSelector(parent, set_sprite, adjuster=True)
|
||||
|
||||
spriteSelectButton2 = Button(spriteDialogFrame2, text='...', command=SpriteSelectAdjuster)
|
||||
|
||||
baseSpriteLabel2.pack(side=LEFT)
|
||||
spriteEntry2.pack(side=LEFT)
|
||||
spriteSelectButton2.pack(side=LEFT)
|
||||
spriteDialogFrame2.pack(anchor=E)
|
||||
|
||||
adjustRomFrame = Frame(self.frames["bottomAdjustFrame"])
|
||||
adjustRomLabel = Label(adjustRomFrame, text='Rom to adjust: ')
|
||||
self.romVar2 = StringVar(value=settings["rom"])
|
||||
romEntry2 = Entry(adjustRomFrame, textvariable=self.romVar2)
|
||||
|
||||
def RomSelect2():
|
||||
rom = filedialog.askopenfilename(filetypes=[("Rom Files", (".sfc", ".smc")), ("All Files", "*")])
|
||||
if rom:
|
||||
settings["rom"] = rom
|
||||
self.romVar2.set(rom)
|
||||
romSelectButton2 = Button(adjustRomFrame, text='Select Rom', command=RomSelect2)
|
||||
|
||||
adjustRomLabel.pack(side=LEFT)
|
||||
romEntry2.pack(side=LEFT, fill=X, expand=True)
|
||||
romSelectButton2.pack(side=LEFT)
|
||||
adjustRomFrame.pack(fill=X)
|
||||
|
||||
def adjustRom():
|
||||
options = {
|
||||
"heartbeep": "heartbeep",
|
||||
"heartcolor": "heartcolor",
|
||||
"menuspeed": "fastmenu",
|
||||
"owpalettes": "ow_palettes",
|
||||
"uwpalettes": "uw_palettes",
|
||||
"quickswap": "quickswap",
|
||||
"nobgm": "disablemusic"
|
||||
}
|
||||
guiargs = Namespace()
|
||||
for option in options:
|
||||
arg = options[option]
|
||||
setattr(guiargs, arg, self.widgets[option].storageVar.get())
|
||||
guiargs.rom = self.romVar2.get()
|
||||
guiargs.baserom = top.pages["randomizer"].pages["generation"].romVar.get()
|
||||
guiargs.sprite = self.sprite
|
||||
try:
|
||||
adjust(args=guiargs)
|
||||
except Exception as e:
|
||||
logging.exception(e)
|
||||
messagebox.showerror(title="Error while creating seed", message=str(e))
|
||||
else:
|
||||
messagebox.showinfo(title="Success", message="Rom patched successfully")
|
||||
|
||||
adjustButton = Button(self.frames["bottomAdjustFrame"], text='Adjust Rom', command=adjustRom)
|
||||
adjustButton.pack(side=BOTTOM, padx=(5, 0))
|
||||
|
||||
return self,settings
|
||||
147
source/gui/bottom.py
Normal file
147
source/gui/bottom.py
Normal file
@@ -0,0 +1,147 @@
|
||||
from tkinter import ttk, messagebox, StringVar, Button, Entry, Frame, Label, Spinbox, E, W, LEFT, RIGHT, X
|
||||
from argparse import Namespace
|
||||
from functools import partial
|
||||
import logging
|
||||
import os
|
||||
import random
|
||||
from CLI import parse_arguments, get_settings
|
||||
from Main import main
|
||||
from Utils import local_path, output_path, open_file
|
||||
import source.classes.constants as CONST
|
||||
import source.gui.widgets as widgets
|
||||
|
||||
|
||||
def bottom_frame(self, parent, args=None):
|
||||
# Bottom Frame
|
||||
self = ttk.Frame(parent)
|
||||
|
||||
# Bottom Frame options
|
||||
self.widgets = {}
|
||||
|
||||
seedCountFrame = Frame(self)
|
||||
seedCountFrame.pack()
|
||||
## Seed #
|
||||
seedLabel = Label(self, text='Seed #')
|
||||
savedSeed = parent.settings["seed"]
|
||||
self.seedVar = StringVar(value=savedSeed)
|
||||
def saveSeed(caller,_,mode):
|
||||
savedSeed = self.seedVar.get()
|
||||
parent.settings["seed"] = int(savedSeed) if savedSeed.isdigit() else None
|
||||
self.seedVar.trace_add("write",saveSeed)
|
||||
seedEntry = Entry(self, width=15, textvariable=self.seedVar)
|
||||
seedLabel.pack(side=LEFT)
|
||||
seedEntry.pack(side=LEFT)
|
||||
|
||||
## Number of Generation attempts
|
||||
key = "generationcount"
|
||||
self.widgets[key] = widgets.make_widget(
|
||||
self,
|
||||
"spinbox",
|
||||
self,
|
||||
"Count",
|
||||
None,
|
||||
None,
|
||||
{"label": {"side": LEFT}, "spinbox": {"side": RIGHT}}
|
||||
)
|
||||
self.widgets[key].pack(side=LEFT)
|
||||
|
||||
def generateRom():
|
||||
guiargs = create_guiargs(parent)
|
||||
# get default values for missing parameters
|
||||
for k,v in vars(parse_arguments(['--multi', str(guiargs.multi)])).items():
|
||||
if k not in vars(guiargs):
|
||||
setattr(guiargs, k, v)
|
||||
elif type(v) is dict: # use same settings for every player
|
||||
setattr(guiargs, k, {player: getattr(guiargs, k) for player in range(1, guiargs.multi + 1)})
|
||||
try:
|
||||
if guiargs.count is not None:
|
||||
seed = guiargs.seed
|
||||
for _ in range(guiargs.count):
|
||||
main(seed=seed, args=guiargs)
|
||||
seed = random.randint(0, 999999999)
|
||||
else:
|
||||
main(seed=guiargs.seed, args=guiargs)
|
||||
except Exception as e:
|
||||
logging.exception(e)
|
||||
messagebox.showerror(title="Error while creating seed", message=str(e))
|
||||
else:
|
||||
messagebox.showinfo(title="Success", message="Rom patched successfully")
|
||||
|
||||
## Generate Button
|
||||
generateButton = Button(self, text='Generate Patched Rom', command=generateRom)
|
||||
generateButton.pack(side=LEFT)
|
||||
|
||||
def open_output():
|
||||
if args and args.outputpath:
|
||||
open_file(output_path(args.outputpath))
|
||||
else:
|
||||
open_file(output_path(parent.settings["outputpath"]))
|
||||
|
||||
openOutputButton = Button(self, text='Open Output Directory', command=open_output)
|
||||
openOutputButton.pack(side=RIGHT)
|
||||
|
||||
## Documentation Button
|
||||
if os.path.exists(local_path('README.html')):
|
||||
def open_readme():
|
||||
open_file(local_path('README.html'))
|
||||
openReadmeButton = Button(self, text='Open Documentation', command=open_readme)
|
||||
openReadmeButton.pack(side=RIGHT)
|
||||
|
||||
return self
|
||||
|
||||
|
||||
def create_guiargs(parent):
|
||||
guiargs = Namespace()
|
||||
|
||||
# set up settings to gather
|
||||
# Page::Subpage::GUI-id::param-id
|
||||
options = CONST.SETTINGSTOPROCESS
|
||||
|
||||
for mainpage in options:
|
||||
for subpage in options[mainpage]:
|
||||
for widget in options[mainpage][subpage]:
|
||||
arg = options[mainpage][subpage][widget]
|
||||
setattr(guiargs, arg, parent.pages[mainpage].pages[subpage].widgets[widget].storageVar.get())
|
||||
|
||||
guiargs.enemizercli = parent.pages["randomizer"].pages["enemizer"].enemizerCLIpathVar.get()
|
||||
|
||||
guiargs.multi = int(parent.pages["randomizer"].pages["multiworld"].widgets["worlds"].storageVar.get())
|
||||
|
||||
guiargs.rom = parent.pages["randomizer"].pages["generation"].romVar.get()
|
||||
guiargs.custom = bool(parent.pages["randomizer"].pages["generation"].widgets["usecustompool"].storageVar.get())
|
||||
|
||||
guiargs.seed = int(parent.frames["bottom"].seedVar.get()) if parent.frames["bottom"].seedVar.get() else None
|
||||
guiargs.count = int(parent.frames["bottom"].widgets["generationcount"].storageVar.get()) if parent.frames["bottom"].widgets["generationcount"].storageVar.get() != '1' else None
|
||||
|
||||
adjustargs = {
|
||||
"nobgm": "disablemusic",
|
||||
"quickswap": "quickswap",
|
||||
"heartcolor": "heartcolor",
|
||||
"heartbeep": "heartbeep",
|
||||
"menuspeed": "fastmenu",
|
||||
"owpalettes": "ow_palettes",
|
||||
"uwpalettes": "uw_palettes"
|
||||
}
|
||||
for adjustarg in adjustargs:
|
||||
internal = adjustargs[adjustarg]
|
||||
setattr(guiargs,"adjust." + internal, parent.pages["adjust"].content.widgets[adjustarg].storageVar.get())
|
||||
|
||||
customitems = CONST.CUSTOMITEMS
|
||||
guiargs.startinventory = []
|
||||
guiargs.customitemarray = {}
|
||||
guiargs.startinventoryarray = {}
|
||||
for customitem in customitems:
|
||||
if customitem not in ["triforcepiecesgoal", "triforce", "rupoor", "rupoorcost"]:
|
||||
amount = int(parent.pages["startinventory"].content.startingWidgets[customitem].storageVar.get())
|
||||
guiargs.startinventoryarray[customitem] = amount
|
||||
for i in range(0, amount):
|
||||
label = CONST.CUSTOMITEMLABELS[customitems.index(customitem)]
|
||||
guiargs.startinventory.append(label)
|
||||
guiargs.customitemarray[customitem] = int(parent.pages["custom"].content.customWidgets[customitem].storageVar.get())
|
||||
|
||||
guiargs.startinventory = ','.join(guiargs.startinventory)
|
||||
|
||||
guiargs.sprite = parent.pages["randomizer"].pages["gameoptions"].widgets["sprite"]["spriteObject"]
|
||||
guiargs.randomSprite = parent.randomSprite.get()
|
||||
guiargs.outputpath = parent.outputPath.get()
|
||||
return guiargs
|
||||
1
source/gui/custom/__init__.py
Normal file
1
source/gui/custom/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
# do nothing, just exist to make "source.gui.custom" package
|
||||
54
source/gui/custom/overview.py
Normal file
54
source/gui/custom/overview.py
Normal file
@@ -0,0 +1,54 @@
|
||||
from tkinter import ttk, StringVar, Entry, Frame, Label, N, E, W, LEFT, RIGHT, X, VERTICAL, Y
|
||||
import source.gui.widgets as widgets
|
||||
import json
|
||||
import os
|
||||
|
||||
import source.classes.constants as CONST
|
||||
|
||||
def custom_page(top,parent):
|
||||
# Custom Item Pool
|
||||
self = ttk.Frame(parent)
|
||||
|
||||
def create_list_frame(parent, framename):
|
||||
parent.frames[framename] = Frame(parent)
|
||||
parent.frames[framename].pack(side=LEFT, padx=(0,0), anchor=N)
|
||||
parent.frames[framename].thisRow = 0
|
||||
parent.frames[framename].thisCol = 0
|
||||
|
||||
def create_vertical_rule(num=1):
|
||||
for i in range(0,num):
|
||||
ttk.Separator(self, orient=VERTICAL).pack(side=LEFT, anchor=N, fill=Y)
|
||||
|
||||
def validation(P):
|
||||
if str.isdigit(P) or P == "":
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
vcmd=(self.register(validation), '%P')
|
||||
|
||||
# Custom Item Pool options
|
||||
self.customWidgets = {}
|
||||
|
||||
# Custom Item Pool option sections
|
||||
self.frames = {}
|
||||
create_list_frame(self,"itemList1")
|
||||
create_vertical_rule(2)
|
||||
create_list_frame(self,"itemList2")
|
||||
create_vertical_rule(2)
|
||||
create_list_frame(self,"itemList3")
|
||||
create_vertical_rule(2)
|
||||
create_list_frame(self,"itemList4")
|
||||
create_vertical_rule(2)
|
||||
create_list_frame(self,"itemList5")
|
||||
|
||||
with open(os.path.join("resources","app","gui","custom","overview","widgets.json")) as widgetDefns:
|
||||
myDict = json.load(widgetDefns)
|
||||
for framename,theseWidgets in myDict.items():
|
||||
dictWidgets = widgets.make_widgets_from_dict(self, theseWidgets, self.frames[framename])
|
||||
for key in dictWidgets:
|
||||
self.customWidgets[key] = dictWidgets[key]
|
||||
|
||||
for key in CONST.CUSTOMITEMS:
|
||||
self.customWidgets[key].storageVar.set(top.settings["customitemarray"][key])
|
||||
|
||||
return self
|
||||
76
source/gui/loadcliargs.py
Normal file
76
source/gui/loadcliargs.py
Normal file
@@ -0,0 +1,76 @@
|
||||
from source.classes.SpriteSelector import SpriteSelector as spriteSelector
|
||||
from source.gui.randomize.gameoptions import set_sprite
|
||||
from Rom import Sprite
|
||||
import source.classes.constants as CONST
|
||||
|
||||
def loadcliargs(gui, args, settings=None):
|
||||
if args is not None:
|
||||
# for k, v in vars(args).items():
|
||||
# if type(v) is dict:
|
||||
# setattr(args, k, v[1]) # only get values for player 1 for now
|
||||
# load values from commandline args
|
||||
|
||||
# set up options to get
|
||||
# Page::Subpage::GUI-id::param-id
|
||||
options = CONST.SETTINGSTOPROCESS
|
||||
|
||||
for mainpage in options:
|
||||
for subpage in options[mainpage]:
|
||||
for widget in options[mainpage][subpage]:
|
||||
arg = options[mainpage][subpage][widget]
|
||||
gui.pages[mainpage].pages[subpage].widgets[widget].storageVar.set(args[arg])
|
||||
if subpage == "gameoptions" and not widget == "hints":
|
||||
hasSettings = settings is not None
|
||||
hasWidget = ("adjust." + widget) in settings if hasSettings else None
|
||||
if hasWidget is None:
|
||||
gui.pages["adjust"].content.widgets[widget].storageVar.set(args[arg])
|
||||
|
||||
gui.pages["randomizer"].pages["enemizer"].enemizerCLIpathVar.set(args["enemizercli"])
|
||||
gui.pages["randomizer"].pages["generation"].romVar.set(args["rom"])
|
||||
|
||||
if args["multi"]:
|
||||
gui.pages["randomizer"].pages["multiworld"].widgets["worlds"].storageVar.set(str(args["multi"]))
|
||||
if args["seed"]:
|
||||
gui.frames["bottom"].seedVar.set(str(args["seed"]))
|
||||
if args["count"]:
|
||||
gui.frames["bottom"].widgets["generationcount"].storageVar.set(str(args["count"]))
|
||||
gui.outputPath.set(args["outputpath"])
|
||||
|
||||
def sprite_setter(spriteObject):
|
||||
gui.pages["randomizer"].pages["gameoptions"].widgets["sprite"]["spriteObject"] = spriteObject
|
||||
if args["sprite"] is not None:
|
||||
sprite_obj = args.sprite if isinstance(args["sprite"], Sprite) else Sprite(args["sprite"])
|
||||
r_sprite_flag = args.randomSprite if hasattr(args, 'randomSprite') else False
|
||||
set_sprite(sprite_obj, r_sprite_flag, spriteSetter=sprite_setter,
|
||||
spriteNameVar=gui.pages["randomizer"].pages["gameoptions"].widgets["sprite"]["spriteNameVar"],
|
||||
randomSpriteVar=gui.randomSprite)
|
||||
|
||||
def sprite_setter_adj(spriteObject):
|
||||
gui.pages["adjust"].content.sprite = spriteObject
|
||||
if args["sprite"] is not None:
|
||||
sprite_obj = args.sprite if isinstance(args.sprite, Sprite) else Sprite(args.sprite)
|
||||
r_sprite_flag = args["randomSprite"] if hasattr(args, 'randomSprite') else False
|
||||
set_sprite(sprite_obj, r_sprite_flag, spriteSetter=sprite_setter_adj,
|
||||
spriteNameVar=gui.pages["adjust"].content.spriteNameVar2,
|
||||
randomSpriteVar=gui.randomSprite)
|
||||
|
||||
def loadadjustargs(gui, settings):
|
||||
options = {
|
||||
"adjust": {
|
||||
"content": {
|
||||
"nobgm": "adjust.nobgm",
|
||||
"quickswap": "adjust.quickswap",
|
||||
"heartcolor": "adjust.heartcolor",
|
||||
"heartbeep": "adjust.heartbeep",
|
||||
"menuspeed": "adjust.menuspeed",
|
||||
"owpalettes": "adjust.owpalettes",
|
||||
"uwpalettes": "adjust.uwpalettes"
|
||||
}
|
||||
}
|
||||
}
|
||||
for mainpage in options:
|
||||
for subpage in options[mainpage]:
|
||||
for widget in options[mainpage][subpage]:
|
||||
key = options[mainpage][subpage][widget]
|
||||
if key in settings:
|
||||
gui.pages[mainpage].content.widgets[widget].storageVar.set(settings[key])
|
||||
1
source/gui/randomize/__init__.py
Normal file
1
source/gui/randomize/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
# do nothing, just exist to make "source.gui.randomize" package
|
||||
38
source/gui/randomize/dungeon.py
Normal file
38
source/gui/randomize/dungeon.py
Normal file
@@ -0,0 +1,38 @@
|
||||
from tkinter import ttk, IntVar, StringVar, Checkbutton, Frame, Label, OptionMenu, E, W, LEFT, RIGHT
|
||||
import source.gui.widgets as widgets
|
||||
import json
|
||||
import os
|
||||
|
||||
def dungeon_page(parent):
|
||||
# Dungeon Shuffle
|
||||
self = ttk.Frame(parent)
|
||||
|
||||
# Dungeon Shuffle options
|
||||
self.widgets = {}
|
||||
|
||||
# Dungeon Shuffle option sections
|
||||
self.frames = {}
|
||||
self.frames["keysanity"] = Frame(self)
|
||||
self.frames["keysanity"].pack(anchor=W)
|
||||
|
||||
## Dungeon Item Shuffle
|
||||
mscbLabel = Label(self.frames["keysanity"], text="Shuffle: ")
|
||||
mscbLabel.pack(side=LEFT)
|
||||
|
||||
with open(os.path.join("resources","app","gui","randomize","dungeon","keysanity.json")) as keysanityItems:
|
||||
myDict = json.load(keysanityItems)
|
||||
dictWidgets = widgets.make_widgets_from_dict(self, myDict, self.frames["keysanity"])
|
||||
for key in dictWidgets:
|
||||
self.widgets[key] = dictWidgets[key]
|
||||
self.widgets[key].pack(side=LEFT)
|
||||
|
||||
self.frames["widgets"] = Frame(self)
|
||||
self.frames["widgets"].pack(anchor=W)
|
||||
with open(os.path.join("resources","app","gui","randomize","dungeon","widgets.json")) as dungeonWidgets:
|
||||
myDict = json.load(dungeonWidgets)
|
||||
dictWidgets = widgets.make_widgets_from_dict(self, myDict, self.frames["widgets"])
|
||||
for key in dictWidgets:
|
||||
self.widgets[key] = dictWidgets[key]
|
||||
self.widgets[key].pack(anchor=W)
|
||||
|
||||
return self
|
||||
63
source/gui/randomize/enemizer.py
Normal file
63
source/gui/randomize/enemizer.py
Normal file
@@ -0,0 +1,63 @@
|
||||
import os
|
||||
from tkinter import ttk, filedialog, IntVar, StringVar, Button, Checkbutton, Entry, Frame, Label, LabelFrame, OptionMenu, N, E, W, LEFT, RIGHT, BOTTOM, X
|
||||
import source.gui.widgets as widgets
|
||||
import json
|
||||
import os
|
||||
import webbrowser
|
||||
|
||||
def enemizer_page(parent,settings):
|
||||
def open_enemizer_download(_evt):
|
||||
webbrowser.open("https://github.com/Bonta0/Enemizer/releases")
|
||||
|
||||
# Enemizer
|
||||
self = ttk.Frame(parent)
|
||||
|
||||
# Enemizer options
|
||||
self.widgets = {}
|
||||
|
||||
# Enemizer option sections
|
||||
self.frames = {}
|
||||
|
||||
self.frames["checkboxes"] = Frame(self)
|
||||
self.frames["checkboxes"].pack(anchor=W)
|
||||
|
||||
self.frames["selectOptionsFrame"] = Frame(self)
|
||||
self.frames["leftEnemizerFrame"] = Frame(self.frames["selectOptionsFrame"])
|
||||
self.frames["rightEnemizerFrame"] = Frame(self.frames["selectOptionsFrame"])
|
||||
self.frames["bottomEnemizerFrame"] = Frame(self)
|
||||
self.frames["selectOptionsFrame"].pack(fill=X)
|
||||
self.frames["leftEnemizerFrame"].pack(side=LEFT)
|
||||
self.frames["rightEnemizerFrame"].pack(side=RIGHT)
|
||||
self.frames["bottomEnemizerFrame"].pack(fill=X)
|
||||
|
||||
with open(os.path.join("resources","app","gui","randomize","enemizer","widgets.json")) as widgetDefns:
|
||||
myDict = json.load(widgetDefns)
|
||||
for framename,theseWidgets in myDict.items():
|
||||
dictWidgets = widgets.make_widgets_from_dict(self, theseWidgets, self.frames[framename])
|
||||
for key in dictWidgets:
|
||||
self.widgets[key] = dictWidgets[key]
|
||||
packAttrs = {"anchor":E}
|
||||
if self.widgets[key].type == "checkbox":
|
||||
packAttrs["anchor"] = W
|
||||
self.widgets[key].pack(packAttrs)
|
||||
|
||||
## Enemizer CLI Path
|
||||
enemizerPathFrame = Frame(self.frames["bottomEnemizerFrame"])
|
||||
enemizerCLIlabel = Label(enemizerPathFrame, text="EnemizerCLI path: ")
|
||||
enemizerCLIlabel.pack(side=LEFT)
|
||||
enemizerURL = Label(enemizerPathFrame, text="(get online)", fg="blue", cursor="hand2")
|
||||
enemizerURL.pack(side=LEFT)
|
||||
enemizerURL.bind("<Button-1>", open_enemizer_download)
|
||||
self.enemizerCLIpathVar = StringVar(value=settings["enemizercli"])
|
||||
enemizerCLIpathEntry = Entry(enemizerPathFrame, textvariable=self.enemizerCLIpathVar)
|
||||
enemizerCLIpathEntry.pack(side=LEFT, fill=X, expand=True)
|
||||
def EnemizerSelectPath():
|
||||
path = filedialog.askopenfilename(filetypes=[("EnemizerCLI executable", "*EnemizerCLI*")], initialdir=os.path.join("."))
|
||||
if path:
|
||||
self.enemizerCLIpathVar.set(path)
|
||||
settings["enemizercli"] = path
|
||||
enemizerCLIbrowseButton = Button(enemizerPathFrame, text='...', command=EnemizerSelectPath)
|
||||
enemizerCLIbrowseButton.pack(side=LEFT)
|
||||
enemizerPathFrame.pack(fill=X)
|
||||
|
||||
return self,settings
|
||||
29
source/gui/randomize/entrando.py
Normal file
29
source/gui/randomize/entrando.py
Normal file
@@ -0,0 +1,29 @@
|
||||
from tkinter import ttk, IntVar, StringVar, Checkbutton, Frame, Label, OptionMenu, E, W, LEFT, RIGHT
|
||||
import source.gui.widgets as widgets
|
||||
import json
|
||||
import os
|
||||
|
||||
def entrando_page(parent):
|
||||
# Entrance Randomizer
|
||||
self = ttk.Frame(parent)
|
||||
|
||||
# Entrance Randomizer options
|
||||
self.widgets = {}
|
||||
|
||||
# Entrance Randomizer option sections
|
||||
self.frames = {}
|
||||
self.frames["widgets"] = Frame(self)
|
||||
self.frames["widgets"].pack(anchor=W)
|
||||
|
||||
with open(os.path.join("resources","app","gui","randomize","entrando","widgets.json")) as widgetDefns:
|
||||
myDict = json.load(widgetDefns)
|
||||
for framename,theseWidgets in myDict.items():
|
||||
dictWidgets = widgets.make_widgets_from_dict(self, theseWidgets, self.frames[framename])
|
||||
for key in dictWidgets:
|
||||
self.widgets[key] = dictWidgets[key]
|
||||
packAttrs = {"anchor":E}
|
||||
if self.widgets[key].type == "checkbox":
|
||||
packAttrs["anchor"] = W
|
||||
self.widgets[key].pack(packAttrs)
|
||||
|
||||
return self
|
||||
78
source/gui/randomize/gameoptions.py
Normal file
78
source/gui/randomize/gameoptions.py
Normal file
@@ -0,0 +1,78 @@
|
||||
from tkinter import ttk, IntVar, StringVar, Button, Checkbutton, Entry, Frame, Label, OptionMenu, E, W, LEFT, RIGHT
|
||||
from functools import partial
|
||||
import source.classes.SpriteSelector as spriteSelector
|
||||
import source.gui.widgets as widgets
|
||||
import json
|
||||
import os
|
||||
|
||||
def gameoptions_page(top, parent):
|
||||
# Game Options
|
||||
self = ttk.Frame(parent)
|
||||
|
||||
# Game Options options
|
||||
self.widgets = {}
|
||||
|
||||
# Game Options option sections
|
||||
self.frames = {}
|
||||
self.frames["checkboxes"] = Frame(self)
|
||||
self.frames["checkboxes"].pack(anchor=W)
|
||||
|
||||
self.frames["leftRomOptionsFrame"] = Frame(self)
|
||||
self.frames["rightRomOptionsFrame"] = Frame(self)
|
||||
self.frames["leftRomOptionsFrame"].pack(side=LEFT)
|
||||
self.frames["rightRomOptionsFrame"].pack(side=RIGHT)
|
||||
|
||||
with open(os.path.join("resources","app","gui","randomize","gameoptions","widgets.json")) as widgetDefns:
|
||||
myDict = json.load(widgetDefns)
|
||||
for framename,theseWidgets in myDict.items():
|
||||
dictWidgets = widgets.make_widgets_from_dict(self, theseWidgets, self.frames[framename])
|
||||
for key in dictWidgets:
|
||||
self.widgets[key] = dictWidgets[key]
|
||||
packAttrs = {"anchor":E}
|
||||
if self.widgets[key].type == "checkbox":
|
||||
packAttrs["anchor"] = W
|
||||
self.widgets[key].pack(packAttrs)
|
||||
|
||||
## Sprite selection
|
||||
spriteDialogFrame = Frame(self.frames["leftRomOptionsFrame"])
|
||||
baseSpriteLabel = Label(spriteDialogFrame, text='Sprite:')
|
||||
|
||||
self.widgets["sprite"] = {}
|
||||
self.widgets["sprite"]["spriteObject"] = None
|
||||
self.widgets["sprite"]["spriteNameVar"] = StringVar()
|
||||
|
||||
self.widgets["sprite"]["spriteNameVar"].set('(unchanged)')
|
||||
spriteEntry = Label(spriteDialogFrame, textvariable=self.widgets["sprite"]["spriteNameVar"])
|
||||
|
||||
def sprite_setter(spriteObject):
|
||||
self.widgets["sprite"]["spriteObject"] = spriteObject
|
||||
|
||||
def sprite_select():
|
||||
spriteSelector.SpriteSelector(parent, partial(set_sprite, spriteSetter=sprite_setter,
|
||||
spriteNameVar=self.widgets["sprite"]["spriteNameVar"],
|
||||
randomSpriteVar=top.randomSprite))
|
||||
|
||||
spriteSelectButton = Button(spriteDialogFrame, text='...', command=sprite_select)
|
||||
|
||||
baseSpriteLabel.pack(side=LEFT)
|
||||
spriteEntry.pack(side=LEFT)
|
||||
spriteSelectButton.pack(side=LEFT)
|
||||
spriteDialogFrame.pack(anchor=E)
|
||||
|
||||
return self
|
||||
|
||||
|
||||
def set_sprite(sprite_param, random_sprite=False, spriteSetter=None, spriteNameVar=None, randomSpriteVar=None):
|
||||
if sprite_param is None or not sprite_param.valid:
|
||||
if spriteSetter:
|
||||
spriteSetter(None)
|
||||
if spriteNameVar is not None:
|
||||
spriteNameVar.set('(unchanged)')
|
||||
else:
|
||||
if spriteSetter:
|
||||
spriteSetter(sprite_param)
|
||||
if spriteNameVar is not None:
|
||||
spriteNameVar.set(sprite_param.name)
|
||||
if randomSpriteVar:
|
||||
randomSpriteVar.set(random_sprite)
|
||||
|
||||
45
source/gui/randomize/generation.py
Normal file
45
source/gui/randomize/generation.py
Normal file
@@ -0,0 +1,45 @@
|
||||
import os
|
||||
from tkinter import ttk, filedialog, IntVar, StringVar, Button, Checkbutton, Entry, Frame, Label, E, W, LEFT, RIGHT, X
|
||||
import source.gui.widgets as widgets
|
||||
import json
|
||||
import os
|
||||
|
||||
def generation_page(parent,settings):
|
||||
# Generation Setup
|
||||
self = ttk.Frame(parent)
|
||||
|
||||
# Generation Setup options
|
||||
self.widgets = {}
|
||||
|
||||
# Generation Setup option sections
|
||||
self.frames = {}
|
||||
self.frames["checkboxes"] = Frame(self)
|
||||
self.frames["checkboxes"].pack(anchor=W)
|
||||
|
||||
with open(os.path.join("resources","app","gui","randomize","generation","checkboxes.json")) as checkboxes:
|
||||
myDict = json.load(checkboxes)
|
||||
dictWidgets = widgets.make_widgets_from_dict(self, myDict, self.frames["checkboxes"])
|
||||
for key in dictWidgets:
|
||||
self.widgets[key] = dictWidgets[key]
|
||||
self.widgets[key].pack(anchor=W)
|
||||
|
||||
self.frames["baserom"] = Frame(self)
|
||||
self.frames["baserom"].pack(anchor=W, fill=X)
|
||||
## Locate base ROM
|
||||
baseRomFrame = Frame(self.frames["baserom"])
|
||||
baseRomLabel = Label(baseRomFrame, text='Base Rom: ')
|
||||
self.romVar = StringVar()
|
||||
romEntry = Entry(baseRomFrame, textvariable=self.romVar)
|
||||
self.romVar.set(settings["rom"])
|
||||
|
||||
def RomSelect():
|
||||
rom = filedialog.askopenfilename(filetypes=[("Rom Files", (".sfc", ".smc")), ("All Files", "*")], initialdir=os.path.join("."))
|
||||
self.romVar.set(rom)
|
||||
romSelectButton = Button(baseRomFrame, text='Select Rom', command=RomSelect)
|
||||
|
||||
baseRomLabel.pack(side=LEFT)
|
||||
romEntry.pack(side=LEFT, fill=X, expand=True)
|
||||
romSelectButton.pack(side=LEFT)
|
||||
baseRomFrame.pack(fill=X)
|
||||
|
||||
return self,settings
|
||||
35
source/gui/randomize/item.py
Normal file
35
source/gui/randomize/item.py
Normal file
@@ -0,0 +1,35 @@
|
||||
from tkinter import ttk, IntVar, StringVar, Checkbutton, Frame, Label, OptionMenu, E, W, LEFT, RIGHT
|
||||
import source.gui.widgets as widgets
|
||||
import json
|
||||
import os
|
||||
|
||||
def item_page(parent):
|
||||
# Item Randomizer
|
||||
self = ttk.Frame(parent)
|
||||
|
||||
# Item Randomizer options
|
||||
self.widgets = {}
|
||||
|
||||
# Item Randomizer option sections
|
||||
self.frames = {}
|
||||
|
||||
self.frames["checkboxes"] = Frame(self)
|
||||
self.frames["checkboxes"].pack(anchor=W)
|
||||
|
||||
self.frames["leftItemFrame"] = Frame(self)
|
||||
self.frames["rightItemFrame"] = Frame(self)
|
||||
self.frames["leftItemFrame"].pack(side=LEFT)
|
||||
self.frames["rightItemFrame"].pack(side=RIGHT)
|
||||
|
||||
with open(os.path.join("resources","app","gui","randomize","item","widgets.json")) as widgetDefns:
|
||||
myDict = json.load(widgetDefns)
|
||||
for framename,theseWidgets in myDict.items():
|
||||
dictWidgets = widgets.make_widgets_from_dict(self, theseWidgets, self.frames[framename])
|
||||
for key in dictWidgets:
|
||||
self.widgets[key] = dictWidgets[key]
|
||||
packAttrs = {"anchor":E}
|
||||
if self.widgets[key].type == "checkbox":
|
||||
packAttrs["anchor"] = W
|
||||
self.widgets[key].pack(packAttrs)
|
||||
|
||||
return self
|
||||
38
source/gui/randomize/multiworld.py
Normal file
38
source/gui/randomize/multiworld.py
Normal file
@@ -0,0 +1,38 @@
|
||||
from tkinter import ttk, StringVar, Entry, Frame, Label, Spinbox, N, E, W, X, LEFT, RIGHT
|
||||
import source.gui.widgets as widgets
|
||||
import json
|
||||
import os
|
||||
|
||||
def multiworld_page(parent,settings):
|
||||
# Multiworld
|
||||
self = ttk.Frame(parent)
|
||||
|
||||
# Multiworld options
|
||||
self.widgets = {}
|
||||
|
||||
# Multiworld option sections
|
||||
self.frames = {}
|
||||
self.frames["widgets"] = Frame(self)
|
||||
self.frames["widgets"].pack(anchor=W, fill=X)
|
||||
|
||||
with open(os.path.join("resources","app","gui","randomize","multiworld","widgets.json")) as multiworldItems:
|
||||
myDict = json.load(multiworldItems)
|
||||
dictWidgets = widgets.make_widgets_from_dict(self, myDict, self.frames["widgets"])
|
||||
for key in dictWidgets:
|
||||
self.widgets[key] = dictWidgets[key]
|
||||
self.widgets[key].pack(side=LEFT, anchor=N)
|
||||
|
||||
## List of Player Names
|
||||
key = "names"
|
||||
self.widgets[key] = Frame(self.frames["widgets"])
|
||||
self.widgets[key].label = Label(self.widgets[key], text='Player names')
|
||||
self.widgets[key].storageVar = StringVar(value=settings["names"])
|
||||
def saveMultiNames(caller,_,mode):
|
||||
settings["names"] = self.widgets[key].storageVar.get()
|
||||
self.widgets[key].storageVar.trace_add("write",saveMultiNames)
|
||||
self.widgets[key].textbox = Entry(self.widgets[key], textvariable=self.widgets[key].storageVar)
|
||||
self.widgets[key].label.pack(side=LEFT)
|
||||
self.widgets[key].textbox.pack(side=LEFT, fill=X, expand=True)
|
||||
self.widgets[key].pack(anchor=N, fill=X, expand=True)
|
||||
|
||||
return self,settings
|
||||
1
source/gui/startinventory/__init__.py
Normal file
1
source/gui/startinventory/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
# do nothing, just exist to make "source.gui.startinventory" package
|
||||
63
source/gui/startinventory/overview.py
Normal file
63
source/gui/startinventory/overview.py
Normal file
@@ -0,0 +1,63 @@
|
||||
from tkinter import ttk, StringVar, Entry, Frame, Label, N, E, W, LEFT, RIGHT, X, VERTICAL, Y
|
||||
import source.gui.widgets as widgets
|
||||
import json
|
||||
import os
|
||||
|
||||
import source.classes.constants as CONST
|
||||
|
||||
def startinventory_page(top,parent):
|
||||
# Starting Inventory
|
||||
self = ttk.Frame(parent)
|
||||
|
||||
def create_list_frame(parent, framename):
|
||||
parent.frames[framename] = Frame(parent)
|
||||
parent.frames[framename].pack(side=LEFT, padx=(0,0), anchor=N)
|
||||
parent.frames[framename].thisRow = 0
|
||||
parent.frames[framename].thisCol = 0
|
||||
|
||||
def create_vertical_rule(num=1):
|
||||
for i in range(0,num):
|
||||
ttk.Separator(self, orient=VERTICAL).pack(side=LEFT, anchor=N, fill=Y)
|
||||
|
||||
def validation(P):
|
||||
if str.isdigit(P) or P == "":
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
vcmd=(self.register(validation), '%P')
|
||||
|
||||
# Starting Inventory options
|
||||
self.startingWidgets = {}
|
||||
|
||||
# Starting Inventory option sections
|
||||
self.frames = {}
|
||||
create_list_frame(self,"itemList1")
|
||||
create_vertical_rule(2)
|
||||
create_list_frame(self,"itemList2")
|
||||
create_vertical_rule(2)
|
||||
create_list_frame(self,"itemList3")
|
||||
create_vertical_rule(2)
|
||||
create_list_frame(self,"itemList4")
|
||||
create_vertical_rule(2)
|
||||
create_list_frame(self,"itemList5")
|
||||
|
||||
with open(os.path.join("resources","app","gui","custom","overview","widgets.json")) as widgetDefns:
|
||||
myDict = json.load(widgetDefns)
|
||||
for key in CONST.CANTSTARTWITH:
|
||||
for num in range(1, 5 + 1):
|
||||
thisList = "itemList" + str(num)
|
||||
if key in myDict[thisList]:
|
||||
del myDict[thisList][key]
|
||||
for framename,theseWidgets in myDict.items():
|
||||
dictWidgets = widgets.make_widgets_from_dict(self, theseWidgets, self.frames[framename])
|
||||
for key in dictWidgets:
|
||||
self.startingWidgets[key] = dictWidgets[key]
|
||||
|
||||
for key in CONST.CUSTOMITEMS:
|
||||
if key not in CONST.CANTSTARTWITH:
|
||||
val = 0
|
||||
if key in top.settings["startinventoryarray"]:
|
||||
val = top.settings["startinventoryarray"][key]
|
||||
self.startingWidgets[key].storageVar.set(val)
|
||||
|
||||
return self
|
||||
145
source/gui/widgets.py
Normal file
145
source/gui/widgets.py
Normal file
@@ -0,0 +1,145 @@
|
||||
from tkinter import Checkbutton, Entry, Frame, IntVar, Label, OptionMenu, Spinbox, StringVar, RIGHT, X
|
||||
|
||||
class Empty():
|
||||
pass
|
||||
|
||||
class mySpinbox(Spinbox):
|
||||
def __init__(self, *args, **kwargs):
|
||||
Spinbox.__init__(self, *args, **kwargs)
|
||||
self.bind('<MouseWheel>', self.mouseWheel)
|
||||
self.bind('<Button-4>', self.mouseWheel)
|
||||
self.bind('<Button-5>', self.mouseWheel)
|
||||
|
||||
def mouseWheel(self, event):
|
||||
if event.num == 5 or event.delta == -120:
|
||||
self.invoke('buttondown')
|
||||
elif event.num == 4 or event.delta == 120:
|
||||
self.invoke('buttonup')
|
||||
|
||||
def make_checkbox(self, parent, label, storageVar, manager, managerAttrs):
|
||||
self = Frame(parent, name="checkframe-" + label.lower())
|
||||
self.storageVar = storageVar
|
||||
self.checkbox = Checkbutton(self, text=label, variable=self.storageVar, name="checkbox-" + label.lower())
|
||||
if managerAttrs is not None:
|
||||
self.checkbox.pack(managerAttrs)
|
||||
else:
|
||||
self.checkbox.pack()
|
||||
return self
|
||||
|
||||
def make_selectbox(self, parent, label, options, storageVar, manager, managerAttrs):
|
||||
def change_storage(*args):
|
||||
self.storageVar.set(options[self.labelVar.get()])
|
||||
def change_selected(*args):
|
||||
keys = options.keys()
|
||||
vals = options.values()
|
||||
keysList = list(keys)
|
||||
valsList = list(vals)
|
||||
self.labelVar.set(keysList[valsList.index(str(self.storageVar.get()))])
|
||||
self = Frame(parent, name="selectframe-" + label.lower())
|
||||
self.storageVar = storageVar
|
||||
self.storageVar.trace_add("write",change_selected)
|
||||
self.labelVar = StringVar()
|
||||
self.labelVar.trace_add("write",change_storage)
|
||||
self.label = Label(self, text=label)
|
||||
if managerAttrs is not None and "label" in managerAttrs:
|
||||
self.label.pack(managerAttrs["label"])
|
||||
else:
|
||||
self.label.pack()
|
||||
self.selectbox = OptionMenu(self, self.labelVar, *options.keys())
|
||||
self.selectbox.config(width=20)
|
||||
self.labelVar.set(managerAttrs["default"] if "default" in managerAttrs else list(options.keys())[0])
|
||||
if managerAttrs is not None and "selectbox" in managerAttrs:
|
||||
self.selectbox.pack(managerAttrs["selectbox"])
|
||||
else:
|
||||
self.selectbox.pack()
|
||||
return self
|
||||
|
||||
def make_spinbox(self, parent, label, storageVar, manager, managerAttrs):
|
||||
self = Frame(parent, name="spinframe-" + label.lower())
|
||||
self.storageVar = storageVar
|
||||
self.label = Label(self, text=label)
|
||||
if managerAttrs is not None and "label" in managerAttrs:
|
||||
self.label.pack(managerAttrs["label"])
|
||||
else:
|
||||
self.label.pack()
|
||||
fromNum = 1
|
||||
toNum = 100
|
||||
if "spinbox" in managerAttrs:
|
||||
if "from" in managerAttrs:
|
||||
fromNum = managerAttrs["spinbox"]["from"]
|
||||
if "to" in managerAttrs:
|
||||
toNum = managerAttrs["spinbox"]["to"]
|
||||
self.spinbox = mySpinbox(self, from_=fromNum, to=toNum, width=5, textvariable=self.storageVar, name="spinbox-" + label.lower())
|
||||
if managerAttrs is not None and "spinbox" in managerAttrs:
|
||||
self.spinbox.pack(managerAttrs["spinbox"])
|
||||
else:
|
||||
self.spinbox.pack()
|
||||
return self
|
||||
|
||||
def make_textbox(self, parent, label, storageVar, manager, managerAttrs):
|
||||
widget = Empty()
|
||||
widget.storageVar = storageVar
|
||||
widget.label = Label(parent, text=label)
|
||||
widget.textbox = Entry(parent, justify=RIGHT, textvariable=widget.storageVar, width=3)
|
||||
if "default" in managerAttrs:
|
||||
widget.storageVar.set(managerAttrs["default"])
|
||||
|
||||
# grid
|
||||
if manager == "grid":
|
||||
widget.label.grid(managerAttrs["label"] if managerAttrs is not None and "label" in managerAttrs else None, row=parent.thisRow, column=parent.thisCol)
|
||||
parent.thisCol += 1
|
||||
widget.textbox.grid(managerAttrs["textbox"] if managerAttrs is not None and "textbox" in managerAttrs else None, row=parent.thisRow, column=parent.thisCol)
|
||||
parent.thisRow += 1
|
||||
parent.thisCol = 0
|
||||
|
||||
# pack
|
||||
elif manager == "pack":
|
||||
widget.label.pack(managerAttrs["label"] if managerAttrs is not None and "label" in managerAttrs else None)
|
||||
widget.textbox.pack(managerAttrs["textbox"] if managerAttrs is not None and "textbox" in managerAttrs else None)
|
||||
return widget
|
||||
|
||||
|
||||
def make_widget(self, type, parent, label, storageVar=None, manager=None, managerAttrs=dict(), options=None):
|
||||
widget = None
|
||||
if manager is None:
|
||||
manager = "pack"
|
||||
thisStorageVar = storageVar
|
||||
if isinstance(storageVar,str):
|
||||
if storageVar == "int" or storageVar == "integer":
|
||||
thisStorageVar = IntVar()
|
||||
elif storageVar == "str" or storageVar == "string":
|
||||
thisStorageVar = StringVar()
|
||||
|
||||
if type == "checkbox":
|
||||
if thisStorageVar is None:
|
||||
thisStorageVar = IntVar()
|
||||
widget = make_checkbox(self, parent, label, thisStorageVar, manager, managerAttrs)
|
||||
elif type == "selectbox":
|
||||
if thisStorageVar is None:
|
||||
thisStorageVar = StringVar()
|
||||
widget = make_selectbox(self, parent, label, options, thisStorageVar, manager, managerAttrs)
|
||||
elif type == "spinbox":
|
||||
if thisStorageVar is None:
|
||||
thisStorageVar = StringVar()
|
||||
widget = make_spinbox(self, parent, label, thisStorageVar, manager, managerAttrs)
|
||||
elif type == "textbox":
|
||||
if thisStorageVar is None:
|
||||
thisStorageVar = StringVar()
|
||||
widget = make_textbox(self, parent, label, thisStorageVar, manager, managerAttrs)
|
||||
widget.type = type
|
||||
return widget
|
||||
|
||||
def make_widget_from_dict(self, defn, parent):
|
||||
type = defn["type"] if "type" in defn else None
|
||||
label = defn["label"]["text"] if "label" in defn and "text" in defn["label"] else ""
|
||||
manager = defn["manager"] if "manager" in defn else None
|
||||
managerAttrs = defn["managerAttrs"] if "managerAttrs" in defn else None
|
||||
options = defn["options"] if "options" in defn else None
|
||||
widget = make_widget(self, type, parent, label, None, manager, managerAttrs, options)
|
||||
return widget
|
||||
|
||||
def make_widgets_from_dict(self, defns, parent):
|
||||
widgets = {}
|
||||
for key,defn in defns.items():
|
||||
widgets[key] = make_widget_from_dict(self, defn, parent)
|
||||
return widgets
|
||||
Reference in New Issue
Block a user