@@ -0,0 +1,292 @@
// Copyright 2020 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#include "DolphinQt/Config/Graphics/BalloonTip.h"

#include <memory>

#include <QBitmap>
#include <QGraphicsEffect>
#include <QGraphicsView>
#include <QGridLayout>
#include <QGuiApplication>
#include <QLabel>
#include <QPainter>
#include <QPainterPath>
#include <QPropertyAnimation>
#include <QPushButton>
#include <QStyle>

#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
#include <QScreen>
#else
#include <QApplication>
#include <QDesktopWidget>
#endif

#if defined(__APPLE__)
#include <QToolTip>
#endif

#include "Core/Config/MainSettings.h"

namespace
{
std::unique_ptr<BalloonTip> s_the_balloon_tip = nullptr;
} // namespace

void BalloonTip::ShowBalloon(const QIcon& icon, const QString& title, const QString& message,
const QPoint& pos, QWidget* parent, ShowArrow show_arrow)
{
HideBalloon();
if (message.isEmpty() && title.isEmpty())
return;

#if defined(__APPLE__)
QString the_message = message;
the_message.replace(QStringLiteral("<dolphin_emphasis>"), QStringLiteral("<b>"));
the_message.replace(QStringLiteral("</dolphin_emphasis>"), QStringLiteral("</b>"));
QToolTip::showText(pos, the_message, parent);
#else
s_the_balloon_tip = std::make_unique<BalloonTip>(PrivateTag{}, icon, title, message, parent);
s_the_balloon_tip->UpdateBoundsAndRedraw(pos, show_arrow);
#endif
}

void BalloonTip::HideBalloon()
{
#if defined(__APPLE__)
QToolTip::hideText();
#else
if (!s_the_balloon_tip)
return;
s_the_balloon_tip->hide();
s_the_balloon_tip.reset();
#endif
}

BalloonTip::BalloonTip(PrivateTag, const QIcon& icon, QString title, QString message,
QWidget* parent)
: QWidget(nullptr, Qt::ToolTip)
{
setAttribute(Qt::WA_DeleteOnClose);
setAutoFillBackground(true);

const QPalette& pal = parent->palette();

const auto theme_window_color = pal.color(QPalette::Base);
const auto theme_window_hsv = theme_window_color.toHsv();

const auto brightness = theme_window_hsv.value();

QColor window_color;
QColor text_color;
QColor dolphin_emphasis;
const bool use_high_contrast = Config::Get(Config::MAIN_USE_HIGH_CONTRAST_TOOLTIPS);
if (brightness > 128)
{
if (use_high_contrast)
{
// Our theme color is light, so make it darker
window_color = QColor(72, 72, 72);
text_color = Qt::white;
dolphin_emphasis = Qt::yellow;
m_border_color = palette().color(QPalette::Window).darker(160);
}
else
{
window_color = pal.color(QPalette::Window);
text_color = pal.color(QPalette::Text);
dolphin_emphasis = QColor(QStringLiteral("#0090ff"));
m_border_color = pal.color(QPalette::Text);
}
}
else
{
if (use_high_contrast)
{
// Our theme color is dark, so make it lighter
window_color = Qt::white;
text_color = Qt::black;
dolphin_emphasis = QColor(QStringLiteral("#0090ff"));
m_border_color = palette().color(QPalette::Window).darker(160);
}
else
{
window_color = pal.color(QPalette::Window);
text_color = pal.color(QPalette::Text);
dolphin_emphasis = Qt::yellow;
m_border_color = pal.color(QPalette::Text);
}
}

const auto style_sheet = QStringLiteral("background-color: #%1; color: #%2;")
.arg(window_color.rgba(), 0, 16)
.arg(text_color.rgba(), 0, 16);
setStyleSheet(style_sheet);

// Replace text in our our message
// if specific "tags" are used
message.replace(QStringLiteral("<dolphin_emphasis>"),
QStringLiteral("<font color=\"#%1\"><b>").arg(dolphin_emphasis.rgba(), 0, 16));
message.replace(QStringLiteral("</dolphin_emphasis>"), QStringLiteral("</b></font>"));

auto* title_label = new QLabel;
title_label->installEventFilter(this);
title_label->setText(title);
QFont f = title_label->font();
f.setBold(true);
title_label->setFont(f);
title_label->setTextFormat(Qt::RichText);
title_label->setSizePolicy(QSizePolicy::Policy::MinimumExpanding,
QSizePolicy::Policy::MinimumExpanding);

auto* message_label = new QLabel;
message_label->installEventFilter(this);
message_label->setText(message);
message_label->setTextFormat(Qt::RichText);
message_label->setAlignment(Qt::AlignTop | Qt::AlignLeft);

#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
const int limit = QApplication::desktop()->availableGeometry(message_label).width() / 3;
#else
const int limit = message_label->screen()->availableGeometry().width() / 3;
#endif
message_label->setMaximumWidth(limit);
message_label->setSizePolicy(QSizePolicy::Policy::MinimumExpanding,
QSizePolicy::Policy::MinimumExpanding);
if (message_label->sizeHint().width() > limit)
{
message_label->setWordWrap(true);
}

auto* layout = new QGridLayout;
layout->addWidget(title_label, 0, 0, 1, 2);

layout->addWidget(message_label, 1, 0, 1, 3);
layout->setSizeConstraint(QLayout::SetMinimumSize);
setLayout(layout);
}

void BalloonTip::paintEvent(QPaintEvent*)
{
QPainter painter(this);
painter.drawPixmap(rect(), m_pixmap);
}

void BalloonTip::UpdateBoundsAndRedraw(const QPoint& pos, ShowArrow show_arrow)
{
m_show_arrow = show_arrow == ShowArrow::Yes;

#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
const QRect screen_rect = QApplication::desktop()->screenGeometry(pos);
#else
QScreen* screen = QGuiApplication::screenAt(pos);
if (!screen)
screen = QGuiApplication::primaryScreen();
const QRect screen_rect = screen->geometry();
#endif
QSize sh = sizeHint();
const int border = 1;
const int arrow_height = 18;
const int arrow_width = 18;
const int arrow_offset = 52;
const int rect_center = 7;
const bool arrow_at_bottom = (pos.y() - sh.height() - arrow_height > 0);
const bool arrow_at_left = (pos.x() + sh.width() - arrow_width < screen_rect.width());
const int default_padding = 10;
layout()->setContentsMargins(border + 3 + default_padding,
border + (arrow_at_bottom ? 0 : arrow_height) + 2 + default_padding,
border + 3 + default_padding,
border + (arrow_at_bottom ? arrow_height : 0) + 2 + default_padding);
updateGeometry();
sh = sizeHint();

int ml, mr, mt, mb;
QSize sz = sizeHint();
if (arrow_at_bottom)
{
ml = mt = 0;
mr = sz.width() - 1;
mb = sz.height() - arrow_height - 1;
}
else
{
ml = 0;
mt = arrow_height;
mr = sz.width() - 1;
mb = sz.height() - 1;
}

QPainterPath path;
path.moveTo(ml + rect_center, mt);
if (!arrow_at_bottom && arrow_at_left)
{
if (m_show_arrow)
{
path.lineTo(ml + arrow_offset - arrow_width, mt);
path.lineTo(ml + arrow_offset, mt - arrow_height);
path.lineTo(ml + arrow_offset + arrow_width, mt);
}
move(qMax(pos.x() - arrow_offset, screen_rect.left() + 2), pos.y());
}
else if (!arrow_at_bottom && !arrow_at_left)
{
if (m_show_arrow)
{
path.lineTo(mr - arrow_offset - arrow_width, mt);
path.lineTo(mr - arrow_offset, mt - arrow_height);
path.lineTo(mr - arrow_offset + arrow_width, mt);
}
move(qMin(pos.x() - sh.width() + arrow_offset, screen_rect.right() - sh.width() - 2), pos.y());
}
path.lineTo(mr - rect_center, mt);
path.arcTo(QRect(mr - rect_center * 2, mt, rect_center * 2, rect_center * 2), 90, -90);
path.lineTo(mr, mb - rect_center);
path.arcTo(QRect(mr - rect_center * 2, mb - rect_center * 2, rect_center * 2, rect_center * 2), 0,
-90);
if (arrow_at_bottom && !arrow_at_left)
{
if (m_show_arrow)
{
path.lineTo(mr - arrow_offset + arrow_width, mb);
path.lineTo(mr - arrow_offset, mb + arrow_height);
path.lineTo(mr - arrow_offset - arrow_width, mb);
}
move(qMin(pos.x() - sh.width() + arrow_offset, screen_rect.right() - sh.width() - 2),
pos.y() - sh.height());
}
else if (arrow_at_bottom && arrow_at_left)
{
if (m_show_arrow)
{
path.lineTo(arrow_offset + arrow_width, mb);
path.lineTo(arrow_offset, mb + arrow_height);
path.lineTo(arrow_offset - arrow_width, mb);
}
move(qMax(pos.x() - arrow_offset, screen_rect.x() + 2), pos.y() - sh.height());
}
path.lineTo(ml + rect_center, mb);
path.arcTo(QRect(ml, mb - rect_center * 2, rect_center * 2, rect_center * 2), -90, -90);
path.lineTo(ml, mt + rect_center);
path.arcTo(QRect(ml, mt, rect_center * 2, rect_center * 2), 180, -90);

// Set the mask
QBitmap bitmap(sizeHint());
bitmap.fill(Qt::color0);
QPainter painter1(&bitmap);
painter1.setPen(QPen(Qt::color1, border));
painter1.setBrush(QBrush(Qt::color1));
painter1.drawPath(path);
setMask(bitmap);

// Draw the border
m_pixmap = QPixmap(sz);
QPainter painter2(&m_pixmap);
painter2.setPen(QPen(m_border_color));
painter2.setBrush(palette().color(QPalette::Window));
painter2.drawPath(path);

show();
}
@@ -0,0 +1,42 @@
// Copyright 2020 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#pragma once

#include <QIcon>
#include <QPixmap>
#include <QWidget>

class BalloonTip : public QWidget
{
Q_OBJECT

struct PrivateTag
{
};

public:
enum class ShowArrow
{
Yes,
No
};
static void ShowBalloon(const QIcon& icon, const QString& title, const QString& msg,
const QPoint& pos, QWidget* parent,
ShowArrow show_arrow = ShowArrow::Yes);
static void HideBalloon();

BalloonTip(PrivateTag, const QIcon& icon, QString title, QString msg, QWidget* parent);

private:
void UpdateBoundsAndRedraw(const QPoint&, ShowArrow);

protected:
void paintEvent(QPaintEvent*) override;

private:
QColor m_border_color;
QPixmap m_pixmap;
bool m_show_arrow = true;
};
@@ -30,8 +30,7 @@
#include "VideoCommon/VideoCommon.h"
#include "VideoCommon/VideoConfig.h"

EnhancementsWidget::EnhancementsWidget(GraphicsWindow* parent)
: GraphicsWidget(parent), m_block_save(false)
EnhancementsWidget::EnhancementsWidget(GraphicsWindow* parent) : m_block_save(false)
{
CreateWidgets();
LoadSettings();
@@ -74,11 +73,11 @@ void EnhancementsWidget::CreateWidgets()
m_ir_combo = new GraphicsChoice(resolution_options, Config::GFX_EFB_SCALE);
m_ir_combo->setMaxVisibleItems(visible_resolution_option_count);

m_aa_combo = new QComboBox();
m_aa_combo = new ToolTipComboBox();
m_af_combo = new GraphicsChoice({tr("1x"), tr("2x"), tr("4x"), tr("8x"), tr("16x")},
Config::GFX_ENHANCE_MAX_ANISOTROPY);

m_pp_effect = new QComboBox();
m_pp_effect = new ToolTipComboBox();
m_configure_pp_effect = new QPushButton(tr("Configure"));
m_scaled_efb_copy = new GraphicsBool(tr("Scaled EFB Copy"), Config::GFX_HACK_COPY_EFB_SCALED);
m_per_pixel_lighting =
@@ -290,97 +289,130 @@ void EnhancementsWidget::SaveSettings()
void EnhancementsWidget::AddDescriptions()
{
static const char TR_INTERNAL_RESOLUTION_DESCRIPTION[] =
QT_TR_NOOP("Controls the rendering resolution.\n\nA high resolution greatly improves "
QT_TR_NOOP("Controls the rendering resolution.<br><br>A high resolution greatly improves "
"visual quality, but also greatly increases GPU load and can cause issues in "
"certain games. Generally speaking, the lower the internal resolution, the "
"better performance will be.\n\nIf unsure, select Native.");

"better performance will be.<br><br><dolphin_emphasis>If unsure, "
"select Native.</dolphin_emphasis>");
static const char TR_ANTIALIAS_DESCRIPTION[] = QT_TR_NOOP(
"Reduces the amount of aliasing caused by rasterizing 3D graphics, resulting "
"in smoother edges on objects. Increases GPU load and sometimes causes graphical "
"issues.\n\nSSAA is significantly more demanding than MSAA, but provides top quality "
"issues.<br><br>SSAA is significantly more demanding than MSAA, but provides top quality "
"geometry anti-aliasing and also applies anti-aliasing to lighting, shader "
"effects, and textures.\n\nIf unsure, select None.");

"effects, and textures.<br><br><dolphin_emphasis>If unsure, select "
"None.</dolphin_emphasis>");
static const char TR_ANISOTROPIC_FILTERING_DESCRIPTION[] = QT_TR_NOOP(
"Enables anisotropic filtering, which enhances the visual quality of textures that "
"are at oblique viewing angles.\n\nMight cause issues in a small "
"number of games.\n\nIf unsure, select 1x.");

static const char TR_POSTPROCESSING_DESCRIPTION[] = QT_TR_NOOP(
"Applies a post-processing effect after rendering a frame.\n\nIf unsure, select (off).");

"are at oblique viewing angles.<br><br>Might cause issues in a small "
"number of games.<br><br><dolphin_emphasis>If unsure, select 1x.</dolphin_emphasis>");
static const char TR_POSTPROCESSING_DESCRIPTION[] =
QT_TR_NOOP("Applies a post-processing effect after rendering a frame.<br><br "
"/><dolphin_emphasis>If unsure, select (off).</dolphin_emphasis>");
static const char TR_SCALED_EFB_COPY_DESCRIPTION[] =
QT_TR_NOOP("Greatly increases the quality of textures generated using render-to-texture "
"effects.\n\nSlightly increases GPU load and causes relatively few graphical "
"effects.<br><br>Slightly increases GPU load and causes relatively few graphical "
"issues. Raising the internal resolution will improve the effect of this setting. "
"\n\nIf unsure, leave this checked.");
"<br><br><dolphin_emphasis>If unsure, leave this checked.</dolphin_emphasis>");
static const char TR_PER_PIXEL_LIGHTING_DESCRIPTION[] = QT_TR_NOOP(
"Calculates lighting of 3D objects per-pixel rather than per-vertex, smoothing out the "
"appearance of lit polygons and making individual triangles less noticeable.\n\nRarely "
"causes slowdowns or graphical issues.\n\nIf unsure, leave this unchecked.");
"appearance of lit polygons and making individual triangles less noticeable.<br><br "
"/>Rarely "
"causes slowdowns or graphical issues.<br><br><dolphin_emphasis>If unsure, leave "
"this unchecked.</dolphin_emphasis>");
static const char TR_WIDESCREEN_HACK_DESCRIPTION[] = QT_TR_NOOP(
"Forces the game to output graphics for any aspect ratio. Use with \"Aspect Ratio\" set to "
"\"Force 16:9\" to force 4:3-only games to run at 16:9.\n\nRarely produces good results and "
"\"Force 16:9\" to force 4:3-only games to run at 16:9.<br><br>Rarely produces good "
"results and "
"often partially breaks graphics and game UIs. Unnecessary (and detrimental) if using any "
"AR/Gecko-code widescreen patches.\n\nIf unsure, leave this unchecked.");
"AR/Gecko-code widescreen patches.<br><br><dolphin_emphasis>If unsure, leave "
"this unchecked.</dolphin_emphasis>");
static const char TR_REMOVE_FOG_DESCRIPTION[] =
QT_TR_NOOP("Makes distant objects more visible by removing fog, thus increasing the overall "
"detail.\n\nDisabling fog will break some games which rely on proper fog "
"emulation.\n\nIf unsure, leave this unchecked.");
"detail.<br><br>Disabling fog will break some games which rely on proper fog "
"emulation.<br><br><dolphin_emphasis>If unsure, leave this "
"unchecked.</dolphin_emphasis>");
static const char TR_3D_MODE_DESCRIPTION[] = QT_TR_NOOP(
"Selects the stereoscopic 3D mode. Stereoscopy allows a better feeling "
"of depth if the necessary hardware is present. Heavily decreases "
"emulation speed and sometimes causes issues.\n\nSide-by-Side and Top-and-Bottom are "
"used by most 3D TVs.\nAnaglyph is used for Red-Cyan colored glasses.\nHDMI 3D is "
"used when the monitor supports 3D display resolutions.\nPassive is another type of 3D "
"used by some TVs.\n\nIf unsure, select Off.");
"emulation speed and sometimes causes issues.<br><br>Side-by-Side and Top-and-Bottom are "
"used by most 3D TVs.<br>Anaglyph is used for Red-Cyan colored glasses.<br>HDMI 3D is "
"used when the monitor supports 3D display resolutions.<br>Passive is another type of 3D "
"used by some TVs.<br><br><dolphin_emphasis>If unsure, select Off.</dolphin_emphasis>");
static const char TR_3D_DEPTH_DESCRIPTION[] = QT_TR_NOOP(
"Controls the separation distance between the virtual cameras. \n\nA higher "
"Controls the separation distance between the virtual cameras.<br><br>A higher "
"value creates a stronger feeling of depth while a lower value is more comfortable.");
static const char TR_3D_CONVERGENCE_DESCRIPTION[] = QT_TR_NOOP(
"Controls the distance of the convergence plane. This is the distance at which "
"virtual objects will appear to be in front of the screen.\n\nA higher value creates "
"virtual objects will appear to be in front of the screen.<br><br>A higher value creates "
"stronger out-of-screen effects while a lower value is more comfortable.");
static const char TR_3D_SWAP_EYES_DESCRIPTION[] =
QT_TR_NOOP("Swaps the left and right eye. Most useful in side-by-side stereoscopy "
"mode.\n\nIf unsure, leave this unchecked.");
static const char TR_FORCE_24BIT_DESCRIPTION[] =
QT_TR_NOOP("Forces the game to render the RGB color channels in 24-bit, thereby increasing "
"quality by reducing color banding.\n\nHas no impact on performance and causes "
"few graphical issues.\n\nIf unsure, leave this checked.");
static const char TR_3D_SWAP_EYES_DESCRIPTION[] = QT_TR_NOOP(
"Swaps the left and right eye. Most useful in side-by-side stereoscopy "
"mode.<br><br><dolphin_emphasis>If unsure, leave this unchecked.</dolphin_emphasis>");
static const char TR_FORCE_24BIT_DESCRIPTION[] = QT_TR_NOOP(
"Forces the game to render the RGB color channels in 24-bit, thereby increasing "
"quality by reducing color banding.<br><br>Has no impact on performance and causes "
"few graphical issues.<br><br><dolphin_emphasis>If unsure, leave this "
"checked.</dolphin_emphasis>");
static const char TR_FORCE_TEXTURE_FILTERING_DESCRIPTION[] =
QT_TR_NOOP("Filters all textures, including any that the game explicitly set as "
"unfiltered.\n\nMay improve quality of certain textures in some games, but "
"will cause issues in others.\n\nIf unsure, leave this unchecked.");
static const char TR_DISABLE_COPY_FILTER_DESCRIPTION[] =
QT_TR_NOOP("Disables the blending of adjacent rows when copying the EFB. This is known in "
"some games as \"deflickering\" or \"smoothing\". \n\nDisabling the filter has no "
"effect on performance, but may result in a sharper image. Causes few "
"graphical issues.\n\nIf unsure, leave this checked.");
"unfiltered.<br><br>May improve quality of certain textures in some games, but "
"will cause issues in others.<br><br><dolphin_emphasis>If unsure, leave this "
"unchecked.</dolphin_emphasis>");
static const char TR_DISABLE_COPY_FILTER_DESCRIPTION[] = QT_TR_NOOP(
"Disables the blending of adjacent rows when copying the EFB. This is known in "
"some games as \"deflickering\" or \"smoothing\".<br><br>Disabling the filter has no "
"effect on performance, but may result in a sharper image. Causes few "
"graphical issues.<br><br><dolphin_emphasis>If unsure, leave this "
"checked.</dolphin_emphasis>");
static const char TR_ARBITRARY_MIPMAP_DETECTION_DESCRIPTION[] = QT_TR_NOOP(
"Enables detection of arbitrary mipmaps, which some games use for special distance-based "
"effects.\n\nMay have false positives that result in blurry textures at increased internal "
"effects.<br><br>May have false positives that result in blurry textures at increased "
"internal "
"resolution, such as in games that use very low resolution mipmaps. Disabling this can also "
"reduce stutter in games that frequently load new textures. This feature is not compatible "
"with GPU Texture Decoding.\n\nIf unsure, leave this checked.");

AddDescription(m_ir_combo, TR_INTERNAL_RESOLUTION_DESCRIPTION);
AddDescription(m_aa_combo, TR_ANTIALIAS_DESCRIPTION);
AddDescription(m_af_combo, TR_ANISOTROPIC_FILTERING_DESCRIPTION);
AddDescription(m_pp_effect, TR_POSTPROCESSING_DESCRIPTION);
AddDescription(m_scaled_efb_copy, TR_SCALED_EFB_COPY_DESCRIPTION);
AddDescription(m_per_pixel_lighting, TR_PER_PIXEL_LIGHTING_DESCRIPTION);
AddDescription(m_widescreen_hack, TR_WIDESCREEN_HACK_DESCRIPTION);
AddDescription(m_disable_fog, TR_REMOVE_FOG_DESCRIPTION);
AddDescription(m_force_24bit_color, TR_FORCE_24BIT_DESCRIPTION);
AddDescription(m_force_texture_filtering, TR_FORCE_TEXTURE_FILTERING_DESCRIPTION);
AddDescription(m_disable_copy_filter, TR_DISABLE_COPY_FILTER_DESCRIPTION);
AddDescription(m_arbitrary_mipmap_detection, TR_ARBITRARY_MIPMAP_DETECTION_DESCRIPTION);
AddDescription(m_3d_mode, TR_3D_MODE_DESCRIPTION);
AddDescription(m_3d_depth, TR_3D_DEPTH_DESCRIPTION);
AddDescription(m_3d_convergence, TR_3D_CONVERGENCE_DESCRIPTION);
AddDescription(m_3d_swap_eyes, TR_3D_SWAP_EYES_DESCRIPTION);
"with GPU Texture Decoding.<br><br><dolphin_emphasis>If unsure, leave this "
"checked.</dolphin_emphasis>");

m_ir_combo->SetTitle(tr("Internal Resolution"));
m_ir_combo->SetDescription(QString::fromStdString(TR_INTERNAL_RESOLUTION_DESCRIPTION));

m_aa_combo->SetTitle(tr("Anti-Aliasing"));
m_aa_combo->SetDescription(QString::fromStdString(TR_ANTIALIAS_DESCRIPTION));

m_af_combo->SetTitle(tr("Anisotropic Filtering"));
m_af_combo->SetDescription(QString::fromStdString(TR_ANISOTROPIC_FILTERING_DESCRIPTION));

m_pp_effect->SetTitle(tr("Post-Processing Effect"));
m_pp_effect->SetDescription(QString::fromStdString(TR_POSTPROCESSING_DESCRIPTION));

m_scaled_efb_copy->SetDescription(QString::fromStdString(TR_SCALED_EFB_COPY_DESCRIPTION));

m_per_pixel_lighting->SetDescription(QString::fromStdString(TR_PER_PIXEL_LIGHTING_DESCRIPTION));

m_widescreen_hack->SetDescription(QString::fromStdString(TR_WIDESCREEN_HACK_DESCRIPTION));

m_disable_fog->SetDescription(QString::fromStdString(TR_REMOVE_FOG_DESCRIPTION));

m_force_24bit_color->SetDescription(QString::fromStdString(TR_FORCE_24BIT_DESCRIPTION));

m_force_texture_filtering->SetDescription(
QString::fromStdString(TR_FORCE_TEXTURE_FILTERING_DESCRIPTION));

m_disable_copy_filter->SetDescription(QString::fromStdString(TR_DISABLE_COPY_FILTER_DESCRIPTION));

m_arbitrary_mipmap_detection->SetDescription(
QString::fromStdString(TR_ARBITRARY_MIPMAP_DETECTION_DESCRIPTION));

m_3d_mode->SetTitle(tr("Stereoscopic 3D Mode"));
m_3d_mode->SetDescription(QString::fromStdString(TR_3D_MODE_DESCRIPTION));

m_3d_depth->SetTitle(tr("Depth"));
m_3d_depth->SetDescription(QString::fromStdString(TR_3D_DEPTH_DESCRIPTION));

m_3d_convergence->SetTitle(tr("Convergence"));
m_3d_convergence->SetDescription(QString::fromStdString(TR_3D_CONVERGENCE_DESCRIPTION));

m_3d_swap_eyes->SetDescription(QString::fromStdString(TR_3D_SWAP_EYES_DESCRIPTION));
}

void EnhancementsWidget::ConfigurePostProcessingShader()
@@ -6,11 +6,15 @@

#include "DolphinQt/Config/Graphics/GraphicsWidget.h"

class GraphicsBool;
class GraphicsChoice;
class GraphicsSlider;
class GraphicsWindow;
class QCheckBox;
class QComboBox;
class QPushButton;
class QSlider;
class ToolTipComboBox;

class EnhancementsWidget final : public GraphicsWidget
{
@@ -29,25 +33,25 @@ class EnhancementsWidget final : public GraphicsWidget
void LoadPPShaders();

// Enhancements
QComboBox* m_ir_combo;
QComboBox* m_aa_combo;
QComboBox* m_af_combo;
QComboBox* m_pp_effect;
GraphicsChoice* m_ir_combo;
ToolTipComboBox* m_aa_combo;
GraphicsChoice* m_af_combo;
ToolTipComboBox* m_pp_effect;
QPushButton* m_configure_pp_effect;
QCheckBox* m_scaled_efb_copy;
QCheckBox* m_per_pixel_lighting;
QCheckBox* m_force_texture_filtering;
QCheckBox* m_widescreen_hack;
QCheckBox* m_disable_fog;
QCheckBox* m_force_24bit_color;
QCheckBox* m_disable_copy_filter;
QCheckBox* m_arbitrary_mipmap_detection;
GraphicsBool* m_scaled_efb_copy;
GraphicsBool* m_per_pixel_lighting;
GraphicsBool* m_force_texture_filtering;
GraphicsBool* m_widescreen_hack;
GraphicsBool* m_disable_fog;
GraphicsBool* m_force_24bit_color;
GraphicsBool* m_disable_copy_filter;
GraphicsBool* m_arbitrary_mipmap_detection;

// Stereoscopy
QComboBox* m_3d_mode;
QSlider* m_3d_depth;
QSlider* m_3d_convergence;
QCheckBox* m_3d_swap_eyes;
GraphicsChoice* m_3d_mode;
GraphicsSlider* m_3d_depth;
GraphicsSlider* m_3d_convergence;
GraphicsBool* m_3d_swap_eyes;

int m_msaa_modes;
bool m_block_save;
@@ -23,6 +23,7 @@
#include "DolphinQt/Config/Graphics/GraphicsChoice.h"
#include "DolphinQt/Config/Graphics/GraphicsRadio.h"
#include "DolphinQt/Config/Graphics/GraphicsWindow.h"
#include "DolphinQt/Config/ToolTipControls/ToolTipComboBox.h"
#include "DolphinQt/QtUtils/ModalMessageBox.h"
#include "DolphinQt/Settings.h"

@@ -32,7 +33,7 @@
#include "VideoCommon/VideoConfig.h"

GeneralWidget::GeneralWidget(X11Utils::XRRConfiguration* xrr_config, GraphicsWindow* parent)
: GraphicsWidget(parent), m_xrr_config(xrr_config)
: m_xrr_config(xrr_config)
{
CreateWidgets();
LoadSettings();
@@ -54,11 +55,11 @@ void GeneralWidget::CreateWidgets()
auto* m_video_box = new QGroupBox(tr("Basic"));
m_video_layout = new QGridLayout();

m_backend_combo = new QComboBox();
m_backend_combo = new ToolTipComboBox();
m_aspect_combo =
new GraphicsChoice({tr("Auto"), tr("Force 16:9"), tr("Force 4:3"), tr("Stretch to Window")},
Config::GFX_ASPECT_RATIO);
m_adapter_combo = new QComboBox;
m_adapter_combo = new ToolTipComboBox;
m_enable_vsync = new GraphicsBool(tr("V-Sync"), Config::GFX_VSYNC);
m_enable_fullscreen = new GraphicsBool(tr("Use Fullscreen"), Config::MAIN_FULLSCREEN);

@@ -197,89 +198,122 @@ void GeneralWidget::AddDescriptions()
// We need QObject::tr
#if defined(_WIN32)
static const char TR_BACKEND_DESCRIPTION[] = QT_TR_NOOP(
"Selects which graphics API to use internally.\n\nThe software renderer is extremely "
"Selects which graphics API to use internally.<br><br>The software renderer is extremely "
"slow and only useful for debugging, so either OpenGL, Direct3D, or Vulkan are "
"recommended. Different games and different GPUs will behave differently on each "
"backend, so for the best emulation experience it is recommended to try each and "
"select the backend that is least problematic.\n\nIf unsure, select OpenGL.");
"select the backend that is least problematic.<br><br><dolphin_emphasis>If unsure, "
"select OpenGL.</dolphin_emphasis>");
#else
static const char TR_BACKEND_DESCRIPTION[] = QT_TR_NOOP(
"Selects which graphics API to use internally.\n\nThe software renderer is extremely "
"Selects which graphics API to use internally.<br><br>The software renderer is extremely "
"slow and only useful for debugging, so any of the other backends are "
"recommended.\n\nIf unsure, select OpenGL.");
"recommended.<br><br><dolphin_emphasis>If unsure, select OpenGL.</dolphin_emphasis>");
#endif
static const char TR_ADAPTER_DESCRIPTION[] =
QT_TR_NOOP("Selects a hardware adapter to use.\n\nIf unsure, select the first one.");
QT_TR_NOOP("Selects a hardware adapter to use.<br><br><dolphin_emphasis>If unsure, "
"select the first one.</dolphin_emphasis>");
static const char TR_FULLSCREEN_DESCRIPTION[] =
QT_TR_NOOP("Uses the entire screen for rendering.\n\nIf disabled, a "
"render window will be created instead.\n\nIf unsure, leave this unchecked.");
QT_TR_NOOP("Uses the entire screen for rendering.<br><br>If disabled, a "
"render window will be created instead.<br><br><dolphin_emphasis>If "
"unsure, leave this unchecked.</dolphin_emphasis>");
static const char TR_AUTOSIZE_DESCRIPTION[] =
QT_TR_NOOP("Automatically adjusts the window size to the internal resolution.\n\nIf unsure, "
"leave this unchecked.");

QT_TR_NOOP("Automatically adjusts the window size to the internal resolution.<br><br>"
"<dolphin_emphasis>If unsure, leave this unchecked.</dolphin_emphasis>");
static const char TR_RENDER_TO_MAINWINDOW_DESCRIPTION[] =
QT_TR_NOOP("Uses the main Dolphin window for rendering rather than "
"a separate render window.\n\nIf unsure, leave this unchecked.");
"a separate render window.<br><br><dolphin_emphasis>If unsure, leave "
"this unchecked.</dolphin_emphasis>");
static const char TR_ASPECT_RATIO_DESCRIPTION[] = QT_TR_NOOP(
"Selects which aspect ratio to use when rendering.\n\nAuto: Uses the native aspect "
"ratio\nForce 16:9: Mimics an analog TV with a widescreen aspect ratio.\nForce 4:3: "
"Mimics a standard 4:3 analog TV.\nStretch to Window: Stretches the picture to the "
"window size.\n\nIf unsure, select Auto.");
static const char TR_VSYNC_DESCRIPTION[] =
QT_TR_NOOP("Waits for vertical blanks in order to prevent tearing.\n\nDecreases performance "
"if emulation speed is below 100%.\n\nIf unsure, leave this unchecked.");
"Selects which aspect ratio to use when rendering.<br><br>Auto: Uses the native aspect "
"ratio<br>Force 16:9: Mimics an analog TV with a widescreen aspect ratio.<br>Force 4:3: "
"Mimics a standard 4:3 analog TV.<br>Stretch to Window: Stretches the picture to the "
"window size.<br><br><dolphin_emphasis>If unsure, select Auto.</dolphin_emphasis>");
static const char TR_VSYNC_DESCRIPTION[] = QT_TR_NOOP(
"Waits for vertical blanks in order to prevent tearing.<br><br>Decreases performance "
"if emulation speed is below 100%.<br><br><dolphin_emphasis>If unsure, leave "
"this "
"unchecked.</dolphin_emphasis>");
static const char TR_SHOW_FPS_DESCRIPTION[] =
QT_TR_NOOP("Shows the number of frames rendered per second as a measure of "
"emulation speed.\n\nIf unsure, leave this unchecked.");
static const char TR_SHOW_NETPLAY_PING_DESCRIPTION[] =
QT_TR_NOOP("Shows the player's maximum ping while playing on "
"NetPlay.\n\nIf unsure, leave this unchecked.");
static const char TR_LOG_RENDERTIME_DESCRIPTION[] =
QT_TR_NOOP("Logs the render time of every frame to User/Logs/render_time.txt.\n\nUse this "
"feature when to measure the performance of Dolphin.\n\nIf "
"unsure, leave this unchecked.");
"emulation speed.<br><br><dolphin_emphasis>If unsure, leave this "
"unchecked.</dolphin_emphasis>");
static const char TR_SHOW_NETPLAY_PING_DESCRIPTION[] = QT_TR_NOOP(
"Shows the player's maximum ping while playing on "
"NetPlay.<br><br><dolphin_emphasis>If unsure, leave this unchecked.</dolphin_emphasis>");
static const char TR_LOG_RENDERTIME_DESCRIPTION[] = QT_TR_NOOP(
"Logs the render time of every frame to User/Logs/render_time.txt.<br><br>Use this "
"feature when to measure the performance of Dolphin.<br><br><dolphin_emphasis>If "
"unsure, leave this unchecked.</dolphin_emphasis>");
static const char TR_SHOW_NETPLAY_MESSAGES_DESCRIPTION[] =
QT_TR_NOOP("Shows chat messages, buffer changes, and desync alerts "
"while playing NetPlay.\n\nIf unsure, leave this unchecked.");
"while playing NetPlay.<br><br><dolphin_emphasis>If unsure, leave "
"this unchecked.</dolphin_emphasis>");
static const char TR_SHADER_COMPILE_SYNC_DESCRIPTION[] =
QT_TR_NOOP("Ubershaders are never used. Stuttering will occur during shader "
"compilation, but GPU demands are low.\n\nRecommended for low-end hardware. "
"\n\nIf unsure, select this mode.");
"compilation, but GPU demands are low.<br><br>Recommended for low-end hardware. "
"<br><br><dolphin_emphasis>If unsure, select this mode.</dolphin_emphasis>");
static const char TR_SHADER_COMPILE_SYNC_UBER_DESCRIPTION[] = QT_TR_NOOP(
"Ubershaders will always be used. Provides a near stutter-free experience at the cost of "
"high GPU performance requirements.\n\nOnly recommended for high-end systems.");
static const char TR_SHADER_COMPILE_ASYNC_UBER_DESCRIPTION[] =
QT_TR_NOOP("Ubershaders will be used to prevent stuttering during shader compilation, but "
"specialized shaders will be used when they will not cause stuttering.\n\nIn the "
"best case it eliminates shader compilation stuttering while having minimal "
"performance impact, but results depend on video driver behavior.");
"high GPU performance requirements.<br><br><dolphin_emphasis>Only recommended "
"for high-end systems.</dolphin_emphasis>");
static const char TR_SHADER_COMPILE_ASYNC_UBER_DESCRIPTION[] = QT_TR_NOOP(
"Ubershaders will be used to prevent stuttering during shader compilation, but "
"specialized shaders will be used when they will not cause stuttering.<br><br>In the "
"best case it eliminates shader compilation stuttering while having minimal "
"performance impact, but results depend on video driver behavior.");
static const char TR_SHADER_COMPILE_ASYNC_SKIP_DESCRIPTION[] = QT_TR_NOOP(
"Prevents shader compilation stuttering by not rendering waiting objects. Can work in "
"scenarios where Ubershaders doesn't, at the cost of introducing visual glitches and broken "
"effects.\n\nNot recommended, only use if the other options give poor results.");
"effects.<br><br><dolphin_emphasis>Not recommended, only use if the other "
"options give poor results.</dolphin_emphasis>");
static const char TR_SHADER_COMPILE_BEFORE_START_DESCRIPTION[] =
QT_TR_NOOP("Waits for all shaders to finish compiling before starting a game. Enabling this "
"option may reduce stuttering or hitching for a short time after the game is "
"started, at the cost of a longer delay before the game starts. For systems with "
"two or fewer cores, it is recommended to enable this option, as a large shader "
"queue may reduce frame rates.\n\nOtherwise, if unsure, leave this unchecked.");

AddDescription(m_backend_combo, TR_BACKEND_DESCRIPTION);
AddDescription(m_adapter_combo, TR_ADAPTER_DESCRIPTION);
AddDescription(m_aspect_combo, TR_ASPECT_RATIO_DESCRIPTION);
AddDescription(m_enable_vsync, TR_VSYNC_DESCRIPTION);
AddDescription(m_enable_fullscreen, TR_FULLSCREEN_DESCRIPTION);
AddDescription(m_show_fps, TR_SHOW_FPS_DESCRIPTION);
AddDescription(m_show_ping, TR_SHOW_NETPLAY_PING_DESCRIPTION);
AddDescription(m_log_render_time, TR_LOG_RENDERTIME_DESCRIPTION);
AddDescription(m_autoadjust_window_size, TR_AUTOSIZE_DESCRIPTION);
AddDescription(m_show_messages, TR_SHOW_NETPLAY_MESSAGES_DESCRIPTION);
AddDescription(m_render_main_window, TR_RENDER_TO_MAINWINDOW_DESCRIPTION);
AddDescription(m_shader_compilation_mode[0], TR_SHADER_COMPILE_SYNC_DESCRIPTION);
AddDescription(m_shader_compilation_mode[1], TR_SHADER_COMPILE_SYNC_UBER_DESCRIPTION);
AddDescription(m_shader_compilation_mode[2], TR_SHADER_COMPILE_ASYNC_UBER_DESCRIPTION);
AddDescription(m_shader_compilation_mode[3], TR_SHADER_COMPILE_ASYNC_SKIP_DESCRIPTION);
AddDescription(m_wait_for_shaders, TR_SHADER_COMPILE_BEFORE_START_DESCRIPTION);
"queue may reduce frame rates.<br><br><dolphin_emphasis>Otherwise, if "
"unsure, leave this unchecked.</dolphin_emphasis>");

m_backend_combo->SetTitle(tr("Backend"));
m_backend_combo->SetDescription(QString::fromStdString(TR_BACKEND_DESCRIPTION));

m_adapter_combo->SetTitle(tr("Adapter"));
m_adapter_combo->SetDescription(QString::fromStdString(TR_ADAPTER_DESCRIPTION));

m_aspect_combo->SetTitle(tr("Aspect Ratio"));
m_aspect_combo->SetDescription(QString::fromStdString(TR_ASPECT_RATIO_DESCRIPTION));

m_enable_vsync->SetDescription(QString::fromStdString(TR_VSYNC_DESCRIPTION));

m_enable_fullscreen->SetDescription(QString::fromStdString(TR_FULLSCREEN_DESCRIPTION));

m_show_fps->SetDescription(QString::fromStdString(TR_SHOW_FPS_DESCRIPTION));

m_show_ping->SetDescription(QString::fromStdString(TR_SHOW_NETPLAY_PING_DESCRIPTION));

m_log_render_time->SetDescription(QString::fromStdString(TR_LOG_RENDERTIME_DESCRIPTION));

m_autoadjust_window_size->SetDescription(QString::fromStdString(TR_AUTOSIZE_DESCRIPTION));

m_show_messages->SetDescription(QString::fromStdString(TR_SHOW_NETPLAY_MESSAGES_DESCRIPTION));

m_render_main_window->SetDescription(QString::fromStdString(TR_RENDER_TO_MAINWINDOW_DESCRIPTION));

m_shader_compilation_mode[0]->SetDescription(
QString::fromStdString(TR_SHADER_COMPILE_SYNC_DESCRIPTION));

m_shader_compilation_mode[1]->SetDescription(
QString::fromStdString(TR_SHADER_COMPILE_SYNC_UBER_DESCRIPTION));

m_shader_compilation_mode[2]->SetDescription(
QString::fromStdString(TR_SHADER_COMPILE_ASYNC_UBER_DESCRIPTION));

m_shader_compilation_mode[3]->SetDescription(
QString::fromStdString(TR_SHADER_COMPILE_ASYNC_SKIP_DESCRIPTION));

m_wait_for_shaders->SetDescription(
QString::fromStdString(TR_SHADER_COMPILE_BEFORE_START_DESCRIPTION));
}

void GeneralWidget::OnBackendChanged(const QString& backend_name)
@@ -7,11 +7,15 @@
#include <array>
#include "DolphinQt/Config/Graphics/GraphicsWidget.h"

class GraphicsBool;
class GraphicsChoice;
class GraphicsRadioInt;
class GraphicsWindow;
class QCheckBox;
class QComboBox;
class QRadioButton;
class QGridLayout;
class ToolTipComboBox;

namespace X11Utils
{
@@ -39,21 +43,21 @@ class GeneralWidget final : public GraphicsWidget

// Video
QGridLayout* m_video_layout;
QComboBox* m_backend_combo;
QComboBox* m_adapter_combo;
QComboBox* m_aspect_combo;
QCheckBox* m_enable_vsync;
QCheckBox* m_enable_fullscreen;
ToolTipComboBox* m_backend_combo;
ToolTipComboBox* m_adapter_combo;
GraphicsChoice* m_aspect_combo;
GraphicsBool* m_enable_vsync;
GraphicsBool* m_enable_fullscreen;

// Options
QCheckBox* m_show_fps;
QCheckBox* m_show_ping;
QCheckBox* m_log_render_time;
QCheckBox* m_autoadjust_window_size;
QCheckBox* m_show_messages;
QCheckBox* m_render_main_window;
std::array<QRadioButton*, 4> m_shader_compilation_mode{};
QCheckBox* m_wait_for_shaders;
GraphicsBool* m_show_fps;
GraphicsBool* m_show_ping;
GraphicsBool* m_log_render_time;
GraphicsBool* m_autoadjust_window_size;
GraphicsBool* m_show_messages;
GraphicsBool* m_render_main_window;
std::array<GraphicsRadioInt*, 4> m_shader_compilation_mode{};
GraphicsBool* m_wait_for_shaders;

X11Utils::XRRConfiguration* m_xrr_config;
};
@@ -3,17 +3,19 @@
// Refer to the license.txt file included.

#include "DolphinQt/Config/Graphics/GraphicsBool.h"
#include "DolphinQt/Config/Graphics/BalloonTip.h"

#include <QSignalBlocker>

#include "Common/Config/Config.h"

#include "DolphinQt/Settings.h"

#include <QEvent>
#include <QFont>

GraphicsBool::GraphicsBool(const QString& label, const Config::Info<bool>& setting, bool reverse)
: QCheckBox(label), m_setting(setting), m_reverse(reverse)
: ToolTipCheckBox(label), m_setting(setting), m_reverse(reverse)
{
connect(this, &QCheckBox::toggled, this, &GraphicsBool::Update);
setChecked(Config::Get(m_setting) ^ reverse);
@@ -35,7 +37,7 @@ void GraphicsBool::Update()

GraphicsBoolEx::GraphicsBoolEx(const QString& label, const Config::Info<bool>& setting,
bool reverse)
: QRadioButton(label), m_setting(setting), m_reverse(reverse)
: ToolTipRadioButton(label), m_setting(setting), m_reverse(reverse)
{
connect(this, &QCheckBox::toggled, this, &GraphicsBoolEx::Update);
setChecked(Config::Get(m_setting) ^ reverse);
@@ -4,16 +4,16 @@

#pragma once

#include <QCheckBox>
#include <QRadioButton>
#include "DolphinQt/Config/ToolTipControls/ToolTipCheckBox.h"
#include "DolphinQt/Config/ToolTipControls/ToolTipRadioButton.h"

namespace Config
{
template <typename T>
struct Info;
}

class GraphicsBool : public QCheckBox
class GraphicsBool : public ToolTipCheckBox
{
Q_OBJECT
public:
@@ -26,7 +26,7 @@ class GraphicsBool : public QCheckBox
bool m_reverse;
};

class GraphicsBoolEx : public QRadioButton
class GraphicsBoolEx : public ToolTipRadioButton
{
Q_OBJECT
public:
@@ -4,11 +4,11 @@

#pragma once

#include <QComboBox>
#include "DolphinQt/Config/ToolTipControls/ToolTipComboBox.h"

#include "Common/Config/Config.h"

class GraphicsChoice : public QComboBox
class GraphicsChoice : public ToolTipComboBox
{
Q_OBJECT
public:
@@ -12,7 +12,7 @@

GraphicsInteger::GraphicsInteger(int minimum, int maximum, const Config::Info<int>& setting,
int step)
: QSpinBox(), m_setting(setting)
: ToolTipSpinBox(), m_setting(setting)
{
setMinimum(minimum);
setMaximum(maximum);
@@ -4,15 +4,15 @@

#pragma once

#include <QSpinBox>
#include "DolphinQt/Config/ToolTipControls/ToolTipSpinBox.h"

namespace Config
{
template <typename T>
struct Info;
}

class GraphicsInteger : public QSpinBox
class GraphicsInteger : public ToolTipSpinBox
{
Q_OBJECT
public:
@@ -12,7 +12,7 @@

GraphicsRadioInt::GraphicsRadioInt(const QString& label, const Config::Info<int>& setting,
int value)
: QRadioButton(label), m_setting(setting), m_value(value)
: ToolTipRadioButton(label), m_setting(setting), m_value(value)
{
setChecked(Config::Get(m_setting) == m_value);
connect(this, &QRadioButton::toggled, this, &GraphicsRadioInt::Update);
@@ -4,11 +4,11 @@

#pragma once

#include <QRadioButton>
#include "DolphinQt/Config/ToolTipControls/ToolTipRadioButton.h"

#include "Common/Config/Config.h"

class GraphicsRadioInt : public QRadioButton
class GraphicsRadioInt : public ToolTipRadioButton
{
Q_OBJECT
public:
@@ -11,7 +11,7 @@
#include "DolphinQt/Settings.h"

GraphicsSlider::GraphicsSlider(int minimum, int maximum, const Config::Info<int>& setting, int tick)
: QSlider(Qt::Horizontal), m_setting(setting)
: ToolTipSlider(Qt::Horizontal), m_setting(setting)
{
setMinimum(minimum);
setMaximum(maximum);
@@ -4,15 +4,15 @@

#pragma once

#include <QSlider>
#include "DolphinQt/Config/ToolTipControls/ToolTipSlider.h"

namespace Config
{
template <typename T>
struct Info;
}

class GraphicsSlider : public QSlider
class GraphicsSlider : public ToolTipSlider
{
Q_OBJECT
public:

This file was deleted.

@@ -6,23 +6,12 @@

#include <QWidget>

class GraphicsWindow;
class QFormLayout;
class QGroupBox;
class QLabel;

class GraphicsWidget : public QWidget
{
Q_OBJECT
public:
explicit GraphicsWidget(GraphicsWindow* parent);

signals:
void DescriptionAdded(QWidget* widget, const char* description);

protected:
void AddDescription(QWidget* widget, const char* description);

virtual void LoadSettings() = 0;
virtual void SaveSettings() = 0;

@@ -40,26 +40,12 @@ GraphicsWindow::GraphicsWindow(X11Utils::XRRConfiguration* xrr_config, MainWindo
void GraphicsWindow::CreateMainLayout()
{
auto* main_layout = new QVBoxLayout();
auto* description_box = new QGroupBox(tr("Description"));
auto* description_layout = new QVBoxLayout();
m_description =
new QLabel(tr("Move the mouse pointer over an option to display a detailed description."));
m_tab_widget = new QTabWidget();
m_button_box = new QDialogButtonBox(QDialogButtonBox::Close);

connect(m_button_box, &QDialogButtonBox::rejected, this, &QDialog::reject);

description_box->setLayout(description_layout);
description_box->setFixedHeight(200);

m_description->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
m_description->setWordWrap(true);
m_description->setAlignment(Qt::AlignTop | Qt::AlignLeft);

description_layout->addWidget(m_description);

main_layout->addWidget(m_tab_widget);
main_layout->addWidget(description_box);
main_layout->addWidget(m_button_box);

m_general_widget = new GeneralWidget(m_xrr_config, this);
@@ -73,11 +59,11 @@ void GraphicsWindow::CreateMainLayout()
connect(m_software_renderer, &SoftwareRendererWidget::BackendChanged, this,
&GraphicsWindow::OnBackendChanged);

m_wrapped_general = GetWrappedWidget(m_general_widget, this, 50, 305);
m_wrapped_enhancements = GetWrappedWidget(m_enhancements_widget, this, 50, 305);
m_wrapped_hacks = GetWrappedWidget(m_hacks_widget, this, 50, 305);
m_wrapped_advanced = GetWrappedWidget(m_advanced_widget, this, 50, 305);
m_wrapped_software = GetWrappedWidget(m_software_renderer, this, 50, 305);
m_wrapped_general = GetWrappedWidget(m_general_widget, this, 50, 100);
m_wrapped_enhancements = GetWrappedWidget(m_enhancements_widget, this, 50, 100);
m_wrapped_hacks = GetWrappedWidget(m_hacks_widget, this, 50, 100);
m_wrapped_advanced = GetWrappedWidget(m_advanced_widget, this, 50, 100);
m_wrapped_software = GetWrappedWidget(m_software_renderer, this, 50, 100);

if (Config::Get(Config::MAIN_GFX_BACKEND) != "Software Renderer")
{
@@ -118,34 +104,3 @@ void GraphicsWindow::OnBackendChanged(const QString& backend_name)

emit BackendChanged(backend_name);
}

void GraphicsWindow::RegisterWidget(GraphicsWidget* widget)
{
connect(widget, &GraphicsWidget::DescriptionAdded, this, &GraphicsWindow::OnDescriptionAdded);
}

void GraphicsWindow::OnDescriptionAdded(QWidget* widget, const char* description)
{
m_widget_descriptions[widget] = description;
widget->installEventFilter(this);
}

bool GraphicsWindow::eventFilter(QObject* object, QEvent* event)
{
if (!m_widget_descriptions.contains(object))
return false;

if (event->type() == QEvent::Enter)
{
m_description->setText(tr(m_widget_descriptions[object]));
return false;
}

if (event->type() == QEvent::Leave)
{
m_description->setText(
tr("Move the mouse pointer over an option to display a detailed description."));
}

return false;
}
@@ -11,7 +11,6 @@ class AdvancedWidget;
class EnhancementsWidget;
class HacksWidget;
class GeneralWidget;
class GraphicsWidget;
class MainWindow;
class QLabel;
class QTabWidget;
@@ -29,18 +28,14 @@ class GraphicsWindow final : public QDialog
public:
explicit GraphicsWindow(X11Utils::XRRConfiguration* xrr_config, MainWindow* parent);

void RegisterWidget(GraphicsWidget* widget);
bool eventFilter(QObject* object, QEvent* event) override;
signals:
void BackendChanged(const QString& backend);

private:
void CreateMainLayout();
void OnBackendChanged(const QString& backend);
void OnDescriptionAdded(QWidget* widget, const char* description);

QTabWidget* m_tab_widget;
QLabel* m_description;
QDialogButtonBox* m_button_box;

AdvancedWidget* m_advanced_widget;
@@ -56,6 +51,4 @@ class GraphicsWindow final : public QDialog
QWidget* m_wrapped_software;

X11Utils::XRRConfiguration* m_xrr_config;

QHash<QObject*, const char*> m_widget_descriptions;
};
@@ -17,11 +17,12 @@
#include "DolphinQt/Config/Graphics/GraphicsBool.h"
#include "DolphinQt/Config/Graphics/GraphicsSlider.h"
#include "DolphinQt/Config/Graphics/GraphicsWindow.h"
#include "DolphinQt/Config/ToolTipControls/ToolTipSlider.h"
#include "DolphinQt/Settings.h"

#include "VideoCommon/VideoConfig.h"

HacksWidget::HacksWidget(GraphicsWindow* parent) : GraphicsWidget(parent)
HacksWidget::HacksWidget(GraphicsWindow* parent)
{
CreateWidgets();
LoadSettings();
@@ -60,7 +61,7 @@ void HacksWidget::CreateWidgets()
auto* texture_cache_layout = new QGridLayout();
texture_cache_box->setLayout(texture_cache_layout);

m_accuracy = new QSlider(Qt::Horizontal);
m_accuracy = new ToolTipSlider(Qt::Horizontal);
m_accuracy->setMinimum(0);
m_accuracy->setMaximum(2);
m_accuracy->setPageStep(1);
@@ -207,81 +208,93 @@ void HacksWidget::SaveSettings()

void HacksWidget::AddDescriptions()
{
static const char TR_SKIP_EFB_CPU_ACCESS_DESCRIPTION[] =
QT_TR_NOOP("Ignores any requests from the CPU to read from or write to the EFB. "
"\n\nImproves performance in some games, but will disable all EFB-based "
"graphical effects or gameplay-related features.\n\nIf unsure, "
"leave this unchecked.");
static const char TR_SKIP_EFB_CPU_ACCESS_DESCRIPTION[] = QT_TR_NOOP(
"Ignores any requests from the CPU to read from or write to the EFB. "
"<br><br>Improves performance in some games, but will disable all EFB-based "
"graphical effects or gameplay-related features.<br><br><dolphin_emphasis>If unsure, "
"leave this unchecked.</dolphin_emphasis>");
static const char TR_IGNORE_FORMAT_CHANGE_DESCRIPTION[] = QT_TR_NOOP(
"Ignores any changes to the EFB format.\n\nImproves performance in many games without "
"Ignores any changes to the EFB format.<br><br>Improves performance in many games "
"without "
"any negative effect. Causes graphical defects in a small number of other "
"games.\n\nIf unsure, leave this checked.");
"games.<br><br><dolphin_emphasis>If unsure, leave this checked.</dolphin_emphasis>");
static const char TR_STORE_EFB_TO_TEXTURE_DESCRIPTION[] = QT_TR_NOOP(
"Stores EFB copies exclusively on the GPU, bypassing system memory. Causes graphical defects "
"in a small number of games.\n\nEnabled = EFB Copies to Texture\nDisabled = EFB Copies to "
"RAM (and Texture)\n\nIf unsure, leave this checked.");
"in a small number of games.<br><br>Enabled = EFB Copies to Texture<br>Disabled = EFB "
"Copies to "
"RAM (and Texture)<br><br><dolphin_emphasis>If unsure, leave this "
"checked.</dolphin_emphasis>");
static const char TR_DEFER_EFB_COPIES_DESCRIPTION[] = QT_TR_NOOP(
"Waits until the game synchronizes with the emulated GPU before writing the contents of EFB "
"copies to RAM.\n\nReduces the overhead of EFB RAM copies, providing a performance boost in "
"copies to RAM.<br><br>Reduces the overhead of EFB RAM copies, providing a performance "
"boost in "
"many games, at the risk of breaking those which do not safely synchronize with the "
"emulated GPU.\n\nIf unsure, leave this checked.");
"emulated GPU.<br><br><dolphin_emphasis>If unsure, leave this "
"checked.</dolphin_emphasis>");
static const char TR_ACCUARCY_DESCRIPTION[] = QT_TR_NOOP(
"Adjusts the accuracy at which the GPU receives texture updates from RAM.\n\n"
"Adjusts the accuracy at which the GPU receives texture updates from RAM.<br><br>"
"The \"Safe\" setting eliminates the likelihood of the GPU missing texture updates "
"from RAM. Lower accuracies cause in-game text to appear garbled in certain "
"games.\n\nIf unsure, select the rightmost value.");

"games.<br><br><dolphin_emphasis>If unsure, select the rightmost "
"value.</dolphin_emphasis>");
static const char TR_STORE_XFB_TO_TEXTURE_DESCRIPTION[] = QT_TR_NOOP(
"Stores XFB copies exclusively on the GPU, bypassing system memory. Causes graphical defects "
"in a small number of games.\n\nEnabled = XFB Copies to "
"Texture\nDisabled = XFB Copies to RAM (and Texture)\n\nIf unsure, leave this checked.");

static const char TR_IMMEDIATE_XFB_DESCRIPTION[] =
QT_TR_NOOP("Displays XFB copies as soon as they are created, instead of waiting for "
"scanout.\n\nCan cause graphical defects in some games if the game doesn't "
"expect all XFB copies to be displayed. However, turning this setting on reduces "
"latency.\n\nIf unsure, leave this unchecked.");

"in a small number of games.<br><br>Enabled = XFB Copies to "
"Texture<br>Disabled = XFB Copies to RAM (and Texture)<br><br><dolphin_emphasis>If "
"unsure, leave this checked.</dolphin_emphasis>");
static const char TR_IMMEDIATE_XFB_DESCRIPTION[] = QT_TR_NOOP(
"Displays XFB copies as soon as they are created, instead of waiting for "
"scanout.<br><br>Can cause graphical defects in some games if the game doesn't "
"expect all XFB copies to be displayed. However, turning this setting on reduces "
"latency.<br><br><dolphin_emphasis>If unsure, leave this unchecked.</dolphin_emphasis>");
static const char TR_SKIP_DUPLICATE_XFBS_DESCRIPTION[] = QT_TR_NOOP(
"Skips presentation of duplicate frames (XFB copies) in 25fps/30fps games. This may improve "
"performance on low-end devices, while making frame pacing less consistent.\n\nDisable this "
"option as well as enabling V-Sync for optimal frame pacing.\n\nIf unsure, leave this "
"checked.");

static const char TR_GPU_DECODING_DESCRIPTION[] =
QT_TR_NOOP("Enables texture decoding using the GPU instead of the CPU.\n\nThis may result in "
"performance gains in some scenarios, or on systems where the CPU is the "
"bottleneck.\n\nIf unsure, leave this unchecked.");

"performance on low-end devices, while making frame pacing less consistent.<br><br "
"/>Disable this "
"option as well as enabling V-Sync for optimal frame pacing.<br><br><dolphin_emphasis>If "
"unsure, leave this "
"checked.</dolphin_emphasis>");
static const char TR_GPU_DECODING_DESCRIPTION[] = QT_TR_NOOP(
"Enables texture decoding using the GPU instead of the CPU.<br><br>This may result in "
"performance gains in some scenarios, or on systems where the CPU is the "
"bottleneck.<br><br><dolphin_emphasis>If unsure, leave this "
"unchecked.</dolphin_emphasis>");
static const char TR_FAST_DEPTH_CALC_DESCRIPTION[] = QT_TR_NOOP(
"Uses a less accurate algorithm to calculate depth values.\n\nCauses issues in a few "
"Uses a less accurate algorithm to calculate depth values.<br><br>Causes issues in a few "
"games, but can result in a decent speed increase depending on the game and/or "
"GPU.\n\nIf unsure, leave this checked.");
"GPU.<br><br><dolphin_emphasis>If unsure, leave this checked.</dolphin_emphasis>");
static const char TR_DISABLE_BOUNDINGBOX_DESCRIPTION[] =
QT_TR_NOOP("Disables bounding box emulation.\n\nThis may improve GPU performance "
"significantly, but some games will break.\n\nIf unsure, leave this checked.");
static const char TR_SAVE_TEXTURE_CACHE_TO_STATE_DESCRIPTION[] = QT_TR_NOOP(
"Includes the contents of the embedded frame buffer (EFB) and upscaled EFB copies "
"in save states. Fixes missing and/or non-upscaled textures/objects when loading "
"states at the cost of additional save/load time.\n\nIf unsure, leave this checked.");
static const char TR_VERTEX_ROUNDING_DESCRIPTION[] =
QT_TR_NOOP("Rounds 2D vertices to whole pixels.\n\nFixes graphical problems in some games at "
"higher internal resolutions. This setting has no effect when native internal "
"resolution is used.\n\nIf unsure, leave this unchecked.");

AddDescription(m_skip_efb_cpu, TR_SKIP_EFB_CPU_ACCESS_DESCRIPTION);
AddDescription(m_ignore_format_changes, TR_IGNORE_FORMAT_CHANGE_DESCRIPTION);
AddDescription(m_store_efb_copies, TR_STORE_EFB_TO_TEXTURE_DESCRIPTION);
AddDescription(m_defer_efb_copies, TR_DEFER_EFB_COPIES_DESCRIPTION);
AddDescription(m_accuracy, TR_ACCUARCY_DESCRIPTION);
AddDescription(m_store_xfb_copies, TR_STORE_XFB_TO_TEXTURE_DESCRIPTION);
AddDescription(m_immediate_xfb, TR_IMMEDIATE_XFB_DESCRIPTION);
AddDescription(m_skip_duplicate_xfbs, TR_SKIP_DUPLICATE_XFBS_DESCRIPTION);
AddDescription(m_gpu_texture_decoding, TR_GPU_DECODING_DESCRIPTION);
AddDescription(m_fast_depth_calculation, TR_FAST_DEPTH_CALC_DESCRIPTION);
AddDescription(m_disable_bounding_box, TR_DISABLE_BOUNDINGBOX_DESCRIPTION);
AddDescription(m_save_texture_cache_state, TR_SAVE_TEXTURE_CACHE_TO_STATE_DESCRIPTION);
AddDescription(m_vertex_rounding, TR_VERTEX_ROUNDING_DESCRIPTION);
QT_TR_NOOP("Disables bounding box emulation.<br><br>This may improve GPU performance "
"significantly, but some games will break.<br><br><dolphin_emphasis>If "
"unsure, leave this checked.</dolphin_emphasis>");
static const char TR_SAVE_TEXTURE_CACHE_TO_STATE_DESCRIPTION[] =
QT_TR_NOOP("Includes the contents of the embedded frame buffer (EFB) and upscaled EFB copies "
"in save states. Fixes missing and/or non-upscaled textures/objects when loading "
"states at the cost of additional save/load time.<br><br><dolphin_emphasis>If "
"unsure, leave this checked.</dolphin_emphasis>");
static const char TR_VERTEX_ROUNDING_DESCRIPTION[] = QT_TR_NOOP(
"Rounds 2D vertices to whole pixels.<br><br>Fixes graphical problems in some games at "
"higher internal resolutions. This setting has no effect when native internal "
"resolution is used.<br><br><dolphin_emphasis>If unsure, leave this "
"unchecked.</dolphin_emphasis>");

m_skip_efb_cpu->SetDescription(QString::fromStdString(TR_SKIP_EFB_CPU_ACCESS_DESCRIPTION));
m_ignore_format_changes->SetDescription(
QString::fromStdString(TR_IGNORE_FORMAT_CHANGE_DESCRIPTION));
m_store_efb_copies->SetDescription(QString::fromStdString(TR_STORE_EFB_TO_TEXTURE_DESCRIPTION));
m_defer_efb_copies->SetDescription(QString::fromStdString(TR_DEFER_EFB_COPIES_DESCRIPTION));
m_accuracy->SetTitle(tr("Texture Cache Accuracy"));
m_accuracy->SetDescription(QString::fromStdString(TR_ACCUARCY_DESCRIPTION));
m_store_xfb_copies->SetDescription(QString::fromStdString(TR_STORE_XFB_TO_TEXTURE_DESCRIPTION));
m_immediate_xfb->SetDescription(QString::fromStdString(TR_IMMEDIATE_XFB_DESCRIPTION));
m_skip_duplicate_xfbs->SetDescription(QString::fromStdString(TR_SKIP_DUPLICATE_XFBS_DESCRIPTION));
m_gpu_texture_decoding->SetDescription(QString::fromStdString(TR_GPU_DECODING_DESCRIPTION));
m_fast_depth_calculation->SetDescription(QString::fromStdString(TR_FAST_DEPTH_CALC_DESCRIPTION));
m_disable_bounding_box->SetDescription(
QString::fromStdString(TR_DISABLE_BOUNDINGBOX_DESCRIPTION));
m_save_texture_cache_state->SetDescription(
QString::fromStdString(TR_SAVE_TEXTURE_CACHE_TO_STATE_DESCRIPTION));
m_vertex_rounding->SetDescription(QString::fromStdString(TR_VERTEX_ROUNDING_DESCRIPTION));
}

void HacksWidget::UpdateDeferEFBCopiesEnabled()
@@ -6,11 +6,10 @@

#include "DolphinQt/Config/Graphics/GraphicsWidget.h"

class GraphicsBool;
class GraphicsWindow;
class QCheckBox;
class QLabel;
class QRadioButton;
class QSlider;
class ToolTipSlider;

class HacksWidget final : public GraphicsWidget
{
@@ -25,26 +24,26 @@ class HacksWidget final : public GraphicsWidget
void OnBackendChanged(const QString& backend_name);

// EFB
QCheckBox* m_skip_efb_cpu;
QCheckBox* m_ignore_format_changes;
QCheckBox* m_store_efb_copies;
GraphicsBool* m_skip_efb_cpu;
GraphicsBool* m_ignore_format_changes;
GraphicsBool* m_store_efb_copies;

// Texture Cache
QLabel* m_accuracy_label;
QSlider* m_accuracy;
QCheckBox* m_gpu_texture_decoding;
ToolTipSlider* m_accuracy;
GraphicsBool* m_gpu_texture_decoding;

// External Framebuffer
QCheckBox* m_store_xfb_copies;
QCheckBox* m_immediate_xfb;
QCheckBox* m_skip_duplicate_xfbs;
GraphicsBool* m_store_xfb_copies;
GraphicsBool* m_immediate_xfb;
GraphicsBool* m_skip_duplicate_xfbs;

// Other
QCheckBox* m_fast_depth_calculation;
QCheckBox* m_disable_bounding_box;
QCheckBox* m_vertex_rounding;
QCheckBox* m_save_texture_cache_state;
QCheckBox* m_defer_efb_copies;
GraphicsBool* m_fast_depth_calculation;
GraphicsBool* m_disable_bounding_box;
GraphicsBool* m_vertex_rounding;
GraphicsBool* m_save_texture_cache_state;
GraphicsBool* m_defer_efb_copies;

void CreateWidgets();
void ConnectWidgets();
@@ -18,14 +18,15 @@

#include "DolphinQt/Config/Graphics/GraphicsBool.h"
#include "DolphinQt/Config/Graphics/GraphicsWindow.h"
#include "DolphinQt/Config/ToolTipControls/ToolTipComboBox.h"
#include "DolphinQt/Settings.h"

#include "UICommon/VideoUtils.h"

#include "VideoCommon/VideoBackendBase.h"
#include "VideoCommon/VideoConfig.h"

SoftwareRendererWidget::SoftwareRendererWidget(GraphicsWindow* parent) : GraphicsWidget(parent)
SoftwareRendererWidget::SoftwareRendererWidget(GraphicsWindow* parent)
{
CreateWidgets();
LoadSettings();
@@ -45,7 +46,7 @@ void SoftwareRendererWidget::CreateWidgets()

auto* rendering_box = new QGroupBox(tr("Rendering"));
auto* rendering_layout = new QGridLayout();
m_backend_combo = new QComboBox();
m_backend_combo = new ToolTipComboBox();

rendering_box->setLayout(rendering_layout);
rendering_layout->addWidget(new QLabel(tr("Backend:")), 1, 1);
@@ -154,38 +155,37 @@ void SoftwareRendererWidget::SaveSettings()

void SoftwareRendererWidget::AddDescriptions()
{
static const char TR_BACKEND_DESCRIPTION[] =
QT_TR_NOOP("Selects what graphics API to use internally.\nThe software renderer is extremely "
"slow and only useful for debugging, so you'll want to use either Direct3D or "
"OpenGL. Different games and different GPUs will behave differently on each "
"backend, so for the best emulation experience it's recommended to try both and "
"choose the one that's less problematic.\n\nIf unsure, select OpenGL.");

static const char TR_BACKEND_DESCRIPTION[] = QT_TR_NOOP(
"Selects what graphics API to use internally.<br>The software renderer is extremely "
"slow and only useful for debugging, so you'll want to use either Direct3D or "
"OpenGL. Different games and different GPUs will behave differently on each "
"backend, so for the best emulation experience it's recommended to try both and "
"choose the one that's less problematic.<br><br><dolphin_emphasis>If unsure, select "
"OpenGL.</dolphin_emphasis>");
static const char TR_SHOW_STATISTICS_DESCRIPTION[] =
QT_TR_NOOP("Show various rendering statistics.\n\nIf unsure, leave this unchecked.");

QT_TR_NOOP("Show various rendering statistics.<br><br><dolphin_emphasis>If unsure, leave "
"this unchecked.</dolphin_emphasis>");
static const char TR_DUMP_TEXTURES_DESCRIPTION[] =
QT_TR_NOOP("Dump decoded game textures to User/Dump/Textures/<game_id>/.\n\nIf unsure, leave "
"this unchecked.");

QT_TR_NOOP("Dump decoded game textures to User/Dump/Textures/<game_id>/.<br><br "
"/><dolphin_emphasis>If unsure, leave "
"this unchecked.</dolphin_emphasis>");
static const char TR_DUMP_OBJECTS_DESCRIPTION[] =
QT_TR_NOOP("Dump objects to User/Dump/Objects/.\n\nIf unsure, leave "
"this unchecked.");

QT_TR_NOOP("Dump objects to User/Dump/Objects/.<br><br><dolphin_emphasis>If unsure, leave "
"this unchecked.</dolphin_emphasis>");
static const char TR_DUMP_TEV_STAGES_DESCRIPTION[] =
QT_TR_NOOP("Dump TEV Stages to User/Dump/Objects/.\n\nIf unsure, leave "
"this unchecked.");

static const char TR_DUMP_TEV_FETCHES_DESCRIPTION[] =
QT_TR_NOOP("Dump Texture Fetches to User/Dump/Objects/.\n\nIf unsure, leave "
"this unchecked.");

AddDescription(m_backend_combo, TR_BACKEND_DESCRIPTION);
AddDescription(m_show_statistics, TR_SHOW_STATISTICS_DESCRIPTION);
AddDescription(m_dump_textures, TR_DUMP_TEXTURES_DESCRIPTION);
AddDescription(m_dump_objects, TR_DUMP_OBJECTS_DESCRIPTION);
AddDescription(m_dump_tev_stages, TR_DUMP_TEV_STAGES_DESCRIPTION);
AddDescription(m_dump_tev_fetches, TR_DUMP_TEV_FETCHES_DESCRIPTION);
QT_TR_NOOP("Dump TEV Stages to User/Dump/Objects/.<br><br><dolphin_emphasis>If unsure, leave "
"this unchecked.</dolphin_emphasis>");
static const char TR_DUMP_TEV_FETCHES_DESCRIPTION[] = QT_TR_NOOP(
"Dump Texture Fetches to User/Dump/Objects/.<br><br><dolphin_emphasis>If unsure, leave "
"this unchecked.</dolphin_emphasis>");

m_backend_combo->SetTitle(tr("Backend"));
m_backend_combo->SetDescription(QString::fromStdString(TR_BACKEND_DESCRIPTION));
m_show_statistics->SetDescription(QString::fromStdString(TR_SHOW_STATISTICS_DESCRIPTION));
m_dump_textures->SetDescription(QString::fromStdString(TR_DUMP_TEXTURES_DESCRIPTION));
m_dump_objects->SetDescription(QString::fromStdString(TR_DUMP_OBJECTS_DESCRIPTION));
m_dump_tev_stages->SetDescription(QString::fromStdString(TR_DUMP_TEV_STAGES_DESCRIPTION));
m_dump_tev_fetches->SetDescription(QString::fromStdString(TR_DUMP_TEV_FETCHES_DESCRIPTION));
}

void SoftwareRendererWidget::OnEmulationStateChanged(bool running)
@@ -6,10 +6,10 @@

#include "DolphinQt/Config/Graphics/GraphicsWidget.h"

class GraphicsBool;
class GraphicsWindow;
class QCheckBox;
class QComboBox;
class QSpinBox;
class ToolTipComboBox;

class SoftwareRendererWidget final : public GraphicsWidget
{
@@ -30,12 +30,12 @@ class SoftwareRendererWidget final : public GraphicsWidget

void OnEmulationStateChanged(bool running);

QComboBox* m_backend_combo;
QCheckBox* m_show_statistics;
QCheckBox* m_dump_textures;
QCheckBox* m_dump_objects;
QCheckBox* m_dump_tev_stages;
QCheckBox* m_dump_tev_fetches;
ToolTipComboBox* m_backend_combo;
GraphicsBool* m_show_statistics;
GraphicsBool* m_dump_textures;
GraphicsBool* m_dump_objects;
GraphicsBool* m_dump_tev_stages;
GraphicsBool* m_dump_tev_fetches;

QSpinBox* m_object_range_min;
QSpinBox* m_object_range_max;
@@ -0,0 +1,27 @@
// Copyright 2020 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#include "DolphinQt/Config/ToolTipControls/ToolTipCheckBox.h"

#include <QStyle>
#include <QStyleOption>

ToolTipCheckBox::ToolTipCheckBox(const QString& label) : ToolTipWidget(label)
{
SetTitle(label);
}

QPoint ToolTipCheckBox::GetToolTipPosition() const
{
int checkbox_width = 18;
if (style())
{
QStyleOptionButton opt;
initStyleOption(&opt);
checkbox_width =
style()->subElementRect(QStyle::SubElement::SE_CheckBoxIndicator, &opt, this).width();
}

return pos() + QPoint(checkbox_width / 2, height() / 2);
}
@@ -0,0 +1,18 @@
// Copyright 2020 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#pragma once

#include "DolphinQt/Config/ToolTipControls/ToolTipWidget.h"

#include <QCheckBox>

class ToolTipCheckBox : public ToolTipWidget<QCheckBox>
{
public:
explicit ToolTipCheckBox(const QString& label);

private:
QPoint GetToolTipPosition() const override;
};
@@ -0,0 +1,10 @@
// Copyright 2020 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#include "DolphinQt/Config/ToolTipControls/ToolTipComboBox.h"

QPoint ToolTipComboBox::GetToolTipPosition() const
{
return pos() + QPoint(width() / 2, height() / 2);
}
@@ -0,0 +1,15 @@
// Copyright 2020 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#pragma once

#include "DolphinQt/Config/ToolTipControls/ToolTipWidget.h"

#include <QComboBox>

class ToolTipComboBox : public ToolTipWidget<QComboBox>
{
private:
QPoint GetToolTipPosition() const override;
};
@@ -0,0 +1,27 @@
// Copyright 2020 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#include "DolphinQt/Config/ToolTipControls/ToolTipRadioButton.h"

#include <QStyle>
#include <QStyleOption>

ToolTipRadioButton::ToolTipRadioButton(const QString& label) : ToolTipWidget(label)
{
SetTitle(label);
}

QPoint ToolTipRadioButton::GetToolTipPosition() const
{
int radio_button_width = 18;
if (style())
{
QStyleOptionButton opt;
initStyleOption(&opt);
radio_button_width =
style()->subElementRect(QStyle::SubElement::SE_RadioButtonIndicator, &opt, this).width();
}

return pos() + QPoint(radio_button_width / 2, height() / 2);
}
@@ -0,0 +1,18 @@
// Copyright 2020 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#pragma once

#include "DolphinQt/Config/ToolTipControls/ToolTipWidget.h"

#include <QRadioButton>

class ToolTipRadioButton : public ToolTipWidget<QRadioButton>
{
public:
explicit ToolTipRadioButton(const QString& label);

private:
QPoint GetToolTipPosition() const override;
};
@@ -0,0 +1,26 @@
// Copyright 2020 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#include "DolphinQt/Config/ToolTipControls/ToolTipSlider.h"

#include <QStyle>
#include <QStyleOption>

ToolTipSlider::ToolTipSlider(Qt::Orientation orientation) : ToolTipWidget(orientation)
{
}

QPoint ToolTipSlider::GetToolTipPosition() const
{
QRect handle_rect(0, 0, 15, 15);
if (style())
{
QStyleOptionSlider opt;
initStyleOption(&opt);
handle_rect = style()->subControlRect(QStyle::ComplexControl::CC_Slider, &opt,
QStyle::SubControl::SC_SliderHandle, this);
}

return pos() + handle_rect.center();
}
@@ -0,0 +1,18 @@
// Copyright 2020 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#pragma once

#include "DolphinQt/Config/ToolTipControls/ToolTipWidget.h"

#include <QSlider>

class ToolTipSlider : public ToolTipWidget<QSlider>
{
public:
explicit ToolTipSlider(Qt::Orientation orientation);

private:
QPoint GetToolTipPosition() const override;
};
@@ -0,0 +1,10 @@
// Copyright 2020 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#include "DolphinQt/Config/ToolTipControls/ToolTipSpinBox.h"

QPoint ToolTipSpinBox::GetToolTipPosition() const
{
return pos() + QPoint(width() / 2, height() / 2);
}
@@ -0,0 +1,15 @@
// Copyright 2020 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#pragma once

#include "DolphinQt/Config/ToolTipControls/ToolTipWidget.h"

#include <QSpinBox>

class ToolTipSpinBox : public ToolTipWidget<QSpinBox>
{
private:
QPoint GetToolTipPosition() const override;
};
@@ -0,0 +1,55 @@
// Copyright 2020 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#pragma once

#include <optional>

#include <QString>

#include "DolphinQt/Config/Graphics/BalloonTip.h"

template <class Derived>
class ToolTipWidget : public Derived
{
public:
using Derived::Derived;

void SetTitle(QString title) { m_title = std::move(title); }

void SetDescription(QString description) { m_description = std::move(description); }

private:
void enterEvent(QEvent* event) override
{
if (m_timer_id)
return;
m_timer_id = this->startTimer(300);
}

void leaveEvent(QEvent* event) override
{
if (m_timer_id)
{
this->killTimer(*m_timer_id);
m_timer_id.reset();
}
BalloonTip::HideBalloon();
}

void timerEvent(QTimerEvent* event) override
{
this->killTimer(*m_timer_id);
m_timer_id.reset();

BalloonTip::ShowBalloon(QIcon(), m_title, m_description,
this->parentWidget()->mapToGlobal(GetToolTipPosition()), this);
}

virtual QPoint GetToolTipPosition() const = 0;

std::optional<int> m_timer_id;
QString m_title;
QString m_description;
};
@@ -60,14 +60,14 @@
<ClCompile Include="Config\GameConfigWidget.cpp" />
<ClCompile Include="Config\GeckoCodeWidget.cpp" />
<ClCompile Include="Config\Graphics\AdvancedWidget.cpp" />
<ClCompile Include="Config\Graphics\BalloonTip.cpp" />
<ClCompile Include="Config\Graphics\EnhancementsWidget.cpp" />
<ClCompile Include="Config\Graphics\GeneralWidget.cpp" />
<ClCompile Include="Config\Graphics\GraphicsBool.cpp" />
<ClCompile Include="Config\Graphics\GraphicsChoice.cpp" />
<ClCompile Include="Config\Graphics\GraphicsInteger.cpp" />
<ClCompile Include="Config\Graphics\GraphicsRadio.cpp" />
<ClCompile Include="Config\Graphics\GraphicsSlider.cpp" />
<ClCompile Include="Config\Graphics\GraphicsWidget.cpp" />
<ClCompile Include="Config\Graphics\GraphicsWindow.cpp" />
<ClCompile Include="Config\Graphics\HacksWidget.cpp" />
<ClCompile Include="Config\Graphics\PostProcessingConfigWindow.cpp" />
@@ -105,6 +105,11 @@
<ClCompile Include="Config\PatchesWidget.cpp" />
<ClCompile Include="Config\PropertiesDialog.cpp" />
<ClCompile Include="Config\SettingsWindow.cpp" />
<ClCompile Include="Config\ToolTipControls\ToolTipCheckBox.cpp" />
<ClCompile Include="Config\ToolTipControls\ToolTipComboBox.cpp" />
<ClCompile Include="Config\ToolTipControls\ToolTipRadioButton.cpp" />
<ClCompile Include="Config\ToolTipControls\ToolTipSlider.cpp" />
<ClCompile Include="Config\ToolTipControls\ToolTipSpinBox.cpp" />
<ClCompile Include="Config\VerifyWidget.cpp" />
<ClCompile Include="ConvertDialog.cpp" />
<ClCompile Include="Debugger\BreakpointWidget.cpp" />
@@ -222,6 +227,7 @@
<QtMoc Include="Config\GameConfigWidget.h" />
<QtMoc Include="Config\GeckoCodeWidget.h" />
<QtMoc Include="Config\Graphics\AdvancedWidget.h" />
<QtMoc Include="Config\Graphics\BalloonTip.h" />
<QtMoc Include="Config\Graphics\EnhancementsWidget.h" />
<QtMoc Include="Config\Graphics\GeneralWidget.h" />
<QtMoc Include="Config\Graphics\GraphicsBool.h" />
@@ -262,6 +268,12 @@
<QtMoc Include="Config\Mapping\WiimoteEmuMotionControlIMU.h" />
<QtMoc Include="Config\PropertiesDialog.h" />
<QtMoc Include="Config\SettingsWindow.h" />
<ClInclude Include="Config\ToolTipControls\ToolTipCheckBox.h" />
<ClInclude Include="Config\ToolTipControls\ToolTipComboBox.h" />
<ClInclude Include="Config\ToolTipControls\ToolTipRadioButton.h" />
<ClInclude Include="Config\ToolTipControls\ToolTipSlider.h" />
<ClInclude Include="Config\ToolTipControls\ToolTipSpinBox.h" />
<ClInclude Include="Config\ToolTipControls\ToolTipWidget.h" />
<QtMoc Include="Config\VerifyWidget.h" />
<QtMoc Include="ConvertDialog.h" />
<QtMoc Include="Debugger\BreakpointWidget.h" />