Skip to content

Commit 01e97dd

Browse files
ReimousTHIsaacMarovitz
authored andcommitted
Little Tweak
1 parent edcb9a4 commit 01e97dd

File tree

1 file changed

+188
-142
lines changed

1 file changed

+188
-142
lines changed

MarathonRecomp/ui/devtitle_menu.cpp

Lines changed: 188 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -175,193 +175,239 @@ static bool Sonic06Button(ImVec2 pos, const char* label, bool& hovered, const Im
175175
return pressed;
176176
}
177177

178+
//DrawStageMapSelector
179+
struct StageMapSelectorConfig {
180+
// Layout
181+
float windowWidthRatio = 0.8f;
182+
float buttonHeightRatio = 0.05f;
183+
float buttonSpacing = 5.0f;
184+
int defaultVisibleItems = 9;
185+
float itemsScaleHeightRatio = 0.05f;
186+
187+
// Positioning
188+
ImVec2 basePosRatio = { 0.15f, 0.45f };
189+
ImVec2 buttonOffset = { 10.0f, 0.0 };
190+
191+
// Colors
192+
ImU32 tooltipBgColor = IM_COL32(0, 0, 0, 180);
193+
ImU32 tooltipBorderColor = IM_COL32(50, 150, 255, 200);
194+
ImU32 tooltipNameColor = IM_COL32(255, 255, 255, 255);
195+
ImU32 tooltipTextColor = IM_COL32(200, 200, 255, 255);
196+
197+
// Tooltip
198+
float tooltipPadding = 15.0f;
199+
float tooltipSeparatorWidth = 5.0f;
200+
float tooltipFontSize = 0.0f; // 0 means use current font size
201+
202+
// Mouse cursor
203+
float cursorRadius = 7.5f;
204+
ImU32 cursorColor = IM_COL32(0, 150, 255, 220);
205+
ImU32 cursorOutlineColor = IM_COL32(255, 255, 255, 180);
206+
};
207+
208+
static StageMapSelectorConfig s_StageMapSelectorConfig;
209+
210+
static void HandleStageMapSelectorInput(Sonicteam::StageSelectMode* pMode, uintptr_t pMsgRec)
211+
{
212+
auto& io = ImGui::GetIO();
213+
214+
// Mouse wheel scrolling
215+
if (abs(io.MouseWheel) > ScrollAmount) {
216+
guest_stack_var<DevMessage> vMsgRec(0x10001, io.MouseWheel > 0 ? 0 : 0xB4, 130);
217+
GuestToHostFunction<void>(sub_824A8FF0, pMsgRec, vMsgRec.get());
218+
}
219+
220+
// Right click handling
221+
if (ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
222+
guest_stack_var<DevMessage> vMsgRec(0x10002, 0, 0);
223+
GuestToHostFunction<void>(sub_824A8FF0, pMsgRec, vMsgRec.get());
224+
}
225+
}
226+
227+
static void DrawStageMapTooltip(stdx::vector<xpointer<Sonicteam::StageMap>>& stages)
228+
{
229+
if (stages.empty()) return;
230+
231+
auto& io = ImGui::GetIO();
232+
auto& config = s_StageMapSelectorConfig;
233+
ImDrawList* draw_list = ImGui::GetForegroundDrawList();
234+
235+
const float font_size = config.tooltipFontSize > 0 ? config.tooltipFontSize : ImGui::GetFontSize();
236+
const float line_spacing = 2.0f;
237+
238+
// Calculate tooltip size
239+
float max_name_width = 0.0f;
240+
float max_text_width = 0.0f;
241+
float total_height = 0.0f;
242+
std::vector<std::pair<std::string, std::string>> entries;
243+
244+
for (auto& stage : stages) {
245+
if (!stage.ptr.get()) continue;
246+
247+
std::string nameUtf8 = ConvertShiftJISToUTF8(stage->m_Name.c_str());
248+
std::string textUtf8 = ConvertShiftJISToUTF8(stage->m_Text.c_str());
249+
entries.emplace_back(nameUtf8, textUtf8);
250+
251+
const ImVec2 name_size = g_mnewRodinFont->CalcTextSizeA(font_size, FLT_MAX, 0.0f, nameUtf8.c_str());
252+
const ImVec2 text_size = g_mnewRodinFont->CalcTextSizeA(font_size, FLT_MAX, 0.0f, textUtf8.c_str());
253+
254+
max_name_width = ImMax(max_name_width, name_size.x);
255+
max_text_width = ImMax(max_text_width, text_size.x);
256+
total_height += ImMax(name_size.y, text_size.y) + line_spacing;
257+
}
258+
259+
const float total_width = max_name_width + config.tooltipSeparatorWidth + max_text_width +
260+
config.tooltipPadding * 2;
261+
total_height += config.tooltipPadding * 2 - line_spacing;
262+
263+
// Position tooltip
264+
ImVec2 mouse_pos = GetMousePos();
265+
ImVec2 tooltip_pos = ImVec2(
266+
ImClamp(mouse_pos.x - total_width * 0.5f, 10.0f, io.DisplaySize.x - total_width - 10.0f),
267+
ImClamp(mouse_pos.y - total_height - 20.0f, 10.0f, io.DisplaySize.y - total_height - 10.0f)
268+
);
269+
270+
if (tooltip_pos.y <= 10) {
271+
tooltip_pos.x += io.DisplaySize.x * 0.040f;
272+
}
273+
274+
// Draw background
275+
const ImVec2 tooltip_min = tooltip_pos;
276+
const ImVec2 tooltip_max = ImVec2(tooltip_pos.x + total_width, tooltip_pos.y + total_height);
277+
draw_list->AddRectFilled(tooltip_min, tooltip_max, config.tooltipBgColor, 5.0f);
278+
draw_list->AddRect(tooltip_min, tooltip_max, config.tooltipBorderColor, 5.0f, 0, 1.5f);
279+
280+
// Draw text entries
281+
float current_y = tooltip_pos.y + config.tooltipPadding;
282+
for (const auto& [name, text] : entries) {
283+
const float name_height = g_mnewRodinFont->CalcTextSizeA(font_size, FLT_MAX, 0.0f, name.c_str()).y;
284+
const float text_height = g_mnewRodinFont->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text.c_str()).y;
285+
const float line_height = ImMax(name_height, text_height);
286+
287+
// Draw name
288+
draw_list->AddText(
289+
g_mnewRodinFont,
290+
font_size,
291+
ImVec2(tooltip_pos.x + config.tooltipPadding, current_y),
292+
config.tooltipNameColor,
293+
name.c_str()
294+
);
295+
296+
// Draw text
297+
draw_list->AddText(
298+
g_mnewRodinFont,
299+
font_size,
300+
ImVec2(tooltip_pos.x + config.tooltipPadding + max_name_width + config.tooltipSeparatorWidth, current_y),
301+
config.tooltipTextColor,
302+
text.c_str()
303+
);
304+
305+
current_y += line_height + line_spacing;
306+
}
307+
}
308+
309+
static void DrawStageMapCursor()
310+
{
311+
auto& config = s_StageMapSelectorConfig;
312+
ImVec2 mouse_pos = GetMousePos();
313+
314+
ImGui::GetBackgroundDrawList()->AddCircleFilled(
315+
mouse_pos, config.cursorRadius, config.cursorColor, 12
316+
);
317+
ImGui::GetBackgroundDrawList()->AddCircle(
318+
mouse_pos, config.cursorRadius, config.cursorOutlineColor, 12, 1.5f
319+
);
320+
}
321+
178322
static void DrawStageMapSelector()
179323
{
180324
auto& io = ImGui::GetIO();
181325
auto& res = io.DisplaySize;
326+
auto& config = s_StageMapSelectorConfig;
182327

183328
auto* pMode = App::s_pApp->m_pDoc->GetDocMode<Sonicteam::StageSelectMode>();
184-
if (!pMode)
185-
return;
329+
if (!pMode) return;
186330

187331
DrawBackgroundDev();
188332

189-
if (Config::DevTitle == EDevTitleMenu::Custom) DrawHUD({ 0, 0 }, res, g_mnewRodinFont, pMode->m_StageMapName.get());
190-
191-
float WINDOW_WIDTH = 0.8f * res.x;
192-
float BUTTON_HEIGHT = 0.05f * res.y;
193-
float BUTTON_SPACING = 5.0f;
194-
int VISIBLE_ITEMS = 9;
195-
float ITEMS_SCALE_HEIGHT = 0.05f * Video::s_viewportHeight;
196-
float WINDOW_HEIGHT = (BUTTON_HEIGHT + BUTTON_SPACING) * VISIBLE_ITEMS + ITEMS_SCALE_HEIGHT;
197-
198-
ImVec2 base_pos = {
199-
(res.x - WINDOW_WIDTH) * 0.15f,
200-
(res.y - WINDOW_HEIGHT) * 0.45f
201-
};
202-
203-
if (Config::DevTitle == EDevTitleMenu::True)
204-
{
205-
VISIBLE_ITEMS = 18;
206-
base_pos.x = 0;
207-
base_pos.y = 0;
208-
}
209-
333+
// Draw HUD if in custom mode
334+
if (Config::DevTitle == EDevTitleMenu::Custom) {
335+
DrawHUD({ 0, 0 }, res, g_mnewRodinFont, pMode->m_StageMapName.get());
336+
}
337+
338+
// Calculate layout
339+
int visibleItems = config.defaultVisibleItems;
340+
ImVec2 base_pos = {
341+
(res.x - config.windowWidthRatio * res.x) * config.basePosRatio.x,
342+
(res.y - (config.buttonHeightRatio * res.y + config.buttonSpacing) * visibleItems +
343+
config.itemsScaleHeightRatio * Video::s_viewportHeight) * config.basePosRatio.y
344+
};
345+
346+
// Adjust for dev mode
347+
if (Config::DevTitle == EDevTitleMenu::True) {
348+
visibleItems = 18;
349+
base_pos = { 0, 0 };
350+
}
351+
210352
auto& items = pMode->m_CurrentStageMap->m_vpStageMap;
211353
const int itemCount = static_cast<int>(items.size());
212354
int currentIdx = pMode->m_CurrentStageMapIndex.get();
213355

214-
// Input handling (Mouse)
356+
// Handle input
215357
auto pMsgRec = reinterpret_cast<uintptr_t>(static_cast<Sonicteam::SoX::MessageReceiver*>(pMode));
216-
217-
if (abs(io.MouseWheel) > ScrollAmount) {
218-
guest_stack_var<DevMessage> vMsgRec(0x10001, io.MouseWheel > 0 ? 0 : 0xB4, 130);
219-
GuestToHostFunction<void>(sub_824A8FF0, pMsgRec, vMsgRec.get());
220-
}
221-
222-
if (ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
223-
guest_stack_var<DevMessage> vMsgRec(0x10002, 0, 0);
224-
GuestToHostFunction<void>(sub_824A8FF0, pMsgRec, vMsgRec.get());
225-
}
358+
HandleStageMapSelectorInput(pMode, pMsgRec);
226359

227360
// Calculate visible range
228-
const int start_idx = std::max(0, currentIdx - VISIBLE_ITEMS / 2);
229-
const int end_idx = std::min(itemCount, start_idx + VISIBLE_ITEMS);
361+
const int start_idx = std::max(0, currentIdx - visibleItems / 2);
362+
const int end_idx = std::min(itemCount, start_idx + visibleItems);
230363

231364
// Draw visible items
232365
for (int i = start_idx; i < end_idx; ++i) {
233366
const auto& item = items[i];
234367
if (!item) continue;
235368

236369
const bool isSelected = (i == currentIdx);
237-
const int visible_index = i - start_idx;
370+
const int visible_index = i - start_idx;
238371
bool hovered = false;
239372

240373
// Calculate button position
241374
const ImVec2 button_pos = {
242-
base_pos.x + 10,
243-
base_pos.y + 40 + visible_index * (BUTTON_HEIGHT + BUTTON_SPACING)
375+
base_pos.x + config.buttonOffset.x,
376+
base_pos.y + config.buttonOffset.y + visible_index *
377+
(config.buttonHeightRatio * res.y + config.buttonSpacing)
244378
};
379+
380+
// Format item name
245381
std::string item_name = item->m_Name.c_str();
246-
if (item->m_vpStageMap.size() > 1)
247-
{
248-
item_name = "[" + item_name + "]"; //mark as group
382+
if (item->m_vpStageMap.size() > 1) {
383+
item_name = "[" + item_name + "]"; // Mark as group
249384
}
250-
if (isSelected)
251-
{
385+
if (isSelected) {
252386
item_name = ">> " + item_name;
253387
}
254388

389+
// Draw button
255390
if (Sonic06Button(button_pos, item_name.c_str(), hovered,
256-
ImVec2(WINDOW_WIDTH - 20, BUTTON_HEIGHT), isSelected,CenterFlag::Y))
257-
{
391+
ImVec2(config.windowWidthRatio * res.x - 20, config.buttonHeightRatio * res.y),
392+
isSelected, CenterFlag::Y)) {
258393
currentIdx = i;
259394
pMode->m_CurrentStageMapIndex = i;
260395
guest_stack_var<DevMessage> vMsgRec(0x10002, 0x5A, 1);
261396
GuestToHostFunction<void>(sub_824A8FF0, pMsgRec, vMsgRec.get());
262397
}
263398

264-
// Tooltip with stage information
399+
// Show tooltip if hovered and in custom mode
265400
if (hovered && item->m_vpStageMap.size() > 0 && Config::DevTitle == EDevTitleMenu::Custom) {
266-
ImDrawList* draw_list = ImGui::GetForegroundDrawList();
267-
const ImVec2 mouse_pos = GetMousePos();
268-
const float font_size = ImGui::GetFontSize();
269-
const float line_spacing = 2.0f;
270-
271-
272-
float max_name_width = 0.0f;
273-
float max_text_width = 0.0f;
274-
float total_height = 0.0f;
275-
std::vector<std::pair<std::string, std::string>> entries;
276-
277-
for (int j = 0; j < item->m_vpStageMap.size(); ++j) {
278-
const auto& stage = item->m_vpStageMap[j];
279-
if (!stage.ptr.get()) continue;
280-
281-
std::string nameUtf8 = ConvertShiftJISToUTF8(stage->m_Name.c_str());
282-
std::string textUtf8 = ConvertShiftJISToUTF8(stage->m_Text.c_str());
283-
entries.emplace_back(nameUtf8, textUtf8);
284-
285-
// Measure each part separately using the actual rendering font
286-
const ImVec2 name_size = g_mnewRodinFont->CalcTextSizeA(font_size, FLT_MAX, 0.0f, nameUtf8.c_str());
287-
const ImVec2 text_size = g_mnewRodinFont->CalcTextSizeA(font_size, FLT_MAX, 0.0f, textUtf8.c_str());
288-
289-
max_name_width = ImMax(max_name_width, name_size.x);
290-
max_text_width = ImMax(max_text_width, text_size.x);
291-
total_height += ImMax(name_size.y, text_size.y) + line_spacing;
292-
}
293-
294-
const float text_padding = 10.0f;
295-
const float separator_width = 5.0f;
296-
const float tooltip_padding = 15.0f;
297-
const float total_width = max_name_width + separator_width + max_text_width + tooltip_padding * 2;
298-
total_height += tooltip_padding * 2 - line_spacing;
299-
300-
// Position tooltip (ensure it stays on screen)
301-
ImVec2 tooltip_pos = ImVec2(
302-
ImClamp(mouse_pos.x - total_width * 0.5f, 10.0f, io.DisplaySize.x - total_width - 10.0f),
303-
ImClamp(mouse_pos.y - total_height - 20.0f, 10.0f, io.DisplaySize.y - total_height - 10.0f)
304-
);
305-
if (tooltip_pos.y <= 10)
306-
{
307-
tooltip_pos.x += io.DisplaySize.x * 0.040;
308-
}
309-
310-
// Draw background
311-
const ImVec2 tooltip_min = tooltip_pos;
312-
const ImVec2 tooltip_max = ImVec2(tooltip_pos.x + total_width, tooltip_pos.y + total_height);
313-
draw_list->AddRectFilled(tooltip_min, tooltip_max, IM_COL32(0, 0, 0, 180), 5.0f);
314-
draw_list->AddRect(tooltip_min, tooltip_max, IM_COL32(50, 150, 255, 200), 5.0f, 0, 1.5f);
315-
316-
// Draw text entries
317-
float current_y = tooltip_pos.y + tooltip_padding;
318-
for (const auto& [name, text] : entries) {
319-
// Calculate this line's height
320-
const float name_height = g_mnewRodinFont->CalcTextSizeA(font_size, FLT_MAX, 0.0f, name.c_str()).y;
321-
const float text_height = g_mnewRodinFont->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text.c_str()).y;
322-
const float line_height = ImMax(name_height, text_height);
323-
324-
// Draw name (left-aligned)
325-
draw_list->AddText(
326-
g_mnewRodinFont,
327-
font_size,
328-
ImVec2(tooltip_pos.x + tooltip_padding, current_y),
329-
IM_COL32(255, 255, 255, 255),
330-
name.c_str()
331-
);
332-
333-
// Draw text (right-aligned)
334-
const float text_width = g_mnewRodinFont->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text.c_str()).x;
335-
draw_list->AddText(
336-
g_mnewRodinFont,
337-
font_size,
338-
ImVec2(tooltip_pos.x + tooltip_padding + max_name_width + separator_width, current_y),
339-
IM_COL32(200, 200, 255, 255),
340-
text.c_str()
341-
);
342-
343-
current_y += line_height + line_spacing;
344-
}
401+
DrawStageMapTooltip(item->m_vpStageMap);
345402
}
346-
347-
348403
}
349-
350-
//Do not draw mouse, if not custom
351-
if (Config::DevTitle != EDevTitleMenu::Custom) return;
352-
// Draw mouse position indicator
353-
const float dot_radius = 7.5f;
354-
const ImU32 dot_color = IM_COL32(0, 150, 255, 220);
355-
const ImU32 outline_color = IM_COL32(255, 255, 255, 180);
356-
ImVec2 mouse_pos = GetMousePos();
357404

358-
ImGui::GetBackgroundDrawList()->AddCircleFilled(
359-
mouse_pos, dot_radius, dot_color, 12
360-
);
361-
ImGui::GetBackgroundDrawList()->AddCircle(
362-
mouse_pos, dot_radius, outline_color, 12, 1.5f
363-
);
405+
// Draw mouse cursor in custom mode
406+
if (Config::DevTitle == EDevTitleMenu::Custom) {
407+
DrawStageMapCursor();
408+
}
364409
}
410+
//DrawStageMapSelector
365411

366412
static void DrawDevTitle() {
367413

0 commit comments

Comments
 (0)