mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-07-06 03:44:30 -04:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 27274e7341 | |||
| ce0d89058a | |||
| 36092f1fdb | |||
| 5eb3184174 |
Vendored
+1
-1
Submodule extern/aurora updated: 77ad549530...41d5c9c5a2
@@ -1469,8 +1469,6 @@ set(DUSK_FILES
|
|||||||
src/dusk/ui/button.hpp
|
src/dusk/ui/button.hpp
|
||||||
src/dusk/ui/component.cpp
|
src/dusk/ui/component.cpp
|
||||||
src/dusk/ui/component.hpp
|
src/dusk/ui/component.hpp
|
||||||
src/dusk/ui/controller_config.cpp
|
|
||||||
src/dusk/ui/controller_config.hpp
|
|
||||||
src/dusk/ui/document.cpp
|
src/dusk/ui/document.cpp
|
||||||
src/dusk/ui/document.hpp
|
src/dusk/ui/document.hpp
|
||||||
src/dusk/ui/editor.cpp
|
src/dusk/ui/editor.cpp
|
||||||
|
|||||||
@@ -25,10 +25,6 @@ public:
|
|||||||
int Draw();
|
int Draw();
|
||||||
int Delete();
|
int Delete();
|
||||||
|
|
||||||
#if TARGET_PC
|
|
||||||
void onInterpCallback();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
enum Param_e {
|
enum Param_e {
|
||||||
LOCK_e = (1 << 6), NO_BASE_DISP = (1 << 7)
|
LOCK_e = (1 << 6), NO_BASE_DISP = (1 << 7)
|
||||||
};
|
};
|
||||||
@@ -54,13 +50,6 @@ private:
|
|||||||
/* 0x1020 */ dCcD_Cyl mCylinderCollider;
|
/* 0x1020 */ dCcD_Cyl mCylinderCollider;
|
||||||
/* 0x115C */ s32 mStopSwingingFrames;
|
/* 0x115C */ s32 mStopSwingingFrames;
|
||||||
|
|
||||||
#if TARGET_PC
|
|
||||||
cXyz mChainInterpPrev[64];
|
|
||||||
cXyz mChainInterpCurr[64];
|
|
||||||
bool mChainInterpPrevValid;
|
|
||||||
bool mChainInterpCurrValid;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Number of chain models
|
// Number of chain models
|
||||||
u32 getArg0() {
|
u32 getArg0() {
|
||||||
return fopAcM_GetParamBit(this, 0, 6);
|
return fopAcM_GetParamBit(this, 0, 6);
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ struct UserSettings {
|
|||||||
ConfigVar<bool> disableRupeeCutscenes;
|
ConfigVar<bool> disableRupeeCutscenes;
|
||||||
ConfigVar<bool> noSwordRecoil;
|
ConfigVar<bool> noSwordRecoil;
|
||||||
ConfigVar<int> damageMultiplier;
|
ConfigVar<int> damageMultiplier;
|
||||||
|
ConfigVar<bool> hyperEnemies;
|
||||||
ConfigVar<bool> noHeartDrops;
|
ConfigVar<bool> noHeartDrops;
|
||||||
ConfigVar<bool> instantDeath;
|
ConfigVar<bool> instantDeath;
|
||||||
ConfigVar<bool> fastClimbing;
|
ConfigVar<bool> fastClimbing;
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -1,21 +1,10 @@
|
|||||||
tab-bar {
|
tab-bar {
|
||||||
display: flex;
|
display: flex;
|
||||||
position: relative;
|
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
overflow: auto hidden;
|
overflow: auto hidden;
|
||||||
clip: always;
|
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
tab-bar scrollbarhorizontal,
|
|
||||||
tab-bar scrollbarhorizontal sliderarrowdec,
|
|
||||||
tab-bar scrollbarhorizontal sliderarrowinc,
|
|
||||||
tab-bar scrollbarhorizontal slidertrack,
|
|
||||||
tab-bar scrollbarhorizontal sliderbar {
|
|
||||||
width: 0;
|
|
||||||
height: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
tab-bar tab {
|
tab-bar tab {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
padding: 0 24dp;
|
padding: 0 24dp;
|
||||||
@@ -42,42 +31,3 @@ tab-bar tab:hover {
|
|||||||
tab-bar tab:active {
|
tab-bar tab:active {
|
||||||
decorator: vertical-gradient(#c2a42d10 #c2a42d40);
|
decorator: vertical-gradient(#c2a42d10 #c2a42d40);
|
||||||
}
|
}
|
||||||
|
|
||||||
tab-bar[closable] tab-end-spacer {
|
|
||||||
display: block;
|
|
||||||
flex: 0 0 64dp;
|
|
||||||
width: 64dp;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
tab-bar[closable] close {
|
|
||||||
display: block;
|
|
||||||
position: fixed;
|
|
||||||
top: 8dp;
|
|
||||||
right: 8dp;
|
|
||||||
z-index: 1;
|
|
||||||
width: 48dp;
|
|
||||||
height: 48dp;
|
|
||||||
font-family: "Material Symbols Rounded";
|
|
||||||
font-weight: normal;
|
|
||||||
font-size: 24dp;
|
|
||||||
line-height: 48dp;
|
|
||||||
text-align: center;
|
|
||||||
text-transform: none;
|
|
||||||
color: rgba(224, 219, 200, 70%);
|
|
||||||
backdrop-filter: blur(2dp);
|
|
||||||
border-radius: 6dp;
|
|
||||||
transition: color background-color 0.12s linear-in-out;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
tab-bar[closable] close:hover,
|
|
||||||
tab-bar[closable] close:focus-visible {
|
|
||||||
color: #fff;
|
|
||||||
background-color: rgba(194, 164, 45, 24%);
|
|
||||||
}
|
|
||||||
|
|
||||||
tab-bar[closable] close:active {
|
|
||||||
color: #fff;
|
|
||||||
background-color: rgba(194, 164, 45, 40%);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -233,10 +233,6 @@ select-button value {
|
|||||||
font-size: 20dp;
|
font-size: 20dp;
|
||||||
}
|
}
|
||||||
|
|
||||||
select-button value.modified {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
select-button input {
|
select-button input {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
font-size: 20dp;
|
font-size: 20dp;
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
#include "d/actor/d_a_obj_automata.h"
|
#include "d/actor/d_a_obj_automata.h"
|
||||||
#include "d/d_msg_object.h"
|
#include "d/d_msg_object.h"
|
||||||
#include "d/actor/d_a_obj_scannon.h"
|
#include "d/actor/d_a_obj_scannon.h"
|
||||||
#include "dusk/frame_interpolation.h"
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
const daNpc_Toby_HIOParam daNpc_Toby_Param_c::m = {
|
const daNpc_Toby_HIOParam daNpc_Toby_Param_c::m = {
|
||||||
@@ -1399,7 +1398,6 @@ int daNpc_Toby_c::cutRepairSCannon(int arg0) {
|
|||||||
old.pos = current.pos;
|
old.pos = current.pos;
|
||||||
setAngle(cM_deg2s(5.0f * f32(mPath.getArg0())));
|
setAngle(cM_deg2s(5.0f * f32(mPath.getArg0())));
|
||||||
mEventTimer = mPath.getArg2();
|
mEventTimer = mPath.getArg2();
|
||||||
dusk::frame_interp::request_presentation_sync();
|
|
||||||
}
|
}
|
||||||
} else if (!mHide) {
|
} else if (!mHide) {
|
||||||
mHide = 1;
|
mHide = 1;
|
||||||
|
|||||||
@@ -11,8 +11,6 @@
|
|||||||
#include "d/d_bg_w.h"
|
#include "d/d_bg_w.h"
|
||||||
#include "d/d_cc_uty.h"
|
#include "d/d_cc_uty.h"
|
||||||
#include "d/d_com_inf_game.h"
|
#include "d/d_com_inf_game.h"
|
||||||
#include "dusk/frame_interpolation.h"
|
|
||||||
#include "dusk/settings.h"
|
|
||||||
|
|
||||||
struct daObjKLift00_HIO_c : public mDoHIO_entry_c {
|
struct daObjKLift00_HIO_c : public mDoHIO_entry_c {
|
||||||
daObjKLift00_HIO_c();
|
daObjKLift00_HIO_c();
|
||||||
@@ -297,11 +295,6 @@ int daObjKLift00_c::Create() {
|
|||||||
if(getLock())
|
if(getLock())
|
||||||
mStopSwingingFrames = 5;
|
mStopSwingingFrames = 5;
|
||||||
|
|
||||||
#if TARGET_PC
|
|
||||||
mChainInterpPrevValid = false;
|
|
||||||
mChainInterpCurrValid = false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -443,34 +436,6 @@ int daObjKLift00_c::Execute(Mtx** i_mtx) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if TARGET_PC
|
|
||||||
static void klift00_interp_callback(bool isSimFrame, void* pUserWork) {
|
|
||||||
static_cast<daObjKLift00_c*>(pUserWork)->onInterpCallback();
|
|
||||||
}
|
|
||||||
|
|
||||||
void daObjKLift00_c::onInterpCallback() {
|
|
||||||
if (!mChainInterpPrevValid || !mChainInterpCurrValid) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const f32 alpha = dusk::frame_interp::get_interpolation_step();
|
|
||||||
cXyz savedPositions[64];
|
|
||||||
|
|
||||||
for (int i = 0; i < mNumChains; i++) {
|
|
||||||
savedPositions[i] = mChainPositions[i].mCurrentPos;
|
|
||||||
const cXyz& p0 = mChainInterpPrev[i];
|
|
||||||
const cXyz& p1 = mChainInterpCurr[i];
|
|
||||||
mChainPositions[i].mCurrentPos = p0 + (p1 - p0) * alpha;
|
|
||||||
}
|
|
||||||
|
|
||||||
setMtx();
|
|
||||||
|
|
||||||
for (int i = 0; i < mNumChains; i++) {
|
|
||||||
mChainPositions[i].mCurrentPos = savedPositions[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int daObjKLift00_c::Draw() {
|
int daObjKLift00_c::Draw() {
|
||||||
g_env_light.settingTevStruct(16, ¤t.pos, &tevStr);
|
g_env_light.settingTevStruct(16, ¤t.pos, &tevStr);
|
||||||
g_env_light.setLightTevColorType_MAJI(mpLiftPlatform, &tevStr);
|
g_env_light.setLightTevColorType_MAJI(mpLiftPlatform, &tevStr);
|
||||||
@@ -492,22 +457,6 @@ int daObjKLift00_c::Draw() {
|
|||||||
|
|
||||||
dComIfGd_setList();
|
dComIfGd_setList();
|
||||||
|
|
||||||
#if TARGET_PC
|
|
||||||
if (dusk::getSettings().game.enableFrameInterpolation) {
|
|
||||||
if (mChainInterpCurrValid) {
|
|
||||||
memcpy(mChainInterpPrev, mChainInterpCurr, mNumChains * sizeof(cXyz));
|
|
||||||
mChainInterpPrevValid = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < mNumChains; i++) {
|
|
||||||
mChainInterpCurr[i] = mChainPositions[i].mCurrentPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
mChainInterpCurrValid = true;
|
|
||||||
dusk::frame_interp::add_interpolation_callback(&klift00_interp_callback, this);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-31
@@ -1,5 +1,3 @@
|
|||||||
#include <memory>
|
|
||||||
|
|
||||||
#include "aurora/lib/logging.hpp"
|
#include "aurora/lib/logging.hpp"
|
||||||
#include "os_report.h"
|
#include "os_report.h"
|
||||||
|
|
||||||
@@ -23,35 +21,10 @@ static bool checkEnabled() {
|
|||||||
|
|
||||||
static std::string FormatToString(const char* msg, va_list list) {
|
static std::string FormatToString(const char* msg, va_list list) {
|
||||||
int ret = vsnprintf(nullptr, 0, msg, list);
|
int ret = vsnprintf(nullptr, 0, msg, list);
|
||||||
if (ret <= 0) {
|
std::string buf(ret, '\0');
|
||||||
return {};
|
vsnprintf(buf.data(), buf.size(), msg, list);
|
||||||
}
|
buf.pop_back();
|
||||||
++ret;
|
return buf;
|
||||||
std::unique_ptr<char[]> buf(new char[ret]);
|
|
||||||
vsnprintf(buf.get(), ret, msg, list);
|
|
||||||
buf[ret - 1] = '\0';
|
|
||||||
return {buf.get()};
|
|
||||||
}
|
|
||||||
|
|
||||||
void OSReport(const char* fmt, ...) {
|
|
||||||
if (!checkEnabled()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
va_list args;
|
|
||||||
va_start(args, fmt);
|
|
||||||
const auto str = FormatToString(fmt, args);
|
|
||||||
va_end(args);
|
|
||||||
|
|
||||||
Log.info("{}", str);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OSPanic(const char* file, int line, const char* fmt, ...) {
|
|
||||||
va_list args;
|
|
||||||
va_start(args, fmt);
|
|
||||||
const auto str = FormatToString(fmt, args);
|
|
||||||
va_end(args);
|
|
||||||
|
|
||||||
Log.fatal("[{}:{}] {}", file, line, str);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OSReport_Error(const char* fmt, ...) {
|
void OSReport_Error(const char* fmt, ...) {
|
||||||
|
|||||||
@@ -320,6 +320,10 @@ namespace dusk {
|
|||||||
ImGuiMenuGame::ToggleFullscreen();
|
ImGuiMenuGame::ToggleFullscreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ImGui::IsKeyPressed(ImGuiKey_Escape) && getSettings().video.enableFullscreen) {
|
||||||
|
ImGuiMenuGame::ToggleFullscreen();
|
||||||
|
}
|
||||||
|
|
||||||
// if (!dusk::IsGameLaunched) {
|
// if (!dusk::IsGameLaunched) {
|
||||||
// m_preLaunchWindow.draw();
|
// m_preLaunchWindow.draw();
|
||||||
// }
|
// }
|
||||||
|
|||||||
@@ -583,6 +583,7 @@ namespace dusk {
|
|||||||
getSettings().game.damageMultiplier.setValue(1);
|
getSettings().game.damageMultiplier.setValue(1);
|
||||||
getSettings().game.instantDeath.setValue(false);
|
getSettings().game.instantDeath.setValue(false);
|
||||||
getSettings().game.noHeartDrops.setValue(false);
|
getSettings().game.noHeartDrops.setValue(false);
|
||||||
|
getSettings().game.hyperEnemies.setValue(false);
|
||||||
|
|
||||||
getSettings().game.infiniteHearts.setValue(false);
|
getSettings().game.infiniteHearts.setValue(false);
|
||||||
getSettings().game.infiniteArrows.setValue(false);
|
getSettings().game.infiniteArrows.setValue(false);
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ UserSettings g_userSettings = {
|
|||||||
.disableRupeeCutscenes {"game.disableRupeeCutscenes", false},
|
.disableRupeeCutscenes {"game.disableRupeeCutscenes", false},
|
||||||
.noSwordRecoil {"game.noSwordRecoil", false},
|
.noSwordRecoil {"game.noSwordRecoil", false},
|
||||||
.damageMultiplier {"game.damageMultiplier", 1},
|
.damageMultiplier {"game.damageMultiplier", 1},
|
||||||
|
.hyperEnemies {"game.hyperEnemies", false},
|
||||||
.noHeartDrops {"game.noHeartDrops", false},
|
.noHeartDrops {"game.noHeartDrops", false},
|
||||||
.instantDeath {"game.instantDeath", false},
|
.instantDeath {"game.instantDeath", false},
|
||||||
.fastClimbing {"game.fastClimbing", false},
|
.fastClimbing {"game.fastClimbing", false},
|
||||||
@@ -147,6 +148,7 @@ void registerSettings() {
|
|||||||
Register(g_userSettings.game.disableRupeeCutscenes);
|
Register(g_userSettings.game.disableRupeeCutscenes);
|
||||||
Register(g_userSettings.game.noSwordRecoil);
|
Register(g_userSettings.game.noSwordRecoil);
|
||||||
Register(g_userSettings.game.damageMultiplier);
|
Register(g_userSettings.game.damageMultiplier);
|
||||||
|
Register(g_userSettings.game.hyperEnemies);
|
||||||
Register(g_userSettings.game.noHeartDrops);
|
Register(g_userSettings.game.noHeartDrops);
|
||||||
Register(g_userSettings.game.instantDeath);
|
Register(g_userSettings.game.instantDeath);
|
||||||
Register(g_userSettings.game.fastClimbing);
|
Register(g_userSettings.game.fastClimbing);
|
||||||
|
|||||||
@@ -5,14 +5,7 @@ namespace dusk::ui {
|
|||||||
BoolButton::BoolButton(Rml::Element* parent, Props props)
|
BoolButton::BoolButton(Rml::Element* parent, Props props)
|
||||||
: BaseControlledSelectButton(parent, {std::move(props.key)}),
|
: BaseControlledSelectButton(parent, {std::move(props.key)}),
|
||||||
mGetValue(std::move(props.getValue)), mSetValue(std::move(props.setValue)),
|
mGetValue(std::move(props.getValue)), mSetValue(std::move(props.setValue)),
|
||||||
mIsDisabled(std::move(props.isDisabled)), mIsModified(std::move(props.isModified)) {}
|
mIsDisabled(std::move(props.isDisabled)) {}
|
||||||
|
|
||||||
bool BoolButton::modified() const {
|
|
||||||
if (mIsModified) {
|
|
||||||
return mIsModified();
|
|
||||||
}
|
|
||||||
return BaseControlledSelectButton::modified();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BoolButton::disabled() const {
|
bool BoolButton::disabled() const {
|
||||||
if (mIsDisabled) {
|
if (mIsDisabled) {
|
||||||
|
|||||||
@@ -10,12 +10,10 @@ public:
|
|||||||
std::function<bool()> getValue;
|
std::function<bool()> getValue;
|
||||||
std::function<void(bool)> setValue;
|
std::function<void(bool)> setValue;
|
||||||
std::function<bool()> isDisabled;
|
std::function<bool()> isDisabled;
|
||||||
std::function<bool()> isModified;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
BoolButton(Rml::Element* parent, Props props);
|
BoolButton(Rml::Element* parent, Props props);
|
||||||
|
|
||||||
bool modified() const override;
|
|
||||||
bool disabled() const override;
|
bool disabled() const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -26,7 +24,6 @@ private:
|
|||||||
std::function<int()> mGetValue;
|
std::function<int()> mGetValue;
|
||||||
std::function<void(int)> mSetValue;
|
std::function<void(int)> mSetValue;
|
||||||
std::function<bool()> mIsDisabled;
|
std::function<bool()> mIsDisabled;
|
||||||
std::function<bool()> mIsModified;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dusk::ui
|
} // namespace dusk::ui
|
||||||
|
|||||||
@@ -1,642 +0,0 @@
|
|||||||
#include "controller_config.hpp"
|
|
||||||
|
|
||||||
#include "bool_button.hpp"
|
|
||||||
#include "button.hpp"
|
|
||||||
#include "pane.hpp"
|
|
||||||
#include "select_button.hpp"
|
|
||||||
|
|
||||||
#include <SDL3/SDL_gamepad.h>
|
|
||||||
#include <SDL3/SDL_keyboard.h>
|
|
||||||
#include <fmt/format.h>
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <string>
|
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace dusk::ui {
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
Rml::String current_controller_name(int port) {
|
|
||||||
const char* name = PADGetName(port);
|
|
||||||
return name == nullptr ? "None" : name;
|
|
||||||
}
|
|
||||||
|
|
||||||
Rml::String controller_index_name(u32 index) {
|
|
||||||
const char* name = PADGetNameForControllerIndex(index);
|
|
||||||
if (name == nullptr) {
|
|
||||||
return fmt::format("Controller {}", index + 1);
|
|
||||||
}
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_Gamepad* gamepad_for_port(int port) {
|
|
||||||
const s32 index = PADGetIndexForPort(port);
|
|
||||||
if (index < 0) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return PADGetSDLGamepadForIndex(static_cast<u32>(index));
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SpecificButtonName {
|
|
||||||
SDL_GamepadType type;
|
|
||||||
const char* name;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ButtonNames {
|
|
||||||
SDL_GamepadButton button;
|
|
||||||
std::vector<SpecificButtonName> names;
|
|
||||||
};
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
const std::vector<ButtonNames> kGamepadButtonNames = {
|
|
||||||
{ SDL_GAMEPAD_BUTTON_LEFT_STICK, {
|
|
||||||
{SDL_GAMEPAD_TYPE_PS3, "L3"},
|
|
||||||
{SDL_GAMEPAD_TYPE_PS4, "L3"},
|
|
||||||
{SDL_GAMEPAD_TYPE_PS5, "L3"},
|
|
||||||
{SDL_GAMEPAD_TYPE_XBOX360, "Left Stick"},
|
|
||||||
{SDL_GAMEPAD_TYPE_XBOXONE, "Left Stick"},
|
|
||||||
{SDL_GAMEPAD_TYPE_GAMECUBE, "Control Stick"},
|
|
||||||
}},
|
|
||||||
{ SDL_GAMEPAD_BUTTON_RIGHT_STICK, {
|
|
||||||
{SDL_GAMEPAD_TYPE_PS3, "R3"},
|
|
||||||
{SDL_GAMEPAD_TYPE_PS4, "R3"},
|
|
||||||
{SDL_GAMEPAD_TYPE_PS5, "R3"},
|
|
||||||
{SDL_GAMEPAD_TYPE_XBOX360, "Right Stick"},
|
|
||||||
{SDL_GAMEPAD_TYPE_XBOXONE, "Right Stick"},
|
|
||||||
{SDL_GAMEPAD_TYPE_GAMECUBE, "C Stick"},
|
|
||||||
}},
|
|
||||||
{ SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, {
|
|
||||||
{SDL_GAMEPAD_TYPE_PS3, "L1"},
|
|
||||||
{SDL_GAMEPAD_TYPE_PS4, "L1"},
|
|
||||||
{SDL_GAMEPAD_TYPE_PS5, "L1"},
|
|
||||||
{SDL_GAMEPAD_TYPE_XBOX360, "LB"},
|
|
||||||
{SDL_GAMEPAD_TYPE_XBOXONE, "LB"},
|
|
||||||
}},
|
|
||||||
{ SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, {
|
|
||||||
{SDL_GAMEPAD_TYPE_PS3, "R1"},
|
|
||||||
{SDL_GAMEPAD_TYPE_PS4, "R1"},
|
|
||||||
{SDL_GAMEPAD_TYPE_PS5, "R1"},
|
|
||||||
{SDL_GAMEPAD_TYPE_XBOX360, "RB"},
|
|
||||||
{SDL_GAMEPAD_TYPE_XBOXONE, "RB"},
|
|
||||||
{SDL_GAMEPAD_TYPE_GAMECUBE, "Z"},
|
|
||||||
}},
|
|
||||||
{ SDL_GAMEPAD_BUTTON_BACK, {
|
|
||||||
{SDL_GAMEPAD_TYPE_PS3, "Select"},
|
|
||||||
{SDL_GAMEPAD_TYPE_PS4, "Share"},
|
|
||||||
{SDL_GAMEPAD_TYPE_PS5, "Create"},
|
|
||||||
{SDL_GAMEPAD_TYPE_XBOX360, "Back"},
|
|
||||||
{SDL_GAMEPAD_TYPE_XBOXONE, "View"},
|
|
||||||
}},
|
|
||||||
{ SDL_GAMEPAD_BUTTON_START, {
|
|
||||||
{SDL_GAMEPAD_TYPE_PS3, "Start"},
|
|
||||||
{SDL_GAMEPAD_TYPE_PS4, "Options"},
|
|
||||||
{SDL_GAMEPAD_TYPE_PS5, "Options"},
|
|
||||||
{SDL_GAMEPAD_TYPE_XBOX360, "Start"},
|
|
||||||
{SDL_GAMEPAD_TYPE_XBOXONE, "Menu"},
|
|
||||||
{SDL_GAMEPAD_TYPE_GAMECUBE, "Start/Pause"},
|
|
||||||
}},
|
|
||||||
};
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
Rml::String native_button_name(SDL_Gamepad* gamepad, u32 buttonUntyped) {
|
|
||||||
if (buttonUntyped == PAD_NATIVE_BUTTON_INVALID) {
|
|
||||||
return "Not bound";
|
|
||||||
}
|
|
||||||
|
|
||||||
auto button = static_cast<SDL_GamepadButton>(buttonUntyped);
|
|
||||||
if (gamepad != nullptr) {
|
|
||||||
switch (SDL_GetGamepadButtonLabel(gamepad, button)) {
|
|
||||||
case SDL_GAMEPAD_BUTTON_LABEL_A:
|
|
||||||
return "A";
|
|
||||||
case SDL_GAMEPAD_BUTTON_LABEL_B:
|
|
||||||
return "B";
|
|
||||||
case SDL_GAMEPAD_BUTTON_LABEL_X:
|
|
||||||
return "X";
|
|
||||||
case SDL_GAMEPAD_BUTTON_LABEL_Y:
|
|
||||||
return "Y";
|
|
||||||
case SDL_GAMEPAD_BUTTON_LABEL_CROSS:
|
|
||||||
return "Cross";
|
|
||||||
case SDL_GAMEPAD_BUTTON_LABEL_CIRCLE:
|
|
||||||
return "Circle";
|
|
||||||
case SDL_GAMEPAD_BUTTON_LABEL_TRIANGLE:
|
|
||||||
return "Triangle";
|
|
||||||
case SDL_GAMEPAD_BUTTON_LABEL_SQUARE:
|
|
||||||
return "Square";
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const SDL_GamepadType type =
|
|
||||||
gamepad != nullptr ? SDL_GetGamepadType(gamepad) : SDL_GAMEPAD_TYPE_UNKNOWN;
|
|
||||||
for (const auto& buttonNames : kGamepadButtonNames) {
|
|
||||||
if (buttonNames.button != button) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& name : buttonNames.names) {
|
|
||||||
if (name.type == type) {
|
|
||||||
return name.name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (button) {
|
|
||||||
case SDL_GAMEPAD_BUTTON_DPAD_LEFT:
|
|
||||||
return "D-pad left";
|
|
||||||
case SDL_GAMEPAD_BUTTON_DPAD_RIGHT:
|
|
||||||
return "D-pad right";
|
|
||||||
case SDL_GAMEPAD_BUTTON_DPAD_UP:
|
|
||||||
return "D-pad up";
|
|
||||||
case SDL_GAMEPAD_BUTTON_DPAD_DOWN:
|
|
||||||
return "D-pad down";
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (const char* name = PADGetNativeButtonName(buttonUntyped)) {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
return "Unknown";
|
|
||||||
}
|
|
||||||
|
|
||||||
Rml::String native_axis_name(const PADAxisMapping& mapping, SDL_Gamepad* gamepad) {
|
|
||||||
if (mapping.nativeAxis.nativeAxis != -1) {
|
|
||||||
Rml::String value = PADGetNativeAxisName(mapping.nativeAxis);
|
|
||||||
if (mapping.padAxis != PAD_AXIS_TRIGGER_L && mapping.padAxis != PAD_AXIS_TRIGGER_R) {
|
|
||||||
value += mapping.nativeAxis.sign == AXIS_SIGN_POSITIVE ? "+" : "-";
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mapping.nativeButton != -1) {
|
|
||||||
return native_button_name(gamepad, static_cast<u32>(mapping.nativeButton));
|
|
||||||
}
|
|
||||||
|
|
||||||
return "Not bound";
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_dpad_button(PADButton button) {
|
|
||||||
return button == PAD_BUTTON_UP || button == PAD_BUTTON_DOWN || button == PAD_BUTTON_LEFT ||
|
|
||||||
button == PAD_BUTTON_RIGHT;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_action_button(PADButton button) {
|
|
||||||
return button == PAD_BUTTON_A || button == PAD_BUTTON_B || button == PAD_BUTTON_X ||
|
|
||||||
button == PAD_BUTTON_Y || button == PAD_BUTTON_START || button == PAD_TRIGGER_Z;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool input_neutral(int port) {
|
|
||||||
if (port < 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return PADGetNativeButtonPressed(port) == -1 && PADGetNativeAxisPulled(port).nativeAxis == -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Keydown event with KI_ESCAPE may have been dispatched from the controller bindings,
|
|
||||||
// so instead poll the keyboard input directly for Escape-to-unbind
|
|
||||||
bool keyboard_escape_pressed() {
|
|
||||||
int keyCount = 0;
|
|
||||||
const bool* keys = SDL_GetKeyboardState(&keyCount);
|
|
||||||
return keys != nullptr && SDL_SCANCODE_ESCAPE < keyCount && keys[SDL_SCANCODE_ESCAPE];
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
ControllerConfigWindow::ControllerConfigWindow() {
|
|
||||||
listen(
|
|
||||||
Rml::EventId::Keydown,
|
|
||||||
[this](Rml::Event& event) {
|
|
||||||
if (capture_active() || mSuppressNavigationUntilNeutral) {
|
|
||||||
event.StopPropagation();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
true);
|
|
||||||
if (auto* context = mDocument != nullptr ? mDocument->GetContext() : nullptr) {
|
|
||||||
if (auto* root = context->GetRootElement()) {
|
|
||||||
mListeners.emplace_back(std::make_unique<ScopedEventListener>(
|
|
||||||
root, "controllerchange", [this](Rml::Event&) { refresh_controller_page(); }));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int port = PAD_CHAN0; port < PAD_CHANMAX; ++port) {
|
|
||||||
add_tab(fmt::format("Port {}", port + 1), [this, port](Rml::Element* content) {
|
|
||||||
if (mPendingPort != -1 && mPendingPort != port) {
|
|
||||||
cancel_pending_binding();
|
|
||||||
}
|
|
||||||
build_port_tab(content, port);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ControllerConfigWindow::hide(bool close) {
|
|
||||||
cancel_pending_binding();
|
|
||||||
Window::hide(close);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ControllerConfigWindow::update() {
|
|
||||||
poll_pending_binding();
|
|
||||||
Window::update();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ControllerConfigWindow::build_port_tab(Rml::Element* content, int port) {
|
|
||||||
auto& leftPane = add_child<Pane>(content, Pane::Type::Controlled);
|
|
||||||
auto& rightPane = add_child<Pane>(content, Pane::Type::Uncontrolled);
|
|
||||||
mRightPane = &rightPane;
|
|
||||||
mActivePort = port;
|
|
||||||
|
|
||||||
auto showPage = [this, &rightPane, port](Page page) {
|
|
||||||
mPage = page;
|
|
||||||
render_page(rightPane, port, page);
|
|
||||||
};
|
|
||||||
auto addPageButton = [&leftPane, showPage](Page page, Rml::String key, auto getValue) {
|
|
||||||
leftPane
|
|
||||||
.add_select_button({
|
|
||||||
.key = std::move(key),
|
|
||||||
.getValue = std::move(getValue),
|
|
||||||
})
|
|
||||||
.on_focus([showPage, page](Rml::Event&) { showPage(page); })
|
|
||||||
.on_pressed([showPage, page] { showPage(page); });
|
|
||||||
};
|
|
||||||
|
|
||||||
addPageButton(Page::Controller, "Controller", [port] { return current_controller_name(port); });
|
|
||||||
addPageButton(Page::Buttons, "Buttons", [] { return Rml::String(">"); });
|
|
||||||
addPageButton(Page::Triggers, "Triggers", [] { return Rml::String(">"); });
|
|
||||||
addPageButton(Page::Sticks, "Sticks", [] { return Rml::String(">"); });
|
|
||||||
|
|
||||||
leftPane.add_section("Options");
|
|
||||||
leftPane
|
|
||||||
.add_child<BoolButton>(BoolButton::Props{
|
|
||||||
.key = "Enable Dead Zones",
|
|
||||||
.getValue =
|
|
||||||
[port] {
|
|
||||||
PADDeadZones* deadZones = PADGetDeadZones(port);
|
|
||||||
return deadZones != nullptr && deadZones->useDeadzones;
|
|
||||||
},
|
|
||||||
.setValue =
|
|
||||||
[port](bool value) {
|
|
||||||
if (PADDeadZones* deadZones = PADGetDeadZones(port)) {
|
|
||||||
deadZones->useDeadzones = value;
|
|
||||||
PADSerializeMappings();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
.isDisabled = [port] { return PADGetDeadZones(port) == nullptr; },
|
|
||||||
})
|
|
||||||
.on_focus([&rightPane](Rml::Event&) {
|
|
||||||
rightPane.clear();
|
|
||||||
rightPane.add_text("Apply configured dead zones to the sticks and analog triggers.");
|
|
||||||
});
|
|
||||||
leftPane
|
|
||||||
.add_child<BoolButton>(BoolButton::Props{
|
|
||||||
.key = "Emulate Triggers",
|
|
||||||
.getValue =
|
|
||||||
[port] {
|
|
||||||
PADDeadZones* deadZones = PADGetDeadZones(port);
|
|
||||||
return deadZones != nullptr && deadZones->emulateTriggers;
|
|
||||||
},
|
|
||||||
.setValue =
|
|
||||||
[port](bool value) {
|
|
||||||
if (PADDeadZones* deadZones = PADGetDeadZones(port)) {
|
|
||||||
deadZones->emulateTriggers = value;
|
|
||||||
PADSerializeMappings();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
.isDisabled = [port] { return PADGetDeadZones(port) == nullptr; },
|
|
||||||
})
|
|
||||||
.on_focus([&rightPane](Rml::Event&) {
|
|
||||||
rightPane.clear();
|
|
||||||
rightPane.add_text("Treat analog trigger movement as digital L and R button input.");
|
|
||||||
});
|
|
||||||
|
|
||||||
render_page(rightPane, port, mPage);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ControllerConfigWindow::render_page(Pane& pane, int port, Page page) {
|
|
||||||
pane.clear();
|
|
||||||
|
|
||||||
switch (page) {
|
|
||||||
case Page::Controller: {
|
|
||||||
const u32 controllerCount = PADCount();
|
|
||||||
if (controllerCount == 0) {
|
|
||||||
pane.add_text("No controllers detected");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
pane.add_button({
|
|
||||||
.text = "None",
|
|
||||||
.isSelected = [port] { return PADGetIndexForPort(port) < 0; },
|
|
||||||
})
|
|
||||||
.on_pressed([this, port] {
|
|
||||||
cancel_pending_binding();
|
|
||||||
PADClearPort(port);
|
|
||||||
PADSerializeMappings();
|
|
||||||
});
|
|
||||||
|
|
||||||
for (u32 i = 0; i < controllerCount; ++i) {
|
|
||||||
pane.add_button(
|
|
||||||
{
|
|
||||||
.text = controller_index_name(i),
|
|
||||||
.isSelected =
|
|
||||||
[port, i] { return PADGetIndexForPort(port) == static_cast<s32>(i); },
|
|
||||||
})
|
|
||||||
.on_pressed([this, port, i] {
|
|
||||||
cancel_pending_binding();
|
|
||||||
PADSetPortForIndex(i, port);
|
|
||||||
PADSerializeMappings();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Page::Buttons: {
|
|
||||||
u32 buttonCount = 0;
|
|
||||||
PADButtonMapping* mappings = PADGetButtonMappings(port, &buttonCount);
|
|
||||||
if (mappings == nullptr) {
|
|
||||||
pane.add_text("No controller selected");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_Gamepad* gamepad = gamepad_for_port(port);
|
|
||||||
pane.add_section("Buttons");
|
|
||||||
for (u32 i = 0; i < buttonCount; ++i) {
|
|
||||||
PADButtonMapping& mapping = mappings[i];
|
|
||||||
if (!is_action_button(mapping.padButton)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
pane.add_select_button({
|
|
||||||
.key = PADGetButtonName(mapping.padButton),
|
|
||||||
.getValue =
|
|
||||||
[this, &mapping, gamepad] {
|
|
||||||
if (mPendingButtonMapping == &mapping) {
|
|
||||||
return pending_button_label();
|
|
||||||
}
|
|
||||||
return native_button_name(
|
|
||||||
gamepad, mapping.nativeButton);
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.on_pressed([this, port, &mapping] {
|
|
||||||
cancel_pending_binding();
|
|
||||||
mPendingPort = port;
|
|
||||||
mPendingBindingArmed = false;
|
|
||||||
mPendingButtonMapping = &mapping;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pane.add_section("D-Pad");
|
|
||||||
for (u32 i = 0; i < buttonCount; ++i) {
|
|
||||||
PADButtonMapping& mapping = mappings[i];
|
|
||||||
if (!is_dpad_button(mapping.padButton)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
pane.add_select_button({
|
|
||||||
.key = PADGetButtonName(mapping.padButton),
|
|
||||||
.getValue =
|
|
||||||
[this, &mapping, gamepad] {
|
|
||||||
if (mPendingButtonMapping == &mapping) {
|
|
||||||
return pending_button_label();
|
|
||||||
}
|
|
||||||
return native_button_name(
|
|
||||||
gamepad, mapping.nativeButton);
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.on_pressed([this, port, &mapping] {
|
|
||||||
cancel_pending_binding();
|
|
||||||
mPendingPort = port;
|
|
||||||
mPendingBindingArmed = false;
|
|
||||||
mPendingButtonMapping = &mapping;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Page::Triggers: {
|
|
||||||
u32 axisCount = 0;
|
|
||||||
PADAxisMapping* axes = PADGetAxisMappings(port, &axisCount);
|
|
||||||
u32 buttonCount = 0;
|
|
||||||
PADButtonMapping* buttons = PADGetButtonMappings(port, &buttonCount);
|
|
||||||
if (axes == nullptr && buttons == nullptr) {
|
|
||||||
pane.add_text("No controller selected");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_Gamepad* gamepad = gamepad_for_port(port);
|
|
||||||
pane.add_section("Analog");
|
|
||||||
constexpr std::array<PADAxis, 2> kTriggerAxes = {PAD_AXIS_TRIGGER_L, PAD_AXIS_TRIGGER_R};
|
|
||||||
if (axes != nullptr) {
|
|
||||||
for (PADAxis axis : kTriggerAxes) {
|
|
||||||
if (axis >= axisCount) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
PADAxisMapping& mapping = axes[axis];
|
|
||||||
pane.add_select_button({
|
|
||||||
.key = PADGetAxisName(mapping.padAxis),
|
|
||||||
.getValue =
|
|
||||||
[this, &mapping, gamepad] {
|
|
||||||
if (mPendingAxisMapping == &mapping) {
|
|
||||||
return pending_axis_label();
|
|
||||||
}
|
|
||||||
return native_axis_name(mapping, gamepad);
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.on_pressed([this, port, &mapping] {
|
|
||||||
cancel_pending_binding();
|
|
||||||
mPendingPort = port;
|
|
||||||
mPendingBindingArmed = false;
|
|
||||||
mPendingAxisMapping = &mapping;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pane.add_section("Digital");
|
|
||||||
if (buttons != nullptr) {
|
|
||||||
for (u32 i = 0; i < buttonCount; ++i) {
|
|
||||||
PADButtonMapping& mapping = buttons[i];
|
|
||||||
if (mapping.padButton != PAD_TRIGGER_L && mapping.padButton != PAD_TRIGGER_R) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
pane.add_select_button({
|
|
||||||
.key = PADGetButtonName(mapping.padButton),
|
|
||||||
.getValue =
|
|
||||||
[this, &mapping, gamepad] {
|
|
||||||
if (mPendingButtonMapping == &mapping) {
|
|
||||||
return pending_button_label();
|
|
||||||
}
|
|
||||||
return native_button_name(
|
|
||||||
gamepad, mapping.nativeButton);
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.on_pressed([this, port, &mapping] {
|
|
||||||
cancel_pending_binding();
|
|
||||||
mPendingPort = port;
|
|
||||||
mPendingBindingArmed = false;
|
|
||||||
mPendingButtonMapping = &mapping;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Page::Sticks: {
|
|
||||||
u32 axisCount = 0;
|
|
||||||
PADAxisMapping* axes = PADGetAxisMappings(port, &axisCount);
|
|
||||||
if (axes == nullptr) {
|
|
||||||
pane.add_text("No controller selected");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_Gamepad* gamepad = gamepad_for_port(port);
|
|
||||||
auto addAxis = [&](PADAxis axis) {
|
|
||||||
if (axis >= axisCount) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
PADAxisMapping& mapping = axes[axis];
|
|
||||||
pane.add_select_button({
|
|
||||||
.key = PADGetAxisDirectionLabel(mapping.padAxis),
|
|
||||||
.getValue =
|
|
||||||
[this, &mapping, gamepad] {
|
|
||||||
if (mPendingAxisMapping == &mapping) {
|
|
||||||
return pending_axis_label();
|
|
||||||
}
|
|
||||||
return native_axis_name(mapping, gamepad);
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.on_pressed([this, port, &mapping] {
|
|
||||||
cancel_pending_binding();
|
|
||||||
mPendingPort = port;
|
|
||||||
mPendingBindingArmed = false;
|
|
||||||
mPendingAxisMapping = &mapping;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
pane.add_section("Control Stick");
|
|
||||||
addAxis(PAD_AXIS_LEFT_Y_POS);
|
|
||||||
addAxis(PAD_AXIS_LEFT_Y_NEG);
|
|
||||||
addAxis(PAD_AXIS_LEFT_X_NEG);
|
|
||||||
addAxis(PAD_AXIS_LEFT_X_POS);
|
|
||||||
|
|
||||||
pane.add_section("C Stick");
|
|
||||||
addAxis(PAD_AXIS_RIGHT_Y_POS);
|
|
||||||
addAxis(PAD_AXIS_RIGHT_Y_NEG);
|
|
||||||
addAxis(PAD_AXIS_RIGHT_X_NEG);
|
|
||||||
addAxis(PAD_AXIS_RIGHT_X_POS);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ControllerConfigWindow::refresh_controller_page() {
|
|
||||||
if (!visible() || mPage != Page::Controller || mRightPane == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
render_page(*mRightPane, mActivePort, Page::Controller);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ControllerConfigWindow::poll_pending_binding() {
|
|
||||||
if (mSuppressNavigationUntilNeutral && input_neutral(mSuppressNavigationPort)) {
|
|
||||||
mSuppressNavigationUntilNeutral = false;
|
|
||||||
mSuppressNavigationPort = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!capture_active()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keyboard_escape_pressed()) {
|
|
||||||
unmap_pending_binding();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mPendingBindingArmed) {
|
|
||||||
if (pending_input_neutral()) {
|
|
||||||
mPendingBindingArmed = true;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mPendingButtonMapping != nullptr) {
|
|
||||||
const s32 nativeButton = PADGetNativeButtonPressed(mPendingPort);
|
|
||||||
if (nativeButton != -1) {
|
|
||||||
const int completedPort = mPendingPort;
|
|
||||||
mPendingButtonMapping->nativeButton = static_cast<u32>(nativeButton);
|
|
||||||
finish_pending_binding(completedPort);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mPendingAxisMapping != nullptr) {
|
|
||||||
const PADSignedNativeAxis nativeAxis = PADGetNativeAxisPulled(mPendingPort);
|
|
||||||
if (nativeAxis.nativeAxis != -1) {
|
|
||||||
const int completedPort = mPendingPort;
|
|
||||||
mPendingAxisMapping->nativeAxis = nativeAxis;
|
|
||||||
mPendingAxisMapping->nativeButton = -1;
|
|
||||||
finish_pending_binding(completedPort);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const s32 nativeButton = PADGetNativeButtonPressed(mPendingPort);
|
|
||||||
if (nativeButton != -1) {
|
|
||||||
const int completedPort = mPendingPort;
|
|
||||||
mPendingAxisMapping->nativeAxis = {-1, AXIS_SIGN_POSITIVE};
|
|
||||||
mPendingAxisMapping->nativeButton = nativeButton;
|
|
||||||
finish_pending_binding(completedPort);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ControllerConfigWindow::finish_pending_binding(int completedPort) {
|
|
||||||
mPendingButtonMapping = nullptr;
|
|
||||||
mPendingAxisMapping = nullptr;
|
|
||||||
mPendingPort = -1;
|
|
||||||
mPendingBindingArmed = false;
|
|
||||||
mSuppressNavigationUntilNeutral = true;
|
|
||||||
mSuppressNavigationPort = completedPort;
|
|
||||||
PADSerializeMappings();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ControllerConfigWindow::unmap_pending_binding() {
|
|
||||||
if (mPendingButtonMapping == nullptr && mPendingAxisMapping == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const int completedPort = mPendingPort;
|
|
||||||
if (mPendingButtonMapping != nullptr) {
|
|
||||||
mPendingButtonMapping->nativeButton = PAD_NATIVE_BUTTON_INVALID;
|
|
||||||
}
|
|
||||||
if (mPendingAxisMapping != nullptr) {
|
|
||||||
mPendingAxisMapping->nativeAxis = {-1, AXIS_SIGN_POSITIVE};
|
|
||||||
mPendingAxisMapping->nativeButton = -1;
|
|
||||||
}
|
|
||||||
finish_pending_binding(completedPort);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ControllerConfigWindow::capture_active() const {
|
|
||||||
return mPendingButtonMapping != nullptr || mPendingAxisMapping != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ControllerConfigWindow::pending_input_neutral() const {
|
|
||||||
return input_neutral(mPendingPort);
|
|
||||||
}
|
|
||||||
|
|
||||||
Rml::String ControllerConfigWindow::pending_button_label() const {
|
|
||||||
return mPendingBindingArmed ? "Press a button..." : "Waiting...";
|
|
||||||
}
|
|
||||||
|
|
||||||
Rml::String ControllerConfigWindow::pending_axis_label() const {
|
|
||||||
return mPendingBindingArmed ? "Move axis or press a button..." : "Waiting...";
|
|
||||||
}
|
|
||||||
|
|
||||||
void ControllerConfigWindow::cancel_pending_binding() {
|
|
||||||
if (mPendingButtonMapping == nullptr && mPendingAxisMapping == nullptr &&
|
|
||||||
!mSuppressNavigationUntilNeutral)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mPendingButtonMapping = nullptr;
|
|
||||||
mPendingAxisMapping = nullptr;
|
|
||||||
mPendingPort = -1;
|
|
||||||
mPendingBindingArmed = false;
|
|
||||||
mSuppressNavigationUntilNeutral = false;
|
|
||||||
mSuppressNavigationPort = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace dusk::ui
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "window.hpp"
|
|
||||||
|
|
||||||
#include <pad.h>
|
|
||||||
|
|
||||||
namespace dusk::ui {
|
|
||||||
|
|
||||||
class ControllerConfigWindow : public Window {
|
|
||||||
public:
|
|
||||||
ControllerConfigWindow();
|
|
||||||
|
|
||||||
void update() override;
|
|
||||||
void hide(bool close) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
enum class Page {
|
|
||||||
Controller,
|
|
||||||
Buttons,
|
|
||||||
Triggers,
|
|
||||||
Sticks,
|
|
||||||
};
|
|
||||||
|
|
||||||
void build_port_tab(Rml::Element* content, int port);
|
|
||||||
void render_page(class Pane& pane, int port, Page page);
|
|
||||||
void refresh_controller_page();
|
|
||||||
void poll_pending_binding();
|
|
||||||
void finish_pending_binding(int completedPort);
|
|
||||||
void unmap_pending_binding();
|
|
||||||
bool capture_active() const;
|
|
||||||
bool pending_input_neutral() const;
|
|
||||||
Rml::String pending_button_label() const;
|
|
||||||
Rml::String pending_axis_label() const;
|
|
||||||
void cancel_pending_binding();
|
|
||||||
|
|
||||||
Page mPage = Page::Controller;
|
|
||||||
Pane* mRightPane = nullptr;
|
|
||||||
int mActivePort = 0;
|
|
||||||
int mPendingPort = -1;
|
|
||||||
bool mPendingBindingArmed = false;
|
|
||||||
bool mSuppressNavigationUntilNeutral = false;
|
|
||||||
int mSuppressNavigationPort = -1;
|
|
||||||
PADButtonMapping* mPendingButtonMapping = nullptr;
|
|
||||||
PADAxisMapping* mPendingAxisMapping = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace dusk::ui
|
|
||||||
+1
-12
@@ -10,20 +10,9 @@ ScopedEventListener::ScopedEventListener(
|
|||||||
mElement->AddEventListener(mEvent, this, mCapture);
|
mElement->AddEventListener(mEvent, this, mCapture);
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopedEventListener::ScopedEventListener(
|
|
||||||
Rml::Element* element, Rml::String event, Callback callback, bool capture)
|
|
||||||
: mElement(element), mEventName(std::move(event)), mCapture(capture),
|
|
||||||
mCallback(std::move(callback)) {
|
|
||||||
mElement->AddEventListener(mEventName, this, mCapture);
|
|
||||||
}
|
|
||||||
|
|
||||||
ScopedEventListener::~ScopedEventListener() {
|
ScopedEventListener::~ScopedEventListener() {
|
||||||
if (mElement != nullptr) {
|
if (mElement != nullptr) {
|
||||||
if (!mEventName.empty()) {
|
mElement->RemoveEventListener(mEvent, this, mCapture);
|
||||||
mElement->RemoveEventListener(mEventName, this, mCapture);
|
|
||||||
} else {
|
|
||||||
mElement->RemoveEventListener(mEvent, this, mCapture);
|
|
||||||
}
|
|
||||||
mElement = nullptr;
|
mElement = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ public:
|
|||||||
|
|
||||||
ScopedEventListener(
|
ScopedEventListener(
|
||||||
Rml::Element* element, Rml::EventId event, Callback callback, bool capture = false);
|
Rml::Element* element, Rml::EventId event, Callback callback, bool capture = false);
|
||||||
ScopedEventListener(
|
|
||||||
Rml::Element* element, Rml::String event, Callback callback, bool capture = false);
|
|
||||||
~ScopedEventListener() override;
|
~ScopedEventListener() override;
|
||||||
|
|
||||||
ScopedEventListener(const ScopedEventListener&) = delete;
|
ScopedEventListener(const ScopedEventListener&) = delete;
|
||||||
@@ -27,7 +25,6 @@ public:
|
|||||||
private:
|
private:
|
||||||
Rml::Element* mElement = nullptr;
|
Rml::Element* mElement = nullptr;
|
||||||
Rml::EventId mEvent = Rml::EventId::Invalid;
|
Rml::EventId mEvent = Rml::EventId::Invalid;
|
||||||
Rml::String mEventName;
|
|
||||||
bool mCapture = false;
|
bool mCapture = false;
|
||||||
Callback mCallback;
|
Callback mCallback;
|
||||||
};
|
};
|
||||||
|
|||||||
+1
-38
@@ -64,40 +64,6 @@ bool should_block_pad_for_menu_chord() noexcept {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* controller_change_type(Uint32 eventType) noexcept {
|
|
||||||
switch (eventType) {
|
|
||||||
case SDL_EVENT_GAMEPAD_ADDED:
|
|
||||||
return "added";
|
|
||||||
case SDL_EVENT_GAMEPAD_REMOVED:
|
|
||||||
return "removed";
|
|
||||||
case SDL_EVENT_GAMEPAD_REMAPPED:
|
|
||||||
return "remapped";
|
|
||||||
default:
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void dispatch_controller_change_event(const SDL_Event& event) noexcept {
|
|
||||||
const char* type = controller_change_type(event.type);
|
|
||||||
if (type == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* context = aurora::rmlui::get_context();
|
|
||||||
if (context == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto* root = context->GetRootElement();
|
|
||||||
if (root == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Rml::Dictionary parameters;
|
|
||||||
parameters["type"] = Rml::String(type);
|
|
||||||
parameters["which"] = static_cast<int>(event.gdevice.which);
|
|
||||||
root->DispatchEvent("controllerchange", parameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
PADButton pad_button_from_axis(PADAxis axis) noexcept {
|
PADButton pad_button_from_axis(PADAxis axis) noexcept {
|
||||||
switch (axis) {
|
switch (axis) {
|
||||||
case PAD_AXIS_TRIGGER_R:
|
case PAD_AXIS_TRIGGER_R:
|
||||||
@@ -536,11 +502,8 @@ void handle_event(const SDL_Event& event) noexcept {
|
|||||||
if (event.type == SDL_EVENT_GAMEPAD_REMOVED || event.type == SDL_EVENT_WINDOW_FOCUS_LOST) {
|
if (event.type == SDL_EVENT_GAMEPAD_REMOVED || event.type == SDL_EVENT_WINDOW_FOCUS_LOST) {
|
||||||
reset_input_state();
|
reset_input_state();
|
||||||
sync_input_block();
|
sync_input_block();
|
||||||
if (event.type != SDL_EVENT_GAMEPAD_REMOVED) {
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
dispatch_controller_change_event(event);
|
|
||||||
if (event.type != SDL_EVENT_GAMEPAD_BUTTON_DOWN && event.type != SDL_EVENT_GAMEPAD_BUTTON_UP &&
|
if (event.type != SDL_EVENT_GAMEPAD_BUTTON_DOWN && event.type != SDL_EVENT_GAMEPAD_BUTTON_UP &&
|
||||||
event.type != SDL_EVENT_GAMEPAD_AXIS_MOTION)
|
event.type != SDL_EVENT_GAMEPAD_AXIS_MOTION)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,16 +8,8 @@ namespace dusk::ui {
|
|||||||
NumberButton::NumberButton(Rml::Element* parent, Props props)
|
NumberButton::NumberButton(Rml::Element* parent, Props props)
|
||||||
: BaseStringButton(parent, {.key = std::move(props.key), .type = "number"}),
|
: BaseStringButton(parent, {.key = std::move(props.key), .type = "number"}),
|
||||||
mGetValue(std::move(props.getValue)), mSetValue(std::move(props.setValue)),
|
mGetValue(std::move(props.getValue)), mSetValue(std::move(props.setValue)),
|
||||||
mIsDisabled(std::move(props.isDisabled)), mIsModified(std::move(props.isModified)),
|
mIsDisabled(std::move(props.isDisabled)), mMin(props.min), mMax(props.max), mStep(props.step),
|
||||||
mMin(props.min), mMax(props.max), mStep(props.step), mPrefix(std::move(props.prefix)),
|
mPrefix(std::move(props.prefix)), mSuffix(std::move(props.suffix)) {}
|
||||||
mSuffix(std::move(props.suffix)) {}
|
|
||||||
|
|
||||||
bool NumberButton::modified() const {
|
|
||||||
if (mIsModified) {
|
|
||||||
return mIsModified();
|
|
||||||
}
|
|
||||||
return BaseStringButton::modified();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NumberButton::disabled() const {
|
bool NumberButton::disabled() const {
|
||||||
if (mIsDisabled) {
|
if (mIsDisabled) {
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ public:
|
|||||||
std::function<int()> getValue;
|
std::function<int()> getValue;
|
||||||
std::function<void(int)> setValue;
|
std::function<void(int)> setValue;
|
||||||
std::function<bool()> isDisabled;
|
std::function<bool()> isDisabled;
|
||||||
std::function<bool()> isModified;
|
|
||||||
int min = 0;
|
int min = 0;
|
||||||
int max = INT_MAX;
|
int max = INT_MAX;
|
||||||
int step = 1;
|
int step = 1;
|
||||||
@@ -21,7 +20,6 @@ public:
|
|||||||
|
|
||||||
NumberButton(Rml::Element* parent, Props props);
|
NumberButton(Rml::Element* parent, Props props);
|
||||||
|
|
||||||
bool modified() const override;
|
|
||||||
bool disabled() const override;
|
bool disabled() const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -34,7 +32,6 @@ private:
|
|||||||
std::function<int()> mGetValue;
|
std::function<int()> mGetValue;
|
||||||
std::function<void(int)> mSetValue;
|
std::function<void(int)> mSetValue;
|
||||||
std::function<bool()> mIsDisabled;
|
std::function<bool()> mIsDisabled;
|
||||||
std::function<bool()> mIsModified;
|
|
||||||
int mMin;
|
int mMin;
|
||||||
int mMax;
|
int mMax;
|
||||||
int mStep;
|
int mStep;
|
||||||
|
|||||||
+6
-14
@@ -23,7 +23,7 @@ const Rml::String kDocumentSource = R"RML(
|
|||||||
<link type="text/rcss" href="res/rml/popup.rcss" />
|
<link type="text/rcss" href="res/rml/popup.rcss" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<popup id="popup"></popup>
|
<popup id="popup"></div>
|
||||||
</body>
|
</body>
|
||||||
</rml>
|
</rml>
|
||||||
)RML";
|
)RML";
|
||||||
@@ -31,21 +31,18 @@ const Rml::String kDocumentSource = R"RML(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Popup::Popup() : Document(kDocumentSource), mRoot(mDocument->GetElementById("popup")) {
|
Popup::Popup() : Document(kDocumentSource), mRoot(mDocument->GetElementById("popup")) {
|
||||||
mTabBar = std::make_unique<TabBar>(mRoot, TabBar::Props{
|
mTabBar = std::make_unique<TabBar>(mRoot, TabBar::Props{.autoSelect = false});
|
||||||
.onClose = [this] { hide(false); },
|
|
||||||
.autoSelect = false,
|
|
||||||
});
|
|
||||||
mTabBar->add_tab("Settings", [] { push_document(std::make_unique<SettingsWindow>()); });
|
mTabBar->add_tab("Settings", [] { push_document(std::make_unique<SettingsWindow>()); });
|
||||||
// mTabBar->add_tab("Warp", [] {
|
mTabBar->add_tab("Warp", [] {
|
||||||
// // TODO
|
// TODO
|
||||||
// });
|
});
|
||||||
mTabBar->add_tab("Editor", [] { push_document(std::make_unique<EditorWindow>()); });
|
mTabBar->add_tab("Editor", [] { push_document(std::make_unique<EditorWindow>()); });
|
||||||
mTabBar->add_tab("Reset", [this] {
|
mTabBar->add_tab("Reset", [this] {
|
||||||
JUTGamePad::C3ButtonReset::sResetSwitchPushing = true;
|
JUTGamePad::C3ButtonReset::sResetSwitchPushing = true;
|
||||||
mTabBar->set_active_tab(-1);
|
mTabBar->set_active_tab(-1);
|
||||||
hide(false);
|
hide(false);
|
||||||
});
|
});
|
||||||
mTabBar->add_tab("Quit", [] { IsRunning = false; });
|
mTabBar->add_tab("Exit", [] { IsRunning = false; });
|
||||||
|
|
||||||
// Hide document after transition completion
|
// Hide document after transition completion
|
||||||
listen(mRoot, Rml::EventId::Transitionend, [this](Rml::Event& event) {
|
listen(mRoot, Rml::EventId::Transitionend, [this](Rml::Event& event) {
|
||||||
@@ -109,11 +106,6 @@ void Popup::update_safe_area() noexcept {
|
|||||||
Rml::PropertyId::PaddingRight, Rml::Property(safeInsets.right, Rml::Unit::PX));
|
Rml::PropertyId::PaddingRight, Rml::Property(safeInsets.right, Rml::Unit::PX));
|
||||||
tabBar->SetProperty(
|
tabBar->SetProperty(
|
||||||
Rml::PropertyId::PaddingLeft, Rml::Property(safeInsets.left, Rml::Unit::PX));
|
Rml::PropertyId::PaddingLeft, Rml::Property(safeInsets.left, Rml::Unit::PX));
|
||||||
if (auto* close = tabBar->QuerySelector("close")) {
|
|
||||||
close->SetProperty(Rml::PropertyId::Right,
|
|
||||||
Rml::Property(safeInsets.right + 8.0f * context->GetDensityIndependentPixelRatio(),
|
|
||||||
Rml::Unit::PX));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Popup::visible() const {
|
bool Popup::visible() const {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#include "ui.hpp"
|
#include "ui.hpp"
|
||||||
|
|
||||||
#include <fmt/format.h>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace dusk::ui {
|
namespace dusk::ui {
|
||||||
@@ -24,51 +23,18 @@ SelectButton::SelectButton(Rml::Element* parent, Props props)
|
|||||||
on_nav_command([this](Rml::Event&, NavCommand cmd) { return handle_nav_command(cmd); });
|
on_nav_command([this](Rml::Event&, NavCommand cmd) { return handle_nav_command(cmd); });
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SelectButton::modified() const {
|
|
||||||
return mProps.modified;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SelectButton::set_modified(bool value) {
|
|
||||||
if (mProps.modified != value) {
|
|
||||||
mValueElem->SetClass("modified", value);
|
|
||||||
if (value) {
|
|
||||||
mValueElem->SetInnerRML(fmt::format("• {}", escape(mProps.value)));
|
|
||||||
} else {
|
|
||||||
mValueElem->SetInnerRML(escape(mProps.value));
|
|
||||||
}
|
|
||||||
mProps.modified = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SelectButton::set_value_label(const Rml::String& value) {
|
void SelectButton::set_value_label(const Rml::String& value) {
|
||||||
if (mProps.value != value) {
|
if (mProps.value != value) {
|
||||||
if (mProps.modified) {
|
mValueElem->SetInnerRML(escape(value));
|
||||||
mValueElem->SetInnerRML(fmt::format("• {}", escape(value)));
|
|
||||||
} else {
|
|
||||||
mValueElem->SetInnerRML(escape(value));
|
|
||||||
}
|
|
||||||
mProps.value = value;
|
mProps.value = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SelectButton& SelectButton::on_pressed(SelectButtonCallback callback) {
|
|
||||||
if (!callback) {
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
listen(Rml::EventId::Submit, [this, callback = std::move(callback)](Rml::Event& event) {
|
|
||||||
if (!disabled() && event.GetTargetElement() == mRoot) {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SelectButton::update_props(Props props) {
|
void SelectButton::update_props(Props props) {
|
||||||
if (mProps.key != props.key) {
|
if (mProps.key != props.key) {
|
||||||
mKeyElem->SetInnerRML(escape(props.key));
|
mKeyElem->SetInnerRML(escape(props.key));
|
||||||
}
|
}
|
||||||
set_value_label(props.value);
|
set_value_label(props.value);
|
||||||
set_modified(props.modified);
|
|
||||||
mProps = std::move(props);
|
mProps = std::move(props);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,17 +49,9 @@ bool SelectButton::handle_nav_command(NavCommand cmd) {
|
|||||||
void BaseControlledSelectButton::update() {
|
void BaseControlledSelectButton::update() {
|
||||||
set_disabled(disabled());
|
set_disabled(disabled());
|
||||||
set_value_label(format_value());
|
set_value_label(format_value());
|
||||||
set_modified(modified());
|
|
||||||
SelectButton::update();
|
SelectButton::update();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ControlledSelectButton::modified() const {
|
|
||||||
if (mIsModified) {
|
|
||||||
return mIsModified();
|
|
||||||
}
|
|
||||||
return BaseControlledSelectButton::modified();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ControlledSelectButton::disabled() const {
|
bool ControlledSelectButton::disabled() const {
|
||||||
if (mIsDisabled) {
|
if (mIsDisabled) {
|
||||||
return mIsDisabled();
|
return mIsDisabled();
|
||||||
|
|||||||
@@ -3,27 +3,18 @@
|
|||||||
#include "component.hpp"
|
#include "component.hpp"
|
||||||
#include "ui.hpp"
|
#include "ui.hpp"
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
namespace dusk::ui {
|
namespace dusk::ui {
|
||||||
|
|
||||||
using SelectButtonCallback = std::function<void()>;
|
|
||||||
|
|
||||||
class SelectButton : public FluentComponent<SelectButton> {
|
class SelectButton : public FluentComponent<SelectButton> {
|
||||||
public:
|
public:
|
||||||
struct Props {
|
struct Props {
|
||||||
Rml::String key;
|
Rml::String key;
|
||||||
Rml::String value;
|
Rml::String value;
|
||||||
bool modified = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
SelectButton(Rml::Element* parent, Props props);
|
SelectButton(Rml::Element* parent, Props props);
|
||||||
|
|
||||||
virtual bool modified() const;
|
|
||||||
void set_modified(bool value);
|
|
||||||
void set_value_label(const Rml::String& value);
|
void set_value_label(const Rml::String& value);
|
||||||
SelectButton& on_pressed(SelectButtonCallback callback);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void update_props(Props props);
|
void update_props(Props props);
|
||||||
@@ -32,6 +23,7 @@ protected:
|
|||||||
Props mProps;
|
Props mProps;
|
||||||
Rml::Element* mKeyElem = nullptr;
|
Rml::Element* mKeyElem = nullptr;
|
||||||
Rml::Element* mValueElem = nullptr;
|
Rml::Element* mValueElem = nullptr;
|
||||||
|
std::function<void()> mOnHover;
|
||||||
};
|
};
|
||||||
|
|
||||||
class BaseControlledSelectButton : public SelectButton {
|
class BaseControlledSelectButton : public SelectButton {
|
||||||
@@ -51,15 +43,12 @@ public:
|
|||||||
Rml::String key;
|
Rml::String key;
|
||||||
std::function<Rml::String()> getValue;
|
std::function<Rml::String()> getValue;
|
||||||
std::function<bool()> isDisabled;
|
std::function<bool()> isDisabled;
|
||||||
std::function<bool()> isModified;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ControlledSelectButton(Rml::Element* parent, Props props)
|
ControlledSelectButton(Rml::Element* parent, Props props)
|
||||||
: BaseControlledSelectButton(parent, {std::move(props.key)}),
|
: BaseControlledSelectButton(parent, {std::move(props.key)}),
|
||||||
mGetValue(std::move(props.getValue)), mIsDisabled(std::move(props.isDisabled)),
|
mGetValue(std::move(props.getValue)), mIsDisabled(std::move(props.isDisabled)) {}
|
||||||
mIsModified(std::move(props.isModified)) {}
|
|
||||||
|
|
||||||
bool modified() const override;
|
|
||||||
bool disabled() const override;
|
bool disabled() const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -67,7 +56,6 @@ protected:
|
|||||||
|
|
||||||
std::function<Rml::String()> mGetValue;
|
std::function<Rml::String()> mGetValue;
|
||||||
std::function<bool()> mIsDisabled;
|
std::function<bool()> mIsDisabled;
|
||||||
std::function<bool()> mIsModified;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dusk::ui
|
} // namespace dusk::ui
|
||||||
|
|||||||
+20
-34
@@ -1,8 +1,9 @@
|
|||||||
#include "settings.hpp"
|
#include "settings.hpp"
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#include "aurora/gfx.h"
|
#include "aurora/gfx.h"
|
||||||
#include "bool_button.hpp"
|
#include "bool_button.hpp"
|
||||||
#include "controller_config.hpp"
|
|
||||||
#include "dusk/audio/DuskAudioSystem.h"
|
#include "dusk/audio/DuskAudioSystem.h"
|
||||||
#include "dusk/audio/DuskDsp.hpp"
|
#include "dusk/audio/DuskDsp.hpp"
|
||||||
#include "dusk/config.hpp"
|
#include "dusk/config.hpp"
|
||||||
@@ -80,7 +81,8 @@ struct ConfigBoolProps {
|
|||||||
SelectButton& config_bool_select(
|
SelectButton& config_bool_select(
|
||||||
Pane& leftPane, Pane& rightPane, ConfigVar<bool>& var, ConfigBoolProps props) {
|
Pane& leftPane, Pane& rightPane, ConfigVar<bool>& var, ConfigBoolProps props) {
|
||||||
return leftPane
|
return leftPane
|
||||||
.add_child<BoolButton>(BoolButton::Props{.key = std::move(props.key),
|
.add_child<BoolButton>(BoolButton::Props{
|
||||||
|
.key = std::move(props.key),
|
||||||
.getValue = [&var] { return var.getValue(); },
|
.getValue = [&var] { return var.getValue(); },
|
||||||
.setValue =
|
.setValue =
|
||||||
[&var, callback = std::move(props.onChange)](bool value) {
|
[&var, callback = std::move(props.onChange)](bool value) {
|
||||||
@@ -94,7 +96,7 @@ SelectButton& config_bool_select(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
.isDisabled = std::move(props.isDisabled),
|
.isDisabled = std::move(props.isDisabled),
|
||||||
.isModified = [&var] { return var.getValue() != var.getDefaultValue(); }})
|
})
|
||||||
.on_focus([&rightPane, helpText = std::move(props.helpText)](Rml::Event&) {
|
.on_focus([&rightPane, helpText = std::move(props.helpText)](Rml::Event&) {
|
||||||
rightPane.clear();
|
rightPane.clear();
|
||||||
rightPane.add_rml(helpText);
|
rightPane.add_rml(helpText);
|
||||||
@@ -114,7 +116,6 @@ SelectButton& config_percent_select(Pane& leftPane, Pane& rightPane, ConfigVar<f
|
|||||||
config::Save();
|
config::Save();
|
||||||
},
|
},
|
||||||
.isDisabled = std::move(isDisabled),
|
.isDisabled = std::move(isDisabled),
|
||||||
.isModified = [&var] { return var.getValue() != var.getDefaultValue(); },
|
|
||||||
.min = min,
|
.min = min,
|
||||||
.max = max,
|
.max = max,
|
||||||
.step = step,
|
.step = step,
|
||||||
@@ -126,6 +127,18 @@ SelectButton& config_percent_select(Pane& leftPane, Pane& rightPane, ConfigVar<f
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ControllerConfigWindow : public Window {
|
||||||
|
public:
|
||||||
|
ControllerConfigWindow() {
|
||||||
|
for (int i = 0; i < 4; ++i) {
|
||||||
|
add_tab(fmt::format("Port {}", i + 1), [this](Rml::Element* content) {
|
||||||
|
auto& pane = add_child<Pane>(content, Pane::Type::Controlled);
|
||||||
|
pane.add_section("Coming soon");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
SettingsWindow::SettingsWindow() {
|
SettingsWindow::SettingsWindow() {
|
||||||
@@ -145,11 +158,6 @@ SettingsWindow::SettingsWindow() {
|
|||||||
config::Save();
|
config::Save();
|
||||||
audio::SetMasterVolume(value / 100.f);
|
audio::SetMasterVolume(value / 100.f);
|
||||||
},
|
},
|
||||||
.isModified =
|
|
||||||
[] {
|
|
||||||
return getSettings().audio.masterVolume.getValue() !=
|
|
||||||
getSettings().audio.masterVolume.getDefaultValue();
|
|
||||||
},
|
|
||||||
.max = 100,
|
.max = 100,
|
||||||
.suffix = "%",
|
.suffix = "%",
|
||||||
})
|
})
|
||||||
@@ -276,11 +284,6 @@ SettingsWindow::SettingsWindow() {
|
|||||||
config::Save();
|
config::Save();
|
||||||
},
|
},
|
||||||
.isDisabled = [] { return getSettings().game.speedrunMode; },
|
.isDisabled = [] { return getSettings().game.speedrunMode; },
|
||||||
.isModified =
|
|
||||||
[] {
|
|
||||||
return getSettings().game.damageMultiplier.getValue() !=
|
|
||||||
getSettings().game.damageMultiplier.getDefaultValue();
|
|
||||||
},
|
|
||||||
.min = 1,
|
.min = 1,
|
||||||
.max = 8,
|
.max = 8,
|
||||||
.prefix = "x",
|
.prefix = "x",
|
||||||
@@ -293,6 +296,8 @@ SettingsWindow::SettingsWindow() {
|
|||||||
"Any hit will instantly kill you.");
|
"Any hit will instantly kill you.");
|
||||||
addSpeedrunDisabledOption("No Heart Drops", getSettings().game.noHeartDrops,
|
addSpeedrunDisabledOption("No Heart Drops", getSettings().game.noHeartDrops,
|
||||||
"Hearts will never drop from enemies, pots, and various other places.");
|
"Hearts will never drop from enemies, pots, and various other places.");
|
||||||
|
addOption("Hyper Enemies", getSettings().game.hyperEnemies,
|
||||||
|
"Enemies and Bosses are twice as fast.");
|
||||||
|
|
||||||
leftPane.add_section("Quality of Life");
|
leftPane.add_section("Quality of Life");
|
||||||
addOption("Bigger Wallets", getSettings().game.biggerWallets,
|
addOption("Bigger Wallets", getSettings().game.biggerWallets,
|
||||||
@@ -468,11 +473,6 @@ SettingsWindow::SettingsWindow() {
|
|||||||
return format_graphics_setting_value(GraphicsOption::InternalResolution,
|
return format_graphics_setting_value(GraphicsOption::InternalResolution,
|
||||||
getSettings().game.internalResolutionScale.getValue());
|
getSettings().game.internalResolutionScale.getValue());
|
||||||
},
|
},
|
||||||
.isModified =
|
|
||||||
[] {
|
|
||||||
return getSettings().game.internalResolutionScale.getValue() !=
|
|
||||||
getSettings().game.internalResolutionScale.getDefaultValue();
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
.on_nav_command([](Rml::Event&, NavCommand cmd) {
|
.on_nav_command([](Rml::Event&, NavCommand cmd) {
|
||||||
if (cmd == NavCommand::Confirm || cmd == NavCommand::Left ||
|
if (cmd == NavCommand::Confirm || cmd == NavCommand::Left ||
|
||||||
@@ -501,11 +501,6 @@ SettingsWindow::SettingsWindow() {
|
|||||||
return format_graphics_setting_value(GraphicsOption::ShadowResolution,
|
return format_graphics_setting_value(GraphicsOption::ShadowResolution,
|
||||||
getSettings().game.shadowResolutionMultiplier.getValue());
|
getSettings().game.shadowResolutionMultiplier.getValue());
|
||||||
},
|
},
|
||||||
.isModified =
|
|
||||||
[] {
|
|
||||||
return getSettings().game.shadowResolutionMultiplier.getValue() !=
|
|
||||||
getSettings().game.shadowResolutionMultiplier.getDefaultValue();
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
.on_nav_command([](Rml::Event&, NavCommand cmd) {
|
.on_nav_command([](Rml::Event&, NavCommand cmd) {
|
||||||
if (cmd == NavCommand::Confirm || cmd == NavCommand::Left ||
|
if (cmd == NavCommand::Confirm || cmd == NavCommand::Left ||
|
||||||
@@ -536,11 +531,6 @@ SettingsWindow::SettingsWindow() {
|
|||||||
return format_graphics_setting_value(GraphicsOption::BloomMode,
|
return format_graphics_setting_value(GraphicsOption::BloomMode,
|
||||||
static_cast<int>(getSettings().game.bloomMode.getValue()));
|
static_cast<int>(getSettings().game.bloomMode.getValue()));
|
||||||
},
|
},
|
||||||
.isModified =
|
|
||||||
[] {
|
|
||||||
return getSettings().game.bloomMode.getValue() !=
|
|
||||||
getSettings().game.bloomMode.getDefaultValue();
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
.on_nav_command([](Rml::Event&, NavCommand cmd) {
|
.on_nav_command([](Rml::Event&, NavCommand cmd) {
|
||||||
if (cmd == NavCommand::Confirm || cmd == NavCommand::Left ||
|
if (cmd == NavCommand::Confirm || cmd == NavCommand::Left ||
|
||||||
@@ -571,11 +561,6 @@ SettingsWindow::SettingsWindow() {
|
|||||||
},
|
},
|
||||||
.isDisabled =
|
.isDisabled =
|
||||||
[] { return getSettings().game.bloomMode.getValue() == BloomMode::Off; },
|
[] { return getSettings().game.bloomMode.getValue() == BloomMode::Off; },
|
||||||
.isModified =
|
|
||||||
[] {
|
|
||||||
return getSettings().game.bloomMultiplier.getValue() !=
|
|
||||||
getSettings().game.bloomMultiplier.getDefaultValue();
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
.on_nav_command([](Rml::Event&, NavCommand cmd) {
|
.on_nav_command([](Rml::Event&, NavCommand cmd) {
|
||||||
if (cmd == NavCommand::Confirm || cmd == NavCommand::Left ||
|
if (cmd == NavCommand::Confirm || cmd == NavCommand::Left ||
|
||||||
@@ -636,6 +621,7 @@ SettingsWindow::SettingsWindow() {
|
|||||||
"- Account Username"
|
"- Account Username"
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
|
leftPane.add_section("Advanced");
|
||||||
config_bool_select(leftPane, rightPane, getSettings().backend.skipPreLaunchUI,
|
config_bool_select(leftPane, rightPane, getSettings().backend.skipPreLaunchUI,
|
||||||
{
|
{
|
||||||
.key = "Skip Pre-Launch UI",
|
.key = "Skip Pre-Launch UI",
|
||||||
|
|||||||
+3
-72
@@ -9,78 +9,16 @@ Rml::Element* createRoot(Rml::Element* parent) {
|
|||||||
return parent->AppendChild(std::move(elem));
|
return parent->AppendChild(std::move(elem));
|
||||||
}
|
}
|
||||||
|
|
||||||
int key_modifiers_from_event(const Rml::Event& event) {
|
|
||||||
int modifiers = 0;
|
|
||||||
if (event.GetParameter("ctrl_key", 0)) {
|
|
||||||
modifiers |= Rml::Input::KM_CTRL;
|
|
||||||
}
|
|
||||||
if (event.GetParameter("shift_key", 0)) {
|
|
||||||
modifiers |= Rml::Input::KM_SHIFT;
|
|
||||||
}
|
|
||||||
if (event.GetParameter("alt_key", 0)) {
|
|
||||||
modifiers |= Rml::Input::KM_ALT;
|
|
||||||
}
|
|
||||||
if (event.GetParameter("meta_key", 0)) {
|
|
||||||
modifiers |= Rml::Input::KM_META;
|
|
||||||
}
|
|
||||||
if (event.GetParameter("caps_lock_key", 0)) {
|
|
||||||
modifiers |= Rml::Input::KM_CAPSLOCK;
|
|
||||||
}
|
|
||||||
if (event.GetParameter("num_lock_key", 0)) {
|
|
||||||
modifiers |= Rml::Input::KM_NUMLOCK;
|
|
||||||
}
|
|
||||||
if (event.GetParameter("scroll_lock_key", 0)) {
|
|
||||||
modifiers |= Rml::Input::KM_SCROLLLOCK;
|
|
||||||
}
|
|
||||||
return modifiers;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
TabBar::TabBar(Rml::Element* parent, Props props)
|
TabBar::TabBar(Rml::Element* parent, Props props)
|
||||||
: FluentComponent(createRoot(parent)), mProps(std::move(props)) {
|
: FluentComponent(createRoot(parent)), mProps(std::move(props)) {
|
||||||
if (mProps.onClose) {
|
|
||||||
mRoot->SetAttribute("closable", "");
|
|
||||||
auto& closeButton =
|
|
||||||
add_child<Button>(Button::Props{}, "close").on_pressed([this] { mProps.onClose(); });
|
|
||||||
closeButton.root()->SetInnerRML("");
|
|
||||||
mEndSpacer = append(mRoot, "tab-end-spacer");
|
|
||||||
}
|
|
||||||
|
|
||||||
listen(Rml::EventId::Keydown, [this](Rml::Event& event) {
|
listen(Rml::EventId::Keydown, [this](Rml::Event& event) {
|
||||||
const auto cmd = map_nav_event(event);
|
const auto cmd = map_nav_event(event);
|
||||||
if (cmd != NavCommand::None && handle_nav_command(event, cmd)) {
|
if (cmd != NavCommand::None && handle_nav_command(event, cmd)) {
|
||||||
event.StopPropagation();
|
event.StopPropagation();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Remap vertical scroll events into horizontal scroll events
|
|
||||||
listen(Rml::EventId::Mousescroll, [this](Rml::Event& event) {
|
|
||||||
if (mRedirectingScroll) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (mRoot->GetScrollWidth() <= mRoot->GetClientWidth() + 0.5f) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const float wheelDeltaX = event.GetParameter("wheel_delta_x", 0.0f);
|
|
||||||
const float wheelDeltaY = event.GetParameter("wheel_delta_y", 0.0f);
|
|
||||||
const float absWheelDeltaX = wheelDeltaX < 0.0f ? -wheelDeltaX : wheelDeltaX;
|
|
||||||
const float absWheelDeltaY = wheelDeltaY < 0.0f ? -wheelDeltaY : wheelDeltaY;
|
|
||||||
if (absWheelDeltaY == 0.0f || absWheelDeltaX >= absWheelDeltaY) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* context = mRoot->GetContext();
|
|
||||||
if (context == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mRedirectingScroll = true;
|
|
||||||
context->ProcessMouseWheel({wheelDeltaY, 0.0f}, key_modifiers_from_event(event));
|
|
||||||
mRedirectingScroll = false;
|
|
||||||
event.StopPropagation();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TabBar::focus() {
|
bool TabBar::focus() {
|
||||||
@@ -110,10 +48,6 @@ void TabBar::add_tab(const Rml::String& title, TabCallback callback) {
|
|||||||
if (selected) {
|
if (selected) {
|
||||||
button.set_selected(true);
|
button.set_selected(true);
|
||||||
}
|
}
|
||||||
if (mEndSpacer != nullptr) {
|
|
||||||
auto spacer = mRoot->RemoveChild(mEndSpacer);
|
|
||||||
mEndSpacer = mRoot->AppendChild(std::move(spacer));
|
|
||||||
}
|
|
||||||
mTabs.emplace_back(Tab{
|
mTabs.emplace_back(Tab{
|
||||||
.title = title,
|
.title = title,
|
||||||
.button = button,
|
.button = button,
|
||||||
@@ -124,8 +58,8 @@ void TabBar::add_tab(const Rml::String& title, TabCallback callback) {
|
|||||||
bool TabBar::set_active_tab(int index) {
|
bool TabBar::set_active_tab(int index) {
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
// Clear currently selected tab
|
// Clear currently selected tab
|
||||||
for (auto& tab : mTabs) {
|
for (int i = 0; i < static_cast<int>(mTabs.size()); ++i) {
|
||||||
tab.button.set_selected(false);
|
mTabs[i].button.set_selected(false);
|
||||||
}
|
}
|
||||||
mProps.selectedTabIndex = -1;
|
mProps.selectedTabIndex = -1;
|
||||||
return true;
|
return true;
|
||||||
@@ -169,10 +103,7 @@ bool TabBar::handle_nav_command(Rml::Event& event, NavCommand cmd) {
|
|||||||
cmd == NavCommand::Previous)
|
cmd == NavCommand::Previous)
|
||||||
{
|
{
|
||||||
bool isNext = cmd == NavCommand::Right || cmd == NavCommand::Next;
|
bool isNext = cmd == NavCommand::Right || cmd == NavCommand::Next;
|
||||||
int currentComponent = mProps.selectedTabIndex;
|
int currentComponent = tab_containing(event.GetTargetElement());
|
||||||
if (cmd == NavCommand::Left || cmd == NavCommand::Right) {
|
|
||||||
currentComponent = tab_containing(event.GetTargetElement());
|
|
||||||
}
|
|
||||||
int direction = isNext ? 1 : -1;
|
int direction = isNext ? 1 : -1;
|
||||||
int i = currentComponent + direction;
|
int i = currentComponent + direction;
|
||||||
if (currentComponent == -1) {
|
if (currentComponent == -1) {
|
||||||
|
|||||||
@@ -36,8 +36,6 @@ private:
|
|||||||
|
|
||||||
Props mProps;
|
Props mProps;
|
||||||
std::vector<Tab> mTabs;
|
std::vector<Tab> mTabs;
|
||||||
Rml::Element* mEndSpacer = nullptr;
|
|
||||||
bool mRedirectingScroll = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dusk::ui
|
} // namespace dusk::ui
|
||||||
|
|||||||
@@ -33,12 +33,10 @@ bool initialize() noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
load_font("FiraSans-Regular.ttf", true);
|
load_font("FiraSans-Regular.ttf", true);
|
||||||
load_font("FiraSans-Bold.ttf");
|
|
||||||
load_font("FiraSansCondensed-Regular.ttf");
|
load_font("FiraSansCondensed-Regular.ttf");
|
||||||
load_font("FiraSansCondensed-Bold.ttf");
|
load_font("FiraSansCondensed-Bold.ttf");
|
||||||
load_font("AlegreyaSC-Regular.ttf");
|
load_font("AlegreyaSC-Regular.ttf");
|
||||||
load_font("AlegreyaSC-Bold.ttf");
|
load_font("AlegreyaSC-Bold.ttf");
|
||||||
load_font("MaterialSymbolsRounded-Regular.ttf");
|
|
||||||
|
|
||||||
sInitialized = true;
|
sInitialized = true;
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ const Rml::String kDocumentSource = R"RML(
|
|||||||
|
|
||||||
Window::Window() : Document(kDocumentSource), mRoot(mDocument->GetElementById("window")) {
|
Window::Window() : Document(kDocumentSource), mRoot(mDocument->GetElementById("window")) {
|
||||||
mTabBar = std::make_unique<TabBar>(mRoot, TabBar::Props{
|
mTabBar = std::make_unique<TabBar>(mRoot, TabBar::Props{
|
||||||
.onClose = [this] { pop(); },
|
|
||||||
.selectedTabIndex = 0,
|
.selectedTabIndex = 0,
|
||||||
.autoSelect = true,
|
.autoSelect = true,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -335,6 +335,13 @@ static int fopAc_Execute(void* i_this) {
|
|||||||
print_error_check_c error_check(actor, print_error_check_c::sEXECUTE);
|
print_error_check_c error_check(actor, print_error_check_c::sEXECUTE);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if TARGET_PC
|
||||||
|
if (dusk::getSettings().game.hyperEnemies && actor->group == fopAc_ENEMY_e && !dComIfGp_event_runCheck())
|
||||||
|
{
|
||||||
|
fpcMtd_Execute((process_method_class*)actor->sub_method, actor);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
ret = fpcMtd_Execute((process_method_class*)actor->sub_method, actor);
|
ret = fpcMtd_Execute((process_method_class*)actor->sub_method, actor);
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
|||||||
Reference in New Issue
Block a user