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;
PLSR_BFSTM music;
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 {
s32 initial_x;
s32 initial_y;
HidTouchState initial;
HidTouchState cur;
s32 cur_x;
s32 cur_y;
s32 prev_x;
s32 prev_y;
u32 finger_id;
auto in_range(s32 x, s32 y, s32 w, s32 h) const -> bool {
return cur.x >= x && cur.x <= x + w && cur.y >= y && cur.y <= y + h;
}
bool is_touching;
bool is_tap;
bool is_clicked;
};
enum class Button : u64 {

View File

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

View File

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

View File

@@ -153,6 +153,27 @@ Menu::~Menu() {
void Menu::Update(Controller* controller, TouchInfo* 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) {

View File

@@ -553,6 +553,36 @@ Menu::~Menu() {
void Menu::Update(Controller* controller, TouchInfo* 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) {

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