Compare commits

...
Author SHA1 Message Date
refractionpcsx2 c1dfdd454b GameDB: Add required GameDB Entries
S.L.A.I. - Steel Lancer Arena International
Syphon Filter - Logan's Shadow
2026-07-26 08:21:08 +01:00
refractionpcsx2 eee577e694 GS/HW: Improve "jiggle" blur effect detection and handling 2026-07-26 08:20:26 +01:00
refractionpcsx2 e791f43899 GS/HW: Native Scaling detection of mild downscale and write back 2026-07-26 04:37:27 +01:00
PCSX2 Botandlightningterror ee4a83b0c9 [ci skip] Qt: Update Base Translation. 2026-07-25 02:30:33 +02:00
SternXDandTy 94ad591d4f FullscreenUI: Add icons to all ShowToasts 2026-07-24 07:40:03 -04:00
SternXDandTy bd0982ed4c FullscreenUI: Fix icon layout in toast notifications 2026-07-24 07:40:03 -04:00
SternXDandTy 8e9be7411c Qt: Fix incorrect setting keys 2026-07-24 07:40:03 -04:00
SternXDandTy 1528e962d2 FullscreenUI: Align Achievements settings layout with Qt
Also don't show the enable prompts until the login dialog is dismissed. Account row now also shows the RA avatar and opens the profile page.
2026-07-24 07:40:03 -04:00
SternXDandTy d9822b8ad8 FullscreenUI: Align setting names with Qt 2026-07-24 07:40:03 -04:00
SternXDandTy 2fc8ae44be FullscreenUI: Expose missing settings 2026-07-24 07:40:03 -04:00
SternXDandTy 66c0771d12 Qt: Fix Optimal Frame Pacing not inheriting from global 2026-07-21 17:31:17 -04:00
10 changed files with 1960 additions and 1624 deletions
+6
View File
@@ -12926,6 +12926,7 @@ SCUS-97584:
autoFlush: 2
preloadFrameData: 1
nativeScaling: 2 # Fixes post-processing.
halfPixelOffset: 4 # Aligns post bloom.
SCUS-97589:
name: "NBA '08 featuring The Life Vol.3"
region: "NTSC-U"
@@ -21921,6 +21922,7 @@ SLES-52940:
region: "PAL-M3"
gsHWFixes:
halfPixelOffset: 5 # Fixes double image and aligns glow effects.
nativeScaling: 1 # Fixes depth blur.
SLES-52941:
name: "Gungrave - Overdose"
region: "PAL-M3"
@@ -45824,6 +45826,7 @@ SLPM-65791:
region: "NTSC-J"
gsHWFixes:
halfPixelOffset: 5 # Fixes double image and aligns glow effects.
nativeScaling: 1 # Fixes depth blur.
SLPM-65793:
name: "SSX3 [EA BEST HITS]"
name-sort: "SSX3 [EA BEST HITS]"
@@ -69367,6 +69370,7 @@ SLUS-20969:
compat: 5
gsHWFixes:
halfPixelOffset: 5 # Fixes double image and aligns glow effects.
nativeScaling: 1 # Fixes depth blur.
SLUS-20970:
name: "Rumble Roses"
region: "NTSC-U"
@@ -75897,6 +75901,7 @@ SLUS-29132:
region: "NTSC-U"
gsHWFixes:
halfPixelOffset: 5 # Fixes double image and aligns glow effects.
nativeScaling: 1 # Fixes depth blur.
SLUS-29133:
name: "Namco Transmission Demo Disc Vol.2"
region: "NTSC-U"
@@ -76699,6 +76704,7 @@ TLES-52940:
region: "PAL-E"
gsHWFixes:
halfPixelOffset: 5 # Fixes double image and aligns glow effects.
nativeScaling: 1 # Fixes depth blur.
TLES-53544:
name: "Pro Evolution Soccer 5 Beta Trial Code"
region: "PAL-E"
+6 -12
View File
@@ -262,20 +262,14 @@ void EmulationSettingsWidget::onOptimalFramePacingChanged()
const QSignalBlocker sb(m_ui.maxFrameLatency);
std::optional<int> value;
bool optimal = false;
if (m_ui.optimalFramePacing->checkState() != Qt::PartiallyChecked)
{
optimal = m_ui.optimalFramePacing->isChecked();
value = optimal ? 0 : DEFAULT_FRAME_LATENCY;
}
else
{
value = dialog()->getEffectiveIntValue("EmuCore/GS", "VsyncQueueSize", DEFAULT_FRAME_LATENCY);
optimal = (value == 0);
}
value = m_ui.optimalFramePacing->isChecked() ? 0 : DEFAULT_FRAME_LATENCY;
const int latency = value.value_or(Host::GetBaseIntSettingValue("EmuCore/GS", "VsyncQueueSize", DEFAULT_FRAME_LATENCY));
const bool optimal = (latency == 0);
m_ui.maxFrameLatency->setMinimum(optimal ? 0 : 1);
m_ui.maxFrameLatency->setValue(optimal ? 0 : DEFAULT_FRAME_LATENCY);
m_ui.maxFrameLatency->setValue(latency);
m_ui.maxFrameLatency->setEnabled(!dialog()->isPerGameSettings() && !m_ui.optimalFramePacing->isChecked());
dialog()->setIntSettingValue("EmuCore/GS", "VsyncQueueSize", value);
@@ -300,7 +294,7 @@ void EmulationSettingsWidget::updateOptimalFramePacing()
}
m_ui.maxFrameLatency->setMinimum(optimal ? 0 : 1);
m_ui.maxFrameLatency->setValue(optimal ? 0 : value);
m_ui.maxFrameLatency->setValue(value);
}
void EmulationSettingsWidget::updateUseVSyncForTimingEnabled()
+1 -1
View File
@@ -19,7 +19,7 @@ FolderSettingsWidget::FolderSettingsWidget(SettingsWindow* settings_dialog, QWid
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.organizeSnapshotsByGame, "EmuCore/GS", "OrganizeScreenshotsByGame", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.organizeVideoDumpByGame, "EmuCore/GS", "OrganizeVideoCaptureByGame", false);
SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.saveStates, m_ui.saveStatesBrowse, m_ui.saveStatesOpen, m_ui.saveStatesReset,
"Folders", "SaveStates", Path::Combine(EmuFolders::DataRoot, "sstates"));
"Folders", "Savestates", Path::Combine(EmuFolders::DataRoot, "sstates"));
SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.videoDumpingDirectory, m_ui.videoDumpingDirectoryBrowse, m_ui.videoDumpingDirectoryOpen, m_ui.videoDumpingDirectoryReset,
"Folders", "Videos", Path::Combine(EmuFolders::DataRoot, "videos"));
dialog()->registerWidgetHelp(m_ui.organizeSnapshotsByGame, tr("Save Snapshots in Game-Specific Folders"), tr("Unchecked"),
+1 -1
View File
@@ -173,7 +173,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* settings_dialog,
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_upscaling.textureOffsetY, "EmuCore/GS", "UserHacks_TCOffsetY", 0);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_upscaling.alignSprite, "EmuCore/GS", "UserHacks_align_sprite_X", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_upscaling.mergeSprite, "EmuCore/GS", "UserHacks_merge_pp_sprite", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_upscaling.forceEvenSpritePosition, "EmuCore/GS", "UserHacks_forceEvenSpritePosition", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_upscaling.forceEvenSpritePosition, "EmuCore/GS", "UserHacks_ForceEvenSpritePosition", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_upscaling.nativePaletteDraw, "EmuCore/GS", "UserHacks_NativePaletteDraw", false);
//////////////////////////////////////////////////////////////////////////
+1 -1
View File
@@ -74,7 +74,7 @@ OSDSettingsWidget::OSDSettingsWidget(SettingsWindow* settings_dialog, QWidget* p
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showVideoCapture, "EmuCore/GS", "OsdShowVideoCapture", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showInputRec, "EmuCore/GS", "OsdShowInputRec", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showTextureReplacements, "EmuCore/GS", "OsdShowTextureReplacements", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.warnAboutUnsafeSettings, "EmuCore", "OsdWarnAboutUnsafeSettings", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.warnAboutUnsafeSettings, "EmuCore", "WarnAboutUnsafeSettings", true);
#ifndef _WIN32
// Currently DX12 only
File diff suppressed because it is too large Load Diff
+8 -5
View File
@@ -10709,8 +10709,10 @@ int GSRendererHW::IsScalingDraw(GSTextureCache::Source* src, bool no_gaps)
IsMipMapDraw() || GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].trbpp <= 8)
return 0;
const bool is_smaller = draw_size.x <= (tex_size.x * 0.75f) && draw_size.y <= (tex_size.y * 0.75f);
const bool is_smaller_and_writing_back = draw_size.x < tex_size.x && draw_size.y < tex_size.y && next_ctx.FRAME.Block() == m_cached_ctx.TEX0.TBP0 && next_ctx.TEX0.TBP0 == m_cached_ctx.FRAME.Block();
// Should usually be 2x but some games like Monster House goes from 512x448 -> 128x128
const bool is_downscale = m_cached_ctx.TEX0.TBW >= m_cached_ctx.FRAME.FBW && draw_size.x <= (tex_size.x * 0.75f) && draw_size.y <= (tex_size.y * 0.75f);
const bool is_downscale = m_cached_ctx.TEX0.TBW >= m_cached_ctx.FRAME.FBW && (is_smaller || is_smaller_and_writing_back);
// Check we're getting most of the texture and not just stenciling a part of it.
// Only allow non-bilineared downscales if it's most of the target (misdetections of shadows in Naruto, Transformers etc), otherwise it's fine.
const GSVector4i src_valid = src->m_from_target ? src->m_from_target->m_valid : src->m_valid_rect;
@@ -10734,7 +10736,8 @@ int GSRendererHW::IsScalingDraw(GSTextureCache::Source* src, bool no_gaps)
}
// Last ditched check if it's doing a lot of small draws exactly the same which could be recursive lighting bloom.
if (m_vt.m_primclass == GS_SPRITE_CLASS && m_index->tail > 2 && !no_gaps_or_single_sprite && m_context->TEX1.MMAG == 1 && !m_context->ALPHA.IsOpaque())
if (m_vt.m_primclass == GS_SPRITE_CLASS && m_index->tail > 2 && !no_gaps_or_single_sprite && m_context->TEX1.MMAG == 1 && is_target_src && (m_cached_ctx.TEST.ZTST == ZTST_ALWAYS || m_cached_ctx.TEST.ZTE == 0) &&
!m_context->ALPHA.IsOpaque() && GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].bpp == GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].bpp)
{
GSVertex* v = &m_vertex->buff[0];
float tw = 1 << src->m_TEX0.TW;
@@ -10745,7 +10748,7 @@ int GSRendererHW::IsScalingDraw(GSTextureCache::Source* src, bool no_gaps)
const int first_x = (v[1].XYZ.X - v[0].XYZ.X) >> 4;
const int first_y = (v[1].XYZ.Y - v[0].XYZ.Y) >> 4;
if (first_x > first_u && first_y > first_v && !no_resize && std::abs(draw_size.x - first_x) <= 4 && std::abs(draw_size.y - first_y) <= 4)
if (first_x >= first_u && first_y >= first_v && !no_resize && ((draw_size.x != first_x && draw_size.y != first_y) || (tex_size.x != first_u && tex_size.y != first_v)) && std::abs(draw_size.x - first_x) <= 4 && std::abs(draw_size.y - first_y) <= 4)
{
for (u32 i = 2; i < m_index->tail; i += 2)
{
@@ -10754,14 +10757,14 @@ int GSRendererHW::IsScalingDraw(GSTextureCache::Source* src, bool no_gaps)
const int next_x = (v[i + 1].XYZ.X - v[i].XYZ.X) >> 4;
const int next_y = (v[i + 1].XYZ.Y - v[i].XYZ.Y) >> 4;
if (std::abs(draw_size.x - next_x) > 4 || std::abs(draw_size.y - next_y) > 4)
if (std::abs(draw_size.x - next_x) > 4 || std::abs(draw_size.y - next_y) > 4 || (draw_size.x == next_x && tex_size.x == next_u) || (draw_size.y == next_y && tex_size.y == next_v))
break;
if (next_u != first_u || next_v != first_v || next_x != first_x || next_y != first_y)
break;
if (i + 2 >= m_index->tail)
return 2;
return (is_target_src && src->m_from_target->m_downscaled) ? -1 : 2;
}
}
}
+13 -13
View File
@@ -893,8 +893,8 @@ void FullscreenUI::DoStartDisc()
std::vector<std::string> devices(GetOpticalDriveList());
if (devices.empty())
{
ShowToast(std::string(), FSUI_STR("Could not find any CD/DVD-ROM devices. Please ensure you have a drive connected and sufficient "
"permissions to access it."));
ShowToast(ICON_FA_COMPACT_DISC, FSUI_STR("Could not find any CD/DVD-ROM devices. Please ensure you have a drive connected and sufficient "
"permissions to access it."));
return;
}
@@ -978,7 +978,7 @@ void FullscreenUI::DoChangeDiscFromFile()
{
if (!VMManager::IsDiscFileName(path))
{
ShowToast({}, fmt::format(FSUI_FSTR("{} is not a valid disc image."), Path::GetFileName(path)));
ShowToast(ICON_FA_TRIANGLE_EXCLAMATION, fmt::format(FSUI_FSTR("{} is not a valid disc image."), Path::GetFileName(path)));
}
else
{
@@ -1949,7 +1949,7 @@ bool FullscreenUI::OpenLoadStateSelectorForGame(const std::string& game_path)
}
}
ShowToast({}, FSUI_STR("No save states found."), 5.0f);
ShowToast(ICON_FA_FLOPPY_DISK, FSUI_STR("No save states found."), 5.0f);
return false;
}
@@ -1964,7 +1964,7 @@ bool FullscreenUI::OpenSaveStateSelector(bool is_loading)
return true;
}
ShowToast({}, FSUI_STR("No save states found."), 5.0f);
ShowToast(ICON_FA_FLOPPY_DISK, FSUI_STR("No save states found."), 5.0f);
return false;
}
@@ -2120,12 +2120,12 @@ void FullscreenUI::DrawSaveStateSelector(bool is_loading)
{
if (!FileSystem::FileExists(entry.path.c_str()))
{
ShowToast({}, fmt::format(FSUI_FSTR("{} does not exist."), ImGuiFullscreen::RemoveHash(entry.title)));
ShowToast(ICON_FA_TRIANGLE_EXCLAMATION, fmt::format(FSUI_FSTR("{} does not exist."), ImGuiFullscreen::RemoveHash(entry.title)));
is_open = true;
}
else if (FileSystem::DeleteFilePath(entry.path.c_str()))
{
ShowToast({}, fmt::format(FSUI_FSTR("{} deleted."), ImGuiFullscreen::RemoveHash(entry.title)));
ShowToast(ICON_FA_TRASH, fmt::format(FSUI_FSTR("{} deleted."), ImGuiFullscreen::RemoveHash(entry.title)));
if (s_save_state_selector_loading)
s_save_state_selector_slots.erase(s_save_state_selector_slots.begin() + i);
else
@@ -2145,7 +2145,7 @@ void FullscreenUI::DrawSaveStateSelector(bool is_loading)
}
else
{
ShowToast({}, fmt::format(FSUI_FSTR("Failed to delete {}."), ImGuiFullscreen::RemoveHash(entry.title)));
ShowToast(ICON_FA_TRIANGLE_EXCLAMATION, fmt::format(FSUI_FSTR("Failed to delete {}."), ImGuiFullscreen::RemoveHash(entry.title)));
is_open = false;
}
}
@@ -2372,7 +2372,7 @@ void FullscreenUI::DrawResumeStateSelector()
}
else
{
ShowToast(std::string(), FSUI_STR("Failed to delete save state."));
ShowToast(ICON_FA_TRIANGLE_EXCLAMATION, FSUI_STR("Failed to delete save state."));
}
}
@@ -3388,9 +3388,9 @@ void FullscreenUI::ExitFullscreenAndOpenURL(const std::string_view url)
void FullscreenUI::CopyTextToClipboard(std::string title, const std::string_view text)
{
if (Host::CopyTextToClipboard(text))
ShowToast(std::string(), std::move(title));
ShowToast(ICON_FA_CLIPBOARD, std::move(title));
else
ShowToast(std::string(), FSUI_STR("Failed to copy text to clipboard."));
ShowToast(ICON_FA_TRIANGLE_EXCLAMATION, FSUI_STR("Failed to copy text to clipboard."));
}
void FullscreenUI::OpenAboutWindow()
@@ -3863,7 +3863,7 @@ void FullscreenUI::SwitchToAchievementsWindow()
if (!Achievements::HasAchievements())
{
ShowToast(std::string(), FSUI_STR("This game has no achievements."));
ShowToast(ICON_FA_TROPHY, FSUI_STR("This game has no achievements."));
return;
}
@@ -3907,7 +3907,7 @@ void FullscreenUI::SwitchToLeaderboardsWindow()
if (!Achievements::HasLeaderboards())
{
ShowToast(std::string(), FSUI_STR("This game has no leaderboards."));
ShowToast(ICON_FA_TROPHY, FSUI_STR("This game has no leaderboards."));
return;
}
File diff suppressed because it is too large Load Diff
+21 -16
View File
@@ -3162,8 +3162,6 @@ void ImGuiFullscreen::DrawNotifications(ImVec2& position, float spacing)
const float badge_size = ImGuiFullscreen::LayoutScale(48.0f);
const float min_width = ImGuiFullscreen::LayoutScale(200.0f);
const float max_width = ImGuiFullscreen::LayoutScale(800.0f);
const float max_text_width = max_width - badge_size - (horizontal_padding * 2.0f) - horizontal_spacing;
const float min_height = (vertical_padding * 2.0f) + badge_size;
const float shadow_size = ImGuiFullscreen::LayoutScale(4.0f);
const float rounding = ImGuiFullscreen::LayoutScale(4.0f);
@@ -3185,13 +3183,19 @@ void ImGuiFullscreen::DrawNotifications(ImVec2& position, float spacing)
continue;
}
const bool has_badge = !notif.badge_path.empty();
const float effective_badge_size = has_badge ? badge_size : 0.0f;
const float effective_badge_spacing = has_badge ? horizontal_spacing : 0.0f;
const float max_text_width = max_width - effective_badge_size - (horizontal_padding * 2.0f) - effective_badge_spacing;
const float min_height = (vertical_padding * 2.0f) + effective_badge_size;
const ImVec2 title_size(title_font.first->CalcTextSizeA(title_font.second, max_text_width, max_text_width,
notif.title.c_str(), notif.title.c_str() + notif.title.size()));
const ImVec2 text_size(text_font.first->CalcTextSizeA(text_font.second, max_text_width, max_text_width,
notif.text.c_str(), notif.text.c_str() + notif.text.size()));
const float box_width = std::max((horizontal_padding * 2.0f) + badge_size + horizontal_spacing +
const float box_width = std::max((horizontal_padding * 2.0f) + effective_badge_size + effective_badge_spacing +
ImCeil(std::max(title_size.x, text_size.x)),
min_width);
const float box_height =
@@ -3250,10 +3254,10 @@ void ImGuiFullscreen::DrawNotifications(ImVec2& position, float spacing)
dl->AddRectFilled(box_min, box_max, background_color, rounding, ImDrawFlags_RoundCornersAll);
dl->AddRect(box_min, box_max, border_color, rounding, ImGuiFullscreen::LayoutScale(1.0f), ImDrawFlags_RoundCornersAll);
const ImVec2 badge_min(box_min.x + horizontal_padding, box_min.y + vertical_padding);
const ImVec2 badge_max(badge_min.x + badge_size, badge_min.y + badge_size);
if (!notif.badge_path.empty())
if (has_badge)
{
const ImVec2 badge_min(box_min.x + horizontal_padding, box_min.y + (box_height - badge_size) * 0.5f);
const ImVec2 badge_max(badge_min.x + badge_size, badge_min.y + badge_size);
GSTexture* tex = GetCachedTexture(notif.badge_path.c_str());
if (tex)
{
@@ -3262,14 +3266,14 @@ void ImGuiFullscreen::DrawNotifications(ImVec2& position, float spacing)
}
}
const ImVec2 title_min(badge_max.x + horizontal_spacing, box_min.y + vertical_padding);
const ImVec2 title_min(box_min.x + horizontal_padding + effective_badge_size + effective_badge_spacing, box_min.y + vertical_padding);
const ImVec2 title_max(title_min.x + title_size.x, title_min.y + title_size.y);
const u32 title_col = (toast_title_color & ~IM_COL32_A_MASK) | (opacity << IM_COL32_A_SHIFT);
const u32 text_shadow_col = IM_COL32(0, 0, 0, (64u * opacity) / 255u);
AddTextWithShadow(dl, title_font, title_min, title_col, notif.title.c_str(), notif.title.c_str() + notif.title.size(), max_text_width,
nullptr, text_shadow_col);
const ImVec2 text_min(badge_max.x + horizontal_spacing, title_max.y + vertical_spacing);
const ImVec2 text_min(title_min.x, title_max.y + vertical_spacing);
const ImVec2 text_max(text_min.x + text_size.x, text_min.y + text_size.y);
const u32 text_col = (toast_text_color & ~IM_COL32_A_MASK) | (opacity << IM_COL32_A_SHIFT);
AddTextWithShadow(dl, text_font, text_min, text_col, notif.text.c_str(), notif.text.c_str() + notif.text.size(), max_text_width,
@@ -3318,15 +3322,17 @@ void ImGuiFullscreen::DrawToast()
const float padding = LayoutScale(20.0f);
const float total_padding = padding * 2.0f;
const float margin = LayoutScale(20.0f + (s_fullscreen_footer_text.empty() ? 0.0f : LAYOUT_FOOTER_HEIGHT));
const float spacing = s_toast_title.empty() ? 0.0f : LayoutScale(10.0f);
const float spacing = (s_toast_title.empty() || s_toast_message.empty()) ? 0.0f : LayoutScale(10.0f);
const ImVec2 display_size(ImGui::GetIO().DisplaySize);
const ImVec2 title_size(s_toast_title.empty() ? ImVec2(0.0f, 0.0f) :
title_font.first->CalcTextSizeA(title_font.second, FLT_MAX, max_width,
s_toast_title.c_str(), s_toast_title.c_str() + s_toast_title.length()));
const float max_message_width = std::max(LayoutScale(100.0f), max_width - (s_toast_title.empty() ? 0.0f : (title_size.x + spacing)));
const ImVec2 message_size(s_toast_message.empty() ? ImVec2(0.0f, 0.0f) :
message_font.first->CalcTextSizeA(message_font.second, FLT_MAX, max_width,
message_font.first->CalcTextSizeA(message_font.second, FLT_MAX, max_message_width,
s_toast_message.c_str(), s_toast_message.c_str() + s_toast_message.length()));
const ImVec2 comb_size(std::max(title_size.x, message_size.x), title_size.y + spacing + message_size.y);
const ImVec2 comb_size(s_toast_title.empty() ? message_size.x : (title_size.x + spacing + message_size.x),
std::max(title_size.y, message_size.y));
const ImVec2 box_size(comb_size.x + total_padding, comb_size.y + total_padding);
const ImVec2 box_pos((display_size.x - box_size.x) * 0.5f, (display_size.y - margin - box_size.y));
@@ -3336,19 +3342,18 @@ void ImGuiFullscreen::DrawToast()
const u32 shadow_col = IM_COL32(0, 0, 0, static_cast<int>(64.0f * alpha));
if (!s_toast_title.empty())
{
const float offset = (comb_size.x - title_size.x) * 0.5f;
const ImVec2 title_pos = box_pos + ImVec2(offset + padding, padding);
const ImVec2 title_pos = box_pos + ImVec2(padding, padding + (comb_size.y - title_size.y) * 0.5f);
AddTextWithShadow(dl, title_font, title_pos,
ImGui::GetColorU32(ModAlpha(UIPrimaryTextColor, alpha)), s_toast_title.c_str(), s_toast_title.c_str() + s_toast_title.length(),
max_width, nullptr, shadow_col);
}
if (!s_toast_message.empty())
{
const float offset = (comb_size.x - message_size.x) * 0.5f;
const ImVec2 message_pos = box_pos + ImVec2(offset + padding, padding + spacing + title_size.y);
const float title_offset = s_toast_title.empty() ? 0.0f : (title_size.x + spacing);
const ImVec2 message_pos = box_pos + ImVec2(padding + title_offset, padding + (comb_size.y - message_size.y) * 0.5f);
AddTextWithShadow(dl, message_font, message_pos,
ImGui::GetColorU32(ModAlpha(UIPrimaryTextColor, alpha)), s_toast_message.c_str(),
s_toast_message.c_str() + s_toast_message.length(), max_width, nullptr, shadow_col);
s_toast_message.c_str() + s_toast_message.length(), max_message_width, nullptr, shadow_col);
}
}