mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 14:19:46 -06:00
Add flexibility to InputConfigDialog
Removed the unecessary forced tabbed layout, removed the layout part of the constructor and remade some method in preparation for tabbed styled input dialog such as the new hotkey configuration one. It breaks every inputconfigDialog, but this will get fixed in the next commits. Also moved to a folder since there will be many more files created in the next commits so it gives better separation.
This commit is contained in:
1271
Source/Core/DolphinWX/Input/InputConfigDiag.cpp
Normal file
1271
Source/Core/DolphinWX/Input/InputConfigDiag.cpp
Normal file
File diff suppressed because it is too large
Load Diff
269
Source/Core/DolphinWX/Input/InputConfigDiag.h
Normal file
269
Source/Core/DolphinWX/Input/InputConfigDiag.h
Normal file
@ -0,0 +1,269 @@
|
||||
// Copyright 2010 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#define SLIDER_TICK_COUNT 100
|
||||
#define DETECT_WAIT_TIME 2500
|
||||
#define PREVIEW_UPDATE_TIME 25
|
||||
#define DEFAULT_HIGH_VALUE 100
|
||||
|
||||
// might have to change this setup for Wiimote
|
||||
#define PROFILES_PATH "Profiles/"
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <wx/button.h>
|
||||
#include <wx/dialog.h>
|
||||
#include <wx/eventfilter.h>
|
||||
#include <wx/panel.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/spinctrl.h>
|
||||
#include <wx/timer.h>
|
||||
|
||||
#include "InputCommon/ControllerEmu.h"
|
||||
#include "InputCommon/ControllerInterface/ControllerInterface.h"
|
||||
#include "InputCommon/ControllerInterface/Device.h"
|
||||
|
||||
class DolphinSlider;
|
||||
class InputConfig;
|
||||
class wxComboBox;
|
||||
class wxListBox;
|
||||
class wxStaticBitmap;
|
||||
class wxStaticText;
|
||||
class wxTextCtrl;
|
||||
|
||||
class PadSetting
|
||||
{
|
||||
protected:
|
||||
PadSetting(wxControl* const _control) : wxcontrol(_control) { wxcontrol->SetClientData(this); }
|
||||
public:
|
||||
virtual void UpdateGUI() = 0;
|
||||
virtual void UpdateValue() = 0;
|
||||
|
||||
virtual ~PadSetting() {}
|
||||
wxControl* const wxcontrol;
|
||||
};
|
||||
|
||||
class PadSettingExtension : public PadSetting
|
||||
{
|
||||
public:
|
||||
PadSettingExtension(wxWindow* const parent, ControllerEmu::Extension* const ext);
|
||||
void UpdateGUI() override;
|
||||
void UpdateValue() override;
|
||||
|
||||
ControllerEmu::Extension* const extension;
|
||||
};
|
||||
|
||||
class PadSettingSpin : public PadSetting
|
||||
{
|
||||
public:
|
||||
PadSettingSpin(wxWindow* const parent,
|
||||
ControllerEmu::ControlGroup::NumericSetting* const setting);
|
||||
void UpdateGUI() override;
|
||||
void UpdateValue() override;
|
||||
|
||||
ControllerEmu::ControlGroup::NumericSetting* const setting;
|
||||
};
|
||||
|
||||
class PadSettingCheckBox : public PadSetting
|
||||
{
|
||||
public:
|
||||
PadSettingCheckBox(wxWindow* const parent,
|
||||
ControllerEmu::ControlGroup::BooleanSetting* const setting);
|
||||
void UpdateGUI() override;
|
||||
void UpdateValue() override;
|
||||
|
||||
ControllerEmu::ControlGroup::BooleanSetting* const setting;
|
||||
};
|
||||
|
||||
class InputEventFilter : public wxEventFilter
|
||||
{
|
||||
public:
|
||||
InputEventFilter() { wxEvtHandler::AddFilter(this); }
|
||||
~InputEventFilter() { wxEvtHandler::RemoveFilter(this); }
|
||||
int FilterEvent(wxEvent& event) override;
|
||||
|
||||
void BlockEvents(bool block) { m_block = block; }
|
||||
private:
|
||||
static bool ShouldCatchEventType(wxEventType type)
|
||||
{
|
||||
return type == wxEVT_KEY_DOWN || type == wxEVT_KEY_UP || type == wxEVT_CHAR ||
|
||||
type == wxEVT_CHAR_HOOK || type == wxEVT_LEFT_DOWN || type == wxEVT_LEFT_UP ||
|
||||
type == wxEVT_MIDDLE_DOWN || type == wxEVT_MIDDLE_UP || type == wxEVT_RIGHT_DOWN ||
|
||||
type == wxEVT_RIGHT_UP;
|
||||
}
|
||||
|
||||
bool m_block = false;
|
||||
};
|
||||
|
||||
class InputConfigDialog;
|
||||
|
||||
class ControlDialog : public wxDialog
|
||||
{
|
||||
public:
|
||||
ControlDialog(InputConfigDialog* const parent, InputConfig& config,
|
||||
ControllerInterface::ControlReference* const ref);
|
||||
|
||||
bool Validate() override;
|
||||
|
||||
int GetRangeSliderValue() const;
|
||||
|
||||
ControllerInterface::ControlReference* const control_reference;
|
||||
InputConfig& m_config;
|
||||
|
||||
private:
|
||||
wxStaticBoxSizer* CreateControlChooser(InputConfigDialog* parent);
|
||||
|
||||
void UpdateGUI();
|
||||
void UpdateListContents();
|
||||
void SelectControl(const std::string& name);
|
||||
|
||||
void DetectControl(wxCommandEvent& event);
|
||||
void ClearControl(wxCommandEvent& event);
|
||||
void SetDevice(wxCommandEvent& event);
|
||||
|
||||
void SetSelectedControl(wxCommandEvent& event);
|
||||
void AppendControl(wxCommandEvent& event);
|
||||
void OnRangeSlide(wxScrollEvent&);
|
||||
void OnRangeSpin(wxSpinEvent&);
|
||||
void OnRangeThumbtrack(wxScrollEvent&);
|
||||
|
||||
bool GetExpressionForSelectedControl(wxString& expr);
|
||||
|
||||
InputConfigDialog* m_parent;
|
||||
wxComboBox* device_cbox;
|
||||
wxTextCtrl* textctrl;
|
||||
wxListBox* control_lbox;
|
||||
DolphinSlider* m_range_slider;
|
||||
wxSpinCtrl* m_range_spinner;
|
||||
wxStaticText* m_bound_label;
|
||||
wxStaticText* m_error_label;
|
||||
InputEventFilter m_event_filter;
|
||||
ciface::Core::DeviceQualifier m_devq;
|
||||
};
|
||||
|
||||
class ExtensionButton : public wxButton
|
||||
{
|
||||
public:
|
||||
ExtensionButton(wxWindow* const parent, ControllerEmu::Extension* const ext)
|
||||
: wxButton(parent, wxID_ANY, _("Configure"), wxDefaultPosition), extension(ext)
|
||||
{
|
||||
}
|
||||
|
||||
ControllerEmu::Extension* const extension;
|
||||
};
|
||||
|
||||
class ControlButton : public wxButton
|
||||
{
|
||||
public:
|
||||
ControlButton(wxWindow* const parent, ControllerInterface::ControlReference* const _ref,
|
||||
const std::string& name, const unsigned int width, const std::string& label = {});
|
||||
|
||||
ControllerInterface::ControlReference* const control_reference;
|
||||
const std::string m_name;
|
||||
|
||||
protected:
|
||||
wxSize DoGetBestSize() const override;
|
||||
|
||||
int m_configured_width = wxDefaultCoord;
|
||||
};
|
||||
|
||||
class ControlGroupBox : public wxStaticBoxSizer
|
||||
{
|
||||
public:
|
||||
ControlGroupBox(ControllerEmu::ControlGroup* const group, wxWindow* const parent,
|
||||
InputConfigDialog* eventsink);
|
||||
~ControlGroupBox();
|
||||
|
||||
bool HasBitmapHeading() const
|
||||
{
|
||||
return control_group->type == GROUP_TYPE_STICK || control_group->type == GROUP_TYPE_TILT ||
|
||||
control_group->type == GROUP_TYPE_CURSOR || control_group->type == GROUP_TYPE_FORCE;
|
||||
}
|
||||
|
||||
std::vector<PadSetting*> options;
|
||||
|
||||
ControllerEmu::ControlGroup* const control_group;
|
||||
wxStaticBitmap* static_bitmap;
|
||||
std::vector<ControlButton*> control_buttons;
|
||||
double m_scale;
|
||||
};
|
||||
|
||||
class ControlGroupsSizer : public wxBoxSizer
|
||||
{
|
||||
public:
|
||||
ControlGroupsSizer(ControllerEmu* const controller, InputConfigDialog* const parent,
|
||||
std::vector<ControlGroupBox*>* const groups = nullptr);
|
||||
};
|
||||
|
||||
class InputConfigDialog : public wxDialog
|
||||
{
|
||||
public:
|
||||
InputConfigDialog(wxWindow* const parent, InputConfig& config, const wxString& name,
|
||||
const int port_num = 0);
|
||||
virtual ~InputConfigDialog() = default;
|
||||
|
||||
void OnClose(wxCloseEvent& event);
|
||||
void OnCloseButton(wxCommandEvent& event);
|
||||
|
||||
void UpdateDeviceComboBox();
|
||||
void UpdateProfileComboBox();
|
||||
|
||||
void UpdateControlReferences();
|
||||
void UpdateBitmaps(wxTimerEvent&);
|
||||
|
||||
void UpdateGUI();
|
||||
|
||||
void RefreshDevices(wxCommandEvent& event);
|
||||
|
||||
void LoadProfile(wxCommandEvent& event);
|
||||
void SaveProfile(wxCommandEvent& event);
|
||||
void DeleteProfile(wxCommandEvent& event);
|
||||
|
||||
void ConfigControl(wxEvent& event);
|
||||
void ClearControl(wxEvent& event);
|
||||
void DetectControl(wxCommandEvent& event);
|
||||
|
||||
void ConfigExtension(wxCommandEvent& event);
|
||||
|
||||
void SetDevice(wxCommandEvent& event);
|
||||
|
||||
void ClearAll(wxCommandEvent& event);
|
||||
void LoadDefaults(wxCommandEvent& event);
|
||||
|
||||
void AdjustControlOption(wxCommandEvent& event);
|
||||
void EnablePadSetting(const std::string& group_name, const std::string& name, bool enabled);
|
||||
void EnableControlButton(const std::string& group_name, const std::string& name, bool enabled);
|
||||
void AdjustSetting(wxCommandEvent& event);
|
||||
void AdjustBooleanSetting(wxCommandEvent& event);
|
||||
|
||||
void GetProfilePath(std::string& path);
|
||||
ControllerEmu* GetController() const;
|
||||
|
||||
wxComboBox* profile_cbox = nullptr;
|
||||
wxComboBox* device_cbox = nullptr;
|
||||
|
||||
std::vector<ControlGroupBox*> control_groups;
|
||||
std::vector<ControlButton*> control_buttons;
|
||||
|
||||
protected:
|
||||
wxBoxSizer* CreateDeviceChooserGroupBox();
|
||||
wxBoxSizer* CreaterResetGroupBox(wxOrientation orientation);
|
||||
wxBoxSizer* CreateProfileChooserGroupBox();
|
||||
|
||||
ControllerEmu* const controller;
|
||||
|
||||
wxTimer m_update_timer;
|
||||
|
||||
private:
|
||||
InputConfig& m_config;
|
||||
int m_port_num;
|
||||
ControlDialog* m_control_dialog;
|
||||
InputEventFilter m_event_filter;
|
||||
|
||||
bool DetectButton(ControlButton* button);
|
||||
bool m_iterate = false;
|
||||
};
|
539
Source/Core/DolphinWX/Input/InputConfigDiagBitmaps.cpp
Normal file
539
Source/Core/DolphinWX/Input/InputConfigDiagBitmaps.cpp
Normal file
@ -0,0 +1,539 @@
|
||||
// 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.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]->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 GROUP_TYPE_TILT:
|
||||
case GROUP_TYPE_STICK:
|
||||
case GROUP_TYPE_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 GROUP_TYPE_STICK:
|
||||
((ControllerEmu::AnalogStick*)g->control_group)->GetState(&x, &y);
|
||||
break;
|
||||
case GROUP_TYPE_TILT:
|
||||
((ControllerEmu::Tilt*)g->control_group)->GetState(&x, &y);
|
||||
break;
|
||||
case GROUP_TYPE_CURSOR:
|
||||
((ControllerEmu::Cursor*)g->control_group)->GetState(&x, &y, &z);
|
||||
break;
|
||||
}
|
||||
|
||||
// ir cursor forward movement
|
||||
if (GROUP_TYPE_CURSOR == g->control_group->type)
|
||||
{
|
||||
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 (GROUP_TYPE_STICK == g->control_group->type)
|
||||
{
|
||||
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 (GROUP_TYPE_CURSOR != g->control_group->type)
|
||||
{
|
||||
int deadzone_idx = g->control_group->type == GROUP_TYPE_STICK ? 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 GROUP_TYPE_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 GROUP_TYPE_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 GROUP_TYPE_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]->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 GROUP_TYPE_MIXED_TRIGGERS:
|
||||
{
|
||||
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]->name), 3 * g->m_scale,
|
||||
(n * 12 + 1) * g->m_scale);
|
||||
gc->DrawText(StrToWxStr(std::string(1, g->control_group->controls[n]->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 GROUP_TYPE_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;
|
||||
auto lock = ControllerEmu::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);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user