From 6ade0ee2ad3c953870f90fe844f4d04ba71c77df Mon Sep 17 00:00:00 2001 From: rubenwardy Date: Sun, 31 Mar 2024 19:24:27 +0100 Subject: [PATCH 1/7] ContentDB redesign: Add package dialog --- builtin/common/misc_helpers.lua | 10 + builtin/mainmenu/content/contentdb.lua | 60 +++- builtin/mainmenu/content/dlg_contentdb.lua | 91 ++---- builtin/mainmenu/content/dlg_package.lua | 351 +++++++++++++++++++++ builtin/mainmenu/content/init.lua | 1 + builtin/mainmenu/content/screenshots.lua | 42 ++- doc/lua_api.md | 3 + doc/menu_lua_api.md | 5 +- src/script/lua_api/l_mainmenu.cpp | 18 ++ src/script/lua_api/l_mainmenu.h | 2 + 10 files changed, 501 insertions(+), 82 deletions(-) create mode 100644 builtin/mainmenu/content/dlg_package.lua diff --git a/builtin/common/misc_helpers.lua b/builtin/common/misc_helpers.lua index 424eb26d2..4497a42b3 100644 --- a/builtin/common/misc_helpers.lua +++ b/builtin/common/misc_helpers.lua @@ -262,6 +262,16 @@ function core.formspec_escape(text) end +local hypertext_escapes = { + ["\\"] = "\\\\", + ["<"] = "\\<", + [">"] = "\\>", +} +function core.hypertext_escape(text) + return text and text:gsub("[\\<>]", hypertext_escapes) +end + + function core.wrap_text(text, max_length, as_table) local result = {} local line = {} diff --git a/builtin/mainmenu/content/contentdb.lua b/builtin/mainmenu/content/contentdb.lua index eb06c8b61..145e9c762 100644 --- a/builtin/mainmenu/content/contentdb.lua +++ b/builtin/mainmenu/content/contentdb.lua @@ -179,6 +179,22 @@ function contentdb.get_package_by_id(id) end +function contentdb.get_package_by_info(author, name) + local id = author:lower() .. "/" .. name + local package = contentdb.package_by_id[id] + if package then + return package + end + + local name_len = #name + if name_len > 5 and name:sub(name_len - 4) == "_game" then + id = author:lower() .. "/" .. name:sub(1, name_len - 5) + return contentdb.package_by_id[id] + end + return nil +end + + local function get_raw_dependencies(package) if package.type ~= "mod" then return {} @@ -374,8 +390,8 @@ local function fetch_pkgs(params) local aliases = {} for _, package in pairs(packages) do - local name_len = #package.name -- This must match what contentdb.update_paths() does! + local name_len = #package.name package.id = package.author:lower() .. "/" if package.type == "game" and name_len > 5 and package.name:sub(name_len - 4) == "_game" then package.id = package.id .. package.name:sub(1, name_len - 5) @@ -540,3 +556,45 @@ function contentdb.filter_packages(query, by_type) end end end + + +function contentdb.get_full_package_info(package, callback) + assert(package) + + local function fetch(params) + local version = core.get_version() + local base_url = core.settings:get("contentdb_url") + + local languages + local current_language = core.get_language() + if current_language ~= "" then + languages = { current_language, "en;q=0.8" } + else + languages = { "en" } + end + + local url = base_url .. + "/api/packages/" .. params.package.url_part .. "/for-client/?" .. + "protocol_version=" .. core.get_max_supp_proto() .. + "&engine_version=" .. core.urlencode(version.string) .. + "&formspec_version=" .. core.urlencode(7) .. + "&include_images=false" + local http = core.get_http_api() + local response = http.fetch_sync({ + url = url, + extra_headers = { + "Accept-Language: " .. table.concat(languages, ", ") + }, + }) + if not response.succeeded then + return nil + end + + return core.parse_json(response.data) + end + + if not core.handle_async(fetch, { package = package }, callback) then + core.log("error", "ERROR: async event failed") + callback(nil) + end +end diff --git a/builtin/mainmenu/content/dlg_contentdb.lua b/builtin/mainmenu/content/dlg_contentdb.lua index 4dafafc45..5c943d0b4 100644 --- a/builtin/mainmenu/content/dlg_contentdb.lua +++ b/builtin/mainmenu/content/dlg_contentdb.lua @@ -46,7 +46,7 @@ local filter_types_type = { } -local function install_or_update_package(this, package) +function install_or_update_package(parent, package) local install_parent if package.type == "mod" then install_parent = core.get_modpath() @@ -66,14 +66,14 @@ local function install_or_update_package(this, package) local has_hard_deps = contentdb.has_hard_deps(package) if has_hard_deps then local dlg = create_install_dialog(package) - dlg:set_parent(this) - this:hide() + dlg:set_parent(parent) + parent:hide() dlg:show() elseif has_hard_deps == nil then local dlg = messagebox("error_checking_deps", fgettext("Error getting dependencies for package")) - dlg:set_parent(this) - this:hide() + dlg:set_parent(parent) + parent:hide() dlg:show() else contentdb.queue_download(package, package.path and contentdb.REASON_UPDATE or contentdb.REASON_NEW) @@ -83,13 +83,13 @@ local function install_or_update_package(this, package) if package.type == "mod" and #pkgmgr.games == 0 then local dlg = messagebox("install_game", fgettext("You need to install a game before you can install a mod")) - dlg:set_parent(this) - this:hide() + dlg:set_parent(parent) + parent:hide() dlg:show() elseif not package.path and core.is_dir(install_parent .. DIR_DELIM .. package.name) then local dlg = create_confirm_overwrite(package, on_confirm) - dlg:set_parent(this) - this:hide() + dlg:set_parent(parent) + parent:hide() dlg:show() else on_confirm() @@ -300,7 +300,7 @@ local function get_formspec(dlgdata) -- image formspec[#formspec + 1] = "image[0,0;1.5,1;" - formspec[#formspec + 1] = core.formspec_escape(get_screenshot(package)) + formspec[#formspec + 1] = core.formspec_escape(get_screenshot(package, package.thumbnail)) formspec[#formspec + 1] = "]" -- title @@ -310,52 +310,17 @@ local function get_formspec(dlgdata) core.colorize("#BFBFBF", " by " .. package.author)) formspec[#formspec + 1] = "]" - -- buttons - local description_width = W - 2.625 - 2 * 0.7 - 2 * 0.15 - - local second_base = "image_button[-1.55,0;0.7,0.7;" .. core.formspec_escape(defaulttexturedir) - local third_base = "image_button[-2.4,0;0.7,0.7;" .. core.formspec_escape(defaulttexturedir) - formspec[#formspec + 1] = "container[" - formspec[#formspec + 1] = W - 0.375*2 - formspec[#formspec + 1] = ",0.1]" - - if package.downloading then - formspec[#formspec + 1] = "animated_image[-1.7,-0.15;1,1;downloading;" - formspec[#formspec + 1] = core.formspec_escape(defaulttexturedir) - formspec[#formspec + 1] = "cdb_downloading.png;3;400;]" - elseif package.queued then - formspec[#formspec + 1] = second_base - formspec[#formspec + 1] = "cdb_queued.png;queued;]" - elseif not package.path then - local elem_name = "install_" .. i .. ";" - formspec[#formspec + 1] = "style[" .. elem_name .. "bgcolor=#71aa34]" - formspec[#formspec + 1] = second_base .. "cdb_add.png;" .. elem_name .. "]" - formspec[#formspec + 1] = "tooltip[" .. elem_name .. fgettext("Install") .. tooltip_colors - else - if package.installed_release < package.release then - -- The install_ action also handles updating - local elem_name = "install_" .. i .. ";" - formspec[#formspec + 1] = "style[" .. elem_name .. "bgcolor=#28ccdf]" - formspec[#formspec + 1] = third_base .. "cdb_update.png;" .. elem_name .. "]" - formspec[#formspec + 1] = "tooltip[" .. elem_name .. fgettext("Update") .. tooltip_colors - - description_width = description_width - 0.7 - 0.15 - end - - local elem_name = "uninstall_" .. i .. ";" - formspec[#formspec + 1] = "style[" .. elem_name .. "bgcolor=#a93b3b]" - formspec[#formspec + 1] = second_base .. "cdb_clear.png;" .. elem_name .. "]" - formspec[#formspec + 1] = "tooltip[" .. elem_name .. fgettext("Uninstall") .. tooltip_colors - end - - local web_elem_name = "view_" .. i .. ";" - formspec[#formspec + 1] = "image_button[-0.7,0;0.7,0.7;" .. - core.formspec_escape(defaulttexturedir) .. "cdb_viewonline.png;" .. web_elem_name .. "]" - formspec[#formspec + 1] = "tooltip[" .. web_elem_name .. - fgettext("View more information in a web browser") .. tooltip_colors - formspec[#formspec + 1] = "container_end[]" + -- button + formspec[#formspec + 1] = "button[" + formspec[#formspec + 1] = W-0.375*2-2 + formspec[#formspec + 1] = ",0.1;2,0.7;view_" + formspec[#formspec + 1] = i + formspec[#formspec + 1] = ";" + formspec[#formspec + 1] = fgettext("View") + formspec[#formspec + 1] = "]" -- description + local description_width = W - 2.625 - 2 * 0.7 - 2 * 0.15 formspec[#formspec + 1] = "textarea[1.855,0.3;" formspec[#formspec + 1] = tostring(description_width) formspec[#formspec + 1] = ",0.8;;;" @@ -437,32 +402,20 @@ local function handle_submit(this, fields) return true end + local num_per_page = this.data.num_per_page local start_idx = (cur_page - 1) * num_per_page + 1 assert(start_idx ~= nil) for i=start_idx, math.min(#contentdb.packages, start_idx+num_per_page-1) do local package = contentdb.packages[i] assert(package) - if fields["install_" .. i] then - install_or_update_package(this, package) - return true - end - - if fields["uninstall_" .. i] then - local dlg = create_delete_content_dlg(package) + if fields["view_" .. i] then + local dlg = create_package_dialog(package) dlg:set_parent(this) this:hide() dlg:show() return true end - - if fields["view_" .. i] then - local url = ("%s/packages/%s?protocol_version=%d"):format( - core.settings:get("contentdb_url"), package.url_part, - core.get_max_supp_proto()) - core.open_url(url) - return true - end end return false diff --git a/builtin/mainmenu/content/dlg_package.lua b/builtin/mainmenu/content/dlg_package.lua new file mode 100644 index 000000000..126b3d8ad --- /dev/null +++ b/builtin/mainmenu/content/dlg_package.lua @@ -0,0 +1,351 @@ +--Minetest +--Copyright (C) 2018-24 rubenwardy +-- +--This program is free software; you can redistribute it and/or modify +--it under the terms of the GNU Lesser General Public License as published by +--the Free Software Foundation; either version 2.1 of the License, or +--(at your option) any later version. +-- +--This program is distributed in the hope that it will be useful, +--but WITHOUT ANY WARRANTY; without even the implied warranty of +--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +--GNU Lesser General Public License for more details. +-- +--You should have received a copy of the GNU Lesser General Public License along +--with this program; if not, write to the Free Software Foundation, Inc., +--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + +local function get_info_formspec(size, text) + return table.concat({ + "formspec_version[6]", + "size[", size.x, ",", size.y, "]", + "padding[-0.01,-0.01]", + + "label[4,4.35;", text, "]", + "container[0,", size.y - 0.8 - 0.375, "]", + "button[0.375,0;2,0.8;back;", fgettext("Back"), "]", + "container_end[]", + }) +end + + +--- Creates a scrollbaroptions for a scroll_container +-- +-- @param visible_l the length of the scroll_container and scrollbar +-- @param total_l length of the scrollable area +-- @param scroll_factor as passed to scroll_container +local function make_scrollbaroptions_for_scroll_container(visible_l, total_l, scroll_factor) + assert(total_l >= visible_l) + local max = total_l - visible_l + local thumb_size = (visible_l / total_l) * max + return ("scrollbaroptions[min=0;max=%f;thumbsize=%f]"):format(max / scroll_factor, thumb_size / scroll_factor) +end + + +local function get_formspec(data) + local window = core.get_window_info() + local size = { x = window.max_formspec_size.x, y = window.max_formspec_size.y } + + if not data.info then + if not data.loading and not data.loading_error then + data.loading = true + + contentdb.get_full_package_info(data.package, function(info) + data.loading = false + + if info == nil then + data.loading_error = true + ui.update() + elseif data.package.name == info.name then + data.info = info + ui.update() + end + end) + end + + if data.loading_error then + return get_info_formspec(size, fgettext("No packages could be retrieved")) + else + return get_info_formspec(size, fgettext("Loading...")) + end + else + -- Check installation status + contentdb.update_paths() + + local info = data.info + + local info_line = + fgettext("by $1 — $2 downloads — +$3 / $4 / -$5", + info.author, info.downloads, + info.reviews.positive, info.reviews.neutral, info.reviews.negative) + + local bottom_buttons_y = size.y - 0.8 - 0.375 + + local formspec = { + "formspec_version[7]", + "size[", size.x, ",", size.y, "]", + "padding[-0.01,-0.01]", + "bgcolor[#0000]", + "box[0,0;", size.x, ",", size.y, ";#0000008C]", + + "button[0.375,", bottom_buttons_y, ";2,0.8;back;", fgettext("Back"), "]", + "button[", size.x - 3.375, ",", bottom_buttons_y, ";3,0.8;open_contentdb;", fgettext("ContentDB page"), "]", + + "style_type[label;font_size=+24;font=bold]", + "label[0.375,0.7;", core.formspec_escape(info.title), "]", + "style_type[label;font_size=;font=]", + + "label[0.375,1.4;", core.formspec_escape(info_line), "]", + } + + local x = size.x - 3.375 + local function add_link_button(label, name) + if info[name] then + x = x - 3.25 + table.insert_all(formspec, { + "button[", x, ",", bottom_buttons_y, ";3,0.8;open_", name, ";", label, "]", + }) + end + end + add_link_button(fgettext("Translate"), "translation_url") + add_link_button(fgettext("Issue Tracker"), "issue_tracker") + add_link_button(fgettext("Forums"), "forums") + add_link_button(fgettext("Source"), "repo") + add_link_button(fgettext("Website"), "website") + + table.insert_all(formspec, { + "container[", size.x - 6.375, ",0.375]" + }) + + local left_button_rect = "0,0;2.875,1" + local right_button_rect = "3.125,0;2.875,1" + if data.package.downloading then + formspec[#formspec + 1] = "animated_image[5,0;1,1;downloading;" + formspec[#formspec + 1] = core.formspec_escape(defaulttexturedir) + formspec[#formspec + 1] = "cdb_downloading.png;3;400;]" + elseif data.package.queued then + formspec[#formspec + 1] = "style[queued;border=false]" + formspec[#formspec + 1] = "image_button[5,0;1,1;" .. core.formspec_escape(defaulttexturedir) + formspec[#formspec + 1] = "cdb_queued.png;queued;]" + elseif not data.package.path then + formspec[#formspec + 1] = "style[install;bgcolor=green]" + formspec[#formspec + 1] = "button[" + formspec[#formspec + 1] = right_button_rect + formspec[#formspec + 1] =";install;" + formspec[#formspec + 1] = fgettext("Install [$1]", info.download_size) + formspec[#formspec + 1] = "]" + else + if data.package.installed_release < data.package.release then + -- The install_ action also handles updating + formspec[#formspec + 1] = "style[install;bgcolor=#28ccdf]" + formspec[#formspec + 1] = "button[" + formspec[#formspec + 1] = left_button_rect + formspec[#formspec + 1] = ";install;" + formspec[#formspec + 1] = fgettext("Update") + formspec[#formspec + 1] = "]" + end + + formspec[#formspec + 1] = "style[uninstall;bgcolor=#a93b3b]" + formspec[#formspec + 1] = "button[" + formspec[#formspec + 1] = right_button_rect + formspec[#formspec + 1] = ";uninstall;" + formspec[#formspec + 1] = fgettext("Uninstall") + formspec[#formspec + 1] = "]" + end + + local current_tab = data.current_tab or 1 + local tab_titles = { + fgettext("Description"), + fgettext("Information"), + } + + local tab_body_height = bottom_buttons_y - 2.8 + + table.insert_all(formspec, { + "container_end[]", + + "tabheader[0.375,2.55;", size.x - 0.375*2, ",0.8;tabs;", + table.concat(tab_titles, ","), ";", current_tab, ";true;true]", + + "container[0,2.8]", + }) + + if current_tab == 1 then + -- Screenshots and description + local hypertext = info.long_description.head .. + "" .. core.hypertext_escape(info.short_description) .. "\n\n" .. + info.long_description.body + + hypertext = hypertext:gsub(" size.x + local hypertext_y = (#info.screenshots > 0 and 2.25 or 0) + (needs_scrollbar and 0.5 or 0) + + table.insert_all(formspec, { + "hypertext[0.375,", hypertext_y, ";", + size.x - 2*0.375, ",", + tab_body_height - hypertext_y - 0.375, + ";desc;", core.formspec_escape(hypertext), "]", + + "scroll_container[0,0;", size.x, ",2.25;images_sb;horizontal;", scroll_factor, "]", + }) + + for i, ss in ipairs(info.screenshots) do + local path = get_screenshot(data.package, ss.url, 2) + table.insert_all(formspec, { + "image_button[", (i-1)*3.25 + 0.375, ",0;3,2;", + core.formspec_escape(path), ";ss_", i, ";;false;false]", + }) + end + + formspec[#formspec + 1] = "scroll_container_end[]" + + if needs_scrollbar then + table.insert_all(formspec, { + make_scrollbaroptions_for_scroll_container(size.x, screenshots_w, scroll_factor), + "scrollbar[0,2.25;", size.x, ",0.25;horizontal;images_sb;0]", + }) + end + elseif current_tab == 2 then + local hypertext = info.info_hypertext.head .. info.info_hypertext.body + + table.insert_all(formspec, { + "hypertext[0.375,0;", size.x - 2*0.375, ",", tab_body_height - 0.375, + ";info;", core.formspec_escape(hypertext), "]", + }) + else + error("Unknown tab " .. current_tab) + end + + formspec[#formspec + 1] = "container_end[]" + + return table.concat(formspec) + end +end + + +local function handle_hypertext_event(this, event, hypertext_object) + if not (event and event:sub(1, 7) == "action:") then + return + end + + -- TODO: escape base_url + local base_url = core.settings:get("contentdb_url") + for key, url in pairs(hypertext_object.links) do + if event == "action:" .. key then + local author, name = url:match("^" .. base_url .. "/?packages/([A-Za-z0-9 _-]+)/([a-z0-9_]+)/?$") + if author and name then + local package2 = contentdb.get_package_by_info(author, name) + if package2 then + local dlg = create_package_dialog(package2) + dlg:set_parent(this) + this:hide() + dlg:show() + return true + end + end + + core.open_url_dialog(url) + return true + end + end +end + + +local function handle_submit(this, fields) + local info = this.data.info + local package = this.data.package + + if fields.back then + this:delete() + return true + end + + if not info then + return false + end + + if fields.open_contentdb then + local url = ("%s/packages/%s/?protocol_version=%d"):format( + core.settings:get("contentdb_url"), package.url_part, + core.get_max_supp_proto()) + core.open_url(url) + return true + end + + if fields.open_translation_url then + core.open_url_dialog(info.translation_url) + return true + end + + if fields.open_issue_tracker then + core.open_url_dialog(info.issue_tracker) + return true + end + + if fields.open_forums then + core.open_url("https://forum.minetest.net/viewtopic.php?t=" .. info.forums) + return true + end + + if fields.open_repo then + core.open_url_dialog(info.repo) + return true + end + + if fields.open_website then + core.open_url_dialog(info.website) + return true + end + + if fields.install then + install_or_update_package(this, package) + return true + end + + if fields.uninstall then + local dlg = create_delete_content_dlg(package) + dlg:set_parent(this) + this:hide() + dlg:show() + return true + end + + if fields.tabs then + this.data.current_tab = tonumber(fields.tabs) + return true + end + + for i, ss in ipairs(info.screenshots) do + if fields["ss_" .. i] then + core.open_url(ss.url) + return true + end + end + + if handle_hypertext_event(this, fields.desc, info.long_description) or + handle_hypertext_event(this, fields.info, info.info_hypertext) then + return true + end +end + + +function create_package_dialog(package) + assert(package) + + local dlg = dialog_create("package_dialog_" .. package.id, + get_formspec, + handle_submit) + local data = dlg.data + + data.package = package + data.info = nil + data.loading = false + data.loading_error = nil + data.current_tab = 1 + return dlg +end diff --git a/builtin/mainmenu/content/init.lua b/builtin/mainmenu/content/init.lua index e66828089..00eac681b 100644 --- a/builtin/mainmenu/content/init.lua +++ b/builtin/mainmenu/content/init.lua @@ -23,4 +23,5 @@ dofile(path .. DIR_DELIM .. "update_detector.lua") dofile(path .. DIR_DELIM .. "screenshots.lua") dofile(path .. DIR_DELIM .. "dlg_install.lua") dofile(path .. DIR_DELIM .. "dlg_overwrite.lua") +dofile(path .. DIR_DELIM .. "dlg_package.lua") dofile(path .. DIR_DELIM .. "dlg_contentdb.lua") diff --git a/builtin/mainmenu/content/screenshots.lua b/builtin/mainmenu/content/screenshots.lua index 98c6658b9..b1321af16 100644 --- a/builtin/mainmenu/content/screenshots.lua +++ b/builtin/mainmenu/content/screenshots.lua @@ -23,23 +23,43 @@ local screenshot_downloading = {} local screenshot_downloaded = {} +local function get_filename(path) + local parts = path:split("/") + return parts[#parts] +end + + local function get_file_extension(path) local parts = path:split(".") return parts[#parts] end -function get_screenshot(package) - if not package.thumbnail then +function get_screenshot(package, screenshot_url, level) + if not screenshot_url then return defaulttexturedir .. "no_screenshot.png" - elseif screenshot_downloading[package.thumbnail] then + end + + -- Minetest only supports png and jpg + local ext = get_file_extension(screenshot_url) + if ext ~= "png" and ext ~= "jpg" then + screenshot_url = screenshot_url:sub(0, -#ext - 1) .. "png" + level = level or 4 + end + + -- Set thumbnail level + if level then + screenshot_url = screenshot_url:gsub("/thumbnails/[0-9]+/", "/thumbnails/" .. level .. "/") + screenshot_url = screenshot_url:gsub("/uploads/", "/thumbnails/" .. level .. "/") + end + + if screenshot_downloading[screenshot_url] then return defaulttexturedir .. "loading_screenshot.png" end - -- Get tmp screenshot path - local ext = get_file_extension(package.thumbnail) local filepath = screenshot_dir .. DIR_DELIM .. - ("%s-%s-%s.%s"):format(package.type, package.author, package.name, ext) + ("%s-%s-%s-l%d-%s"):format(package.type, package.author, package.name, + level or 1, get_filename(screenshot_url)) -- Return if already downloaded local file = io.open(filepath, "r") @@ -49,7 +69,7 @@ function get_screenshot(package) end -- Show error if we've failed to download before - if screenshot_downloaded[package.thumbnail] then + if screenshot_downloaded[screenshot_url] then return defaulttexturedir .. "error_screenshot.png" end @@ -59,16 +79,16 @@ function get_screenshot(package) return core.download_file(params.url, params.dest) end local function callback(success) - screenshot_downloading[package.thumbnail] = nil - screenshot_downloaded[package.thumbnail] = true + screenshot_downloading[screenshot_url] = nil + screenshot_downloaded[screenshot_url] = true if not success then core.log("warning", "Screenshot download failed for some reason") end ui.update() end if core.handle_async(download_screenshot, - { dest = filepath, url = package.thumbnail }, callback) then - screenshot_downloading[package.thumbnail] = true + { dest = filepath, url = screenshot_url }, callback) then + screenshot_downloading[screenshot_url] = true else core.log("error", "ERROR: async event failed") return defaulttexturedir .. "error_screenshot.png" diff --git a/doc/lua_api.md b/doc/lua_api.md index b08f7356d..fe4deb52e 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -6443,6 +6443,9 @@ Formspec * `minetest.formspec_escape(string)`: returns a string * escapes the characters "[", "]", "\", "," and ";", which cannot be used in formspecs. +* `minetest.hypertext_escape(string)`: returns a string + * escapes the charecters "\", "<", and ">" to show text in a hypertext element. + * not safe for use with tag attributes. * `minetest.explode_table_event(string)`: returns a table * returns e.g. `{type="CHG", row=1, column=2}` * `type` is one of: diff --git a/doc/menu_lua_api.md b/doc/menu_lua_api.md index cb1f07a90..c7c49aea8 100644 --- a/doc/menu_lua_api.md +++ b/doc/menu_lua_api.md @@ -47,7 +47,10 @@ Functions * returns the maximum supported network protocol version * `core.open_url(url)` * opens the URL in a web browser, returns false on failure. - * Must begin with http:// or https:// + * `url` must begin with http:// or https:// +* `core.open_url_dialog(url)` + * shows a dialog to allow the user to choose whether to open a URL. + * `url` must begin with http:// or https:// * `core.open_dir(path)` * opens the path in the system file browser/explorer, returns false on failure. * Must be an existing directory. diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp index a5913e807..75f8592ab 100644 --- a/src/script/lua_api/l_mainmenu.cpp +++ b/src/script/lua_api/l_mainmenu.cpp @@ -40,6 +40,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "content/mod_configuration.h" #include "threading/mutex_auto_lock.h" #include "common/c_converter.h" +#include "gui/guiOpenURL.h" /******************************************************************************/ std::string ModApiMainMenu::getTextData(lua_State *L, const std::string &name) @@ -1038,6 +1039,22 @@ int ModApiMainMenu::l_open_url(lua_State *L) return 1; } +/******************************************************************************/ +int ModApiMainMenu::l_open_url_dialog(lua_State *L) +{ + GUIEngine* engine = getGuiEngine(L); + sanity_check(engine != NULL); + + std::string url = luaL_checkstring(L, 1); + + GUIOpenURLMenu* openURLMenu = + new GUIOpenURLMenu(engine->m_rendering_engine->get_gui_env(), + engine->m_parent, -1, engine->m_menumanager, + engine->m_texture_source.get(), url); + openURLMenu->drop(); + return 1; +} + /******************************************************************************/ int ModApiMainMenu::l_open_dir(lua_State *L) { @@ -1129,6 +1146,7 @@ void ModApiMainMenu::Initialize(lua_State *L, int top) API_FCT(get_min_supp_proto); API_FCT(get_max_supp_proto); API_FCT(open_url); + API_FCT(open_url_dialog); API_FCT(open_dir); API_FCT(share_file); API_FCT(do_async_callback); diff --git a/src/script/lua_api/l_mainmenu.h b/src/script/lua_api/l_mainmenu.h index 5535d2170..e2dfbd3f8 100644 --- a/src/script/lua_api/l_mainmenu.h +++ b/src/script/lua_api/l_mainmenu.h @@ -162,6 +162,8 @@ class ModApiMainMenu: public ModApiBase // other static int l_open_url(lua_State *L); + static int l_open_url_dialog(lua_State *L); + static int l_open_dir(lua_State *L); static int l_share_file(lua_State *L); From 9d890c992ae6c03d8fbc82115b03ca4e29d5b1fd Mon Sep 17 00:00:00 2001 From: rubenwardy Date: Mon, 1 Apr 2024 02:00:38 +0100 Subject: [PATCH 2/7] ContentDB redesign: Redesign package list dialog --- LICENSE.txt | 3 - builtin/mainmenu/content/dlg_contentdb.lua | 274 +++++++++++++-------- textures/base/pack/cdb_add.png | Bin 147 -> 0 bytes textures/base/pack/cdb_clear.png | Bin 150 -> 0 bytes textures/base/pack/cdb_viewonline.png | Bin 191 -> 0 bytes 5 files changed, 177 insertions(+), 100 deletions(-) delete mode 100644 textures/base/pack/cdb_add.png delete mode 100644 textures/base/pack/cdb_clear.png delete mode 100644 textures/base/pack/cdb_viewonline.png diff --git a/LICENSE.txt b/LICENSE.txt index de76c7a80..03ca35100 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -57,12 +57,10 @@ srifqi: textures/base/pack/minimap_btn.png Zughy: - textures/base/pack/cdb_add.png textures/base/pack/cdb_downloading.png textures/base/pack/cdb_queued.png textures/base/pack/cdb_update.png textures/base/pack/cdb_update_cropped.png - textures/base/pack/cdb_viewonline.png textures/base/pack/settings_btn.png textures/base/pack/settings_info.png textures/base/pack/settings_reset.png @@ -79,7 +77,6 @@ kilbith: textures/base/pack/progress_bar_bg.png SmallJoker: - textures/base/pack/cdb_clear.png textures/base/pack/server_favorite_delete.png (based on server_favorite.png) DS: diff --git a/builtin/mainmenu/content/dlg_contentdb.lua b/builtin/mainmenu/content/dlg_contentdb.lua index 5c943d0b4..e8749b370 100644 --- a/builtin/mainmenu/content/dlg_contentdb.lua +++ b/builtin/mainmenu/content/dlg_contentdb.lua @@ -26,23 +26,17 @@ end -- Filter local search_string = "" local cur_page = 1 -local num_per_page = 5 -local filter_type = 1 -local filter_types_titles = { - fgettext("All packages"), - fgettext("Games"), - fgettext("Mods"), - fgettext("Texture packs"), -} +local filter_type -- Automatic package installation local auto_install_spec = nil -local filter_types_type = { - nil, - "game", - "mod", - "txp", + +local filter_type_names = { + { "type_all", nil }, + { "type_game", "game" }, + { "type_mod", "mod" }, + { "type_txp", "txp" }, } @@ -154,7 +148,7 @@ end local function sort_and_filter_pkgs() contentdb.update_paths() contentdb.sort_packages() - contentdb.filter_packages(search_string, filter_types_type[filter_type]) + contentdb.filter_packages(search_string, filter_type) local auto_install_pkg = resolve_auto_install_spec() if auto_install_pkg then @@ -185,72 +179,130 @@ local function load() end -local function get_info_formspec(text) - local H = 9.5 +local function get_info_formspec(size, safezone_left, text) return table.concat({ "formspec_version[6]", - "size[15.75,9.5]", - core.settings:get_bool("enable_touch") and "padding[0.01,0.01]" or "position[0.5,0.55]", + "size[", size.x, ",", size.y, "]", + "padding[-0.01,-0.01]", - "label[4,4.35;", text, "]", - "container[0,", H - 0.8 - 0.375, "]", - "button[0.375,0;5,0.8;back;", fgettext("Back to Main Menu"), "]", + "label[", safezone_left + 3.625, ",4.35;", text, "]", + "container[0,", size.y - 0.8 - 0.375, "]", + "button[", safezone_left, ",0;4,0.8;back;", fgettext("Back"), "]", "container_end[]", }) end +-- Determines how to fit `num_per_page` into `size` space +local function fit_cells(num_per_page, size) + local cell_spacing = 0.25 + local desired_size = 4.5 + local row_cells = math.min(5, math.floor(size.x / desired_size)) + local cell_w, cell_h + -- Fit cells into the available height + while true do + cell_w = (size.x - (row_cells-1)*cell_spacing) / row_cells + cell_h = cell_w * 2 / 3 + + local required_height = math.ceil(num_per_page / row_cells) * (cell_h + cell_spacing) - cell_spacing + -- Add 0.1 to be more lenient + if required_height <= size.y + 0.1 then + break + end + + row_cells = row_cells + 1 + end + + return cell_spacing, row_cells, cell_w, cell_h +end + + local function get_formspec(dlgdata) + local safezone_left = PLATFORM == "Android" and 1 or 0.375 + local window = core.get_window_info() + local size = { x = window.max_formspec_size.x, y = window.max_formspec_size.y } + if contentdb.loading then - return get_info_formspec(fgettext("Loading...")) + return get_info_formspec(size, safezone_left, fgettext("Loading...")) end if contentdb.load_error then - return get_info_formspec(fgettext("No packages could be retrieved")) + return get_info_formspec(size, safezone_left, fgettext("No packages could be retrieved")) end assert(contentdb.load_ok) contentdb.update_paths() + local num_per_page = dlgdata.num_per_page dlgdata.pagemax = math.max(math.ceil(#contentdb.packages / num_per_page), 1) if cur_page > dlgdata.pagemax then cur_page = 1 end - local W = 15.75 - local H = 9.5 + local W = size.x - safezone_left + local H = size.y + + local category_x = 0 + local number_category_buttons = 4 + local max_button_w = (W - 0.375 - 0.25 - 7) / number_category_buttons + local category_button_w = math.min(max_button_w, 3) + local function make_category_button(name, label, selected) + category_x = category_x + 1 + local color = selected and mt_color_green or "" + return ("style[%s;bgcolor=%s]button[%f,0;%f,0.8;%s;%s]"):format(name, color, + (category_x - 1) * category_button_w, category_button_w, name, label) + end + + + local selected_type = filter_type + + local search_box_width = W - 0.375 - 0.25 - 2*0.8 + - number_category_buttons * category_button_w local formspec = { - "formspec_version[6]", - "size[15.75,9.5]", - core.settings:get_bool("enable_touch") and "padding[0.01,0.01]" or "position[0.5,0.55]", + "formspec_version[7]", + "size[", size.x, ",", size.y, "]", + "padding[-0.01,-0.01]", - "style[status,downloading,queued;border=false]", + "container[", safezone_left, ",0]", - "container[0.375,0.375]", - "field[0,0;7.225,0.8;search_string;;", core.formspec_escape(search_string), "]", + -- Top-left: categories + "container[0,0.375]", + make_category_button("type_all", fgettext("All"), selected_type == nil), + make_category_button("type_game", fgettext("Games"), selected_type == "game"), + make_category_button("type_mod", fgettext("Mods"), selected_type == "mod"), + make_category_button("type_txp", fgettext("Texture Packs"), selected_type == "txp"), + "container_end[]", + + -- Top-right: Search + "container[", W - 0.375 - search_box_width - 0.8*2, ",0.375]", + "field[0,0;", search_box_width, ",0.8;search_string;;", core.formspec_escape(search_string), "]", "field_enter_after_edit[search_string;true]", - "image_button[7.3,0;0.8,0.8;", core.formspec_escape(defaulttexturedir .. "search.png"), ";search;]", - "image_button[8.125,0;0.8,0.8;", core.formspec_escape(defaulttexturedir .. "clear.png"), ";clear;]", - "dropdown[9.175,0;2.7875,0.8;type;", table.concat(filter_types_titles, ","), ";", filter_type, "]", + "image_button[", search_box_width, ",0;0.8,0.8;", + core.formspec_escape(defaulttexturedir .. "search.png"), ";search;]", + "image_button[", search_box_width + 0.8, ",0;0.8,0.8;", + core.formspec_escape(defaulttexturedir .. "clear.png"), ";clear;]", "container_end[]", - -- Page nav buttons + -- Bottom strip start "container[0,", H - 0.8 - 0.375, "]", - "button[0.375,0;5,0.8;back;", fgettext("Back to Main Menu"), "]", + "button[0,0;4,0.8;back;", fgettext("Back to Main Menu"), "]", - "container[", W - 0.375 - 0.8*4 - 2, ",0]", - "image_button[0,0;0.8,0.8;", core.formspec_escape(defaulttexturedir), "start_icon.png;pstart;]", - "image_button[0.8,0;0.8,0.8;", core.formspec_escape(defaulttexturedir), "prev_icon.png;pback;]", + -- Bottom-center: Page nav buttons + "container[", (W - 1*4 - 2) / 2, ",0]", + "image_button[0,0;1,0.8;", core.formspec_escape(defaulttexturedir), "start_icon.png;pstart;]", + "image_button[1,0;1,0.8;", core.formspec_escape(defaulttexturedir), "prev_icon.png;pback;]", "style[pagenum;border=false]", - "button[1.6,0;2,0.8;pagenum;", tonumber(cur_page), " / ", tonumber(dlgdata.pagemax), "]", - "image_button[3.6,0;0.8,0.8;", core.formspec_escape(defaulttexturedir), "next_icon.png;pnext;]", - "image_button[4.4,0;0.8,0.8;", core.formspec_escape(defaulttexturedir), "end_icon.png;pend;]", - "container_end[]", + "button[2,0;2,0.8;pagenum;", tonumber(cur_page), " / ", tonumber(dlgdata.pagemax), "]", + "image_button[4,0;1,0.8;", core.formspec_escape(defaulttexturedir), "next_icon.png;pnext;]", + "image_button[5,0;1,0.8;", core.formspec_escape(defaulttexturedir), "end_icon.png;pend;]", + "container_end[]", -- page nav end - "container_end[]", + -- Bottom-right: updating + "container[", W - 0.375 - 3, ",0]", + "style[status,downloading,queued;border=false]", } if contentdb.number_downloading > 0 then - formspec[#formspec + 1] = "button[12.5875,0.375;2.7875,0.8;downloading;" + formspec[#formspec + 1] = "button[0,0;3,0.8;downloading;" if #contentdb.download_queue > 0 then formspec[#formspec + 1] = fgettext("$1 downloading,\n$2 queued", contentdb.number_downloading, #contentdb.download_queue) @@ -269,16 +321,19 @@ local function get_formspec(dlgdata) end if num_avail_updates == 0 then - formspec[#formspec + 1] = "button[12.5875,0.375;2.7875,0.8;status;" + formspec[#formspec + 1] = "button[0,0;3,0.8;status;" formspec[#formspec + 1] = fgettext("No updates") formspec[#formspec + 1] = "]" else - formspec[#formspec + 1] = "button[12.5875,0.375;2.7875,0.8;update_all;" + formspec[#formspec + 1] = "button[0,0;3,0.8;update_all;" formspec[#formspec + 1] = fgettext("Update All [$1]", num_avail_updates) formspec[#formspec + 1] = "]" end end + formspec[#formspec + 1] = "container_end[]" -- updating end + formspec[#formspec + 1] = "container_end[]" -- bottom strip end + if #contentdb.packages == 0 then formspec[#formspec + 1] = "label[4,4.75;" formspec[#formspec + 1] = fgettext("No results") @@ -290,46 +345,80 @@ local function get_formspec(dlgdata) formspec[#formspec + 1] = "tooltip[downloading;" .. fgettext("Downloading...") .. tooltip_colors formspec[#formspec + 1] = "tooltip[queued;" .. fgettext("Queued") .. tooltip_colors + formspec[#formspec + 1] = "container[0,1.425]" + + local cell_spacing, row_cells, cell_w, cell_h = fit_cells(num_per_page, { + x = W - 0.375, + y = H - 1.425 - 0.25 - 0.8 - 0.375 + }) + local start_idx = (cur_page - 1) * num_per_page + 1 for i=start_idx, math.min(#contentdb.packages, start_idx+num_per_page-1) do local package = contentdb.packages[i] - local container_y = (i - start_idx) * 1.375 + (2*0.375 + 0.8) - formspec[#formspec + 1] = "container[0.375," - formspec[#formspec + 1] = container_y - formspec[#formspec + 1] = "]" - -- image - formspec[#formspec + 1] = "image[0,0;1.5,1;" - formspec[#formspec + 1] = core.formspec_escape(get_screenshot(package, package.thumbnail)) - formspec[#formspec + 1] = "]" + table.insert_all(formspec, { + "container[", + (cell_w + cell_spacing) * ((i - start_idx) % row_cells), + ",", + (cell_h + cell_spacing) * math.floor((i - start_idx) / row_cells), + "]", - -- title - formspec[#formspec + 1] = "label[1.875,0.1;" - formspec[#formspec + 1] = core.formspec_escape( - core.colorize(mt_color_green, package.title) .. - core.colorize("#BFBFBF", " by " .. package.author)) - formspec[#formspec + 1] = "]" + -- image, + "image_button[0,0;", cell_w, ",", cell_h, ";", + core.formspec_escape(get_screenshot(package, package.thumbnail, 2)), + ";view_", i, ";;;false]", - -- button - formspec[#formspec + 1] = "button[" - formspec[#formspec + 1] = W-0.375*2-2 - formspec[#formspec + 1] = ",0.1;2,0.7;view_" - formspec[#formspec + 1] = i - formspec[#formspec + 1] = ";" - formspec[#formspec + 1] = fgettext("View") - formspec[#formspec + 1] = "]" + --"style[title_", i, ";border=false]", + -- The 0.01 here fixes a single line of image pixels appearing below the box + "box[0,", cell_h - 0.8 + 0.01, ";", cell_w, ",0.8;#0009]", - -- description - local description_width = W - 2.625 - 2 * 0.7 - 2 * 0.15 - formspec[#formspec + 1] = "textarea[1.855,0.3;" - formspec[#formspec + 1] = tostring(description_width) - formspec[#formspec + 1] = ",0.8;;;" - formspec[#formspec + 1] = core.formspec_escape(package.short_description) - formspec[#formspec + 1] = "]" + "style_type[button;border=false;textcolor=", mt_color_green, "]", + "button[0.25,", cell_h - 0.8, ";", cell_w - 0.5, ",0.5;title_", i ,";", + core.formspec_escape(core.colorize(mt_color_green, package.title)), "]", + "style_type[button;font_size=*0.9;textcolor=#fff9]", + "button[0.25,", cell_h - 0.3, ";", cell_w - 0.5, ",0.3;author_", i, ";", + core.formspec_escape(core.colorize("#fff9", package.author)), "]", + "style_type[button;font_size=;border=;textcolor=]", + }) - formspec[#formspec + 1] = "container_end[]" + if package.featured then + table.insert_all(formspec, { + "tooltip[0,0;0.8,0.8;", fgettext("Featured"), "]", + "image[0.2,0.2;0.4,0.4;", defaulttexturedir, "server_favorite.png]", + }) + end + + if package.downloading then + table.insert_all(formspec, { + "animated_image[", cell_w - 0.8, ",0;0.8,0.8;downloading;", defaulttexturedir, "cdb_downloading.png;3;400;;]", + }) + elseif package.queued then + table.insert_all(formspec, { + "image[", cell_w - 0.8, ",0;0.8,0.8;", defaulttexturedir, "cdb_queued.png]", + }) + elseif package.path then + if package.installed_release < package.release then + table.insert_all(formspec, { + "image[", cell_w - 0.8, ",0;0.8,0.8;", defaulttexturedir, "cdb_update.png]", + }) + else + table.insert_all(formspec, { + "image[", cell_w - 0.6, ",0.2;0.4,0.4;", defaulttexturedir, "checkbox_64.png]", + }) + end + end + + local tooltip = package.short_description + + table.insert_all(formspec, { + "tooltip[0,0;", cell_w, ",", cell_h, ";", core.formspec_escape(tooltip), "]", + "container_end[]", + }) end + formspec[#formspec + 1] = "container_end[]" + formspec[#formspec + 1] = "container_end[]" + return table.concat(formspec) end @@ -338,14 +427,14 @@ local function handle_submit(this, fields) if fields.search or fields.key_enter_field == "search_string" then search_string = fields.search_string:trim() cur_page = 1 - contentdb.filter_packages(search_string, filter_types_type[filter_type]) + contentdb.filter_packages(search_string, filter_type) return true end if fields.clear then search_string = "" cur_page = 1 - contentdb.filter_packages("", filter_types_type[filter_type]) + contentdb.filter_packages("", filter_type) return true end @@ -381,12 +470,11 @@ local function handle_submit(this, fields) return true end - if fields.type then - local new_type = table.indexof(filter_types_titles, fields.type) - if new_type ~= filter_type then - filter_type = new_type + for _, pair in ipairs(filter_type_names) do + if fields[pair[1]] then + filter_type = pair[2] cur_page = 1 - contentdb.filter_packages(search_string, filter_types_type[filter_type]) + contentdb.filter_packages(search_string, filter_type) return true end end @@ -409,7 +497,7 @@ local function handle_submit(this, fields) local package = contentdb.packages[i] assert(package) - if fields["view_" .. i] then + if fields["view_" .. i] or fields["title_" .. i] or fields["author_" .. i] then local dlg = create_package_dialog(package) dlg:set_parent(this) this:hide() @@ -447,17 +535,7 @@ end function create_contentdb_dlg(type, install_spec) search_string = "" cur_page = 1 - if type then - -- table.indexof does not work on tables that contain `nil` - for i, v in pairs(filter_types_type) do - if v == type then - filter_type = i - break - end - end - else - filter_type = 1 - end + filter_type = type -- Keep the old auto_install_spec if the caller doesn't specify one. if install_spec then @@ -466,8 +544,10 @@ function create_contentdb_dlg(type, install_spec) load() - return dialog_create("contentdb", + local dlg = dialog_create("contentdb", get_formspec, handle_submit, handle_events) + dlg.data.num_per_page = core.settings:get_bool("enable_touch") and 8 or 15 + return dlg end diff --git a/textures/base/pack/cdb_add.png b/textures/base/pack/cdb_add.png deleted file mode 100644 index 3e3d067e33b98a39c1e07e17a611fa88eeb23281..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 147 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@o&cW^S0KIZs!ic46U%BBo0DHI z0{M(3L4Lsu4$p3+0Xe3gE{-7;w~`YU$UTT^IQPJ(!6<^cz%Z<>Ev-?~+u3<>fMmhS q|M8FiKQ>~|V_o+4kG#frVTP$m0*-x0uSx?AVDNPHb6Mw<&;$S-YA!PX diff --git a/textures/base/pack/cdb_clear.png b/textures/base/pack/cdb_clear.png deleted file mode 100644 index d5df4a067f5e207257eecef0fffd4f98cdf88984..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 150 zcmeAS@N?(olHy`uVBq!ia0vp^3Lq@N0wg;h=h*-_(J z_(MZPU%!2gOoPmsCrMqh8^7H8|NlwSuOr7dus=DX8oK%UrR*7Pf`^w!NlBC*Si$Tj xYoH)>u3+61;WK$w!4@ewplLUl7&N|CO}ul-Vm$ z-@z#j6k;q1@(X5gcy=QV$cgiGaSW-rm7E|E(%|Xo$v9PiNr%#+6&g7jDlJPKJOXY6 z1Ozf}ZgpxuS3das?*KDHmN@U5yct51fi^LCy85}Sb4q9e08d;#XaE2J From 18ef9b0f50fb365a94f743a6ed4d87d8606984c9 Mon Sep 17 00:00:00 2001 From: Gregor Parzefall Date: Wed, 10 Apr 2024 21:46:00 +0200 Subject: [PATCH 3/7] Consistent size for internal scrollbars of formspec elements --- src/client/clientlauncher.cpp | 2 +- src/gui/guiTable.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client/clientlauncher.cpp b/src/client/clientlauncher.cpp index 52fadb192..da8118a7e 100644 --- a/src/client/clientlauncher.cpp +++ b/src/client/clientlauncher.cpp @@ -343,7 +343,7 @@ void ClientLauncher::init_guienv(gui::IGUIEnvironment *guienv) float density = rangelim(g_settings->getFloat("gui_scaling"), 0.5f, 20) * RenderingEngine::getDisplayDensity(); skin->setSize(gui::EGDS_CHECK_BOX_WIDTH, (s32)(17.0f * density)); - skin->setSize(gui::EGDS_SCROLLBAR_SIZE, (s32)(14.0f * density)); + skin->setSize(gui::EGDS_SCROLLBAR_SIZE, (s32)(21.0f * density)); skin->setSize(gui::EGDS_WINDOW_BUTTON_WIDTH, (s32)(15.0f * density)); if (density > 1.5f) { std::string sprite_path = porting::path_share + "/textures/base/pack/"; diff --git a/src/gui/guiTable.cpp b/src/gui/guiTable.cpp index 530580124..df3898611 100644 --- a/src/gui/guiTable.cpp +++ b/src/gui/guiTable.cpp @@ -60,7 +60,7 @@ GUITable::GUITable(gui::IGUIEnvironment *env, m_rowheight = MYMAX(m_rowheight, 1); } - const s32 s = skin->getSize(gui::EGDS_SCROLLBAR_SIZE) * 1.5f; + const s32 s = skin->getSize(gui::EGDS_SCROLLBAR_SIZE); m_scrollbar = new GUIScrollBar(Environment, this, -1, core::rect(RelativeRect.getWidth() - s, 0, From c1bc340b786a0ad144d2e36d502c20d68d01b7cc Mon Sep 17 00:00:00 2001 From: Gregor Parzefall Date: Thu, 11 Apr 2024 00:21:13 +0200 Subject: [PATCH 4/7] ContentDB: Tweak package page --- builtin/mainmenu/content/dlg_package.lua | 73 ++++++++---------------- 1 file changed, 25 insertions(+), 48 deletions(-) diff --git a/builtin/mainmenu/content/dlg_package.lua b/builtin/mainmenu/content/dlg_package.lua index 126b3d8ad..ed1ab97ff 100644 --- a/builtin/mainmenu/content/dlg_package.lua +++ b/builtin/mainmenu/content/dlg_package.lua @@ -30,19 +30,6 @@ local function get_info_formspec(size, text) end ---- Creates a scrollbaroptions for a scroll_container --- --- @param visible_l the length of the scroll_container and scrollbar --- @param total_l length of the scrollable area --- @param scroll_factor as passed to scroll_container -local function make_scrollbaroptions_for_scroll_container(visible_l, total_l, scroll_factor) - assert(total_l >= visible_l) - local max = total_l - visible_l - local thumb_size = (visible_l / total_l) * max - return ("scrollbaroptions[min=0;max=%f;thumbsize=%f]"):format(max / scroll_factor, thumb_size / scroll_factor) -end - - local function get_formspec(data) local window = core.get_window_info() local size = { x = window.max_formspec_size.x, y = window.max_formspec_size.y } @@ -173,48 +160,38 @@ local function get_formspec(data) if current_tab == 1 then -- Screenshots and description - local hypertext = info.long_description.head .. - "" .. core.hypertext_escape(info.short_description) .. "\n\n" .. + local hypertext = "" .. core.hypertext_escape(info.short_description) .. "\n" + local winfo = core.get_window_info() + local fs_to_px = winfo.size.x / winfo.max_formspec_size.x + for i, ss in ipairs(info.screenshots) do + local path = get_screenshot(data.package, ss.url, 2) + hypertext = hypertext .. "" + if i ~= #info.screenshots then + hypertext = hypertext .. "" + end + end + hypertext = hypertext .. "\n" .. info.long_description.head .. info.long_description.body hypertext = hypertext:gsub(" size.x - local hypertext_y = (#info.screenshots > 0 and 2.25 or 0) + (needs_scrollbar and 0.5 or 0) - table.insert_all(formspec, { - "hypertext[0.375,", hypertext_y, ";", - size.x - 2*0.375, ",", - tab_body_height - hypertext_y - 0.375, + "hypertext[0.375,0;", + size.x - 3*0.375, ",", + tab_body_height - 0.375, ";desc;", core.formspec_escape(hypertext), "]", - "scroll_container[0,0;", size.x, ",2.25;images_sb;horizontal;", scroll_factor, "]", }) - for i, ss in ipairs(info.screenshots) do - local path = get_screenshot(data.package, ss.url, 2) - table.insert_all(formspec, { - "image_button[", (i-1)*3.25 + 0.375, ",0;3,2;", - core.formspec_escape(path), ";ss_", i, ";;false;false]", - }) - end - - formspec[#formspec + 1] = "scroll_container_end[]" - - if needs_scrollbar then - table.insert_all(formspec, { - make_scrollbaroptions_for_scroll_container(size.x, screenshots_w, scroll_factor), - "scrollbar[0,2.25;", size.x, ",0.25;horizontal;images_sb;0]", - }) - end elseif current_tab == 2 then local hypertext = info.info_hypertext.head .. info.info_hypertext.body table.insert_all(formspec, { - "hypertext[0.375,0;", size.x - 2*0.375, ",", tab_body_height - 0.375, + "hypertext[0.375,0;", size.x - 3*0.375, ",", tab_body_height - 0.375, ";info;", core.formspec_escape(hypertext), "]", }) else @@ -233,6 +210,13 @@ local function handle_hypertext_event(this, event, hypertext_object) return end + for i, ss in ipairs(this.data.info.screenshots) do + if event == "action:ss_" .. i then + core.open_url(ss.url) + return true + end + end + -- TODO: escape base_url local base_url = core.settings:get("contentdb_url") for key, url in pairs(hypertext_object.links) do @@ -320,13 +304,6 @@ local function handle_submit(this, fields) return true end - for i, ss in ipairs(info.screenshots) do - if fields["ss_" .. i] then - core.open_url(ss.url) - return true - end - end - if handle_hypertext_event(this, fields.desc, info.long_description) or handle_hypertext_event(this, fields.info, info.info_hypertext) then return true From e81f3857ddee29b0d4616785449eb2e9cf6a3923 Mon Sep 17 00:00:00 2001 From: rubenwardy Date: Wed, 17 Apr 2024 18:51:45 +0100 Subject: [PATCH 5/7] ContentDB redesign: Move links to hypertext --- builtin/mainmenu/content/dlg_package.lua | 78 ++++++++++-------------- 1 file changed, 33 insertions(+), 45 deletions(-) diff --git a/builtin/mainmenu/content/dlg_package.lua b/builtin/mainmenu/content/dlg_package.lua index ed1ab97ff..0ea7db617 100644 --- a/builtin/mainmenu/content/dlg_package.lua +++ b/builtin/mainmenu/content/dlg_package.lua @@ -44,7 +44,14 @@ local function get_formspec(data) if info == nil then data.loading_error = true ui.update() - elseif data.package.name == info.name then + return + end + + if info.forums then + info.forums = "https://forum.minetest.net/viewtopic.php?t=" .. info.forums + end + + if data.package.name == info.name then data.info = info ui.update() end @@ -86,21 +93,6 @@ local function get_formspec(data) "label[0.375,1.4;", core.formspec_escape(info_line), "]", } - local x = size.x - 3.375 - local function add_link_button(label, name) - if info[name] then - x = x - 3.25 - table.insert_all(formspec, { - "button[", x, ",", bottom_buttons_y, ";3,0.8;open_", name, ";", label, "]", - }) - end - end - add_link_button(fgettext("Translate"), "translation_url") - add_link_button(fgettext("Issue Tracker"), "issue_tracker") - add_link_button(fgettext("Forums"), "forums") - add_link_button(fgettext("Source"), "repo") - add_link_button(fgettext("Website"), "website") - table.insert_all(formspec, { "container[", size.x - 6.375, ",0.375]" }) @@ -158,6 +150,7 @@ local function get_formspec(data) "container[0,2.8]", }) + local safezone_right = PLATFORM == "Android" and 0.375 or 0 if current_tab == 1 then -- Screenshots and description local hypertext = "" .. core.hypertext_escape(info.short_description) .. "\n" @@ -173,15 +166,35 @@ local function get_formspec(data) " height=" .. (2.25 * fs_to_px).. ">" end end - hypertext = hypertext .. "\n" .. info.long_description.head .. - info.long_description.body + hypertext = hypertext .. "\n" .. info.long_description.head + + local first = true + local function add_link_button(label, name) + if info[name] then + if not first then + hypertext = hypertext .. " | " + end + hypertext = hypertext .. "" .. core.hypertext_escape(label) .. "" + info.long_description.links["link_" .. name] = info[name] + first = false + end + end + + add_link_button(fgettext("Donate"), "donate_url") + add_link_button(fgettext("Website"), "website") + add_link_button(fgettext("Source"), "repo") + add_link_button(fgettext("Issue Tracker"), "issue_tracker") + add_link_button(fgettext("Translate"), "translation_url") + add_link_button(fgettext("Forum Topic"), "forums") + + hypertext = hypertext .. "\n\n" .. info.long_description.body hypertext = hypertext:gsub(" Date: Sun, 5 May 2024 14:54:20 +0100 Subject: [PATCH 7/7] Escape img name --- builtin/mainmenu/content/dlg_package.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/mainmenu/content/dlg_package.lua b/builtin/mainmenu/content/dlg_package.lua index 0ea7db617..2c1494d8d 100644 --- a/builtin/mainmenu/content/dlg_package.lua +++ b/builtin/mainmenu/content/dlg_package.lua @@ -190,7 +190,7 @@ local function get_formspec(data) hypertext = hypertext .. "\n\n" .. info.long_description.body hypertext = hypertext:gsub("