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/contentdb.lua b/builtin/mainmenu/content/contentdb.lua index 4d59826dd..5d6d6c482 100644 --- a/builtin/mainmenu/content/contentdb.lua +++ b/builtin/mainmenu/content/contentdb.lua @@ -641,3 +641,27 @@ function contentdb.get_full_package_info(package, callback) callback(nil) end end + + +function contentdb.get_formspec_padding() + -- Padding is increased on Android to account for notches + -- TODO: use Android API to determine size of cut outs + return { x = PLATFORM == "Android" and 1 or 0.5, y = PLATFORM == "Android" and 0.25 or 0.5 } +end + + +function contentdb.get_formspec_size() + local window = core.get_window_info() + local size = { x = window.max_formspec_size.x, y = window.max_formspec_size.y } + + -- Minimum formspec size + local min_x = 15.5 + local min_y = 10 + if size.x < min_x or size.y < min_y then + local scale = math.max(min_x / size.x, min_y / size.y) + size.x = size.x * scale + size.y = size.y * scale + end + + return size +end diff --git a/builtin/mainmenu/content/dlg_contentdb.lua b/builtin/mainmenu/content/dlg_contentdb.lua index 025430bfa..a86815b77 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" }, } @@ -103,7 +97,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 @@ -134,72 +128,151 @@ local function load() end -local function get_info_formspec(text) - local H = 9.5 +local function get_info_formspec(size, padding, text) return table.concat({ "formspec_version[6]", - "size[15.75,9.5]", - core.settings:get_bool("touch_gui") and "padding[0.01,0.01]" or "position[0.5,0.55]", + "size[", size.x, ",", size.y, "]", + "padding[0,0]", + "bgcolor[;true]", - "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[", padding.x + 3.625, ",4.35;", text, "]", + "container[", padding.x, ",", size.y - 0.8 - padding.y, "]", + "button[0,0;2,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.5 + local columns = 1 + local cell_w, cell_h + -- Fit cells into the available height + while true do + cell_w = (size.x - (columns-1)*cell_spacing) / columns + cell_h = cell_w / 4 + + local required_height = math.ceil(num_per_page / columns) * (cell_h + cell_spacing) - cell_spacing + -- Add 0.1 to be more lenient + if required_height <= size.y + 0.1 then + break + end + + columns = columns + 1 + end + + return cell_spacing, columns, cell_w, cell_h +end + + +local function calculate_num_per_page() + local size = contentdb.get_formspec_size() + local padding = contentdb.get_formspec_padding() + local window = core.get_window_info() + + size.x = size.x - padding.x * 2 + size.y = size.y - padding.y * 2 - 1.425 - 0.25 - 0.8 + + local coordToPx = window.size.x / window.max_formspec_size.x / window.real_gui_scaling + + local num_per_page = 12 + while num_per_page > 2 do + local _, _, cell_w, _ = fit_cells(num_per_page, size) + if cell_w * coordToPx > 350 then + break + end + + num_per_page = num_per_page - 1 + end + return num_per_page +end + + local function get_formspec(dlgdata) + local window_padding = contentdb.get_formspec_padding() + local size = contentdb.get_formspec_size() + if contentdb.loading then - return get_info_formspec(fgettext("Loading...")) + return get_info_formspec(size, window_padding, fgettext("Loading...")) end if contentdb.load_error then - return get_info_formspec(fgettext("No packages could be retrieved")) + return get_info_formspec(size, window_padding, 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 - window_padding.x * 2 + local H = size.y - window_padding.y * 2 + + 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("touch_gui") and "padding[0.01,0.01]" or "position[0.5,0.55]", + "formspec_version[7]", + "size[", size.x, ",", size.y, "]", + "padding[0,0]", + "bgcolor[;true]", - "style[status,downloading,queued;border=false]", + "container[", window_padding.x, ",", window_padding.y, "]", - "container[0.375,0.375]", - "field[0,0;7.225,0.8;search_string;;", core.formspec_escape(search_string), "]", + -- Top-left: categories + 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"), + + -- Top-right: Search + "container[", W - search_box_width - 0.8*2, ",0]", + "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 - "container[0,", H - 0.8 - 0.375, "]", - "button[0.375,0;5,0.8;back;", fgettext("Back to Main Menu"), "]", + -- Bottom strip start + "container[0,", H - 0.8, "]", + "button[0,0;2,0.8;back;", fgettext("Back"), "]", - "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 - 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) @@ -218,16 +291,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") @@ -239,46 +315,85 @@ 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, columns, cell_w, cell_h = fit_cells(num_per_page, { + x = W, + y = H - 1.425 - 0.25 - 0.8 + }) + local img_w = cell_h * 3 / 2 + 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, 1)) - formspec[#formspec + 1] = "]" + table.insert_all(formspec, { + "container[", + (cell_w + cell_spacing) * ((i - start_idx) % columns), + ",", + (cell_h + cell_spacing) * math.floor((i - start_idx) / columns), + "]", - -- 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] = "]" + "box[0,0;", cell_w, ",", cell_h, ";#ffffff11]", - -- 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] = "]" + -- image, + "image[0,0;", img_w, ",", cell_h, ";", + core.formspec_escape(get_screenshot(package, package.thumbnail, 2)), "]", - -- 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] = "]" + "label[", img_w + 0.25 + 0.05, ",0.5;", + core.formspec_escape( + core.colorize(mt_color_green, package.title) .. + core.colorize("#BFBFBF", " by " .. package.author)), "]", - formspec[#formspec + 1] = "container_end[]" + "textarea[", img_w + 0.25, ",0.75;", cell_w - img_w - 0.25, ",", cell_h - 0.75, ";;;", + core.formspec_escape(package.short_description), "]", + + "style[view_", i, ";border=false]", + "style[view_", i, ":hovered;bgimg=", core.formspec_escape(defaulttexturedir .. "button_hover_semitrans.png"), "]", + "style[view_", i, ":pressed;bgimg=", core.formspec_escape(defaulttexturedir .. "button_press_semitrans.png"), "]", + "button[0,0;", cell_w, ",", cell_h, ";view_", i, ";]", + }) + + 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 + + table.insert_all(formspec, { + "container[", cell_w - 0.625,",", 0.25, "]", + }) + + if package.downloading then + table.insert_all(formspec, { + "animated_image[0,0;0.5,0.5;downloading;", defaulttexturedir, "cdb_downloading.png;3;400;;]", + }) + elseif package.queued then + table.insert_all(formspec, { + "image[0,0;0.5,0.5;", defaulttexturedir, "cdb_queued.png]", + }) + elseif package.path then + if package.installed_release < package.release then + table.insert_all(formspec, { + "image[0,0;0.5,0.5;", defaulttexturedir, "cdb_update.png]", + }) + else + table.insert_all(formspec, { + "image[0.1,0.1;0.3,0.3;", defaulttexturedir, "checkbox_64.png]", + }) + end + end + + table.insert_all(formspec, { + "container_end[]", + "container_end[]", + }) end + formspec[#formspec + 1] = "container_end[]" + formspec[#formspec + 1] = "container_end[]" + return table.concat(formspec) end @@ -287,14 +402,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 @@ -330,12 +445,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 @@ -351,13 +465,14 @@ 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["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() @@ -372,8 +487,8 @@ end local function handle_events(event) if event == "DialogShow" then - -- On touchscreen, don't show the "MINETEST" header behind the dialog. - mm_game_theme.set_engine(core.settings:get_bool("touch_gui")) + -- Don't show the "MINETEST" header behind the dialog. + mm_game_theme.set_engine(true) -- If ContentDB is already loaded, auto-install packages here. do_auto_install() @@ -395,17 +510,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 @@ -414,8 +519,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 = calculate_num_per_page() + return dlg end diff --git a/builtin/mainmenu/content/dlg_package.lua b/builtin/mainmenu/content/dlg_package.lua index 78bdf2e71..5b9db4860 100644 --- a/builtin/mainmenu/content/dlg_package.lua +++ b/builtin/mainmenu/content/dlg_package.lua @@ -32,11 +32,8 @@ end local function get_formspec(data) - -- Padding is increased on Android to account for notches - -- TODO: use Android API to determine size of cut outs - local window_padding = { x = PLATFORM == "Android" and 1 or 0.5, y = PLATFORM == "Android" and 0.25 or 0.5 } - local window = core.get_window_info() - local size = { x = window.max_formspec_size.x, y = window.max_formspec_size.y } + local window_padding = contentdb.get_formspec_padding() + local size = contentdb.get_formspec_size() size.x = math.min(size.x, 20) local W = size.x - window_padding.x * 2 local H = size.y - window_padding.y * 2 diff --git a/textures/base/pack/button_hover_semitrans.png b/textures/base/pack/button_hover_semitrans.png new file mode 100644 index 000000000..5cf294ead Binary files /dev/null and b/textures/base/pack/button_hover_semitrans.png differ diff --git a/textures/base/pack/button_press_semitrans.png b/textures/base/pack/button_press_semitrans.png new file mode 100644 index 000000000..ba0ddd510 Binary files /dev/null and b/textures/base/pack/button_press_semitrans.png differ diff --git a/textures/base/pack/cdb_add.png b/textures/base/pack/cdb_add.png deleted file mode 100644 index 3e3d067e3..000000000 Binary files a/textures/base/pack/cdb_add.png and /dev/null differ diff --git a/textures/base/pack/cdb_clear.png b/textures/base/pack/cdb_clear.png deleted file mode 100644 index d5df4a067..000000000 Binary files a/textures/base/pack/cdb_clear.png and /dev/null differ diff --git a/textures/base/pack/cdb_viewonline.png b/textures/base/pack/cdb_viewonline.png deleted file mode 100644 index ae2a146b8..000000000 Binary files a/textures/base/pack/cdb_viewonline.png and /dev/null differ