mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-25 01:31:05 +00:00
feat(qt): add custom screen layout editor
This commit is contained in:
parent
8e3c7674d8
commit
85063565b7
@ -160,7 +160,6 @@ void Config::ReadValues() {
|
|||||||
static_cast<Settings::LayoutOption>(sdl2_config->GetInteger("Layout", "layout_option", 0));
|
static_cast<Settings::LayoutOption>(sdl2_config->GetInteger("Layout", "layout_option", 0));
|
||||||
Settings::values.swap_screen = sdl2_config->GetBoolean("Layout", "swap_screen", false);
|
Settings::values.swap_screen = sdl2_config->GetBoolean("Layout", "swap_screen", false);
|
||||||
Settings::values.upright_screen = sdl2_config->GetBoolean("Layout", "upright_screen", false);
|
Settings::values.upright_screen = sdl2_config->GetBoolean("Layout", "upright_screen", false);
|
||||||
Settings::values.custom_layout = sdl2_config->GetBoolean("Layout", "custom_layout", false);
|
|
||||||
Settings::values.custom_top_left =
|
Settings::values.custom_top_left =
|
||||||
static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_top_left", 0));
|
static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_top_left", 0));
|
||||||
Settings::values.custom_top_top =
|
Settings::values.custom_top_top =
|
||||||
|
@ -79,6 +79,12 @@ add_executable(citra-qt
|
|||||||
configuration/configure_web.cpp
|
configuration/configure_web.cpp
|
||||||
configuration/configure_web.h
|
configuration/configure_web.h
|
||||||
configuration/configure_web.ui
|
configuration/configure_web.ui
|
||||||
|
configuration/custom_screen.cpp
|
||||||
|
configuration/custom_screen.h
|
||||||
|
configuration/custom_screen.ui
|
||||||
|
configuration/custom_screen_layout_editor.cpp
|
||||||
|
configuration/custom_screen_layout_editor.h
|
||||||
|
configuration/custom_screen_layout_editor.ui
|
||||||
debugger/console.h
|
debugger/console.h
|
||||||
debugger/console.cpp
|
debugger/console.cpp
|
||||||
debugger/graphics/graphics.cpp
|
debugger/graphics/graphics.cpp
|
||||||
|
@ -343,7 +343,6 @@ void Config::ReadLayoutValues() {
|
|||||||
static_cast<Settings::LayoutOption>(ReadSetting(QStringLiteral("layout_option")).toInt());
|
static_cast<Settings::LayoutOption>(ReadSetting(QStringLiteral("layout_option")).toInt());
|
||||||
Settings::values.swap_screen = ReadSetting(QStringLiteral("swap_screen"), false).toBool();
|
Settings::values.swap_screen = ReadSetting(QStringLiteral("swap_screen"), false).toBool();
|
||||||
Settings::values.upright_screen = ReadSetting(QStringLiteral("upright_screen"), false).toBool();
|
Settings::values.upright_screen = ReadSetting(QStringLiteral("upright_screen"), false).toBool();
|
||||||
Settings::values.custom_layout = ReadSetting(QStringLiteral("custom_layout"), false).toBool();
|
|
||||||
Settings::values.custom_top_left = ReadSetting(QStringLiteral("custom_top_left"), 0).toInt();
|
Settings::values.custom_top_left = ReadSetting(QStringLiteral("custom_top_left"), 0).toInt();
|
||||||
Settings::values.custom_top_top = ReadSetting(QStringLiteral("custom_top_top"), 0).toInt();
|
Settings::values.custom_top_top = ReadSetting(QStringLiteral("custom_top_top"), 0).toInt();
|
||||||
Settings::values.custom_top_right =
|
Settings::values.custom_top_right =
|
||||||
@ -887,7 +886,6 @@ void Config::SaveLayoutValues() {
|
|||||||
WriteSetting(QStringLiteral("layout_option"), static_cast<int>(Settings::values.layout_option));
|
WriteSetting(QStringLiteral("layout_option"), static_cast<int>(Settings::values.layout_option));
|
||||||
WriteSetting(QStringLiteral("swap_screen"), Settings::values.swap_screen, false);
|
WriteSetting(QStringLiteral("swap_screen"), Settings::values.swap_screen, false);
|
||||||
WriteSetting(QStringLiteral("upright_screen"), Settings::values.upright_screen, false);
|
WriteSetting(QStringLiteral("upright_screen"), Settings::values.upright_screen, false);
|
||||||
WriteSetting(QStringLiteral("custom_layout"), Settings::values.custom_layout, false);
|
|
||||||
WriteSetting(QStringLiteral("custom_top_left"), Settings::values.custom_top_left, 0);
|
WriteSetting(QStringLiteral("custom_top_left"), Settings::values.custom_top_left, 0);
|
||||||
WriteSetting(QStringLiteral("custom_top_top"), Settings::values.custom_top_top, 0);
|
WriteSetting(QStringLiteral("custom_top_top"), Settings::values.custom_top_top, 0);
|
||||||
WriteSetting(QStringLiteral("custom_top_right"), Settings::values.custom_top_right, 400);
|
WriteSetting(QStringLiteral("custom_top_right"), Settings::values.custom_top_right, 400);
|
||||||
|
@ -2,16 +2,41 @@
|
|||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
#include <QColorDialog>
|
#include <QColorDialog>
|
||||||
|
#include <QPoint>
|
||||||
|
#include <QString>
|
||||||
#include "citra_qt/configuration/configure_enhancements.h"
|
#include "citra_qt/configuration/configure_enhancements.h"
|
||||||
|
#include "core/3ds.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
#include "ui_configure_enhancements.h"
|
#include "ui_configure_enhancements.h"
|
||||||
#include "video_core/renderer_opengl/post_processing_opengl.h"
|
#include "video_core/renderer_opengl/post_processing_opengl.h"
|
||||||
#include "video_core/renderer_opengl/texture_filters/texture_filterer.h"
|
#include "video_core/renderer_opengl/texture_filters/texture_filterer.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
const QString g_top_screen_name{QObject::tr("Top")};
|
||||||
|
const QString g_bottom_screen_name{QObject::tr("Bottom")};
|
||||||
|
|
||||||
|
void AddScreens(CustomScreenLayoutEditor& layout_editor) {
|
||||||
|
layout_editor.addScreen(
|
||||||
|
g_top_screen_name, {0, 0, Core::kScreenTopWidth, Core::kScreenTopHeight},
|
||||||
|
{QPoint{Settings::values.custom_top_left, Settings::values.custom_top_top},
|
||||||
|
QPoint{Settings::values.custom_top_right - 1, Settings::values.custom_top_bottom - 1}});
|
||||||
|
layout_editor.addScreen(
|
||||||
|
g_bottom_screen_name,
|
||||||
|
{40, Core::kScreenTopHeight, Core::kScreenBottomWidth, Core::kScreenBottomHeight},
|
||||||
|
{QPoint{Settings::values.custom_bottom_left, Settings::values.custom_bottom_top},
|
||||||
|
QPoint{Settings::values.custom_bottom_right - 1,
|
||||||
|
Settings::values.custom_bottom_bottom - 1}});
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
ConfigureEnhancements::ConfigureEnhancements(QWidget* parent)
|
ConfigureEnhancements::ConfigureEnhancements(QWidget* parent)
|
||||||
: QWidget(parent), ui(std::make_unique<Ui::ConfigureEnhancements>()) {
|
: QWidget(parent), ui(std::make_unique<Ui::ConfigureEnhancements>()),
|
||||||
|
layout_editor(std::make_unique<CustomScreenLayoutEditor>(this)) {
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
for (const auto& filter : OpenGL::TextureFilterer::GetFilterNames())
|
for (const auto& filter : OpenGL::TextureFilterer::GetFilterNames())
|
||||||
@ -19,16 +44,19 @@ ConfigureEnhancements::ConfigureEnhancements(QWidget* parent)
|
|||||||
|
|
||||||
SetConfiguration();
|
SetConfiguration();
|
||||||
|
|
||||||
ui->layoutBox->setEnabled(!Settings::values.custom_layout);
|
|
||||||
|
|
||||||
ui->resolution_factor_combobox->setEnabled(Settings::values.use_hw_renderer);
|
ui->resolution_factor_combobox->setEnabled(Settings::values.use_hw_renderer);
|
||||||
|
|
||||||
|
AddScreens(*layout_editor);
|
||||||
|
|
||||||
connect(ui->render_3d_combobox,
|
connect(ui->render_3d_combobox,
|
||||||
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
|
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
|
||||||
[this](int currentIndex) {
|
[this](int currentIndex) {
|
||||||
updateShaders(static_cast<Settings::StereoRenderOption>(currentIndex));
|
updateShaders(static_cast<Settings::StereoRenderOption>(currentIndex));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
connect(ui->editor_button, &QPushButton::clicked, this,
|
||||||
|
[this] { layout_editor->showMaximized(); });
|
||||||
|
|
||||||
connect(ui->bg_button, &QPushButton::clicked, this, [this] {
|
connect(ui->bg_button, &QPushButton::clicked, this, [this] {
|
||||||
const QColor new_bg_color = QColorDialog::getColor(bg_color);
|
const QColor new_bg_color = QColorDialog::getColor(bg_color);
|
||||||
if (!new_bg_color.isValid()) {
|
if (!new_bg_color.isValid()) {
|
||||||
@ -113,6 +141,23 @@ void ConfigureEnhancements::ApplyConfiguration() {
|
|||||||
Settings::values.texture_filter_name = ui->texture_filter_combobox->currentText().toStdString();
|
Settings::values.texture_filter_name = ui->texture_filter_combobox->currentText().toStdString();
|
||||||
Settings::values.layout_option =
|
Settings::values.layout_option =
|
||||||
static_cast<Settings::LayoutOption>(ui->layout_combobox->currentIndex());
|
static_cast<Settings::LayoutOption>(ui->layout_combobox->currentIndex());
|
||||||
|
{
|
||||||
|
const auto geometry = [this](const QString& screen_name) {
|
||||||
|
const auto* const screen{layout_editor->getScreen(screen_name)};
|
||||||
|
assert(screen);
|
||||||
|
return screen->geometry();
|
||||||
|
};
|
||||||
|
const QRect top_screen{geometry(g_top_screen_name)};
|
||||||
|
Settings::values.custom_top_left = top_screen.left();
|
||||||
|
Settings::values.custom_top_top = top_screen.top();
|
||||||
|
Settings::values.custom_top_right = top_screen.right() + 1;
|
||||||
|
Settings::values.custom_top_bottom = top_screen.bottom() + 1;
|
||||||
|
const QRect bottom_screen{geometry(g_bottom_screen_name)};
|
||||||
|
Settings::values.custom_bottom_left = bottom_screen.left();
|
||||||
|
Settings::values.custom_bottom_top = bottom_screen.top();
|
||||||
|
Settings::values.custom_bottom_right = bottom_screen.right() + 1;
|
||||||
|
Settings::values.custom_bottom_bottom = bottom_screen.bottom() + 1;
|
||||||
|
}
|
||||||
Settings::values.swap_screen = ui->swap_screen->isChecked();
|
Settings::values.swap_screen = ui->swap_screen->isChecked();
|
||||||
Settings::values.upright_screen = ui->upright_screen->isChecked();
|
Settings::values.upright_screen = ui->upright_screen->isChecked();
|
||||||
Settings::values.dump_textures = ui->toggle_dump_textures->isChecked();
|
Settings::values.dump_textures = ui->toggle_dump_textures->isChecked();
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
#include "citra_qt/configuration/custom_screen_layout_editor.h"
|
||||||
|
|
||||||
namespace Settings {
|
namespace Settings {
|
||||||
enum class StereoRenderOption;
|
enum class StereoRenderOption;
|
||||||
@ -31,5 +32,6 @@ private:
|
|||||||
void updateTextureFilter(int index);
|
void updateTextureFilter(int index);
|
||||||
|
|
||||||
std::unique_ptr<Ui::ConfigureEnhancements> ui;
|
std::unique_ptr<Ui::ConfigureEnhancements> ui;
|
||||||
|
std::unique_ptr<CustomScreenLayoutEditor> layout_editor;
|
||||||
QColor bg_color;
|
QColor bg_color;
|
||||||
};
|
};
|
||||||
|
@ -216,6 +216,13 @@
|
|||||||
<string>Layout</string>
|
<string>Layout</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="editor_button">
|
||||||
|
<property name="text">
|
||||||
|
<string>Edit Custom Screen Layout</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||||
<item>
|
<item>
|
||||||
@ -247,6 +254,11 @@
|
|||||||
<string>Side by Side</string>
|
<string>Side by Side</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Custom</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
261
src/citra_qt/configuration/custom_screen.cpp
Normal file
261
src/citra_qt/configuration/custom_screen.cpp
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
// Copyright 2019 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cmath>
|
||||||
|
#include <numeric>
|
||||||
|
#include <utility>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QMoveEvent>
|
||||||
|
#include <QResizeEvent>
|
||||||
|
#include <QSpinBox>
|
||||||
|
#include <QtGlobal>
|
||||||
|
#include "citra_qt/configuration/custom_screen.h"
|
||||||
|
#include "common/diagnostic.h"
|
||||||
|
#include "ui_custom_screen.h"
|
||||||
|
|
||||||
|
CITRA_DIAGNOSTIC_IGNORE_SWITCH
|
||||||
|
|
||||||
|
constexpr unsigned to_underlying(RectangleSides s) {
|
||||||
|
return static_cast<unsigned>(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr RectangleSides operator|(RectangleSides l, RectangleSides r) {
|
||||||
|
return RectangleSides{to_underlying(l) | to_underlying(r)};
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr RectangleSides operator&(RectangleSides l, RectangleSides r) {
|
||||||
|
return RectangleSides{to_underlying(l) & to_underlying(r)};
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomScreen::CustomScreen(QWidget* parent)
|
||||||
|
: QFrame(parent), ui(std::make_unique<Ui::CustomScreen>()) {
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
const auto value_changed{QOverload<int>::of(&QSpinBox::valueChanged)};
|
||||||
|
|
||||||
|
connect(ui->left, value_changed, this, [this](int x) { move(x, y()); });
|
||||||
|
connect(ui->top, value_changed, this, [this](int y) { move(x(), y); });
|
||||||
|
connect(ui->width, value_changed, this, [this](int width) {
|
||||||
|
resize(width, height());
|
||||||
|
ui->width->setValue(this->width());
|
||||||
|
});
|
||||||
|
connect(ui->height, value_changed, this, [this](int height) {
|
||||||
|
resize(width(), height);
|
||||||
|
ui->height->setValue(this->height());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QString CustomScreen::name() const {
|
||||||
|
return ui->name->text();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CustomScreen::setName(const QString& name) {
|
||||||
|
ui->name->setText(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
bool IsClamped(int v, int lo, int hi) {
|
||||||
|
return lo <= v && v < hi;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
auto CustomScreen::SidesAt(QPoint pt) -> RectangleSides {
|
||||||
|
return RectangleSides{
|
||||||
|
(IsClamped(pt.x(), 0, lineWidth()) ? RectangleSides::left : RectangleSides{}) |
|
||||||
|
(IsClamped(pt.y(), 0, lineWidth()) ? RectangleSides::top : RectangleSides{}) |
|
||||||
|
(IsClamped(pt.x(), width() - lineWidth(), width()) ? RectangleSides::right
|
||||||
|
: RectangleSides{}) |
|
||||||
|
(IsClamped(pt.y(), height() - lineWidth(), height()) ? RectangleSides::bottom
|
||||||
|
: RectangleSides{})};
|
||||||
|
}
|
||||||
|
|
||||||
|
void CustomScreen::mousePressEvent(QMouseEvent* event) {
|
||||||
|
switch (event->buttons()) {
|
||||||
|
case Qt::MouseButton::LeftButton:
|
||||||
|
drag = {SidesAt(event->pos()), geometry(), event->globalPos()};
|
||||||
|
if (drag.sides == RectangleSides{})
|
||||||
|
setCursor(Qt::CursorShape::ClosedHandCursor);
|
||||||
|
return event->accept();
|
||||||
|
default:
|
||||||
|
return event->ignore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CustomScreen::mouseMoveEvent(QMouseEvent* event) {
|
||||||
|
switch (event->buttons()) {
|
||||||
|
case Qt::MouseButton::NoButton:
|
||||||
|
switch (SidesAt(event->pos())) {
|
||||||
|
case RectangleSides::left:
|
||||||
|
case RectangleSides::right:
|
||||||
|
setCursor(Qt::CursorShape::SizeHorCursor);
|
||||||
|
break;
|
||||||
|
case RectangleSides::top:
|
||||||
|
case RectangleSides::bottom:
|
||||||
|
setCursor(Qt::CursorShape::SizeVerCursor);
|
||||||
|
break;
|
||||||
|
case RectangleSides::top | RectangleSides::left:
|
||||||
|
case RectangleSides::bottom | RectangleSides::right:
|
||||||
|
setCursor(Qt::CursorShape::SizeFDiagCursor);
|
||||||
|
break;
|
||||||
|
case RectangleSides::top | RectangleSides::right:
|
||||||
|
case RectangleSides::bottom | RectangleSides::left:
|
||||||
|
setCursor(Qt::CursorShape::SizeBDiagCursor);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
setCursor(Qt::CursorShape::OpenHandCursor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Qt::MouseButton::LeftButton:
|
||||||
|
drag(*this, event->globalPos());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return event->ignore();
|
||||||
|
}
|
||||||
|
|
||||||
|
event->accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
bool HasSingleBit(unsigned x) {
|
||||||
|
return x != 0 && (x & (x - 1)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned BitWidth(unsigned x) {
|
||||||
|
return x == 0 ? 0 : 1 + static_cast<unsigned>(std::log2(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RectangleSideOffsets {
|
||||||
|
int sides[4]{};
|
||||||
|
|
||||||
|
int& operator[](RectangleSides s) {
|
||||||
|
assert(HasSingleBit(to_underlying(s)));
|
||||||
|
return sides[BitWidth(to_underlying(s)) - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
int& left() {
|
||||||
|
return operator[](RectangleSides::left);
|
||||||
|
}
|
||||||
|
int& top() {
|
||||||
|
return operator[](RectangleSides::top);
|
||||||
|
}
|
||||||
|
int& right() {
|
||||||
|
return operator[](RectangleSides::right);
|
||||||
|
}
|
||||||
|
int& bottom() {
|
||||||
|
return operator[](RectangleSides::bottom);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
RectangleSides prev(RectangleSides side) {
|
||||||
|
assert(HasSingleBit(to_underlying(side)));
|
||||||
|
return side == RectangleSides::left ? RectangleSides::bottom
|
||||||
|
: RectangleSides{to_underlying(side) >> 1};
|
||||||
|
}
|
||||||
|
|
||||||
|
RectangleSides next(RectangleSides side) {
|
||||||
|
assert(HasSingleBit(to_underlying(side)));
|
||||||
|
return side == RectangleSides::bottom ? RectangleSides::left
|
||||||
|
: RectangleSides{to_underlying(side) << 1};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HaveEqualOutwardsDirectionSign(RectangleSides l, RectangleSides r) {
|
||||||
|
assert(l != r);
|
||||||
|
return (l | r) == (RectangleSides::top | RectangleSides::left) ||
|
||||||
|
(l | r) == (RectangleSides::bottom | RectangleSides::right);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GrowAdjacents(double aspect_ratio, RectangleSideOffsets& offsets, RectangleSides side) {
|
||||||
|
assert(HasSingleBit(to_underlying(side)));
|
||||||
|
const int adjacent_growth{static_cast<int>(aspect_ratio * offsets[side])};
|
||||||
|
RectangleSides adjacent_sides[2]{prev(side), next(side)};
|
||||||
|
if (!HaveEqualOutwardsDirectionSign(side, adjacent_sides[0]))
|
||||||
|
std::swap(adjacent_sides[0], adjacent_sides[1]);
|
||||||
|
offsets[adjacent_sides[0]] = adjacent_growth / 2;
|
||||||
|
offsets[adjacent_sides[1]] = -adjacent_growth / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FurthestOffset(RectangleSides side, int l, int r) {
|
||||||
|
assert(HasSingleBit(to_underlying(side)));
|
||||||
|
return (side & (RectangleSides::top | RectangleSides::left)) != RectangleSides{}
|
||||||
|
? std::min(l, r)
|
||||||
|
: std::max(l, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr RectangleSides vertical_sides{RectangleSides::left | RectangleSides::right};
|
||||||
|
constexpr RectangleSides horizontal_sides{RectangleSides::top | RectangleSides::bottom};
|
||||||
|
|
||||||
|
[[maybe_unused]] bool IsCorner(RectangleSides sides) {
|
||||||
|
return HasSingleBit(to_underlying(sides & vertical_sides)) &&
|
||||||
|
HasSingleBit(to_underlying(sides & horizontal_sides));
|
||||||
|
}
|
||||||
|
|
||||||
|
void GrowCorner(double aspect_ratio, RectangleSideOffsets& offsets, RectangleSides corner) {
|
||||||
|
assert(IsCorner(corner));
|
||||||
|
const RectangleSides vertical_side{corner & vertical_sides};
|
||||||
|
const RectangleSides horizontal_side{corner & horizontal_sides};
|
||||||
|
int& vertical_offset{offsets[vertical_side]};
|
||||||
|
int& horizontal_offset{offsets[horizontal_side]};
|
||||||
|
const int adjust{HaveEqualOutwardsDirectionSign(vertical_side, horizontal_side) ? 1 : -1};
|
||||||
|
const int grown_vertical_offset{static_cast<int>(horizontal_offset * aspect_ratio) * adjust};
|
||||||
|
const int grown_horizontal_offset{static_cast<int>(vertical_offset / aspect_ratio) * adjust};
|
||||||
|
vertical_offset = FurthestOffset(vertical_side, vertical_offset, grown_vertical_offset);
|
||||||
|
horizontal_offset = FurthestOffset(horizontal_side, horizontal_offset, grown_horizontal_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void CustomScreen::Drag::operator()(CustomScreen& screen, QPoint move_position) const {
|
||||||
|
const auto drag_offset{move_position - press_position};
|
||||||
|
|
||||||
|
if (sides == RectangleSides{})
|
||||||
|
return screen.move(original_screen_geometry.topLeft() + drag_offset);
|
||||||
|
|
||||||
|
RectangleSideOffsets offsets{
|
||||||
|
(sides & RectangleSides::left) != RectangleSides{} ? drag_offset.x() : 0,
|
||||||
|
(sides & RectangleSides::top) != RectangleSides{} ? drag_offset.y() : 0,
|
||||||
|
(sides & RectangleSides::right) != RectangleSides{} ? drag_offset.x() : 0,
|
||||||
|
(sides & RectangleSides::bottom) != RectangleSides{} ? drag_offset.y() : 0};
|
||||||
|
|
||||||
|
if (screen.ui->keep_aspect_ratio->isChecked()) {
|
||||||
|
const double aspect_ratio{original_screen_geometry.width() * 1.0 /
|
||||||
|
original_screen_geometry.height()};
|
||||||
|
(HasSingleBit(to_underlying(sides)) ? GrowAdjacents : GrowCorner)(aspect_ratio, offsets,
|
||||||
|
sides);
|
||||||
|
}
|
||||||
|
|
||||||
|
screen.move(std::min(original_screen_geometry.x() + offsets.left(),
|
||||||
|
original_screen_geometry.right() - screen.minimumWidth() + 1),
|
||||||
|
std::min(original_screen_geometry.y() + offsets.top(),
|
||||||
|
original_screen_geometry.bottom() - screen.minimumHeight() + 1));
|
||||||
|
screen.resize(original_screen_geometry.width() + offsets.right() - offsets.left(),
|
||||||
|
original_screen_geometry.height() + offsets.bottom() - offsets.top());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CustomScreen::moveEvent(QMoveEvent*) {
|
||||||
|
move(std::max(0, x()), std::max(0, y()));
|
||||||
|
ui->left->setValue(x());
|
||||||
|
ui->top->setValue(y());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CustomScreen::resizeEvent(QResizeEvent*) {
|
||||||
|
moveEvent(nullptr);
|
||||||
|
ui->width->setValue(width());
|
||||||
|
ui->height->setValue(height());
|
||||||
|
|
||||||
|
#if !defined(NDEBUG)
|
||||||
|
const int num{width()};
|
||||||
|
const int den{height()};
|
||||||
|
const int gcd{std::gcd(num, den)};
|
||||||
|
ui->keep_aspect_ratio->setText(
|
||||||
|
tr("Keep aspect ratio (%1, %2:%3)").arg(1.0 * num / den).arg(num / gcd).arg(den / gcd));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomScreen::~CustomScreen() {}
|
57
src/citra_qt/configuration/custom_screen.h
Normal file
57
src/citra_qt/configuration/custom_screen.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
// Copyright 2019 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <QFrame>
|
||||||
|
#include <QPoint>
|
||||||
|
#include <QRect>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
enum class RectangleSides : unsigned {
|
||||||
|
left = (1 << 0),
|
||||||
|
top = (1 << 1),
|
||||||
|
right = (1 << 2),
|
||||||
|
bottom = (1 << 3)
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class CustomScreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
class CustomScreen : public QFrame {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit CustomScreen(QWidget* parent = nullptr);
|
||||||
|
~CustomScreen();
|
||||||
|
|
||||||
|
QString name() const;
|
||||||
|
|
||||||
|
void setName(const QString&);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void mousePressEvent(QMouseEvent*) override;
|
||||||
|
void mouseMoveEvent(QMouseEvent*) override;
|
||||||
|
|
||||||
|
void moveEvent(QMoveEvent*) override;
|
||||||
|
void resizeEvent(QResizeEvent*) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
RectangleSides SidesAt(QPoint);
|
||||||
|
|
||||||
|
struct Drag {
|
||||||
|
RectangleSides sides;
|
||||||
|
QRect original_screen_geometry;
|
||||||
|
QPoint press_position;
|
||||||
|
|
||||||
|
void operator()(CustomScreen& screen, QPoint move_position) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
friend Drag;
|
||||||
|
|
||||||
|
std::unique_ptr<Ui::CustomScreen> ui;
|
||||||
|
Drag drag;
|
||||||
|
};
|
146
src/citra_qt/configuration/custom_screen.ui
Normal file
146
src/citra_qt/configuration/custom_screen.ui
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>CustomScreen</class>
|
||||||
|
<widget class="QFrame" name="CustomScreen">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>400</width>
|
||||||
|
<height>300</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="mouseTracking">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="lineWidth">
|
||||||
|
<number>5</number>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||||
|
<property name="sizeConstraint">
|
||||||
|
<enum>QLayout::SetMinimumSize</enum>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="name">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>TextLabel</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="keep_aspect_ratio">
|
||||||
|
<property name="text">
|
||||||
|
<string>Keep aspect ratio</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QFrame" name="frame">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Left</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="left">
|
||||||
|
<property name="maximum">
|
||||||
|
<number>16777215</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Top</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="top">
|
||||||
|
<property name="maximum">
|
||||||
|
<number>16777215</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>Width</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="width">
|
||||||
|
<property name="maximum">
|
||||||
|
<number>16777215</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="text">
|
||||||
|
<string>Height</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="height">
|
||||||
|
<property name="maximum">
|
||||||
|
<number>16777215</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
47
src/citra_qt/configuration/custom_screen_layout_editor.cpp
Normal file
47
src/citra_qt/configuration/custom_screen_layout_editor.cpp
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
// Copyright 2019 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <utility>
|
||||||
|
#include <QMainWindow>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include "citra_qt/configuration/custom_screen_layout_editor.h"
|
||||||
|
#include "ui_custom_screen_layout_editor.h"
|
||||||
|
|
||||||
|
CustomScreenLayoutEditor::CustomScreenLayoutEditor(QWidget* parent)
|
||||||
|
: QDialog(parent), ui(std::make_unique<Ui::CustomScreenLayoutEditor>()) {
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
auto* const framebuffer = new QMainWindow;
|
||||||
|
ui->scroll_area->setWidget(framebuffer);
|
||||||
|
|
||||||
|
const auto set = [this](QRect RestorableScreen::*geometry) {
|
||||||
|
return [this, geometry] {
|
||||||
|
for (auto& s : screens)
|
||||||
|
s.screen->setGeometry(s.*geometry);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
connect(ui->buttonBox->button(QDialogButtonBox::Reset), &QPushButton::clicked, this,
|
||||||
|
set(&RestorableScreen::reset_geometry));
|
||||||
|
connect(ui->buttonBox->button(QDialogButtonBox::RestoreDefaults), &QPushButton::clicked, this,
|
||||||
|
set(&RestorableScreen::default_geometry));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CustomScreenLayoutEditor::addScreen(QString name, QRect default_geometry,
|
||||||
|
QRect current_geometry) {
|
||||||
|
auto s{std::make_unique<CustomScreen>(ui->scroll_area->widget())};
|
||||||
|
s->setGeometry(current_geometry);
|
||||||
|
s->setName(name);
|
||||||
|
screens.emplace_back(RestorableScreen{std::move(s), default_geometry});
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomScreen* CustomScreenLayoutEditor::getScreen(QString name) const {
|
||||||
|
auto s{std::find_if(screens.begin(), screens.end(),
|
||||||
|
[&](auto& s) { return s.screen->name() == name; })};
|
||||||
|
return s == screens.end() ? nullptr : s->screen.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomScreenLayoutEditor::~CustomScreenLayoutEditor() {}
|
38
src/citra_qt/configuration/custom_screen_layout_editor.h
Normal file
38
src/citra_qt/configuration/custom_screen_layout_editor.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
// Copyright 2019 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QRect>
|
||||||
|
#include <QString>
|
||||||
|
#include "citra_qt/configuration/custom_screen.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class CustomScreenLayoutEditor;
|
||||||
|
}
|
||||||
|
|
||||||
|
class CustomScreenLayoutEditor : public QDialog {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit CustomScreenLayoutEditor(QWidget* parent = nullptr);
|
||||||
|
~CustomScreenLayoutEditor();
|
||||||
|
|
||||||
|
void addScreen(QString name, QRect default_geometry, QRect current_geometry);
|
||||||
|
|
||||||
|
CustomScreen* getScreen(QString name) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct RestorableScreen {
|
||||||
|
std::unique_ptr<CustomScreen> screen;
|
||||||
|
QRect default_geometry;
|
||||||
|
QRect reset_geometry{screen->geometry()};
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<Ui::CustomScreenLayoutEditor> ui;
|
||||||
|
std::vector<RestorableScreen> screens;
|
||||||
|
};
|
81
src/citra_qt/configuration/custom_screen_layout_editor.ui
Normal file
81
src/citra_qt/configuration/custom_screen_layout_editor.ui
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>CustomScreenLayoutEditor</class>
|
||||||
|
<widget class="QDialog" name="CustomScreenLayoutEditor">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>490</width>
|
||||||
|
<height>300</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Custom Screen Layout Editor</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QScrollArea" name="scroll_area">
|
||||||
|
<property name="widgetResizable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="scrollAreaWidgetContents">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>470</width>
|
||||||
|
<height>250</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Reset|QDialogButtonBox::RestoreDefaults</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>CustomScreenLayoutEditor</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>257</x>
|
||||||
|
<y>290</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>CustomScreenLayoutEditor</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>325</x>
|
||||||
|
<y>290</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
@ -301,6 +301,7 @@ void GMainWindow::InitializeWidgets() {
|
|||||||
actionGroup_ScreenLayouts->addAction(ui->action_Screen_Layout_Single_Screen);
|
actionGroup_ScreenLayouts->addAction(ui->action_Screen_Layout_Single_Screen);
|
||||||
actionGroup_ScreenLayouts->addAction(ui->action_Screen_Layout_Large_Screen);
|
actionGroup_ScreenLayouts->addAction(ui->action_Screen_Layout_Large_Screen);
|
||||||
actionGroup_ScreenLayouts->addAction(ui->action_Screen_Layout_Side_by_Side);
|
actionGroup_ScreenLayouts->addAction(ui->action_Screen_Layout_Side_by_Side);
|
||||||
|
actionGroup_ScreenLayouts->addAction(ui->action_Screen_Layout_Custom);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GMainWindow::InitializeDebugWidgets() {
|
void GMainWindow::InitializeDebugWidgets() {
|
||||||
@ -734,6 +735,8 @@ void GMainWindow::ConnectMenuEvents() {
|
|||||||
&GMainWindow::ChangeScreenLayout);
|
&GMainWindow::ChangeScreenLayout);
|
||||||
connect(ui->action_Screen_Layout_Side_by_Side, &QAction::triggered, this,
|
connect(ui->action_Screen_Layout_Side_by_Side, &QAction::triggered, this,
|
||||||
&GMainWindow::ChangeScreenLayout);
|
&GMainWindow::ChangeScreenLayout);
|
||||||
|
connect(ui->action_Screen_Layout_Custom, &QAction::triggered, this,
|
||||||
|
&GMainWindow::ChangeScreenLayout);
|
||||||
connect(ui->action_Screen_Layout_Swap_Screens, &QAction::triggered, this,
|
connect(ui->action_Screen_Layout_Swap_Screens, &QAction::triggered, this,
|
||||||
&GMainWindow::OnSwapScreens);
|
&GMainWindow::OnSwapScreens);
|
||||||
connect(ui->action_Screen_Layout_Upright_Screens, &QAction::triggered, this,
|
connect(ui->action_Screen_Layout_Upright_Screens, &QAction::triggered, this,
|
||||||
@ -1664,6 +1667,8 @@ void GMainWindow::ChangeScreenLayout() {
|
|||||||
new_layout = Settings::LayoutOption::LargeScreen;
|
new_layout = Settings::LayoutOption::LargeScreen;
|
||||||
} else if (ui->action_Screen_Layout_Side_by_Side->isChecked()) {
|
} else if (ui->action_Screen_Layout_Side_by_Side->isChecked()) {
|
||||||
new_layout = Settings::LayoutOption::SideScreen;
|
new_layout = Settings::LayoutOption::SideScreen;
|
||||||
|
} else if (ui->action_Screen_Layout_Custom->isChecked()) {
|
||||||
|
new_layout = Settings::LayoutOption::Custom;
|
||||||
}
|
}
|
||||||
|
|
||||||
Settings::values.layout_option = new_layout;
|
Settings::values.layout_option = new_layout;
|
||||||
@ -1671,24 +1676,9 @@ void GMainWindow::ChangeScreenLayout() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GMainWindow::ToggleScreenLayout() {
|
void GMainWindow::ToggleScreenLayout() {
|
||||||
Settings::LayoutOption new_layout = Settings::LayoutOption::Default;
|
Settings::values.layout_option =
|
||||||
|
static_cast<Settings::LayoutOption>((static_cast<int>(Settings::values.layout_option) + 1) %
|
||||||
switch (Settings::values.layout_option) {
|
(static_cast<int>(Settings::LayoutOption::Custom) + 1)),
|
||||||
case Settings::LayoutOption::Default:
|
|
||||||
new_layout = Settings::LayoutOption::SingleScreen;
|
|
||||||
break;
|
|
||||||
case Settings::LayoutOption::SingleScreen:
|
|
||||||
new_layout = Settings::LayoutOption::LargeScreen;
|
|
||||||
break;
|
|
||||||
case Settings::LayoutOption::LargeScreen:
|
|
||||||
new_layout = Settings::LayoutOption::SideScreen;
|
|
||||||
break;
|
|
||||||
case Settings::LayoutOption::SideScreen:
|
|
||||||
new_layout = Settings::LayoutOption::Default;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Settings::values.layout_option = new_layout;
|
|
||||||
SyncMenuUISettings();
|
SyncMenuUISettings();
|
||||||
Settings::Apply();
|
Settings::Apply();
|
||||||
}
|
}
|
||||||
@ -2387,6 +2377,8 @@ void GMainWindow::SyncMenuUISettings() {
|
|||||||
Settings::LayoutOption::LargeScreen);
|
Settings::LayoutOption::LargeScreen);
|
||||||
ui->action_Screen_Layout_Side_by_Side->setChecked(Settings::values.layout_option ==
|
ui->action_Screen_Layout_Side_by_Side->setChecked(Settings::values.layout_option ==
|
||||||
Settings::LayoutOption::SideScreen);
|
Settings::LayoutOption::SideScreen);
|
||||||
|
ui->action_Screen_Layout_Custom->setChecked(Settings::values.layout_option ==
|
||||||
|
Settings::LayoutOption::Custom);
|
||||||
ui->action_Screen_Layout_Swap_Screens->setChecked(Settings::values.swap_screen);
|
ui->action_Screen_Layout_Swap_Screens->setChecked(Settings::values.swap_screen);
|
||||||
ui->action_Screen_Layout_Upright_Screens->setChecked(Settings::values.upright_screen);
|
ui->action_Screen_Layout_Upright_Screens->setChecked(Settings::values.upright_screen);
|
||||||
}
|
}
|
||||||
|
@ -125,6 +125,7 @@
|
|||||||
<addaction name="action_Screen_Layout_Single_Screen"/>
|
<addaction name="action_Screen_Layout_Single_Screen"/>
|
||||||
<addaction name="action_Screen_Layout_Large_Screen"/>
|
<addaction name="action_Screen_Layout_Large_Screen"/>
|
||||||
<addaction name="action_Screen_Layout_Side_by_Side"/>
|
<addaction name="action_Screen_Layout_Side_by_Side"/>
|
||||||
|
<addaction name="action_Screen_Layout_Custom"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="action_Screen_Layout_Upright_Screens"/>
|
<addaction name="action_Screen_Layout_Upright_Screens"/>
|
||||||
<addaction name="action_Screen_Layout_Swap_Screens"/>
|
<addaction name="action_Screen_Layout_Swap_Screens"/>
|
||||||
@ -461,6 +462,14 @@
|
|||||||
<string>Side by Side</string>
|
<string>Side by Side</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="action_Screen_Layout_Custom">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Custom</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
<action name="action_Screen_Layout_Swap_Screens">
|
<action name="action_Screen_Layout_Swap_Screens">
|
||||||
<property name="checkable">
|
<property name="checkable">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
|
27
src/common/diagnostic.h
Normal file
27
src/common/diagnostic.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// Copyright 2019 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Adapted from
|
||||||
|
// https://github.com/ericniebler/range-v3/blob/master/include/range/v3/detail/config.hpp#L185.
|
||||||
|
#define CITRA_PRAGMA(X) _Pragma(#X)
|
||||||
|
#if !CITRA_COMP_MSVC
|
||||||
|
#define CITRA_DIAGNOSTIC_PUSH CITRA_PRAGMA(GCC diagnostic push)
|
||||||
|
#define CITRA_DIAGNOSTIC_POP CITRA_PRAGMA(GCC diagnostic pop)
|
||||||
|
#define CITRA_DIAGNOSTIC_IGNORE_PRAGMAS CITRA_PRAGMA(GCC diagnostic ignored "-Wpragmas")
|
||||||
|
#define CITRA_DIAGNOSTIC_IGNORE(X) \
|
||||||
|
CITRA_DIAGNOSTIC_IGNORE_PRAGMAS \
|
||||||
|
CITRA_PRAGMA(GCC diagnostic ignored "-Wunknown-pragmas") \
|
||||||
|
CITRA_PRAGMA(GCC diagnostic ignored "-Wunknown-warning-option") \
|
||||||
|
CITRA_PRAGMA(GCC diagnostic ignored X)
|
||||||
|
#define CITRA_DIAGNOSTIC_IGNORE_SWITCH CITRA_DIAGNOSTIC_IGNORE("-Wswitch")
|
||||||
|
#else
|
||||||
|
#define CITRA_DIAGNOSTIC_PUSH CITRA_PRAGMA(warning(push))
|
||||||
|
#define CITRA_DIAGNOSTIC_POP CITRA_PRAGMA(warning(pop))
|
||||||
|
#define CITRA_DIAGNOSTIC_IGNORE_PRAGMAS CITRA_PRAGMA(warning(disable : 4068))
|
||||||
|
#define CITRA_DIAGNOSTIC_IGNORE(X) \
|
||||||
|
CITRA_DIAGNOSTIC_IGNORE_PRAGMAS CITRA_PRAGMA(warning(disable : X))
|
||||||
|
#define CITRA_DIAGNOSTIC_IGNORE_SWITCH
|
||||||
|
#endif
|
@ -151,12 +151,12 @@ void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height)
|
|||||||
const auto min_size =
|
const auto min_size =
|
||||||
Layout::GetMinimumSizeFromLayout(layout_option, Settings::values.upright_screen);
|
Layout::GetMinimumSizeFromLayout(layout_option, Settings::values.upright_screen);
|
||||||
|
|
||||||
if (Settings::values.custom_layout == true) {
|
|
||||||
layout = Layout::CustomFrameLayout(width, height);
|
|
||||||
} else {
|
|
||||||
width = std::max(width, min_size.first);
|
width = std::max(width, min_size.first);
|
||||||
height = std::max(height, min_size.second);
|
height = std::max(height, min_size.second);
|
||||||
switch (layout_option) {
|
switch (layout_option) {
|
||||||
|
case Settings::LayoutOption::Custom:
|
||||||
|
layout = Layout::CustomFrameLayout(width, height);
|
||||||
|
break;
|
||||||
case Settings::LayoutOption::SingleScreen:
|
case Settings::LayoutOption::SingleScreen:
|
||||||
layout = Layout::SingleFrameLayout(width, height, Settings::values.swap_screen,
|
layout = Layout::SingleFrameLayout(width, height, Settings::values.swap_screen,
|
||||||
Settings::values.upright_screen);
|
Settings::values.upright_screen);
|
||||||
@ -176,7 +176,6 @@ void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
UpdateMinimumWindowSize(min_size);
|
UpdateMinimumWindowSize(min_size);
|
||||||
}
|
|
||||||
NotifyFramebufferLayoutChanged(layout);
|
NotifyFramebufferLayoutChanged(layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,13 +286,13 @@ FramebufferLayout CustomFrameLayout(u32 width, u32 height) {
|
|||||||
|
|
||||||
FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale) {
|
FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale) {
|
||||||
FramebufferLayout layout;
|
FramebufferLayout layout;
|
||||||
if (Settings::values.custom_layout == true) {
|
int width, height;
|
||||||
|
switch (Settings::values.layout_option) {
|
||||||
|
case Settings::LayoutOption::Custom:
|
||||||
layout = CustomFrameLayout(
|
layout = CustomFrameLayout(
|
||||||
std::max(Settings::values.custom_top_right, Settings::values.custom_bottom_right),
|
std::max(Settings::values.custom_top_right, Settings::values.custom_bottom_right),
|
||||||
std::max(Settings::values.custom_top_bottom, Settings::values.custom_bottom_bottom));
|
std::max(Settings::values.custom_top_bottom, Settings::values.custom_bottom_bottom));
|
||||||
} else {
|
break;
|
||||||
int width, height;
|
|
||||||
switch (Settings::values.layout_option) {
|
|
||||||
case Settings::LayoutOption::SingleScreen:
|
case Settings::LayoutOption::SingleScreen:
|
||||||
if (Settings::values.upright_screen) {
|
if (Settings::values.upright_screen) {
|
||||||
if (Settings::values.swap_screen) {
|
if (Settings::values.swap_screen) {
|
||||||
@ -359,7 +359,6 @@ FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale) {
|
|||||||
Settings::values.upright_screen);
|
Settings::values.upright_screen);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return layout;
|
return layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ enum class LayoutOption {
|
|||||||
SingleScreen,
|
SingleScreen,
|
||||||
LargeScreen,
|
LargeScreen,
|
||||||
SideScreen,
|
SideScreen,
|
||||||
|
Custom,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class MicInputType {
|
enum class MicInputType {
|
||||||
@ -163,7 +164,6 @@ struct Values {
|
|||||||
LayoutOption layout_option;
|
LayoutOption layout_option;
|
||||||
bool swap_screen;
|
bool swap_screen;
|
||||||
bool upright_screen;
|
bool upright_screen;
|
||||||
bool custom_layout;
|
|
||||||
u16 custom_top_left;
|
u16 custom_top_left;
|
||||||
u16 custom_top_top;
|
u16 custom_top_top;
|
||||||
u16 custom_top_right;
|
u16 custom_top_right;
|
||||||
|
Loading…
Reference in New Issue
Block a user