From 63f36816ef4386470dbb0c68dff3596de102a114 Mon Sep 17 00:00:00 2001 From: Ryan Ward Date: Sat, 5 Sep 2026 10:16:22 -0700 Subject: [PATCH] feat: more cosmetics --- README.md | 4 +- gui | 2 +- main.lua | 15 +++++ package.bat | 19 ------ utils/filepicker.lua | 151 +++++++++++++++++++++++++++++++++++++++++++ version.txt | 2 +- 6 files changed, 171 insertions(+), 22 deletions(-) delete mode 100644 package.bat create mode 100644 utils/filepicker.lua diff --git a/README.md b/README.md index f438da9..69f351b 100644 --- a/README.md +++ b/README.md @@ -1 +1,3 @@ -# jeopardy game \ No newline at end of file +# jeopardy game + +build with `love-build.exe .\main.lua` \ No newline at end of file diff --git a/gui b/gui index 4bc968e..38b07e5 160000 --- a/gui +++ b/gui @@ -1 +1 @@ -Subproject commit 4bc968e8dcec7f0fc31976d82659e1193de16e62 +Subproject commit 38b07e5f2701a27752d983bcd13d9733667d1fe8 diff --git a/main.lua b/main.lua index c0a9f2e..c95cd24 100644 --- a/main.lua +++ b/main.lua @@ -62,6 +62,16 @@ function readFileData(path) return io.open(path,"r"):read("*a") end +local picker = THREAD:newFunction(function() + local filepicker = require("utils/filepicker") + local path, err = filepicker.open_file{ title = "Select a file" } + if path then + return path + else + return nil, "No file selected." .. (err and (" (" .. err .. ")") or "") + end +end, true) + function love.load() -- local z = zip.new() -- z:add("main.lua",readFileData("main.lua")) @@ -71,6 +81,11 @@ function love.load() -- file:write(data) -- file:close() + -- thread:newThread(function() + -- local file = picker() + -- print("File selected",file) + -- end).OnError(print) + loadLog:info("Starting Jeopardy Game") loadLog:debug("Setting game identity to jeopardy") for i,v in ipairs(color.listColors(showAllColors)) do diff --git a/package.bat b/package.bat deleted file mode 100644 index 3c0b00e..0000000 --- a/package.bat +++ /dev/null @@ -1,19 +0,0 @@ -:: Read the first line of version.txt and assign it to the MY_VERSION variable -for /f "usebackq delims=" %%i in ("version.txt") do ( - set "userInput=%%i" - goto :done -) - -:done -"C:\Program Files\7-Zip\7z.exe" a -tzip game.love templates version.txt assets multi\integration\loveManager multi\integration\sharedExtensions multi\init.lua utils gui menus conf.lua main.lua -rd /s /q "bin\%userInput%" -if not exist "bin\%userInput%" mkdir "bin\%userInput%" -copy /b love\love.exe + game.love "bin\%userInput%\Jeopardy.exe" -copy /b love\love.dll "bin\%userInput%\love.dll" -copy /b lovel\lua51.dll "bin\%userInput%\lua51.dll" -copy /b love\mpg123.dll "bin\%userInput%\mpg123.dll" -copy /b love\msvcp120.dll "bin\%userInput%\msvcp120.dll" -copy /b love\msvcr120.dll "bin\%userInput%\msvcr120.dll" -copy /b love\OpenAL32.dll "bin\%userInput%\OpenAL32.dll" -copy /b love\SDL2.dll "bin\%userInput%\SDL2.dll" -copy /b love\license.txt "bin\%userInput%\license.txt" \ No newline at end of file diff --git a/utils/filepicker.lua b/utils/filepicker.lua new file mode 100644 index 0000000..2c50405 --- /dev/null +++ b/utils/filepicker.lua @@ -0,0 +1,151 @@ +--[[ + file_picker.lua + Cross-platform native file picker for LuaJIT (Windows + Linux). + + Windows: uses the native Win32 comdlg32.dll GetOpenFileNameA API via FFI. + No external dependencies required. + + Linux: there is no single native "file picker" API — shells out to + whichever dialog tool is installed (zenity, kdialog, or yad). + Install one of these: + sudo apt install zenity # GNOME/GTK + sudo apt install kdialog # KDE + sudo apt install yad # lightweight alternative + + Usage: + local picker = require("file_picker") + local path = picker.open_file{ title = "Select a file", filter = "*.txt" } +]] + +local ffi = require("ffi") + +local M = {} + +-- --------------------------------------------------------------------- +-- Windows implementation +-- --------------------------------------------------------------------- +local function win_open_file(opts) + opts = opts or {} + + ffi.cdef[[ + typedef struct { + unsigned long lStructSize; + void* hwndOwner; + void* hInstance; + const char* lpstrFilter; + char* lpstrCustomFilter; + unsigned long nMaxCustFilter; + unsigned long nFilterIndex; + char* lpstrFile; + unsigned long nMaxFile; + char* lpstrFileTitle; + unsigned long nMaxFileTitle; + const char* lpstrInitialDir; + const char* lpstrTitle; + unsigned long Flags; + unsigned short nFileOffset; + unsigned short nFileExtension; + const char* lpstrDefExt; + long lCustData; + void* lpfnHook; + const char* lpTemplateName; + void* pvReserved; + unsigned long dwReserved; + unsigned long FlagsEx; + } OPENFILENAMEA; + + int GetOpenFileNameA(OPENFILENAMEA* lpofn); + int GetSaveFileNameA(OPENFILENAMEA* lpofn); + ]] + + local comdlg32 = ffi.load("comdlg32") + + local OFN_EXPLORER = 0x00080000 + local OFN_FILEMUSTEXIST = 0x00001000 + local OFN_PATHMUSTEXIST = 0x00000800 + + local MAX_PATH = 32768 -- generous buffer for long paths + local file_buf = ffi.new("char[?]", MAX_PATH) + + -- Filter must be a "\0"-delimited, double-"\0"-terminated string, + -- e.g. "Text Files\0*.txt\0All Files\0*.*\0\0" + local filter = opts.filter or "All Files\0*.*\0\0" + + local ofn = ffi.new("OPENFILENAMEA") + ofn.lStructSize = ffi.sizeof("OPENFILENAMEA") + ofn.lpstrFile = file_buf + ofn.nMaxFile = MAX_PATH + ofn.lpstrFilter = filter + ofn.lpstrTitle = opts.title or "Select a file" + ofn.Flags = OFN_EXPLORER + OFN_FILEMUSTEXIST + OFN_PATHMUSTEXIST + + local picker_fn = opts.save and comdlg32.GetSaveFileNameA or comdlg32.GetOpenFileNameA + local ok = picker_fn(ofn) + + if ok ~= 0 then + return ffi.string(file_buf) + end + return nil -- user cancelled or an error occurred +end + +-- --------------------------------------------------------------------- +-- Linux implementation +-- --------------------------------------------------------------------- +local function shell_escape(s) + return "'" .. s:gsub("'", "'\\''") .. "'" +end + +local function try_command(cmd) + local handle = io.popen(cmd) + if not handle then return nil end + local result = handle:read("*l") + local ok = handle:close() + if ok and result and #result > 0 then + return result + end + return nil +end + +local function linux_open_file(opts) + opts = opts or {} + local title = shell_escape(opts.title or "Select a file") + local save = opts.save + + local candidates = { + save + and ("zenity --file-selection --save --confirm-overwrite --title=%s 2>/dev/null"):format(title) + or ("zenity --file-selection --title=%s 2>/dev/null"):format(title), + save + and ("kdialog --getsavefilename . --title %s 2>/dev/null"):format(title) + or ("kdialog --getopenfilename . --title %s 2>/dev/null"):format(title), + save + and ("yad --file-selection --save --title=%s 2>/dev/null"):format(title) + or ("yad --file-selection --title=%s 2>/dev/null"):format(title), + } + + for _, cmd in ipairs(candidates) do + local result = try_command(cmd) + if result then return result end + end + + return nil, "No supported dialog tool found (install zenity, kdialog, or yad)" +end + +-- --------------------------------------------------------------------- +-- Public API +-- --------------------------------------------------------------------- + +--- Opens a native file picker dialog. +-- @param opts table: { title = string, filter = string (Windows only), save = bool } +-- @return path (string) or nil, err +function M.open_file(opts) + if ffi.os == "Windows" then + return win_open_file(opts) + elseif ffi.os == "Linux" then + return linux_open_file(opts) + else + return nil, "Unsupported OS: " .. ffi.os + end +end + +return M \ No newline at end of file diff --git a/version.txt b/version.txt index a6a3a43..1464c52 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.0.4 \ No newline at end of file +1.0.5 \ No newline at end of file