Add "Separate Windows" LayoutOption (#6177)
This commit is contained in:
parent
4f715b6718
commit
f44c95d638
24 changed files with 358 additions and 124 deletions
|
@ -4,12 +4,13 @@
|
|||
|
||||
#include <cmath>
|
||||
#include <mutex>
|
||||
#include "core/3ds.h"
|
||||
#include "core/frontend/emu_window.h"
|
||||
#include "core/frontend/input.h"
|
||||
#include "core/settings.h"
|
||||
|
||||
namespace Frontend {
|
||||
/// We need a global touch state that is shared across the different window instances
|
||||
static std::weak_ptr<EmuWindow::TouchState> global_touch_state;
|
||||
|
||||
GraphicsContext::~GraphicsContext() = default;
|
||||
|
||||
|
@ -45,18 +46,14 @@ private:
|
|||
};
|
||||
|
||||
EmuWindow::EmuWindow() {
|
||||
// TODO: Find a better place to set this.
|
||||
config.min_client_area_size =
|
||||
std::make_pair(Core::kScreenTopWidth, Core::kScreenTopHeight + Core::kScreenBottomHeight);
|
||||
active_config = config;
|
||||
touch_state = std::make_shared<TouchState>();
|
||||
Input::RegisterFactory<Input::TouchDevice>("emu_window", touch_state);
|
||||
}
|
||||
|
||||
EmuWindow::~EmuWindow() {
|
||||
Input::UnregisterFactory<Input::TouchDevice>("emu_window");
|
||||
CreateTouchState();
|
||||
};
|
||||
|
||||
EmuWindow::EmuWindow(bool is_secondary_) : is_secondary{is_secondary_} {
|
||||
CreateTouchState();
|
||||
}
|
||||
|
||||
EmuWindow::~EmuWindow() = default;
|
||||
/**
|
||||
* Check if the given x/y coordinates are within the touchpad specified by the framebuffer layout
|
||||
* @param layout FramebufferLayout object describing the framebuffer size and screen positions
|
||||
|
@ -111,6 +108,15 @@ std::tuple<unsigned, unsigned> EmuWindow::ClipToTouchScreen(unsigned new_x, unsi
|
|||
return std::make_tuple(new_x, new_y);
|
||||
}
|
||||
|
||||
void EmuWindow::CreateTouchState() {
|
||||
if (touch_state = global_touch_state.lock()) {
|
||||
return;
|
||||
}
|
||||
touch_state = std::make_shared<TouchState>();
|
||||
Input::RegisterFactory<Input::TouchDevice>("emu_window", touch_state);
|
||||
global_touch_state = touch_state;
|
||||
}
|
||||
|
||||
bool EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) {
|
||||
if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y))
|
||||
return false;
|
||||
|
@ -194,6 +200,12 @@ void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height,
|
|||
layout = Layout::SideFrameLayout(width, height, Settings::values.swap_screen,
|
||||
Settings::values.upright_screen);
|
||||
break;
|
||||
#ifndef ANDROID
|
||||
case Settings::LayoutOption::SeparateWindows:
|
||||
layout = Layout::SeparateWindowsLayout(width, height, is_secondary,
|
||||
Settings::values.upright_screen);
|
||||
break;
|
||||
#endif
|
||||
case Settings::LayoutOption::MobilePortrait:
|
||||
layout = Layout::MobilePortraitFrameLayout(width, height, Settings::values.swap_screen);
|
||||
break;
|
||||
|
|
|
@ -7,7 +7,9 @@
|
|||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/3ds.h"
|
||||
#include "core/frontend/framebuffer_layout.h"
|
||||
|
||||
namespace Frontend {
|
||||
|
@ -87,12 +89,15 @@ public:
|
|||
*/
|
||||
class EmuWindow : public GraphicsContext {
|
||||
public:
|
||||
class TouchState;
|
||||
|
||||
/// Data structure to store emuwindow configuration
|
||||
struct WindowConfig {
|
||||
bool fullscreen = false;
|
||||
int res_width = 0;
|
||||
int res_height = 0;
|
||||
std::pair<unsigned, unsigned> min_client_area_size;
|
||||
std::pair<unsigned, unsigned> min_client_area_size{
|
||||
Core::kScreenTopWidth, Core::kScreenTopHeight + Core::kScreenBottomHeight};
|
||||
};
|
||||
|
||||
/// Polls window events
|
||||
|
@ -177,6 +182,7 @@ public:
|
|||
|
||||
protected:
|
||||
EmuWindow();
|
||||
EmuWindow(bool is_secondary);
|
||||
virtual ~EmuWindow();
|
||||
|
||||
/**
|
||||
|
@ -204,6 +210,8 @@ protected:
|
|||
framebuffer_layout = layout;
|
||||
}
|
||||
|
||||
bool is_secondary{};
|
||||
|
||||
private:
|
||||
/**
|
||||
* Handler called when the minimal client area was requested to be changed via SetConfig.
|
||||
|
@ -214,13 +222,14 @@ private:
|
|||
// By default, ignore this request and do nothing.
|
||||
}
|
||||
|
||||
void CreateTouchState();
|
||||
|
||||
Layout::FramebufferLayout framebuffer_layout; ///< Current framebuffer layout
|
||||
|
||||
WindowConfig config; ///< Internal configuration (changes pending for being applied in
|
||||
/// ProcessConfigurationChanges)
|
||||
WindowConfig active_config; ///< Internal active configuration
|
||||
WindowConfig config{}; ///< Internal configuration (changes pending for being applied in
|
||||
/// ProcessConfigurationChanges)
|
||||
WindowConfig active_config{}; ///< Internal active configuration
|
||||
|
||||
class TouchState;
|
||||
std::shared_ptr<TouchState> touch_state;
|
||||
|
||||
/**
|
||||
|
|
|
@ -342,6 +342,13 @@ FramebufferLayout SideFrameLayout(u32 width, u32 height, bool swapped, bool upri
|
|||
return res;
|
||||
}
|
||||
|
||||
FramebufferLayout SeparateWindowsLayout(u32 width, u32 height, bool is_secondary, bool upright) {
|
||||
// When is_secondary is true, we disable the top screen, and enable the bottom screen.
|
||||
// The same logic is found in the SingleFrameLayout using the is_swapped bool.
|
||||
is_secondary = Settings::values.swap_screen ? !is_secondary : is_secondary;
|
||||
return SingleFrameLayout(width, height, is_secondary, upright);
|
||||
}
|
||||
|
||||
FramebufferLayout CustomFrameLayout(u32 width, u32 height) {
|
||||
ASSERT(width > 0);
|
||||
ASSERT(height > 0);
|
||||
|
@ -360,7 +367,7 @@ FramebufferLayout CustomFrameLayout(u32 width, u32 height) {
|
|||
return res;
|
||||
}
|
||||
|
||||
FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale) {
|
||||
FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale, bool is_secondary) {
|
||||
FramebufferLayout layout;
|
||||
if (Settings::values.custom_layout == true) {
|
||||
layout = CustomFrameLayout(
|
||||
|
@ -370,8 +377,13 @@ FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale) {
|
|||
int width, height;
|
||||
switch (Settings::values.layout_option) {
|
||||
case Settings::LayoutOption::SingleScreen:
|
||||
#ifndef ANDROID
|
||||
case Settings::LayoutOption::SeparateWindows:
|
||||
#endif
|
||||
{
|
||||
const bool swap_screens = is_secondary || Settings::values.swap_screen;
|
||||
if (Settings::values.upright_screen) {
|
||||
if (Settings::values.swap_screen) {
|
||||
if (swap_screens) {
|
||||
width = Core::kScreenBottomHeight * res_scale;
|
||||
height = Core::kScreenBottomWidth * res_scale;
|
||||
} else {
|
||||
|
@ -379,7 +391,7 @@ FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale) {
|
|||
height = Core::kScreenTopWidth * res_scale;
|
||||
}
|
||||
} else {
|
||||
if (Settings::values.swap_screen) {
|
||||
if (swap_screens) {
|
||||
width = Core::kScreenBottomWidth * res_scale;
|
||||
height = Core::kScreenBottomHeight * res_scale;
|
||||
} else {
|
||||
|
@ -387,9 +399,10 @@ FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale) {
|
|||
height = Core::kScreenTopHeight * res_scale;
|
||||
}
|
||||
}
|
||||
layout = SingleFrameLayout(width, height, Settings::values.swap_screen,
|
||||
Settings::values.upright_screen);
|
||||
layout =
|
||||
SingleFrameLayout(width, height, swap_screens, Settings::values.upright_screen);
|
||||
break;
|
||||
}
|
||||
case Settings::LayoutOption::LargeScreen:
|
||||
if (Settings::values.upright_screen) {
|
||||
if (Settings::values.swap_screen) {
|
||||
|
@ -544,6 +557,9 @@ std::pair<unsigned, unsigned> GetMinimumSizeFromLayout(Settings::LayoutOption la
|
|||
|
||||
switch (layout) {
|
||||
case Settings::LayoutOption::SingleScreen:
|
||||
#ifndef ANDROID
|
||||
case Settings::LayoutOption::SeparateWindows:
|
||||
#endif
|
||||
min_width = Settings::values.swap_screen ? Core::kScreenBottomWidth : Core::kScreenTopWidth;
|
||||
min_height = Core::kScreenBottomHeight;
|
||||
break;
|
||||
|
|
|
@ -98,6 +98,16 @@ FramebufferLayout LargeFrameLayout(u32 width, u32 height, bool is_swapped, bool
|
|||
*/
|
||||
FramebufferLayout SideFrameLayout(u32 width, u32 height, bool is_swapped, bool upright);
|
||||
|
||||
/**
|
||||
* Factory method for constructing a Frame with the Top screen and bottom
|
||||
* screen on separate windows
|
||||
* @param width Window framebuffer width in pixels
|
||||
* @param height Window framebuffer height in pixels
|
||||
* @param is_secondary if true, the bottom screen will be enabled instead of the top screen
|
||||
* @return Newly created FramebufferLayout object with default screen regions initialized
|
||||
*/
|
||||
FramebufferLayout SeparateWindowsLayout(u32 width, u32 height, bool is_secondary, bool upright);
|
||||
|
||||
/**
|
||||
* Factory method for constructing a custom FramebufferLayout
|
||||
* @param width Window framebuffer width in pixels
|
||||
|
@ -111,7 +121,7 @@ FramebufferLayout CustomFrameLayout(u32 width, u32 height);
|
|||
* Read from the current settings to determine which layout to use.
|
||||
* @param res_scale resolution scale factor
|
||||
*/
|
||||
FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale);
|
||||
FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale, bool is_secondary = false);
|
||||
|
||||
/**
|
||||
* Convenience method for transforming a frame layout when using Cardboard VR
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue