mirror of
https://github.com/UltimateMenu/UltimateMenu.git
synced 2026-10-10 03:43:09 +08:00
Show Ultimate Menu information in companion panel
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
||||
# Ultimate Menu for Nenyoo (GTA V Legacy)
|
||||
|
||||
This edition runs the YimMenu Legacy script through a Nenyoo API adapter. The bundled `lib/Ultimate_Menu_Legacy.lua` is an unchanged copy of `YimMenu/Ultimate_Menu_Legacy.lua`; the original menu hierarchy and action callbacks remain in one source file. YimMenu tabs, ImGui groups, controls, and popups appear as nested Nenyoo menu lists. Controls that depend on game state are added when their conditions become true.
|
||||
This edition runs the YimMenu Legacy script through a Nenyoo API adapter. The bundled `lib/Ultimate_Menu_Legacy.lua` is an unchanged copy of `YimMenu/Ultimate_Menu_Legacy.lua`; the original menu hierarchy and action callbacks remain in one source file. YimMenu tabs, controls, and popups appear as nested Nenyoo menu lists. Informational text and live status appear in a companion panel only while their submenu is open; hover the panel and use the mouse wheel for longer instructions. Controls that depend on game state are added when their conditions become true.
|
||||
|
||||
Copy the contents of this folder to `%LOCALAPPDATA%\Nenyoo\Plus\Scripts\User\UltimateMenu\`, then select `Ultimate_Menu.lua` from Nenyoo's Scripts menu to load its page. Keep the `lib` folder beside the entry script. The script targets GTA V Legacy build 3889 and uses the online menus only after joining GTA Online.
|
||||
|
||||
|
||||
+2
-2
@@ -4,8 +4,8 @@ Use GTA V **Legacy build 3889** and the Nenyoo DLL built with the `__ny_execute_
|
||||
|
||||
## First run
|
||||
|
||||
1. In Story Mode, open the page. Confirm `Ultimate Menu 1.73 By L7NEG` appears with `Story Mode`, `Self Menu`, `Recovery Menu`, `Online Services Menu`, `Collectibles`, `Events Menu`, `Gun Van Menu`, `YimResupplier`, and `Heists Data Editor Menu`. Open and back out of several nested lists. Record any missing row, empty page, freeze, or Lua error.
|
||||
2. In `Story Mode`, record the current character's cash, use `Current Character Cash` to set a distinct value, and confirm the game shows it. Restore the original value. Online-only pages should show a single, non-selectable `Unavailable in Single Player.` notice rather than actionable controls.
|
||||
1. In Story Mode, open the page. Confirm `Ultimate Menu 1.73 By L7NEG` appears with `Story Mode`, `Self Menu`, `Recovery Menu`, `Online Services Menu`, `Collectibles`, `Events Menu`, `Gun Van Menu`, `YimResupplier`, and `Heists Data Editor Menu`. Open and back out of several nested lists. Pages with explanations should show a companion information panel; the panel should close when leaving the page. Hover and scroll the panel to read long text. Record any missing row, empty page, freeze, or Lua error.
|
||||
2. In `Story Mode`, record the current character's cash, use `Current Character Cash` to set a distinct value, and confirm the game shows it. Restore the original value. Online-only pages should show `Unavailable in Single Player.` in the information panel rather than actionable controls.
|
||||
3. Join a GTA Online session and reopen the menu. Verify changing text, toggle, slider, combo, and button controls update the displayed value or game state. Leave the session and confirm Story Mode controls still work.
|
||||
4. In `Gun Van Menu > Weapons > Edit Weapons`, search for `Pistol`, select its row, and use `Set Weapon` on a recorded slot. Check that the displayed slot and the in-game Gun Van show Pistol. Restore the original weapon. Test `Remove Weapon` and `Close`, then reopen the editor.
|
||||
5. For a business you own, open `YimResupplier` and verify its controls appear after ownership is detected. Test a teleport to a known property and confirm the landing position. Repeat after changing sessions.
|
||||
|
||||
@@ -36,5 +36,6 @@ end
|
||||
|
||||
local compatibility = run(directory .. "lib\\yim_compat.lua")
|
||||
run(directory .. "lib\\Ultimate_Menu_Legacy.lua")
|
||||
run(directory .. "lib\\info_panel.lua")(compatibility)
|
||||
compatibility.materialize_imgui()
|
||||
return compatibility
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
-- Companion information panel for the Nenyoo edition of Ultimate Menu.
|
||||
-- The menu adapter publishes text on the script thread. Draw only the
|
||||
-- published strings here; overlay.on_draw runs on Nenyoo's render thread.
|
||||
return function(compat)
|
||||
local scroll_by_page = {}
|
||||
local last_page
|
||||
|
||||
local function clamp(value, low, high)
|
||||
return math.max(low, math.min(high, value))
|
||||
end
|
||||
|
||||
local function wrap_paragraph(value, max_width, output, heading, color)
|
||||
local line = ""
|
||||
for word in value:gmatch("%S+") do
|
||||
local candidate = line == "" and word or line .. " " .. word
|
||||
if line ~= "" and text.width(font.small, candidate) > max_width then
|
||||
output[#output + 1] = {text = line, heading = heading, color = color}
|
||||
line = word
|
||||
else
|
||||
line = candidate
|
||||
end
|
||||
end
|
||||
if line ~= "" then output[#output + 1] = {text = line, heading = heading, color = color} end
|
||||
end
|
||||
|
||||
local function make_lines(rows, max_width)
|
||||
local lines = {}
|
||||
for _, row in ipairs(rows) do
|
||||
local value = tostring(row.text or ""):gsub("\r", "")
|
||||
if value == "" then
|
||||
lines[#lines + 1] = {gap = 8}
|
||||
else
|
||||
local compact = value:gsub("%s+", " "):match("^%s*(.-)%s*$")
|
||||
local heading = #compact <= 38 and (compact:sub(-1) == ":" or compact == "Preps")
|
||||
for paragraph in (value .. "\n"):gmatch("(.-)\n") do
|
||||
if paragraph:match("%S") then wrap_paragraph(paragraph, max_width, lines, heading, row.color)
|
||||
else lines[#lines + 1] = {gap = 8} end
|
||||
end
|
||||
lines[#lines + 1] = {gap = heading and 7 or 11}
|
||||
end
|
||||
if row.tooltip then
|
||||
wrap_paragraph(row.tooltip:gsub("%s+", " "), max_width, lines, false, nil)
|
||||
lines[#lines + 1] = {gap = 11}
|
||||
end
|
||||
end
|
||||
while #lines > 0 and lines[#lines].gap do lines[#lines] = nil end
|
||||
return lines
|
||||
end
|
||||
|
||||
overlay.on_draw("ultimate_menu_information", function()
|
||||
if not menu.is_visible() then return end
|
||||
local id = menu.page_id()
|
||||
local info = compat.info_for_page(id)
|
||||
if not info or #info.rows == 0 then return end
|
||||
local sw, sh = ctx.screen_w(), ctx.screen_h()
|
||||
local bx, by, bw = menu.bounds()
|
||||
if not bw or bw <= 0 then return end
|
||||
|
||||
local gap, pad, header_h = 14, 14, 36
|
||||
local width = math.min(420, math.max(280, sw * 0.30))
|
||||
local side = bx + bw + gap + width <= sw - 8 or bx - gap - width >= 8
|
||||
if not side then width = math.min(600, sw - 16) end
|
||||
local x
|
||||
if side and bx + bw + gap + width <= sw - 8 then x = bx + bw + gap
|
||||
elseif side then x = bx - gap - width
|
||||
else x = clamp(bx + (bw - width) * 0.5, 8, sw - width - 8) end
|
||||
|
||||
local lines = make_lines(info.rows, width - pad * 2)
|
||||
if #lines == 0 then return end
|
||||
local line_h = text.height(font.small) + 4
|
||||
local content_h = 0
|
||||
for _, line in ipairs(lines) do content_h = content_h + (line.gap or line_h) end
|
||||
local desired_h = header_h + pad * 2 + content_h
|
||||
local height = math.min(desired_h, sh - 16, 650)
|
||||
local y = clamp(by, 8, sh - height - 8)
|
||||
if not side then
|
||||
local _, content_y, _, content_height = menu.content_rect()
|
||||
local below = content_y + content_height + 56
|
||||
local space_below = sh - below - 8
|
||||
if content_height > 0 and space_below >= 170 then
|
||||
y = below
|
||||
height = math.min(height, space_below)
|
||||
elseif by >= 180 then
|
||||
height = math.min(height, by - 16)
|
||||
y = by - height - 8
|
||||
end
|
||||
end
|
||||
local viewport_h = height - header_h - pad * 2
|
||||
if viewport_h <= line_h then return end
|
||||
|
||||
if last_page ~= id then scroll_by_page[id] = 0; last_page = id end
|
||||
local max_scroll = math.max(0, content_h - viewport_h)
|
||||
local scroll = clamp(scroll_by_page[id] or 0, 0, max_scroll)
|
||||
local mx, my = input.mouse_x(), input.mouse_y()
|
||||
if mx >= x and mx <= x + width and my >= y and my <= y + height then
|
||||
scroll = clamp(scroll - input.mouse_wheel() * line_h * 3, 0, max_scroll)
|
||||
end
|
||||
scroll_by_page[id] = scroll
|
||||
|
||||
local ar, ag, ab = theme.accent()
|
||||
draw.rect(x, y, x + width, y + height, 12, 15, 22, 232, 7)
|
||||
draw.rect(x, y, x + width, y + header_h, 24, 32, 44, 245, 7)
|
||||
draw.rect(x, y + header_h - 2, x + width, y + header_h, ar, ag, ab, 255)
|
||||
draw.rect_outline(x, y, x + width, y + height, ar, ag, ab, 125, 7)
|
||||
text.draw_ellipsis(font.item, x + pad, y + (header_h - text.height(font.item)) * 0.5,
|
||||
240, 245, 250, 255, info.title, width - pad * 2)
|
||||
|
||||
local top = y + header_h + pad
|
||||
draw.push_clip(x + pad, top, x + width - pad, top + viewport_h)
|
||||
local cursor = top - scroll
|
||||
for _, line in ipairs(lines) do
|
||||
if line.gap then cursor = cursor + line.gap
|
||||
else
|
||||
if cursor + line_h >= top and cursor <= top + viewport_h then
|
||||
local r, g, b = 220, 228, 238
|
||||
if line.heading then r, g, b = ar, ag, ab end
|
||||
if line.color then
|
||||
local function channel(value)
|
||||
value = value or 1
|
||||
return clamp(math.floor((value <= 1 and value * 255 or value) + 0.5), 0, 255)
|
||||
end
|
||||
r, g, b = channel(line.color[1]), channel(line.color[2]), channel(line.color[3])
|
||||
end
|
||||
text.draw(font.small, x + pad, cursor, r, g, b, 245, line.text)
|
||||
end
|
||||
cursor = cursor + line_h
|
||||
end
|
||||
end
|
||||
draw.pop_clip()
|
||||
if max_scroll > 0 then
|
||||
local track_top, track_height = top, viewport_h
|
||||
local thumb_h = math.max(22, track_height * viewport_h / content_h)
|
||||
local thumb_y = track_top + (track_height - thumb_h) * scroll / max_scroll
|
||||
draw.rect(x + width - 5, thumb_y, x + width - 2, thumb_y + thumb_h,
|
||||
ar, ag, ab, 190, 2)
|
||||
end
|
||||
end)
|
||||
end
|
||||
@@ -5,7 +5,7 @@ local threads_created = 0
|
||||
local thread_callbacks = {}
|
||||
local thread_origins = {}
|
||||
local menu_back_calls = 0
|
||||
local notices, deleted_notices = {}, {}
|
||||
local list_refs, current_page_id, panel_draw, drawn_text, menu_visible = {}, 0, nil, {}, true
|
||||
local memory_values = {}
|
||||
local last_pointer
|
||||
local function ref()
|
||||
@@ -17,7 +17,9 @@ menu = {
|
||||
list = function(_, label)
|
||||
counters.list = counters.list + 1
|
||||
list_names[label] = true
|
||||
return ref()
|
||||
local result = ref()
|
||||
list_refs[label] = result
|
||||
return result
|
||||
end,
|
||||
action = function(_, label, _, _, callback)
|
||||
counters.action = counters.action + 1
|
||||
@@ -34,14 +36,11 @@ menu = {
|
||||
return ref()
|
||||
end,
|
||||
readonly = function() counters.text = counters.text + 1; return ref() end,
|
||||
divider = function(_, label)
|
||||
local result = ref()
|
||||
if label == "Unavailable in Single Player." or label == "Waiting for game..." then
|
||||
notices[result.id] = label
|
||||
end
|
||||
return result
|
||||
end,
|
||||
delete = function(value) deleted_notices[value.id] = true end,
|
||||
divider = function() return ref() end,
|
||||
is_visible = function() return menu_visible end,
|
||||
page_id = function() return current_page_id end,
|
||||
bounds = function() return 100, 80, 420 end,
|
||||
content_rect = function() return 100, 250, 420, 440 end,
|
||||
get_value = function() return false end,
|
||||
set_value = function() end,
|
||||
get_menu_name = function() return "" end,
|
||||
@@ -57,7 +56,10 @@ __smenu = {
|
||||
node_in_viewport = function() return true end,
|
||||
}
|
||||
util = {
|
||||
joaat = function(name) return #tostring(name) end,
|
||||
joaat = function(name)
|
||||
local page = tostring(name):match("^Stand#(%d+)$")
|
||||
return page and (100000 + tonumber(page)) or #tostring(name)
|
||||
end,
|
||||
toast = function() end,
|
||||
yield = function()
|
||||
local _, is_main = coroutine.running()
|
||||
@@ -70,6 +72,23 @@ util = {
|
||||
return {}
|
||||
end,
|
||||
}
|
||||
overlay = {on_draw = function(name, callback)
|
||||
assert(name == "ultimate_menu_information", "Unexpected overlay registration")
|
||||
panel_draw = callback
|
||||
end}
|
||||
font = {small = 1, item = 2}
|
||||
ctx = {screen_w = function() return 1280 end, screen_h = function() return 900 end}
|
||||
input = {mouse_x = function() return 0 end, mouse_y = function() return 0 end,
|
||||
mouse_wheel = function() return 0 end}
|
||||
theme = {accent = function() return 55, 145, 245 end}
|
||||
text = {
|
||||
width = function(_, value) return #tostring(value) * 8 end,
|
||||
height = function() return 16 end,
|
||||
draw = function(_, _, _, _, _, _, _, value) drawn_text[#drawn_text + 1] = value end,
|
||||
draw_ellipsis = function(_, _, _, _, _, _, _, value) drawn_text[#drawn_text + 1] = value end,
|
||||
}
|
||||
draw = {rect = function() end, rect_outline = function() end,
|
||||
push_clip = function() end, pop_clip = function() end}
|
||||
__ny_execute_as_script = function(_, callback) callback(); return true end
|
||||
__ny_request_script_host = function() return true end
|
||||
memory = {
|
||||
@@ -187,22 +206,59 @@ if not os.getenv("UM_START_OFFLINE") then
|
||||
assert(counters.action >= 940, "Missing initial actions: " .. counters.action)
|
||||
end
|
||||
assert(#compat.imgui_sections >= 43, "Missing ImGui sections: " .. #compat.imgui_sections)
|
||||
assert(panel_draw, "Information overlay did not register")
|
||||
if os.getenv("UM_START_OFFLINE") then
|
||||
local viewport_thread = coroutine.create(thread_callbacks[#thread_callbacks])
|
||||
local ok, message = coroutine.resume(viewport_thread)
|
||||
assert(ok, message)
|
||||
assert(next(notices), "Single Player warning did not appear as a non-selectable row")
|
||||
for _, label in pairs(notices) do
|
||||
assert(not label:find("\n", 1, true), "Single Player warning spans multiple menu rows")
|
||||
local recovery_id = util.joaat("Stand#" .. list_refs["Set Rank menu"].id)
|
||||
local offline_info = compat.info_for_page(recovery_id)
|
||||
local warning = false
|
||||
for _, row in ipairs(offline_info.rows) do
|
||||
if row.text:find("Unavailable in Single Player", 1, true) then warning = true end
|
||||
end
|
||||
assert(warning, "Single Player warning did not reach the information panel")
|
||||
session_started = true
|
||||
ok, message = coroutine.resume(viewport_thread)
|
||||
assert(ok, message)
|
||||
for id in pairs(notices) do
|
||||
assert(deleted_notices[id], "Single Player warning remained after joining online")
|
||||
for _, row in ipairs(compat.info_for_page(recovery_id).rows) do
|
||||
assert(not row.text:find("Unavailable in Single Player", 1, true),
|
||||
"Single Player warning remained after joining online")
|
||||
end
|
||||
assert(counters.action >= 940, "Online controls did not appear after joining: " .. counters.action)
|
||||
end
|
||||
local apartment_id = util.joaat("Stand#" .. list_refs["Apartment Heist "].id)
|
||||
local apartment_info = compat.info_for_page(apartment_id)
|
||||
assert(apartment_info and #apartment_info.rows >= 5, "Apartment Heist instructions did not reach the panel")
|
||||
assert(counters.text == 0, "Informational text still occupies selectable menu rows")
|
||||
local kortz_id = util.joaat("Stand#" .. list_refs["Kortz Center Heist"].id)
|
||||
local kortz_info = compat.info_for_page(kortz_id)
|
||||
local colored_status, expanded_help = false, false
|
||||
for _, row in ipairs(kortz_info.rows) do
|
||||
if row.color then colored_status = true end
|
||||
if row.text:find("Select the main painting", 1, true) then expanded_help = true end
|
||||
end
|
||||
assert(colored_status, "Colored YimMenu status text lost its color")
|
||||
assert(expanded_help, "YimMenu help marker was not expanded in the panel")
|
||||
current_page_id = apartment_id
|
||||
panel_draw()
|
||||
local found_instruction = false
|
||||
local found_wrapped_instruction = false
|
||||
for _, value in ipairs(drawn_text) do
|
||||
if value:find("Pay for the preparation", 1, true) then found_instruction = true end
|
||||
if value:find("change the session", 1, true) then found_wrapped_instruction = true end
|
||||
end
|
||||
assert(found_instruction, "Long heist instructions were not drawn in the information panel")
|
||||
assert(found_wrapped_instruction, "Long heist instructions were cut off instead of wrapped")
|
||||
local drawn_count = #drawn_text
|
||||
current_page_id = 0
|
||||
panel_draw()
|
||||
assert(#drawn_text == drawn_count, "Information panel appeared outside its submenu")
|
||||
current_page_id = apartment_id
|
||||
menu_visible = false
|
||||
panel_draw()
|
||||
assert(#drawn_text == drawn_count, "Information panel remained after the menu closed")
|
||||
menu_visible = true
|
||||
for _, name in ipairs({"Self Menu", "Story Mode", "Recovery Menu", "Online Services Menu",
|
||||
"Collectibles", "Events Menu", "YimResupplier", "Heists Data Editor Menu", "Kortz Center Heist"}) do
|
||||
assert(list_names[name], "Missing original menu section: " .. name)
|
||||
|
||||
+70
-34
@@ -254,7 +254,16 @@ end
|
||||
|
||||
local tab_methods = {}
|
||||
local imgui_sections = {}
|
||||
local info_pages = {}
|
||||
local tab_mt = {__index = tab_methods}
|
||||
local function page_id(ref)
|
||||
return util.joaat("Stand#" .. tostring(type(ref) == "table" and ref.id or ref))
|
||||
end
|
||||
local function info_page(ref, title)
|
||||
local id = page_id(ref)
|
||||
if not info_pages[id] then info_pages[id] = {title = title or "Information", static = {}} end
|
||||
return info_pages[id], id
|
||||
end
|
||||
local function text_input(parent, label, help, callback, value)
|
||||
if menu.text_input then
|
||||
return menu.text_input(parent, label, {}, help, callback, value)
|
||||
@@ -262,6 +271,7 @@ local function text_input(parent, label, help, callback, value)
|
||||
return __smenu.text_input(type(parent) == "table" and parent.id or parent, label, {}, help, callback, value)
|
||||
end
|
||||
local function tab(ref, path)
|
||||
info_page(ref, path:match("([^/]+)$") or path)
|
||||
return setmetatable({ref = ref, path = path}, tab_mt)
|
||||
end
|
||||
|
||||
@@ -297,7 +307,10 @@ function tab_methods:add_input_int(label, default_value)
|
||||
function obj:set_value(value) self.value = value end
|
||||
return obj
|
||||
end
|
||||
function tab_methods:add_text(label) return menu.readonly(self.ref, label, "") end
|
||||
function tab_methods:add_text(label)
|
||||
local page = info_page(self.ref)
|
||||
page.static[#page.static + 1] = {text = tostring(label or "")}
|
||||
end
|
||||
function tab_methods:add_separator() return menu.divider(self.ref, "") end
|
||||
function tab_methods:add_sameline() end
|
||||
function tab_methods:add_imgui(callback)
|
||||
@@ -327,7 +340,7 @@ function script.execute_as_script(name, callback)
|
||||
return __ny_execute_as_script(name, callback)
|
||||
end
|
||||
|
||||
local current_section, current_event, building, widget_index, widget_occurrences, text_occurrences, separator_occurrences, parent_stack
|
||||
local current_section, current_event, building, widget_index, widget_occurrences, separator_occurrences, parent_stack
|
||||
local function current_parent() return parent_stack[#parent_stack] end
|
||||
local function push_parent(ref) parent_stack[#parent_stack + 1] = ref end
|
||||
local function pop_parent() if #parent_stack > 1 then parent_stack[#parent_stack] = nil end end
|
||||
@@ -364,13 +377,9 @@ local function label_for_menu(label)
|
||||
end
|
||||
local function replay(section, event)
|
||||
current_section, current_event = section, event
|
||||
building, widget_index, widget_occurrences, text_occurrences, separator_occurrences, parent_stack = false, 0, {}, {}, {}, {section.parent}
|
||||
section.notice_seen = false
|
||||
building, widget_index, widget_occurrences, separator_occurrences, parent_stack = false, 0, {}, {}, {section.parent}
|
||||
section.info_rows = {}
|
||||
section.callback()
|
||||
if section.notice_ref and not section.notice_seen then
|
||||
menu.delete(section.notice_ref)
|
||||
section.notice_ref = nil
|
||||
end
|
||||
current_section, current_event, parent_stack = nil, nil, nil
|
||||
end
|
||||
local function event_for(id, value)
|
||||
@@ -386,6 +395,7 @@ local function register_action(label, value)
|
||||
end)
|
||||
end
|
||||
section.last_ref = section.widget_refs[id]
|
||||
section.last_info_row = nil
|
||||
return event_for(id, value)
|
||||
end
|
||||
|
||||
@@ -402,6 +412,7 @@ function ImGui.Checkbox(label, value)
|
||||
end, value and true or false)
|
||||
end
|
||||
section.last_ref = section.widget_refs[id]
|
||||
section.last_info_row = nil
|
||||
if current_event and current_event.id == id then return current_event.value, true end
|
||||
return value, false
|
||||
end
|
||||
@@ -419,6 +430,7 @@ local function numeric_input(label, value, as_float)
|
||||
end, tostring(value or 0))
|
||||
end
|
||||
section.last_ref = section.widget_refs[id]
|
||||
section.last_info_row = nil
|
||||
if current_event and current_event.id == id then return current_event.value, true end
|
||||
return value, false
|
||||
end
|
||||
@@ -435,6 +447,7 @@ function ImGui.SliderInt(label, value, min_value, max_value)
|
||||
end)
|
||||
end
|
||||
section.last_ref = section.widget_refs[id]
|
||||
section.last_info_row = nil
|
||||
if current_event and current_event.id == id then return current_event.value, true end
|
||||
return value, false
|
||||
end
|
||||
@@ -448,6 +461,7 @@ function ImGui.InputText(label, value)
|
||||
end, value or "")
|
||||
end
|
||||
section.last_ref = section.widget_refs[id]
|
||||
section.last_info_row = nil
|
||||
if current_event and current_event.id == id then return current_event.value, true end
|
||||
return value, false
|
||||
end
|
||||
@@ -469,6 +483,7 @@ function ImGui.Combo(label, selected, choices, count)
|
||||
end
|
||||
end
|
||||
section.last_ref = section.containers_by_id[id]
|
||||
section.last_info_row = nil
|
||||
local current_choice = choices[(selected or 0) + 1]
|
||||
if current_choice then
|
||||
local display = menu_label .. ": " .. tostring(current_choice)
|
||||
@@ -477,7 +492,7 @@ function ImGui.Combo(label, selected, choices, count)
|
||||
if current_event and current_event.id == id then return current_event.value, true end
|
||||
return selected, false
|
||||
end
|
||||
function ImGui.Text(value)
|
||||
local function record_text(value, color)
|
||||
if value == nil or value == "" then return end
|
||||
local label = tostring(value)
|
||||
if current_section.tooltip then
|
||||
@@ -487,29 +502,21 @@ function ImGui.Text(value)
|
||||
return
|
||||
end
|
||||
local compact = label:gsub("%s+", " "):match("^%s*(.-)%s*$")
|
||||
if compact == "Unavailable in Single Player." or compact == "Waiting for game..." then
|
||||
current_section.notice_seen = true
|
||||
if not current_section.notice_ref then
|
||||
current_section.notice_ref = menu.divider(current_parent(), compact)
|
||||
elseif menu.get_menu_name(current_section.notice_ref) ~= compact then
|
||||
menu.set_menu_name(current_section.notice_ref, compact)
|
||||
end
|
||||
return
|
||||
end
|
||||
label = compact
|
||||
local text_id = source_key(text_occurrences, "text:" .. tostring(#current_section.text_refs + 1))
|
||||
if not current_section.text_refs[text_id] then
|
||||
current_section.text_refs[text_id] = menu.readonly(current_parent(), label, "")
|
||||
else
|
||||
local ref = current_section.text_refs[text_id]
|
||||
if menu.get_menu_name(ref) ~= label then menu.set_menu_name(ref, label) end
|
||||
end
|
||||
current_section.last_ref = current_section.text_refs[text_id]
|
||||
if #label <= 60 then current_section.last_text = label:gsub(":$", "") end
|
||||
local _, id = info_page(current_parent())
|
||||
local rows = current_section.info_rows[id]
|
||||
if not rows then rows = {}; current_section.info_rows[id] = rows end
|
||||
local row = {text = label, color = color}
|
||||
rows[#rows + 1] = row
|
||||
current_section.last_info_row = row
|
||||
current_section.last_ref = nil
|
||||
if #compact <= 60 then current_section.last_text = compact:gsub(":$", "") end
|
||||
end
|
||||
ImGui.Text = record_text
|
||||
ImGui.TextUnformatted = ImGui.Text
|
||||
ImGui.TextWrapped = ImGui.Text
|
||||
function ImGui.TextColored(_, _, _, _, value) ImGui.Text(value) end
|
||||
function ImGui.TextColored(r, g, b, a, value)
|
||||
record_text(value, {r, g, b, a})
|
||||
end
|
||||
function ImGui.Separator()
|
||||
local id = source_key(separator_occurrences, "separator:" .. tostring(widget_index))
|
||||
if not current_section.separator_refs[id] then
|
||||
@@ -523,7 +530,13 @@ function ImGui.ProgressBar(fraction, _, _, overlay)
|
||||
ImGui.Text(overlay or string.format("%d%%", math.floor(math.max(0, math.min(1, fraction or 0)) * 100)))
|
||||
end
|
||||
function ImGui.SetTooltip(message)
|
||||
if current_section.last_ref then menu.set_help_text(current_section.last_ref, tostring(message)) end
|
||||
if current_section.last_info_row then
|
||||
local row = current_section.last_info_row
|
||||
if row.text == "[?]" then row.text = tostring(message)
|
||||
else row.tooltip = tostring(message) end
|
||||
elseif current_section.last_ref then
|
||||
menu.set_help_text(current_section.last_ref, tostring(message))
|
||||
end
|
||||
end
|
||||
function ImGui.BeginTooltip() current_section.tooltip = true; return true end
|
||||
function ImGui.EndTooltip() current_section.tooltip = false end
|
||||
@@ -550,11 +563,13 @@ function ImGui.BeginTabItem(label)
|
||||
local ref = current_section.containers_by_id[id]
|
||||
if not ref then
|
||||
ref = menu.list(current_parent(), label, {}, "")
|
||||
info_page(ref, label)
|
||||
current_section.containers[#current_section.containers + 1] = ref
|
||||
current_section.containers_by_id[id] = ref
|
||||
end
|
||||
if not ref then return false end
|
||||
if current_event and not current_event.ancestors[ref.id] then return false end
|
||||
current_section.last_info_row = nil
|
||||
push_parent(ref)
|
||||
return true
|
||||
end
|
||||
@@ -577,15 +592,36 @@ ImGuiCol = {Text = 0}
|
||||
ImGuiTabBarFlags = {None = 0}
|
||||
ImGuiWindowFlags = {Modal = 0, NoCollapse = 0, NoMove = 0, NoResize = 0}
|
||||
|
||||
local compat = {imgui_sections = imgui_sections}
|
||||
local compat = {imgui_sections = imgui_sections, info_pages = info_pages}
|
||||
function compat.info_for_page(id)
|
||||
local page = info_pages[id]
|
||||
if not page then return nil end
|
||||
local rows, last_label = {}, nil
|
||||
local function append(row)
|
||||
local label = row.text:gsub("%s+", " "):match("^%s*(.-)%s*$")
|
||||
if label == "" then
|
||||
if #rows > 0 and rows[#rows].text ~= "" then rows[#rows + 1] = {text = ""} end
|
||||
last_label = nil
|
||||
elseif label ~= last_label then
|
||||
rows[#rows + 1] = row
|
||||
last_label = label
|
||||
end
|
||||
end
|
||||
for _, row in ipairs(page.static) do append(row) end
|
||||
for _, section in ipairs(imgui_sections) do
|
||||
local live = section.info_rows and section.info_rows[id]
|
||||
if live then for _, row in ipairs(live) do append(row) end end
|
||||
end
|
||||
return {title = page.title, rows = rows}
|
||||
end
|
||||
function compat.materialize_imgui()
|
||||
for _, section in ipairs(imgui_sections) do
|
||||
section.text_refs, section.widget_refs, section.separator_refs = {}, {}, {}
|
||||
section.widget_refs, section.separator_refs = {}, {}
|
||||
section.info_rows = {}
|
||||
section.containers, section.containers_by_id = {}, {}
|
||||
section.tooltip, section.last_ref, section.last_text = false, nil, nil
|
||||
section.notice_ref, section.notice_seen = nil, false
|
||||
current_section, current_event = section, nil
|
||||
building, widget_index, widget_occurrences, text_occurrences, separator_occurrences, parent_stack = true, 0, {}, {}, {}, {section.parent}
|
||||
building, widget_index, widget_occurrences, separator_occurrences, parent_stack = true, 0, {}, {}, {section.parent}
|
||||
scan_context = section.path:find("Story Mode", 1, true) and "story" or "online"
|
||||
section.callback()
|
||||
scan_context = nil
|
||||
|
||||
Reference in New Issue
Block a user