mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2026-04-22 10:01:46 +00:00
Merge edfa2d750f into 24c5a226ed
This commit is contained in:
commit
83ddeffd76
5 changed files with 169 additions and 5 deletions
|
|
@ -1,5 +1,6 @@
|
|||
#include "djui.h"
|
||||
#include "djui_panel.h"
|
||||
#include "djui_flow_layout.h"
|
||||
#include "pc/controller/controller_mouse.h"
|
||||
#include "pc/gfx/gfx_window_manager_api.h"
|
||||
#include "pc/pc_main.h"
|
||||
|
|
@ -115,6 +116,24 @@ void djui_cursor_move(s8 xDir, s8 yDir) {
|
|||
if (pick != NULL) {
|
||||
sCursorMouseControlled = false;
|
||||
djui_cursor_input_controlled_center(pick);
|
||||
|
||||
// auto-scroll scrollable flow layout to show the picked element
|
||||
if (gDjuiFlowLayoutScrollRender) {
|
||||
struct DjuiBase* parent = pick->parent;
|
||||
while (parent) {
|
||||
if (parent->render == gDjuiFlowLayoutScrollRender) {
|
||||
struct DjuiFlowLayout* layout = (struct DjuiFlowLayout*)parent;
|
||||
f32 targetTop = pick->elem.y;
|
||||
f32 targetBot = pick->elem.y + pick->elem.height;
|
||||
f32 visTop = parent->clip.y;
|
||||
f32 visBot = parent->clip.y + parent->clip.height;
|
||||
if (targetTop < visTop) { layout->scrollY -= (visTop - targetTop); }
|
||||
else if (targetBot > visBot) { layout->scrollY += (targetBot - visBot); }
|
||||
break;
|
||||
}
|
||||
parent = parent->parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
#include "djui.h"
|
||||
|
||||
bool (*gDjuiFlowLayoutScrollRender)(struct DjuiBase*) = NULL;
|
||||
|
||||
////////////////
|
||||
// properties //
|
||||
////////////////
|
||||
|
|
@ -41,6 +43,97 @@ static void djui_flow_layout_on_child_render(struct DjuiBase* base, struct DjuiB
|
|||
}
|
||||
}
|
||||
|
||||
////////////
|
||||
// scroll //
|
||||
////////////
|
||||
|
||||
static bool djui_flow_layout_scroll_render(struct DjuiBase* base) {
|
||||
struct DjuiFlowLayout* layout = (struct DjuiFlowLayout*)base;
|
||||
|
||||
// draw background
|
||||
djui_rect_render(base);
|
||||
|
||||
// compute content height from visible children
|
||||
f32 contentHeight = layout->margin.value;
|
||||
struct DjuiBaseChild* child = base->child;
|
||||
while (child != NULL) {
|
||||
if (child->base->visible) {
|
||||
contentHeight += child->base->height.value + layout->margin.value;
|
||||
}
|
||||
child = child->next;
|
||||
}
|
||||
layout->contentHeight = contentHeight;
|
||||
|
||||
// clamp scroll
|
||||
f32 maxScroll = contentHeight - base->elem.height - 32;
|
||||
if (maxScroll < 0) { maxScroll = 0; }
|
||||
if (layout->scrollY < 0) { layout->scrollY = 0; }
|
||||
if (layout->scrollY > maxScroll) { layout->scrollY = maxScroll; }
|
||||
|
||||
// shift comp so children render scrolled
|
||||
base->comp.y -= layout->scrollY;
|
||||
|
||||
// draw scrollbar indicator
|
||||
if (maxScroll > 0) {
|
||||
struct DjuiBaseRect* clip = &base->clip;
|
||||
f32 thumbRatio = clip->height / contentHeight;
|
||||
f32 thumbH = clip->height * thumbRatio;
|
||||
if (thumbH < 20) { thumbH = 20; }
|
||||
f32 thumbY = clip->y + (layout->scrollY / maxScroll) * (clip->height - thumbH);
|
||||
f32 thumbX = clip->x + clip->width + 6;
|
||||
|
||||
f32 tX = thumbX, tY = thumbY;
|
||||
djui_gfx_position_translate(&tX, &tY);
|
||||
create_dl_translation_matrix(DJUI_MTX_PUSH, tX, tY, 0);
|
||||
|
||||
f32 tW = 4, tH = thumbH;
|
||||
djui_gfx_scale_translate(&tW, &tH);
|
||||
create_dl_scale_matrix(DJUI_MTX_NOPUSH, tW, tH, 1.0f);
|
||||
|
||||
gDPSetEnvColor(gDisplayListHead++, 200, 200, 200, 128);
|
||||
gSPDisplayList(gDisplayListHead++, dl_djui_simple_rect);
|
||||
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void djui_flow_layout_on_scroll(struct DjuiBase* base, float x, float y) {
|
||||
UNUSED f32 unused = x;
|
||||
struct DjuiFlowLayout* layout = (struct DjuiFlowLayout*)base;
|
||||
layout->scrollY -= y * 48.0f;
|
||||
}
|
||||
|
||||
static void flow_scroll_begin(struct DjuiBase* base, UNUSED bool inputCursor) {
|
||||
struct DjuiFlowLayout* layout = (struct DjuiFlowLayout*)base;
|
||||
layout->touchStartY = gCursorY;
|
||||
}
|
||||
|
||||
static void flow_scroll_update(struct DjuiBase* base) {
|
||||
struct DjuiFlowLayout* layout = (struct DjuiFlowLayout*)base;
|
||||
f32 delta = layout->touchStartY - gCursorY;
|
||||
layout->scrollY += delta;
|
||||
layout->touchStartY = gCursorY;
|
||||
}
|
||||
|
||||
static void flow_scroll_end(UNUSED struct DjuiBase* base) {}
|
||||
|
||||
void djui_flow_layout_enable_scroll(struct DjuiFlowLayout* layout) {
|
||||
layout->scrollEnabled = true;
|
||||
layout->scrollY = 0;
|
||||
layout->base.render = djui_flow_layout_scroll_render;
|
||||
layout->base.abandonAfterChildRenderFail = false;
|
||||
|
||||
if (!gDjuiFlowLayoutScrollRender) {
|
||||
gDjuiFlowLayoutScrollRender = djui_flow_layout_scroll_render;
|
||||
}
|
||||
|
||||
djui_interactable_create(&layout->base, NULL);
|
||||
djui_interactable_hook_scroll(&layout->base, djui_flow_layout_on_scroll);
|
||||
djui_interactable_hook_cursor_down(&layout->base,
|
||||
flow_scroll_begin, flow_scroll_update, flow_scroll_end);
|
||||
}
|
||||
|
||||
static void djui_flow_layout_destroy(struct DjuiBase* base) {
|
||||
struct DjuiFlowLayout* layout = (struct DjuiFlowLayout*)base;
|
||||
free(layout);
|
||||
|
|
|
|||
|
|
@ -5,10 +5,18 @@ struct DjuiFlowLayout {
|
|||
struct DjuiBase base;
|
||||
enum DjuiFlowDirection flowDirection;
|
||||
struct DjuiScreenValue margin;
|
||||
// Scroll
|
||||
bool scrollEnabled;
|
||||
f32 scrollY;
|
||||
f32 contentHeight;
|
||||
f32 touchStartY;
|
||||
};
|
||||
|
||||
extern bool (*gDjuiFlowLayoutScrollRender)(struct DjuiBase*);
|
||||
|
||||
void djui_flow_layout_set_flow_direction(struct DjuiFlowLayout* layout, enum DjuiFlowDirection flowDirection);
|
||||
void djui_flow_layout_set_margin(struct DjuiFlowLayout* layout, f32 margin);
|
||||
void djui_flow_layout_set_margin_type(struct DjuiFlowLayout* layout, enum DjuiScreenValueType marginType);
|
||||
void djui_flow_layout_enable_scroll(struct DjuiFlowLayout* layout);
|
||||
|
||||
struct DjuiFlowLayout* djui_flow_layout_create(struct DjuiBase* parent);
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include "djui_panel_modlist.h"
|
||||
#include "djui_panel_playerlist.h"
|
||||
|
||||
#include "djui_flow_layout.h"
|
||||
#include "pc/controller/controller_sdl.h"
|
||||
#include "pc/controller/controller_mouse.h"
|
||||
#include "pc/controller/controller_keyboard.h"
|
||||
|
|
@ -22,6 +23,8 @@ static enum PadHoldDirection sKeyboardHoldDirection = PAD_HOLD_DIR_NONE;
|
|||
static u16 sKeyboardButtons = 0;
|
||||
|
||||
static bool sIgnoreInteractableUntilCursorReleased = false;
|
||||
static f32 sCursorDownStartY = 0;
|
||||
static bool sDragScrollActive = false;
|
||||
|
||||
struct DjuiBase* gDjuiHovered = NULL;
|
||||
struct DjuiBase* gDjuiCursorDownOn = NULL;
|
||||
|
|
@ -336,10 +339,21 @@ void djui_interactable_on_text_editing(char* text, int cursorPos) {
|
|||
}
|
||||
|
||||
void djui_interactable_on_scroll(float x, float y) {
|
||||
if (gInteractableFocus == NULL) { return; }
|
||||
if (gInteractableFocus->interactable == NULL) { return; }
|
||||
if (gInteractableFocus->interactable->on_scroll == NULL) { return; }
|
||||
gInteractableFocus->interactable->on_scroll(gInteractableFocus, x, y);
|
||||
// Priority: focused element (e.g. chat input)
|
||||
if (gInteractableFocus && gInteractableFocus->interactable
|
||||
&& gInteractableFocus->interactable->on_scroll) {
|
||||
gInteractableFocus->interactable->on_scroll(gInteractableFocus, x, y);
|
||||
return;
|
||||
}
|
||||
// Bubble from hovered element up to ancestors
|
||||
struct DjuiBase* base = gDjuiHovered;
|
||||
while (base) {
|
||||
if (base->interactable && base->interactable->on_scroll) {
|
||||
base->interactable->on_scroll(base, x, y);
|
||||
return;
|
||||
}
|
||||
base = base->parent;
|
||||
}
|
||||
}
|
||||
|
||||
void djui_interactable_update_pad(void) {
|
||||
|
|
@ -454,15 +468,44 @@ void djui_interactable_update(void) {
|
|||
if (gDjuiHovered != NULL) {
|
||||
gInteractableMouseDown = gDjuiHovered;
|
||||
gDjuiHovered = NULL;
|
||||
sCursorDownStartY = gCursorY;
|
||||
sDragScrollActive = false;
|
||||
djui_interactable_on_cursor_down_begin(gInteractableMouseDown, !mouseButtons);
|
||||
} else {
|
||||
} else if (sDragScrollActive) {
|
||||
djui_interactable_on_cursor_down(gInteractableMouseDown);
|
||||
} else {
|
||||
// check if vertical drag exceeds threshold to steal touch for scrolling
|
||||
f32 dragDist = gCursorY - sCursorDownStartY;
|
||||
if (dragDist < 0) { dragDist = -dragDist; }
|
||||
if (gInteractableMouseDown != NULL && dragDist > 10.0f
|
||||
&& gDjuiFlowLayoutScrollRender
|
||||
&& (!gInteractableMouseDown->interactable
|
||||
|| !gInteractableMouseDown->interactable->on_cursor_down)) {
|
||||
struct DjuiBase* parent = gInteractableMouseDown->parent;
|
||||
while (parent) {
|
||||
if (parent->render == gDjuiFlowLayoutScrollRender) {
|
||||
gDjuiCursorDownOn = NULL;
|
||||
djui_interactable_update_style(gInteractableMouseDown);
|
||||
gInteractableMouseDown = parent;
|
||||
sDragScrollActive = true;
|
||||
djui_interactable_on_cursor_down_begin(parent, !mouseButtons);
|
||||
break;
|
||||
}
|
||||
parent = parent->parent;
|
||||
}
|
||||
if (!sDragScrollActive) {
|
||||
djui_interactable_on_cursor_down(gInteractableMouseDown);
|
||||
}
|
||||
} else {
|
||||
djui_interactable_on_cursor_down(gInteractableMouseDown);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// cursor up event
|
||||
if (gInteractableMouseDown != NULL) {
|
||||
djui_interactable_on_cursor_down_end(gInteractableMouseDown);
|
||||
gInteractableMouseDown = NULL;
|
||||
sDragScrollActive = false;
|
||||
}
|
||||
struct DjuiBase* lastHovered = gDjuiHovered;
|
||||
gDjuiHovered = NULL;
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ struct DjuiThreePanel* djui_panel_menu_create(char* headerText, bool forcedLeftS
|
|||
djui_base_set_color(&body->base, 0, 0, 0, 0);
|
||||
djui_flow_layout_set_margin(body, 16);
|
||||
djui_flow_layout_set_flow_direction(body, DJUI_FLOW_DIR_DOWN);
|
||||
djui_flow_layout_enable_scroll(body);
|
||||
}
|
||||
return panel;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue