Skip to content

Commit

Permalink
Merge pull request #41 from Infiland/infiland
Browse files Browse the repository at this point in the history
R0.0.10
  • Loading branch information
Infiland authored Aug 6, 2024
2 parents 8fcaf90 + bdb9bdf commit 5646438
Show file tree
Hide file tree
Showing 18 changed files with 292 additions and 132 deletions.
Binary file added img/Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
188 changes: 56 additions & 132 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,160 +2,76 @@
import threading
import time
import webbrowser
from functools import partial
import requests
import markdown2

from html.parser import HTMLParser
from tkhtmlview import HTMLLabel
import tkinter as tk
from tkinter import filedialog, messagebox, ttk, font as tkfont
from tkhtmlview import HTMLLabel

#TODO: REPLACE THIS WITH from src.conversion.converter import Converter
from src.conversion.sprites import SpriteConverter
from src.conversion.sounds import SoundConverter
from src.conversion.fonts import FontConverter
from src.conversion.notes import NoteConverter
from src.conversion.tilesets import TileSetConverter
from src.conversion.project_settings import ProjectSettingsConverter

from sprites import SpriteConverter
from sounds import SoundConverter
from fonts import FontConverter
from notes import NoteConverter
from tilesets import TileSetConverter
from project_settings import ProjectSettingsConverter
# Import Version
from src.version import get_version

class ModernButton(ttk.Button):
def __init__(self, master=None, **kw):
super().__init__(master, style="Modern.TButton", **kw)
# Import GUI
from src.gui.modern_button import ModernButton
from src.gui.icon import Icon
from src.gui.setupui import SetupUI

class ConverterGUI:
def __init__(self, master):
self.master = master
master.title("GM2Godot")
master.geometry("800x600")
master.configure(bg="#222222")
self.master.title(f"GM2Godot v{get_version()}")
self.master.geometry("800x600")
self.master.configure(bg="#222222")
self.icon = Icon(self.master)

self.style = ttk.Style()
self.style.theme_use('clam')
self.setup_styles()

self.gm_icon = self.load_icon("img/Gamemaker.png")
self.godot_icon = self.load_icon("img/Godot.png")
self.setup_ui = SetupUI(self.master, self)
self.setup_ui.setup_ui()

self.console = self.setup_ui.console
self.progress = self.setup_ui.progress
self.timer_label = self.setup_ui.timer_label
self.status_label = self.setup_ui.status_label

self.convert_button = self.setup_ui.get_button("convert")
self.stop_button = self.setup_ui.get_button("stop")

self.setup_ui()
self.setup_conversion_settings()
self.conversion_running = threading.Event()
self.conversion_thread = None
self.timer_running = False
self.start_time = 0

self.stop_button.config(state=tk.DISABLED, style="TButton")

def load_icon(self, path):
try:
from PIL import Image, ImageTk
img = Image.open(path)
return ImageTk.PhotoImage(img.resize((20, 20), Image.Resampling.LANCZOS))
except ImportError:
return None

def setup_styles(self):
self.style = ttk.Style()
styles = {
"TFrame": {"background": "#222222"},
"TLabel": {"background": "#222222", "foreground": "#ffffff", "font": ('Helvetica', 10)},
"TEntry": {"fieldbackground": "#3d3d3d", "foreground": "#ffffff", "insertcolor": "#ffffff", "font": ('Helvetica', 10)},
"Modern.TButton": {"background": "#abc9ff", "foreground": "#222222", "font": ('Helvetica', 10, 'bold'), "padding": (10, 5)},
"TProgressbar": {"background": "#42ffc2", "troughcolor": "#3d3d3d"},
"TCheckbutton": {"background": "#222222", "foreground": "#ffffff"},
"Console.Vertical.TScrollbar": {"background": "#3d3d3d", "troughcolor": "#222222", "arrowcolor": "#ffffff"}
"Console.Vertical.TScrollbar": {"background": "#3d3d3d", "troughcolor": "#222222", "arrowcolor": "#ffffff"},
"Red.TButton": {"background": "red", "foreground": "white"}
}
for style, options in styles.items():
self.style.configure(style, **options)

self.style.map("TEntry", fieldbackground=[('readonly', '#3d3d3d')])
self.style.map("Modern.TButton", background=[('active', '#9ab8ee'), ('disabled', '#666666')], foreground=[('disabled', '#aaaaaa')])
self.style.map("TCheckbutton", background=[('active', '#222222')])
self.style.configure("Red.TButton", background="red", foreground="white")
self.style.map("Red.TButton", background=[('active', '#ff6666')])

def setup_ui(self):
main_frame = ttk.Frame(self.master, padding="20 20 20 20", style="TFrame")
main_frame.grid(column=0, row=0, sticky=(tk.W, tk.E, tk.N, tk.S))
self.master.columnconfigure(0, weight=1)
self.master.rowconfigure(0, weight=1)

self.create_project_path_inputs(main_frame)
self.create_buttons(main_frame)
self.create_console(main_frame)
self.create_progress_bar(main_frame)
self.create_info_labels(main_frame)

def create_project_path_inputs(self, parent):
paths = [("GameMaker", self.browse_gm, self.gm_icon), ("Godot", self.browse_godot, self.godot_icon)]
for idx, (label, command, icon) in enumerate(paths):
frame = ttk.Frame(parent, style="TFrame")
frame.grid(row=idx, column=0, sticky=tk.W, padx=5, pady=5)

ttk.Label(frame, text=label[:2] if icon is None else "", image=icon, style="TLabel").pack(side=tk.LEFT, padx=(0, 5))
ttk.Label(frame, text=f"{label} Project Path:", style="TLabel").pack(side=tk.LEFT)

entry = ttk.Entry(parent, width=50, style="TEntry")
entry.grid(row=idx, column=1, padx=5, pady=5, sticky=(tk.W, tk.E))
ModernButton(parent, text=f"Browse {label} Path", command=command).grid(row=idx, column=2, padx=5, pady=5)
setattr(self, f"{label.lower()}_entry", entry)
parent.columnconfigure(1, weight=1)

def create_buttons(self, parent):
button_frame = ttk.Frame(parent, style="TFrame")
button_frame.grid(row=2, column=0, columnspan=3, pady=10)

buttons = [
("Convert", self.start_conversion, tk.NORMAL),
("Stop", self.stop_conversion, tk.DISABLED),
("Settings", self.open_settings, tk.NORMAL)
]

for idx, (text, command, state) in enumerate(buttons):
button = ModernButton(button_frame, text=text, command=command, state=state)
button.grid(row=0, column=idx, padx=5, pady=10)
setattr(self, f"{text.lower()}_button", button)

self.stop_button.configure(style="Red.TButton")
self.stop_button.config(padding=(10, 5))

def create_console(self, parent):
console_frame = ttk.Frame(parent, style="TFrame")
console_frame.grid(row=3, column=0, columnspan=3, sticky=(tk.W, tk.E, tk.N, tk.S), pady=10)
parent.rowconfigure(3, weight=1)

self.console = tk.Text(console_frame, wrap=tk.WORD, height=15, bg="#3d3d3d", fg="#ffffff", insertbackground="#ffffff", font=('Consolas', 10), state='disabled')
self.console.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

scrollbar = ttk.Scrollbar(console_frame, orient="vertical", command=self.console.yview, style="Console.Vertical.TScrollbar")
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
self.console.configure(yscrollcommand=scrollbar.set)

def create_progress_bar(self, parent):
progress_frame = ttk.Frame(parent, style="TFrame")
progress_frame.grid(row=4, column=0, columnspan=3, sticky=(tk.W, tk.E), pady=10)

self.progress = ttk.Progressbar(progress_frame, orient="horizontal", length=300, mode="determinate", style="TProgressbar")
self.progress.pack(side=tk.LEFT, expand=True, fill=tk.X)

self.progress_label = ttk.Label(progress_frame, text="0%", style="TLabel")
self.progress_label.pack(side=tk.RIGHT, padx=5)

self.timer_label = ttk.Label(parent, text="Time: 00:00:00", style="TLabel")
self.timer_label.grid(row=5, column=0, columnspan=3, pady=(0, 10))

def create_info_labels(self, parent):
info_frame = ttk.Frame(parent, style="TFrame")
info_frame.grid(row=6, column=0, columnspan=3, sticky=(tk.W, tk.E), pady=10)

labels = [
("Version 0.0.9", self.show_release_notes, tk.LEFT),
("Contribute", self.open_github, tk.LEFT),
("Made by Infiland", self.open_infiland_website, tk.RIGHT)
]

for text, command, side in labels:
label = ttk.Label(info_frame, text=text, style="TLabel", cursor="hand2")
label.pack(side=side, padx=10)
label.bind("<Button-1>", command)
self.style.configure("Red.TButton", background="white", foreground="white")

def show_release_notes(self, event):
release_notes = self.fetch_release_notes()
Expand Down Expand Up @@ -230,8 +146,8 @@ def setup_conversion_settings(self):
"game_icon", "project_settings", "project_name", "audio_buses"
]
self.conversion_settings = {setting: tk.BooleanVar(value=True) for setting in settings}
self.conversion_settings["notes"] = tk.BooleanVar(value=False)
self.conversion_settings["objects"] = tk.BooleanVar(value=False)
self.conversion_settings["notes"].set(False)
self.conversion_settings["objects"].set(False)

def open_settings(self):
settings_window = tk.Toplevel(self.master)
Expand All @@ -250,7 +166,7 @@ def open_settings(self):
categories = {
"Assets": ["sprites", "sounds", "fonts"],
"Project": ["game_icon", "project_settings", "project_name", "audio_buses", "notes"],
"Not Working": ["objects", "shaders", "tilesets"]
"WIP": ["objects", "shaders", "tilesets"]
}

row = 0
Expand Down Expand Up @@ -278,10 +194,13 @@ def deselect_all():
ModernButton(button_frame, text="Save", command=settings_window.destroy).pack(side=tk.LEFT, padx=5)

def log(self, message):
self.console.configure(state='normal')
self.console.insert(tk.END, message + "\n")
self.console.see(tk.END)
self.console.configure(state='disabled')
if self.console:
self.console.configure(state='normal')
self.console.insert(tk.END, message + "\n")
self.console.see(tk.END)
self.console.configure(state='disabled')
else:
print(f"Console not initialized. Message: {message}")

def browse_project(self, entry, file_check, dialog_title):
folder = filedialog.askdirectory(title=dialog_title)
Expand All @@ -291,10 +210,10 @@ def browse_project(self, entry, file_check, dialog_title):
file_check(folder)

def browse_gm(self):
self.browse_project(self.gamemaker_entry, self.check_gm_project, "Select your GameMaker Project")
self.browse_project(self.setup_ui.entries['gamemaker'], self.check_gm_project, "Select your GameMaker Project")

def browse_godot(self):
self.browse_project(self.godot_entry, self.check_godot_project, "Select your new Godot project")
self.browse_project(self.setup_ui.entries['godot'], self.check_godot_project, "Select your new Godot project")

def check_project_file(self, folder, file_extension, file_name):
files = [f for f in os.listdir(folder) if f.endswith(file_extension)]
Expand All @@ -316,7 +235,7 @@ def update_progress(self, value):
self.progress_label.config(text=f"{value}%")

def start_conversion(self):
gm_path, godot_path = self.gamemaker_entry.get(), self.godot_entry.get()
gm_path, godot_path = self.setup_ui.entries['gamemaker'].get(), self.setup_ui.entries['godot'].get()
if not gm_path or not godot_path:
self.log("Please select both GameMaker and Godot project paths.")
return
Expand All @@ -328,6 +247,7 @@ def start_conversion(self):
self.conversion_thread = threading.Thread(target=self.convert, args=(gm_path, godot_path))
self.conversion_thread.start()
self.start_timer()
self.style.configure("Red.TButton", background="red", foreground="white")
self.stop_button.config(state=tk.NORMAL, style="Red.TButton")

def validate_projects(self, gm_path, godot_path):
Expand All @@ -352,14 +272,14 @@ def prepare_for_conversion(self):
self.stop_button.config(state=tk.NORMAL)
self.conversion_running.set()
self.console.delete('1.0', tk.END)
self.progress['value'] = 0
self.progress_label.config(text="0%")
self.progress.update_progress(0)
self.log("Starting conversion...")

def stop_conversion(self):
if self.conversion_running.is_set():
self.conversion_running.clear()
self.log("Stopping conversion process...")
self.style.configure("Red.TButton", background="white", foreground="white")
self.stop_button.config(state=tk.DISABLED, style="TButton")
self.master.after(100, self.check_conversion_stopped)

Expand Down Expand Up @@ -398,6 +318,7 @@ def convert(self, gm_path, godot_path):
for setting, converter, log_message in converters:
if self.conversion_settings[setting].get() and self.conversion_running.is_set():
self.threadsafe_log(log_message)
self.threadsafe_update_status(log_message)
converter()
self.threadsafe_update_progress(0)

Expand All @@ -412,12 +333,15 @@ def check_conversion_stopped(self):
def threadsafe_log(self, message):
self.master.after(0, self.log, message)

def threadsafe_update_status(self, message):
self.master.after(0, self.status_label.config, {"text": message})

def threadsafe_update_progress(self, value):
self.master.after(0, self.update_progress, value)
self.master.after(0, self.progress.update_progress, value)

def conversion_complete(self):
self.progress['value'] = 100
self.progress_label.config(text="100%")
self.progress.update_progress(100)
self.status_label.config(text="Conversion complete!")
self.log("You have ported your project from GameMaker to Godot! Have fun!" if self.conversion_running.is_set() else "Conversion process stopped.")
self.conversion_running.clear()
self.convert_button.config(state=tk.NORMAL)
Expand Down
35 changes: 35 additions & 0 deletions src/conversion/converter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from src.conversion.sprites import SpriteConverter
from src.conversion.sounds import SoundConverter
from src.conversion.fonts import FontConverter
from src.conversion.notes import NoteConverter
from src.conversion.tilesets import TileSetConverter
from src.conversion.project_settings import ProjectSettingsConverter

#WORK IN PROGRESS
class Converter:
def __init__(self, log_callback, progress_callback):
self.log = log_callback
self.update_progress = progress_callback

def convert(self, gm_path, godot_path, settings):
project_settings_converter = ProjectSettingsConverter(gm_path, godot_path, self.log)

converters = [
("game_icon", project_settings_converter.convert_icon, "Converting game icon..."),
("project_name", project_settings_converter.update_project_name, "Updating project name..."),
("project_settings", project_settings_converter.update_project_settings, "Updating project settings..."),
("audio_buses", project_settings_converter.generate_audio_bus_layout, "Generating audio bus layout..."),
("sprites", lambda: SpriteConverter(gm_path, godot_path, self.log, self.update_progress).convert_all(), "Converting sprites..."),
("fonts", lambda: FontConverter(gm_path, godot_path, self.log, self.update_progress).convert_all(), "Converting fonts..."),
("tilesets", lambda: TileSetConverter(gm_path, godot_path, self.log, self.update_progress).convert_all(), "Converting tilesets..."),
("sounds", lambda: SoundConverter(gm_path, godot_path, self.log, self.update_progress).convert_sounds(), "Converting sounds..."),
("notes", lambda: NoteConverter(gm_path, godot_path, self.log, self.update_progress).convert_all(), "Converting notes...")
]

for setting, converter, log_message in converters:
if settings[setting].get():
self.log(log_message)
converter()
self.update_progress(0)

self.log("Conversion complete!")
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Empty file added src/gui/gui.py
Empty file.
Loading

0 comments on commit 5646438

Please sign in to comment.