initial work on touch support

list of things not done:
- no scrolling
- only some menus
- no widgets
- no buttons
This commit is contained in:
ITotalJustice
2025-01-01 17:32:58 +00:00
parent 54c63d6f3b
commit f824187248
7 changed files with 101 additions and 43 deletions

View File

@@ -196,39 +196,19 @@ struct Theme {
fs::FsPath path; fs::FsPath path;
PLSR_BFSTM music; PLSR_BFSTM music;
ElementEntry elements[ThemeEntryID_MAX]; ElementEntry elements[ThemeEntryID_MAX];
// NVGcolor background; // bg
// NVGcolor lines; // grid lines
// NVGcolor spacer; // lines in popup box
// NVGcolor text; // text colour
// NVGcolor text_info; // description text
NVGcolor selected; // selected colours
// NVGcolor overlay; // popup overlay colour
// void DrawElement(float x, float y, float w, float h, ThemeEntryID id);
};
enum class TouchState {
Start, // set when touch has started
Touching, // set when touch is held longer than 1 frame
Stop, // set after touch is released
None, // set when there is no touch
}; };
struct TouchInfo { struct TouchInfo {
s32 initial_x; HidTouchState initial;
s32 initial_y; HidTouchState cur;
s32 cur_x; auto in_range(s32 x, s32 y, s32 w, s32 h) const -> bool {
s32 cur_y; return cur.x >= x && cur.x <= x + w && cur.y >= y && cur.y <= y + h;
}
s32 prev_x;
s32 prev_y;
u32 finger_id;
bool is_touching; bool is_touching;
bool is_tap; bool is_tap;
bool is_clicked;
}; };
enum class Button : u64 { enum class Button : u64 {

View File

@@ -49,6 +49,8 @@ struct Widget : public Object {
m_actions.clear(); m_actions.clear();
} }
auto FireAction(Button button, u8 type = ActionType::DOWN) -> bool;
void SetPop(bool pop = true) { void SetPop(bool pop = true) {
m_pop = pop; m_pop = pop;
} }

View File

@@ -707,34 +707,27 @@ void App::Poll() {
m_controller.m_kup = padGetButtonsUp(&m_pad); m_controller.m_kup = padGetButtonsUp(&m_pad);
m_controller.UpdateButtonHeld(static_cast<u64>(Button::ANY_DIRECTION)); m_controller.UpdateButtonHeld(static_cast<u64>(Button::ANY_DIRECTION));
HidTouchScreenState touch_state{}; HidTouchScreenState state{};
hidGetTouchScreenStates(&touch_state, 1); hidGetTouchScreenStates(&state, 1);
m_touch_info.is_clicked = false;
if (touch_state.count == 1 && !m_touch_info.is_touching) { if (state.count == 1 && !m_touch_info.is_touching) {
m_touch_info.initial_x = m_touch_info.prev_x = m_touch_info.cur_x = touch_state.touches[0].x; m_touch_info.initial = m_touch_info.cur = state.touches[0];
m_touch_info.initial_y = m_touch_info.prev_y = m_touch_info.cur_y = touch_state.touches[0].y;
m_touch_info.finger_id = touch_state.touches[0].finger_id;
m_touch_info.is_touching = true; m_touch_info.is_touching = true;
m_touch_info.is_tap = true; m_touch_info.is_tap = true;
// PlaySoundEffect(SoundEffect_Limit); // PlaySoundEffect(SoundEffect_Limit);
} else if (touch_state.count >= 1 && m_touch_info.is_touching && m_touch_info.finger_id == touch_state.touches[0].finger_id) { } else if (state.count >= 1 && m_touch_info.is_touching) {
m_touch_info.prev_x = m_touch_info.cur_x; m_touch_info.cur = state.touches[0];
m_touch_info.prev_y = m_touch_info.cur_y;
m_touch_info.cur_x = touch_state.touches[0].x;
m_touch_info.cur_y = touch_state.touches[0].y;
if (m_touch_info.is_tap && if (m_touch_info.is_tap &&
(std::abs(m_touch_info.initial_x - m_touch_info.cur_x) > 20 || (std::abs((s32)m_touch_info.initial.x - (s32)m_touch_info.cur.x) > 20 ||
std::abs(m_touch_info.initial_y - m_touch_info.cur_y) > 20)) { std::abs((s32)m_touch_info.initial.y - (s32)m_touch_info.cur.y) > 20)) {
m_touch_info.is_tap = false; m_touch_info.is_tap = false;
} }
} else if (m_touch_info.is_touching) { } else if (m_touch_info.is_touching) {
m_touch_info.is_touching = false; m_touch_info.is_touching = false;
// check if we clicked on anything, if so, handle it
if (m_touch_info.is_tap) { if (m_touch_info.is_tap) {
// todo: m_touch_info.is_clicked = true;
} }
} }
} }

View File

@@ -1014,6 +1014,27 @@ Menu::~Menu() {
void Menu::Update(Controller* controller, TouchInfo* touch) { void Menu::Update(Controller* controller, TouchInfo* touch) {
MenuBase::Update(controller, touch); MenuBase::Update(controller, touch);
const u64 SCROLL = m_start;
const u64 max_entry_display = 9;
const u64 nro_total = m_entries.size();
const u64 cursor_pos = m_index;
if (touch->is_clicked) {
for (u64 i = 0, pos = SCROLL, y = 110, w = 370, h = 155; pos < nro_total && i < max_entry_display; y += h + 10) {
for (u64 j = 0, x = 75; j < 3 && pos < nro_total && i < max_entry_display; j++, i++, pos++, x += w + 10) {
if (touch->in_range(x, y, w, h)) {
if (pos == m_index) {
FireAction(Button::A);
} else {
App::PlaySoundEffect(SoundEffect_Focus);
SetIndex(pos);
}
break;
}
}
}
}
} }
void Menu::Draw(NVGcontext* vg, Theme* theme) { void Menu::Draw(NVGcontext* vg, Theme* theme) {

View File

@@ -153,6 +153,27 @@ Menu::~Menu() {
void Menu::Update(Controller* controller, TouchInfo* touch) { void Menu::Update(Controller* controller, TouchInfo* touch) {
MenuBase::Update(controller, touch); MenuBase::Update(controller, touch);
const u64 SCROLL = m_start;
const u64 max_entry_display = 9;
const u64 nro_total = m_entries.size();
const u64 cursor_pos = m_index;
if (touch->is_clicked) {
for (u64 i = 0, pos = SCROLL, y = 110, w = 370, h = 155; pos < nro_total && i < max_entry_display; y += h + 10) {
for (u64 j = 0, x = 75; j < 3 && pos < nro_total && i < max_entry_display; j++, i++, pos++, x += w + 10) {
if (touch->in_range(x, y, w, h)) {
if (pos == m_index) {
FireAction(Button::A);
} else {
App::PlaySoundEffect(SoundEffect_Focus);
SetIndex(pos);
}
break;
}
}
}
}
} }
void Menu::Draw(NVGcontext* vg, Theme* theme) { void Menu::Draw(NVGcontext* vg, Theme* theme) {

View File

@@ -553,6 +553,36 @@ Menu::~Menu() {
void Menu::Update(Controller* controller, TouchInfo* touch) { void Menu::Update(Controller* controller, TouchInfo* touch) {
MenuBase::Update(controller, touch); MenuBase::Update(controller, touch);
if (m_pages.empty()) {
return;
}
const auto& page = m_pages[m_page_index];
if (page.m_ready != PageLoadState::Done) {
return;
}
const u64 SCROLL = m_start;
const u64 max_entry_display = 9;
const u64 nro_total = page.m_packList.size();// m_entries_current.size();
const u64 cursor_pos = m_index;
if (touch->is_clicked) {
for (u64 i = 0, pos = SCROLL, y = 110, w = 350, h = 250; pos < nro_total && i < max_entry_display; y += h + 10) {
for (u64 j = 0, x = 75; j < 3 && pos < nro_total && i < max_entry_display; j++, i++, pos++, x += w + 10) {
if (touch->in_range(x, y, w, h)) {
if (pos == m_index) {
FireAction(Button::A);
} else {
App::PlaySoundEffect(SoundEffect_Focus);
SetIndex(pos);
}
break;
}
}
}
}
} }
void Menu::Draw(NVGcontext* vg, Theme* theme) { void Menu::Draw(NVGcontext* vg, Theme* theme) {

View File

@@ -47,4 +47,15 @@ void Widget::RemoveAction(Button button) {
} }
} }
auto Widget::FireAction(Button b, u8 type) -> bool {
for (const auto& [button, action] : m_actions) {
if (button == b && (action.m_type & type)) {
App::PlaySoundEffect(SoundEffect_Focus);
action.Invoke(true);
return true;
}
}
return false;
}
} // namespace sphaira::ui } // namespace sphaira::ui