SidebySide Layout (#2859)
* added a SidebySide Layout * Reworked, so both screen have the same height and cleaned up screen translates. * added the option in the UI, hope this is the right way to do it. formated framebuffer_layout.cpp * delete the x64 files * deleted ui_configure_graphics.h * added Option for the Layout in the xml * got rid of SIDE_BY_SIDE_ASPECT_RATIO because it was useless. pulled translate into variables * changed shift variables to u32 and moved them in their respective branch. remove notr="true" for the Screen layout drop down * reworked intends :). changed function description for SideFrameLayout * some description reworking
This commit is contained in:
parent
61442d6afb
commit
3cdf854e44
|
@ -146,17 +146,22 @@
|
||||||
<widget class="QComboBox" name="layout_combobox">
|
<widget class="QComboBox" name="layout_combobox">
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string notr="true">Default</string>
|
<string>Default</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string notr="true">Single Screen</string>
|
<string>Single Screen</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string notr="true">Large Screen</string>
|
<string>Large Screen</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Side by Side</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
</widget>
|
</widget>
|
||||||
|
|
|
@ -74,6 +74,9 @@ void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height)
|
||||||
case Settings::LayoutOption::LargeScreen:
|
case Settings::LayoutOption::LargeScreen:
|
||||||
layout = Layout::LargeFrameLayout(width, height, Settings::values.swap_screen);
|
layout = Layout::LargeFrameLayout(width, height, Settings::values.swap_screen);
|
||||||
break;
|
break;
|
||||||
|
case Settings::LayoutOption::SideScreen:
|
||||||
|
layout = Layout::SideFrameLayout(width, height, Settings::values.swap_screen);
|
||||||
|
break;
|
||||||
case Settings::LayoutOption::Default:
|
case Settings::LayoutOption::Default:
|
||||||
default:
|
default:
|
||||||
layout = Layout::DefaultFrameLayout(width, height, Settings::values.swap_screen);
|
layout = Layout::DefaultFrameLayout(width, height, Settings::values.swap_screen);
|
||||||
|
|
|
@ -141,6 +141,40 @@ FramebufferLayout LargeFrameLayout(unsigned width, unsigned height, bool swapped
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FramebufferLayout SideFrameLayout(unsigned width, unsigned height, bool swapped) {
|
||||||
|
ASSERT(width > 0);
|
||||||
|
ASSERT(height > 0);
|
||||||
|
|
||||||
|
FramebufferLayout res{width, height, true, true, {}, {}};
|
||||||
|
// Aspect ratio of both screens side by side
|
||||||
|
const float emulation_aspect_ratio = static_cast<float>(Core::kScreenTopHeight) /
|
||||||
|
(Core::kScreenTopWidth + Core::kScreenBottomWidth);
|
||||||
|
float window_aspect_ratio = static_cast<float>(height) / width;
|
||||||
|
MathUtil::Rectangle<unsigned> screen_window_area{0, 0, width, height};
|
||||||
|
// Find largest Rectangle that can fit in the window size with the given aspect ratio
|
||||||
|
MathUtil::Rectangle<unsigned> screen_rect =
|
||||||
|
maxRectangle(screen_window_area, emulation_aspect_ratio);
|
||||||
|
// Find sizes of top and bottom screen
|
||||||
|
MathUtil::Rectangle<unsigned> top_screen = maxRectangle(screen_rect, TOP_SCREEN_ASPECT_RATIO);
|
||||||
|
MathUtil::Rectangle<unsigned> bot_screen = maxRectangle(screen_rect, BOT_SCREEN_ASPECT_RATIO);
|
||||||
|
|
||||||
|
if (window_aspect_ratio < emulation_aspect_ratio) {
|
||||||
|
// Apply borders to the left and right sides of the window.
|
||||||
|
u32 shift_horizontal = (screen_window_area.GetWidth() - screen_rect.GetWidth()) / 2;
|
||||||
|
top_screen = top_screen.TranslateX(shift_horizontal);
|
||||||
|
bot_screen = bot_screen.TranslateX(shift_horizontal);
|
||||||
|
} else {
|
||||||
|
// Window is narrower than the emulation content => apply borders to the top and bottom
|
||||||
|
u32 shift_vertical = (screen_window_area.GetHeight() - screen_rect.GetHeight()) / 2;
|
||||||
|
top_screen = top_screen.TranslateY(shift_vertical);
|
||||||
|
bot_screen = bot_screen.TranslateY(shift_vertical);
|
||||||
|
}
|
||||||
|
// Move the top screen to the right if we are swapped.
|
||||||
|
res.top_screen = swapped ? top_screen.TranslateX(bot_screen.GetWidth()) : top_screen;
|
||||||
|
res.bottom_screen = swapped ? bot_screen : bot_screen.TranslateX(top_screen.GetWidth());
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
FramebufferLayout CustomFrameLayout(unsigned width, unsigned height) {
|
FramebufferLayout CustomFrameLayout(unsigned width, unsigned height) {
|
||||||
ASSERT(width > 0);
|
ASSERT(width > 0);
|
||||||
ASSERT(height > 0);
|
ASSERT(height > 0);
|
||||||
|
@ -158,4 +192,4 @@ FramebufferLayout CustomFrameLayout(unsigned width, unsigned height) {
|
||||||
res.bottom_screen = bot_screen;
|
res.bottom_screen = bot_screen;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
} // namespace Layout
|
||||||
|
|
|
@ -53,6 +53,17 @@ FramebufferLayout SingleFrameLayout(unsigned width, unsigned height, bool is_swa
|
||||||
*/
|
*/
|
||||||
FramebufferLayout LargeFrameLayout(unsigned width, unsigned height, bool is_swapped);
|
FramebufferLayout LargeFrameLayout(unsigned width, unsigned height, bool is_swapped);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory method for constructing a Frame with the Top screen and bottom
|
||||||
|
* screen side by side
|
||||||
|
* This is useful for devices with small screens, like the GPDWin
|
||||||
|
* @param width Window framebuffer width in pixels
|
||||||
|
* @param height Window framebuffer height in pixels
|
||||||
|
* @param is_swapped if true, the bottom screen will be the left display
|
||||||
|
* @return Newly created FramebufferLayout object with default screen regions initialized
|
||||||
|
*/
|
||||||
|
FramebufferLayout SideFrameLayout(unsigned width, unsigned height, bool is_swapped);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Factory method for constructing a custom FramebufferLayout
|
* Factory method for constructing a custom FramebufferLayout
|
||||||
* @param width Window framebuffer width in pixels
|
* @param width Window framebuffer width in pixels
|
||||||
|
|
|
@ -36,4 +36,4 @@ void Apply() {
|
||||||
Service::IR::ReloadInputDevices();
|
Service::IR::ReloadInputDevices();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace Settings
|
||||||
|
|
|
@ -15,6 +15,7 @@ enum class LayoutOption {
|
||||||
Default,
|
Default,
|
||||||
SingleScreen,
|
SingleScreen,
|
||||||
LargeScreen,
|
LargeScreen,
|
||||||
|
SideScreen,
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace NativeButton {
|
namespace NativeButton {
|
||||||
|
@ -70,7 +71,7 @@ enum Values {
|
||||||
static const std::array<const char*, NumAnalogs> mapping = {{
|
static const std::array<const char*, NumAnalogs> mapping = {{
|
||||||
"circle_pad", "c_stick",
|
"circle_pad", "c_stick",
|
||||||
}};
|
}};
|
||||||
} // namespace NumAnalog
|
} // namespace NativeAnalog
|
||||||
|
|
||||||
struct Values {
|
struct Values {
|
||||||
// CheckNew3DS
|
// CheckNew3DS
|
||||||
|
@ -137,4 +138,4 @@ struct Values {
|
||||||
static constexpr int REGION_VALUE_AUTO_SELECT = -1;
|
static constexpr int REGION_VALUE_AUTO_SELECT = -1;
|
||||||
|
|
||||||
void Apply();
|
void Apply();
|
||||||
}
|
} // namespace Settings
|
||||||
|
|
Reference in New Issue