mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-11-15 13:57:57 -07:00
0146456af0
Since these button names are printed on all real controllers,
we should show them in the same way as they are printed on
the controllers, regardless of the user's language. It seems
like this was intended all along (except for "Start"), but the
_ markers in TASInputDlg.cpp (accidentally?) led to the button
names in the controller configs also becoming translatable.
I'm making exceptions for "L" and "R" because translators
may want to mark them in some way (for instance "L-Digital")
to clarify the difference from "L-Analog" and "R-Analog".
I'm also making an exception for START/PAUSE because it's
referred to as スタート in Japanese games.
I'm changing "Home" and "Start" to uppercase for consistency
with how Nintendo refers to those buttons, and because someone
who isn't familiar with the Latin script might not know the
connection between the lowercase and uppercase letters (most
users likely do know the connection, but we shouldn't assume it),
and because leaving "Start" as "Start" makes it "collide" with
unrelated strings, such as the string for the button that starts
a netplay session.
To rename "Start" and "Home" without breaking INI
compatibility, I added a ui_name variable like in f5c82ad
.
560 lines
17 KiB
C++
560 lines
17 KiB
C++
// Copyright 2010 Dolphin Emulator Project
|
|
// Licensed under GPLv2+
|
|
// Refer to the license.txt file included.
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
#include <cstring>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <wx/bitmap.h>
|
|
#include <wx/brush.h>
|
|
#include <wx/colour.h>
|
|
#include <wx/dcmemory.h>
|
|
#include <wx/font.h>
|
|
#include <wx/graphics.h>
|
|
#include <wx/notebook.h>
|
|
#include <wx/pen.h>
|
|
#include <wx/settings.h>
|
|
#include <wx/statbmp.h>
|
|
|
|
#include "DolphinWX/Input/InputConfigDiag.h"
|
|
#include "DolphinWX/WxUtils.h"
|
|
|
|
#include "InputCommon/ControllerEmu/Control/Control.h"
|
|
#include "InputCommon/ControllerEmu/ControlGroup/AnalogStick.h"
|
|
#include "InputCommon/ControllerEmu/ControlGroup/Buttons.h"
|
|
#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h"
|
|
#include "InputCommon/ControllerEmu/ControlGroup/Cursor.h"
|
|
#include "InputCommon/ControllerEmu/ControlGroup/Force.h"
|
|
#include "InputCommon/ControllerEmu/ControlGroup/Slider.h"
|
|
#include "InputCommon/ControllerEmu/ControlGroup/Tilt.h"
|
|
#include "InputCommon/ControllerEmu/ControlGroup/Triggers.h"
|
|
#include "InputCommon/ControllerEmu/ControllerEmu.h"
|
|
#include "InputCommon/ControllerInterface/ControllerInterface.h"
|
|
#include "InputCommon/ControllerInterface/Device.h"
|
|
|
|
struct ShapePosition
|
|
{
|
|
double max;
|
|
double diag;
|
|
double box;
|
|
double scale;
|
|
|
|
double dz;
|
|
double range;
|
|
|
|
wxCoord offset;
|
|
};
|
|
|
|
// regular octagon
|
|
static void DrawOctagon(wxGraphicsContext* gc, ShapePosition p)
|
|
{
|
|
static constexpr int vertices = 8;
|
|
double radius = p.max;
|
|
|
|
wxGraphicsPath path = gc->CreatePath();
|
|
|
|
double angle = 2.0 * M_PI / vertices;
|
|
|
|
for (int i = 0; i < vertices; i++)
|
|
{
|
|
double a = angle * i;
|
|
double x = radius * cos(a);
|
|
double y = radius * sin(a);
|
|
if (i == 0)
|
|
path.MoveToPoint(x, y);
|
|
else
|
|
path.AddLineToPoint(x, y);
|
|
}
|
|
path.CloseSubpath();
|
|
|
|
wxGraphicsMatrix matrix = gc->CreateMatrix();
|
|
matrix.Translate(p.offset, p.offset);
|
|
path.Transform(matrix);
|
|
|
|
gc->DrawPath(path);
|
|
}
|
|
|
|
// irregular dodecagon
|
|
static void DrawDodecagon(wxGraphicsContext* gc, ShapePosition p)
|
|
{
|
|
wxGraphicsPath path = gc->CreatePath();
|
|
path.MoveToPoint(p.dz, p.max);
|
|
path.AddLineToPoint(p.diag, p.diag);
|
|
path.AddLineToPoint(p.max, p.dz);
|
|
path.AddLineToPoint(p.max, -p.dz);
|
|
path.AddLineToPoint(p.diag, -p.diag);
|
|
path.AddLineToPoint(p.dz, -p.max);
|
|
path.AddLineToPoint(-p.dz, -p.max);
|
|
path.AddLineToPoint(-p.diag, -p.diag);
|
|
path.AddLineToPoint(-p.max, -p.dz);
|
|
path.AddLineToPoint(-p.max, p.dz);
|
|
path.AddLineToPoint(-p.diag, p.diag);
|
|
path.AddLineToPoint(-p.dz, p.max);
|
|
path.CloseSubpath();
|
|
|
|
wxGraphicsMatrix matrix = gc->CreateMatrix();
|
|
matrix.Translate(p.offset, p.offset);
|
|
path.Transform(matrix);
|
|
|
|
gc->DrawPath(path);
|
|
}
|
|
|
|
static void DrawCenteredRectangle(wxGraphicsContext* gc, double x, double y, double w, double h)
|
|
{
|
|
x -= w / 2;
|
|
y -= h / 2;
|
|
gc->DrawRectangle(x, y, w, h);
|
|
}
|
|
|
|
#define VIS_BITMAP_SIZE 64
|
|
|
|
#define VIS_NORMALIZE(a) ((a / 2.0) + 0.5)
|
|
#define VIS_COORD(a) ((VIS_NORMALIZE(a)) * VIS_BITMAP_SIZE)
|
|
|
|
#define COORD_VIS_SIZE 4
|
|
|
|
static void DrawCoordinate(wxGraphicsContext* gc, ControlState x, ControlState y)
|
|
{
|
|
double xc = VIS_COORD(x);
|
|
double yc = VIS_COORD(y);
|
|
DrawCenteredRectangle(gc, xc, yc, COORD_VIS_SIZE, COORD_VIS_SIZE);
|
|
}
|
|
|
|
static void DrawButton(const std::vector<unsigned int>& bitmasks, unsigned int buttons,
|
|
unsigned int n, wxGraphicsContext* gc, ControlGroupBox* g, unsigned int row,
|
|
const wxGraphicsMatrix& null_matrix)
|
|
{
|
|
if (buttons & bitmasks[(row * 8) + n])
|
|
{
|
|
gc->SetBrush(*wxRED_BRUSH);
|
|
}
|
|
else
|
|
{
|
|
unsigned char amt = 255 - g->control_group->controls[(row * 8) + n]->control_ref->State() * 128;
|
|
gc->SetBrush(wxBrush(wxColour(amt, amt, amt)));
|
|
}
|
|
gc->DrawRectangle(n * 12, (row == 0) ? 0 : (row * 11), 14, 12);
|
|
|
|
// text
|
|
const std::string name = g->control_group->controls[(row * 8) + n]->ui_name;
|
|
// Matrix transformation needs to be disabled so we don't draw scaled/zoomed text.
|
|
wxGraphicsMatrix old_matrix = gc->GetTransform();
|
|
gc->SetTransform(null_matrix);
|
|
// bit of hax so ZL, ZR show up as L, R
|
|
gc->DrawText(wxUniChar((name[1] && name[1] < 'a') ? name[1] : name[0]), (n * 12 + 2) * g->m_scale,
|
|
(1 + (row == 0 ? 0 : row * 11)) * g->m_scale);
|
|
gc->SetTransform(old_matrix);
|
|
}
|
|
|
|
static void DrawControlGroupBox(wxGraphicsContext* gc, ControlGroupBox* g)
|
|
{
|
|
wxGraphicsMatrix null_matrix = gc->GetTransform();
|
|
wxGraphicsMatrix scale_matrix = null_matrix;
|
|
scale_matrix.Scale(g->m_scale, g->m_scale);
|
|
|
|
gc->SetTransform(scale_matrix);
|
|
|
|
switch (g->control_group->type)
|
|
{
|
|
case ControllerEmu::GroupType::Tilt:
|
|
case ControllerEmu::GroupType::Stick:
|
|
case ControllerEmu::GroupType::Cursor:
|
|
{
|
|
// this is starting to be a mess combining all these in one case
|
|
|
|
ControlState x = 0, y = 0, z = 0;
|
|
|
|
switch (g->control_group->type)
|
|
{
|
|
case ControllerEmu::GroupType::Stick:
|
|
((ControllerEmu::AnalogStick*)g->control_group)->GetState(&x, &y);
|
|
break;
|
|
case ControllerEmu::GroupType::Tilt:
|
|
((ControllerEmu::Tilt*)g->control_group)->GetState(&x, &y);
|
|
break;
|
|
case ControllerEmu::GroupType::Cursor:
|
|
((ControllerEmu::Cursor*)g->control_group)->GetState(&x, &y, &z);
|
|
break;
|
|
case ControllerEmu::GroupType::Other:
|
|
case ControllerEmu::GroupType::MixedTriggers:
|
|
case ControllerEmu::GroupType::Buttons:
|
|
case ControllerEmu::GroupType::Force:
|
|
case ControllerEmu::GroupType::Extension:
|
|
case ControllerEmu::GroupType::Triggers:
|
|
case ControllerEmu::GroupType::Slider:
|
|
break;
|
|
}
|
|
|
|
// ir cursor forward movement
|
|
if (g->control_group->type == ControllerEmu::GroupType::Cursor)
|
|
{
|
|
gc->SetBrush(z ? *wxRED_BRUSH : *wxGREY_BRUSH);
|
|
wxGraphicsPath path = gc->CreatePath();
|
|
path.AddRectangle(0, 31 - z * 31, 64, 2);
|
|
gc->FillPath(path);
|
|
}
|
|
|
|
// input zone
|
|
gc->SetPen(*wxLIGHT_GREY_PEN);
|
|
if (g->control_group->type == ControllerEmu::GroupType::Stick)
|
|
{
|
|
gc->SetBrush(wxColour(0xDDDDDD)); // Light Gray
|
|
|
|
ShapePosition p;
|
|
p.box = 64;
|
|
p.offset = p.box / 2;
|
|
p.range = 256;
|
|
p.scale = p.box / p.range;
|
|
p.dz = 15 * p.scale;
|
|
bool octagon = false;
|
|
|
|
if (g->control_group->name == "Main Stick")
|
|
{
|
|
p.max = 87 * p.scale;
|
|
p.diag = 55 * p.scale;
|
|
}
|
|
else if (g->control_group->name == "C-Stick")
|
|
{
|
|
p.max = 74 * p.scale;
|
|
p.diag = 46 * p.scale;
|
|
}
|
|
else
|
|
{
|
|
p.scale = 1;
|
|
p.max = 32;
|
|
octagon = true;
|
|
}
|
|
|
|
if (octagon)
|
|
DrawOctagon(gc, p);
|
|
else
|
|
DrawDodecagon(gc, p);
|
|
}
|
|
else
|
|
{
|
|
gc->SetBrush(*wxWHITE_BRUSH);
|
|
gc->DrawRectangle(16, 16, 32, 32);
|
|
}
|
|
|
|
if (g->control_group->type != ControllerEmu::GroupType::Cursor)
|
|
{
|
|
const int deadzone_idx = g->control_group->type == ControllerEmu::GroupType::Stick ?
|
|
ControllerEmu::AnalogStick::SETTING_DEADZONE :
|
|
0;
|
|
|
|
wxGraphicsPath path = gc->CreatePath();
|
|
path.AddCircle(VIS_BITMAP_SIZE / 2, VIS_BITMAP_SIZE / 2,
|
|
g->control_group->numeric_settings[deadzone_idx]->GetValue() *
|
|
VIS_BITMAP_SIZE / 2);
|
|
gc->SetBrush(*wxLIGHT_GREY_BRUSH);
|
|
gc->FillPath(path);
|
|
}
|
|
|
|
// raw dot
|
|
ControlState xx, yy;
|
|
xx = g->control_group->controls[3]->control_ref->State();
|
|
xx -= g->control_group->controls[2]->control_ref->State();
|
|
yy = g->control_group->controls[1]->control_ref->State();
|
|
yy -= g->control_group->controls[0]->control_ref->State();
|
|
|
|
gc->SetPen(*wxTRANSPARENT_PEN);
|
|
gc->SetBrush(*wxGREY_BRUSH);
|
|
DrawCoordinate(gc, xx, yy);
|
|
|
|
// adjusted dot
|
|
if (x != 0 || y != 0)
|
|
{
|
|
gc->SetBrush(*wxRED_BRUSH);
|
|
// XXX: The adjusted values flip the Y axis to be in the format
|
|
// the Wii expects. Should this be in WiimoteEmu.cpp instead?
|
|
DrawCoordinate(gc, x, -y);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ControllerEmu::GroupType::Force:
|
|
{
|
|
ControlState raw_dot[3];
|
|
ControlState adj_dot[3];
|
|
const ControlState deadzone = g->control_group->numeric_settings[0]->GetValue();
|
|
|
|
// adjusted
|
|
((ControllerEmu::Force*)g->control_group)->GetState(adj_dot);
|
|
|
|
// raw
|
|
for (unsigned int i = 0; i < 3; ++i)
|
|
{
|
|
raw_dot[i] = (g->control_group->controls[i * 2 + 1]->control_ref->State() -
|
|
g->control_group->controls[i * 2]->control_ref->State());
|
|
}
|
|
|
|
// deadzone rect for forward/backward visual
|
|
gc->SetPen(*wxTRANSPARENT_PEN);
|
|
gc->SetBrush(*wxLIGHT_GREY_BRUSH);
|
|
int deadzone_height = deadzone * VIS_BITMAP_SIZE;
|
|
DrawCenteredRectangle(gc, 0, VIS_BITMAP_SIZE / 2, VIS_BITMAP_SIZE, deadzone_height);
|
|
|
|
#define LINE_HEIGHT 2
|
|
int line_y;
|
|
|
|
// raw forward/background line
|
|
gc->SetBrush(*wxGREY_BRUSH);
|
|
line_y = VIS_COORD(raw_dot[2]);
|
|
DrawCenteredRectangle(gc, VIS_BITMAP_SIZE / 2, line_y, VIS_BITMAP_SIZE, LINE_HEIGHT);
|
|
|
|
// adjusted forward/background line
|
|
if (adj_dot[2] != 0.0)
|
|
{
|
|
gc->SetBrush(*wxRED_BRUSH);
|
|
line_y = VIS_COORD(adj_dot[2]);
|
|
DrawCenteredRectangle(gc, VIS_BITMAP_SIZE / 2, line_y, VIS_BITMAP_SIZE, LINE_HEIGHT);
|
|
}
|
|
|
|
#define DEADZONE_RECT_SIZE 32
|
|
|
|
// empty deadzone square
|
|
gc->SetPen(*wxLIGHT_GREY_PEN);
|
|
gc->SetBrush(*wxWHITE_BRUSH);
|
|
DrawCenteredRectangle(gc, VIS_BITMAP_SIZE / 2, VIS_BITMAP_SIZE / 2, DEADZONE_RECT_SIZE,
|
|
DEADZONE_RECT_SIZE);
|
|
|
|
// deadzone square
|
|
gc->SetPen(*wxTRANSPARENT_PEN);
|
|
gc->SetBrush(*wxLIGHT_GREY_BRUSH);
|
|
int dz_size = (deadzone * DEADZONE_RECT_SIZE);
|
|
DrawCenteredRectangle(gc, VIS_BITMAP_SIZE / 2, VIS_BITMAP_SIZE / 2, dz_size, dz_size);
|
|
|
|
// raw dot
|
|
gc->SetBrush(*wxGREY_BRUSH);
|
|
DrawCoordinate(gc, raw_dot[1], raw_dot[0]);
|
|
|
|
// adjusted dot
|
|
if (adj_dot[1] != 0 && adj_dot[0] != 0)
|
|
{
|
|
gc->SetBrush(*wxRED_BRUSH);
|
|
DrawCoordinate(gc, adj_dot[1], adj_dot[0]);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ControllerEmu::GroupType::Buttons:
|
|
{
|
|
const unsigned int button_count = static_cast<unsigned int>(g->control_group->controls.size());
|
|
std::vector<unsigned int> bitmasks(button_count);
|
|
|
|
// draw the shit
|
|
gc->SetPen(*wxGREY_PEN);
|
|
|
|
for (unsigned int n = 0; n < button_count; ++n)
|
|
bitmasks[n] = (1 << n);
|
|
|
|
unsigned int buttons = 0;
|
|
((ControllerEmu::Buttons*)g->control_group)->GetState(&buttons, bitmasks.data());
|
|
|
|
// Draw buttons in rows of 8
|
|
for (unsigned int row = 0; row < ceil((float)button_count / 8.0f); row++)
|
|
{
|
|
unsigned int buttons_to_draw = 8;
|
|
if ((button_count - row * 8) <= 8)
|
|
buttons_to_draw = button_count - row * 8;
|
|
|
|
for (unsigned int n = 0; n < buttons_to_draw; ++n)
|
|
{
|
|
DrawButton(bitmasks, buttons, n, gc, g, row, null_matrix);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ControllerEmu::GroupType::Triggers:
|
|
{
|
|
const unsigned int trigger_count = static_cast<unsigned int>(g->control_group->controls.size());
|
|
std::vector<ControlState> trigs(trigger_count);
|
|
|
|
// draw the shit
|
|
gc->SetPen(*wxGREY_PEN);
|
|
|
|
ControlState deadzone = g->control_group->numeric_settings[0]->GetValue();
|
|
((ControllerEmu::Triggers*)g->control_group)->GetState(trigs.data());
|
|
|
|
for (unsigned int n = 0; n < trigger_count; ++n)
|
|
{
|
|
ControlState trig_r = g->control_group->controls[n]->control_ref->State();
|
|
|
|
// outline
|
|
gc->SetBrush(*wxWHITE_BRUSH);
|
|
gc->DrawRectangle(0, n * 12, 64, 14);
|
|
|
|
// raw
|
|
gc->SetBrush(*wxGREY_BRUSH);
|
|
gc->DrawRectangle(0, n * 12, trig_r * 64, 14);
|
|
|
|
// deadzone affected
|
|
gc->SetBrush(*wxRED_BRUSH);
|
|
gc->DrawRectangle(0, n * 12, trigs[n] * 64, 14);
|
|
|
|
// text
|
|
// We don't want the text to be scaled/zoomed
|
|
gc->SetTransform(null_matrix);
|
|
gc->DrawText(StrToWxStr(g->control_group->controls[n]->ui_name), 3 * g->m_scale,
|
|
(n * 12 + 1) * g->m_scale);
|
|
gc->SetTransform(scale_matrix);
|
|
}
|
|
|
|
// deadzone box
|
|
gc->SetPen(*wxLIGHT_GREY_PEN);
|
|
gc->SetBrush(*wxTRANSPARENT_BRUSH);
|
|
gc->DrawRectangle(0, 0, deadzone * 64, trigger_count * 14);
|
|
}
|
|
break;
|
|
|
|
case ControllerEmu::GroupType::MixedTriggers:
|
|
{
|
|
const unsigned int trigger_count = ((unsigned int)(g->control_group->controls.size() / 2));
|
|
|
|
// draw the shit
|
|
gc->SetPen(*wxGREY_PEN);
|
|
ControlState thresh = g->control_group->numeric_settings[0]->GetValue();
|
|
|
|
for (unsigned int n = 0; n < trigger_count; ++n)
|
|
{
|
|
gc->SetBrush(*wxRED_BRUSH);
|
|
|
|
ControlState trig_d = g->control_group->controls[n]->control_ref->State();
|
|
|
|
ControlState trig_a =
|
|
trig_d > thresh ? 1 : g->control_group->controls[n + trigger_count]->control_ref->State();
|
|
|
|
gc->DrawRectangle(0, n * 12, 64 + 20, 14);
|
|
if (trig_d <= thresh)
|
|
gc->SetBrush(*wxWHITE_BRUSH);
|
|
gc->DrawRectangle(trig_a * 64, n * 12, 64 + 20, 14);
|
|
gc->DrawRectangle(64, n * 12, 32, 14);
|
|
|
|
// text
|
|
// We don't want the text to be scaled/zoomed
|
|
gc->SetTransform(null_matrix);
|
|
gc->DrawText(StrToWxStr(g->control_group->controls[n + trigger_count]->ui_name),
|
|
3 * g->m_scale, (n * 12 + 1) * g->m_scale);
|
|
gc->DrawText(StrToWxStr(std::string(1, g->control_group->controls[n]->ui_name[0])),
|
|
(64 + 3) * g->m_scale, (n * 12 + 1) * g->m_scale);
|
|
gc->SetTransform(scale_matrix);
|
|
}
|
|
|
|
// threshold box
|
|
gc->SetPen(*wxLIGHT_GREY_PEN);
|
|
gc->SetBrush(*wxTRANSPARENT_BRUSH);
|
|
gc->DrawRectangle(thresh * 64, 0, 128, trigger_count * 14);
|
|
}
|
|
break;
|
|
|
|
case ControllerEmu::GroupType::Slider:
|
|
{
|
|
const ControlState deadzone = g->control_group->numeric_settings[0]->GetValue();
|
|
|
|
ControlState state = g->control_group->controls[1]->control_ref->State() -
|
|
g->control_group->controls[0]->control_ref->State();
|
|
gc->SetPen(*wxTRANSPARENT_PEN);
|
|
gc->SetBrush(*wxGREY_BRUSH);
|
|
gc->DrawRectangle(31 + state * 30, 0, 2, 14);
|
|
|
|
ControlState adj_state;
|
|
((ControllerEmu::Slider*)g->control_group)->GetState(&adj_state);
|
|
if (state)
|
|
{
|
|
gc->SetBrush(*wxRED_BRUSH);
|
|
gc->DrawRectangle(31 + adj_state * 30, 0, 2, 14);
|
|
}
|
|
|
|
// deadzone box
|
|
gc->SetPen(*wxLIGHT_GREY_PEN);
|
|
gc->SetBrush(*wxTRANSPARENT_BRUSH);
|
|
gc->DrawRectangle(32 - deadzone * 32, 0, deadzone * 64, 14);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
gc->SetTransform(null_matrix);
|
|
}
|
|
|
|
static void DrawBorder(wxGraphicsContext* gc, double scale)
|
|
{
|
|
double pen_width = std::round(scale); // Pen width = 1px * scale
|
|
|
|
// Use the window caption bar color as a safe accent color.
|
|
wxPen border_pen(wxSystemSettings::GetColour(wxSYS_COLOUR_ACTIVECAPTION),
|
|
static_cast<int>(pen_width));
|
|
border_pen.SetCap(wxCAP_PROJECTING);
|
|
|
|
double width, height;
|
|
gc->GetSize(&width, &height);
|
|
|
|
wxGraphicsPath path = gc->CreatePath();
|
|
path.AddRectangle(pen_width / 2, pen_width / 2, width - pen_width, height - pen_width);
|
|
gc->SetPen(border_pen);
|
|
gc->StrokePath(path);
|
|
}
|
|
|
|
void InputConfigDialog::UpdateBitmaps(wxTimerEvent& WXUNUSED(event))
|
|
{
|
|
wxFont small_font(6, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
|
|
const wxColour font_color{0xB8B8B8};
|
|
|
|
g_controller_interface.UpdateInput();
|
|
|
|
wxMemoryDC dc;
|
|
const auto lock = ControllerEmu::EmulatedController::GetStateLock();
|
|
for (ControlGroupBox* g : control_groups)
|
|
{
|
|
// Only if this control group has a bitmap
|
|
if (!g->static_bitmap)
|
|
continue;
|
|
|
|
wxBitmap bitmap(g->static_bitmap->GetBitmap());
|
|
// NOTE: Selecting the bitmap inherits the bitmap's ScaleFactor onto the DC as well.
|
|
dc.SelectObjectAsSource(bitmap);
|
|
dc.SetBackground(*wxWHITE_BRUSH);
|
|
dc.Clear();
|
|
|
|
#ifdef __WXGTK20__
|
|
int dc_height = 0;
|
|
dc.SetFont(small_font);
|
|
dc.GetTextExtent(g->control_group->name, nullptr, &dc_height);
|
|
#endif
|
|
|
|
std::unique_ptr<wxGraphicsContext> gc{wxGraphicsContext::Create(dc)};
|
|
gc->DisableOffset();
|
|
gc->SetFont(small_font, font_color);
|
|
|
|
#ifdef __WXGTK20__
|
|
double gc_height = 0;
|
|
gc->GetTextExtent(g->control_group->name, nullptr, &gc_height);
|
|
// On GTK2, wx creates a new empty Cairo/Pango context for the graphics context instead
|
|
// of reusing the wxMemoryDC one, this causes it to forget the screen DPI so fonts stop
|
|
// scaling, we need to scale it manually instead.
|
|
if (std::ceil(gc_height) < dc_height)
|
|
{
|
|
wxFont fixed_font(small_font);
|
|
fixed_font.SetPointSize(static_cast<int>(fixed_font.GetPointSize() * g->m_scale));
|
|
gc->SetFont(fixed_font, font_color);
|
|
}
|
|
#endif
|
|
|
|
DrawControlGroupBox(gc.get(), g);
|
|
DrawBorder(gc.get(), g->m_scale);
|
|
|
|
// label for sticks and stuff
|
|
if (g->HasBitmapHeading())
|
|
gc->DrawText(StrToWxStr(g->control_group->name).Upper(), 4 * g->m_scale, 2 * g->m_scale);
|
|
|
|
gc.reset();
|
|
dc.SelectObject(wxNullBitmap);
|
|
g->static_bitmap->SetBitmap(bitmap);
|
|
}
|
|
}
|