add widget containers and widget mouse picking

This commit is contained in:
Zack Buhman 2025-06-29 00:02:45 -05:00
parent ec517fb455
commit d69b2245b8
12 changed files with 318 additions and 111 deletions

View File

@ -9,6 +9,8 @@
#include "sh7091/serial.hpp" #include "sh7091/serial.hpp"
#include "math/math.hpp"
#include "input.hpp" #include "input.hpp"
#include "cursor.hpp" #include "cursor.hpp"
#include "framebuffer.hpp" #include "framebuffer.hpp"
@ -39,10 +41,12 @@ namespace cursor {
auto& data = data_fields.data; auto& data = data_fields.data;
float dx = static_cast<float>(data.analog_coordinate_axis[2] - 0x80) * 0.015; float dx = static_cast<float>(data.analog_coordinate_axis[2] - 0x80) * 0.015;
float dy = static_cast<float>(data.analog_coordinate_axis[3] - 0x80) * -0.015; float dy = static_cast<float>(data.analog_coordinate_axis[3] - 0x80) * 0.015;
state[port_ix].x += dx; state[port_ix].x += dx;
state[port_ix].y += dy; state[port_ix].y += dy;
state[port_ix].a = ft0::data_transfer::digital_button::a(data.digital_button) == 0;
state[port_ix].b = ft0::data_transfer::digital_button::b(data.digital_button) == 0;
state[port_ix].active = true; state[port_ix].active = true;
} else if ((port.function_type & function_type::pointing) != 0 && port.host_response_data_transfer_ft9 != nullptr) { } else if ((port.function_type & function_type::pointing) != 0 && port.host_response_data_transfer_ft9 != nullptr) {
@ -51,13 +55,18 @@ namespace cursor {
if ((std::byteswap(data_fields.function_type) & function_type::pointing) == 0) if ((std::byteswap(data_fields.function_type) & function_type::pointing) == 0)
continue; continue;
auto& data = data_fields.data; auto& data = data_fields.data;
float dx = static_cast<float>(data.analog_coordinate_axis[0] - 0x200) * 0.065; float dx = static_cast<float>(data.analog_coordinate_axis[0] - 0x200) * 0.65;
float dy = static_cast<float>(data.analog_coordinate_axis[1] - 0x200) * -0.065; float dy = static_cast<float>(data.analog_coordinate_axis[1] - 0x200) * 0.65;
state[port_ix].x += dx; state[port_ix].x += dx;
state[port_ix].y += dy; state[port_ix].y += dy;
state[port_ix].a = ft9::data_transfer::digital_button::a(data.digital_button) == 0;
state[port_ix].b = ft9::data_transfer::digital_button::b(data.digital_button) == 0;
state[port_ix].active = true; state[port_ix].active = true;
} }
state[port_ix].x = clamp<float>(state[port_ix].x, 0, framebuffer.px_width - 1);
state[port_ix].y = clamp<float>(state[port_ix].y, 0, framebuffer.px_height - 1);
} }
} }

View File

@ -6,6 +6,8 @@ namespace cursor {
bool active; bool active;
float x; float x;
float y; float y;
bool a;
bool b;
}; };
extern struct cursor state[4]; extern struct cursor state[4];

View File

@ -59,75 +59,6 @@ void vbr600()
asm volatile ("ldc %0,sr" : : "r" (sr)); asm volatile ("ldc %0,sr" : : "r" (sr));
} }
/*
void input_update()
{
int ra = ft0::data_transfer::digital_button::ra(data[0].digital_button) == 0;
int la = ft0::data_transfer::digital_button::la(data[0].digital_button) == 0;
int da = ft0::data_transfer::digital_button::da(data[0].digital_button) == 0;
int ua = ft0::data_transfer::digital_button::ua(data[0].digital_button) == 0;
int x = ft0::data_transfer::digital_button::x(data[0].digital_button) == 0;
int y = ft0::data_transfer::digital_button::y(data[0].digital_button) == 0;
int a = ft0::data_transfer::digital_button::a(data[0].digital_button) == 0;
int b = ft0::data_transfer::digital_button::b(data[0].digital_button) == 0;
static int last_ra = 0;
static int last_la = 0;
static int last_da = 0;
static int last_ua = 0;
static int last_x = 0;
static int last_y = 0;
static int last_a = 0;
static int last_b = 0;
if (ra && ra != last_ra) {
sandbox_state.channel_ix += 1;
if (sandbox_state.channel_ix > 63)
sandbox_state.channel_ix = 0;
}
if (la && la != last_la) {
sandbox_state.channel_ix -= 1;
if (sandbox_state.channel_ix < 0)
sandbox_state.channel_ix = 63;
}
if (da && da != last_da) {
sandbox_state.pointer_row += 1;
if (sandbox_state.pointer_row >= sandbox_labels_length)
sandbox_state.pointer_row = 0;
}
if (ua && ua != last_ua) {
sandbox_state.pointer_row -= 1;
if (sandbox_state.pointer_row < 0)
sandbox_state.pointer_row = sandbox_labels_length - 1;
}
if (x && x != last_x) {
label_update(-1);
}
if (y && y != last_y) {
execute_key(0);
}
if (a && a != last_a) {
execute_key(1);
}
if (b && b != last_b) {
label_update(1);
}
last_ra = ra;
last_la = la;
last_ua = ua;
last_da = da;
last_x = x;
last_y = y;
last_a = a;
last_b = b;
}
*/
void load_xm(float clock_multiplier) void load_xm(float clock_multiplier)
{ {
using namespace interpreter; using namespace interpreter;
@ -194,7 +125,6 @@ void main()
//test_pattern(); //test_pattern();
interrupt_init(); interrupt_init();
//channel_sandbox_defaults();
system.IML6NRM = istnrm::end_of_render_tsp system.IML6NRM = istnrm::end_of_render_tsp
| istnrm::v_blank_in | istnrm::v_blank_in

View File

@ -8,6 +8,50 @@
#include "channel_status.hpp" #include "channel_status.hpp"
#include "texture.hpp" #include "texture.hpp"
#include "widget/button.hpp" #include "widget/button.hpp"
#include "widget/left_aligned.hpp"
#include "widget/top_aligned.hpp"
#include "cursor.hpp"
void prev_click()
{
printf("prev\n");
}
widget::button prev_button(50, 50, "prev", prev_click);
widget::button play_button(50, 50, "play");
widget::button pause_button(50, 50, "pause");
widget::button stop_button(50, 50, "stop");
widget::button next_button(50, 50, "next");
widget::widget * left1_children[] = {
&prev_button,
&play_button,
&pause_button,
&stop_button,
&next_button,
};
int left1_length = (sizeof (left1_children)) / (sizeof (left1_children[0]));
widget::button up_button(50, 50, "up");
widget::button down_button(50, 50, "down");
widget::widget * left2_children[] = {
&up_button,
&down_button,
};
int left2_length = (sizeof (left2_children)) / (sizeof (left2_children[0]));
widget::left_aligned left_container1(0, 0, 5, left1_children, left1_length);
widget::left_aligned left_container2(0, 0, 5, left2_children, left2_length);
widget::widget * top_children[] = {
&left_container1,
&left_container2,
};
int top_length = (sizeof (top_children)) / (sizeof (top_children[0]));
widget::top_aligned top = widget::top_aligned(100, 100, 5, top_children, top_length);
namespace scene::tracker { namespace scene::tracker {
@ -25,10 +69,31 @@ namespace scene::tracker {
.punch_through = 32 * 4 .punch_through = 32 * 4
}, },
.transfer = transfer, .transfer = transfer,
.init = init,
}; };
void init()
{
top.freeze(0, 0);
}
void update()
{
for (int i = 0; i < 4; i++) {
cursor::cursor& c = cursor::state[i];
if (c.active && c.a) {
widget::widget * w = top.pick(c.x, c.y);
if (w != nullptr) {
w->click();
}
}
}
}
void transfer(ta_multiwriter& multi) void transfer(ta_multiwriter& multi)
{ {
update();
const int x = 3; const int x = 3;
const int y = 100; const int y = 100;
@ -69,7 +134,8 @@ namespace scene::tracker {
//tracker::channel_status::transfer(multi.op, 0, 0); //tracker::channel_status::transfer(multi.op, 0, 0);
widget::button(60, 60, 50, 50, "test").draw(multi); //test_container.draw(multi);
} top.draw(multi);
}
} }
} }

View File

@ -8,5 +8,7 @@ namespace scene::tracker {
void transfer(ta_multiwriter& multi); void transfer(ta_multiwriter& multi);
void init();
extern const struct scene::scene scene; extern const struct scene::scene scene;
} }

View File

@ -3,10 +3,35 @@
namespace widget { namespace widget {
struct bounding_box { struct bounding_box {
const float x; float _x;
const float y; float _y;
const float width; float width;
const float height; float height;
}; float dx;
float dy;
constexpr inline bounding_box(float __x, float __y, float _width, float _height)
: _x(__x), _y(__y), width(_width), height(_height), dx(0), dy(0)
{ }
constexpr inline float x()
{
return dx + _x;
}
constexpr inline float y()
{
return dy + _y;
}
constexpr inline bool inside(float __x, float __y)
{
return
(__x >= x())
&& (__y >= y())
&& (__x <= (x() + width))
&& (__y <= (y() + height))
;
}
};
} }

View File

@ -14,6 +14,8 @@ namespace widget {
const static float highlight_depth = 1.0 / 8.0; const static float highlight_depth = 1.0 / 8.0;
const static int highlight_color = 0x353a3a; const static int highlight_color = 0x353a3a;
const static int highlight_click_color = 0x141616;
const static float background_depth = 1.0 / 7.0; const static float background_depth = 1.0 / 7.0;
const static int background_color = 0x282c2c; const static int background_color = 0x282c2c;
@ -23,10 +25,10 @@ namespace widget {
void button::draw_shadow(ta_parameter_writer& writer) void button::draw_shadow(ta_parameter_writer& writer)
{ {
{ {
float x0 = x + 1; float x0 = x() + 1;
float x1 = x + width - 1; float x1 = x() + width - 1;
float y0 = y; float y0 = y();
float y1 = y + height; float y1 = y() + height;
quad_type_0(writer, quad_type_0(writer,
{x0, y0, shadow_depth}, {x0, y0, shadow_depth},
{x1, y0, shadow_depth}, {x1, y0, shadow_depth},
@ -35,10 +37,10 @@ namespace widget {
shadow_color); shadow_color);
} }
{ {
float x0 = x; float x0 = x();
float x1 = x + width; float x1 = x() + width;
float y0 = y + 1; float y0 = y() + 1;
float y1 = y + height - 1; float y1 = y() + height - 1;
quad_type_0(writer, quad_type_0(writer,
{x0, y0, shadow_depth}, {x0, y0, shadow_depth},
{x1, y0, shadow_depth}, {x1, y0, shadow_depth},
@ -50,10 +52,10 @@ namespace widget {
void button::draw_lowlight(ta_parameter_writer& writer) void button::draw_lowlight(ta_parameter_writer& writer)
{ {
float x0 = x + 1; float x0 = x() + 1;
float x1 = x + width - 1; float x1 = x() + width - 1;
float y0 = y + 1; float y0 = y() + 1;
float y1 = y + height - 1; float y1 = y() + height - 1;
quad_type_0(writer, quad_type_0(writer,
{x0, y0, lowlight_depth}, {x0, y0, lowlight_depth},
{x1, y0, lowlight_depth}, {x1, y0, lowlight_depth},
@ -64,24 +66,26 @@ namespace widget {
void button::draw_highlight(ta_parameter_writer& writer) void button::draw_highlight(ta_parameter_writer& writer)
{ {
float x0 = x + 1; float x0 = x() + 1;
float x1 = x + width - 2; float x1 = x() + width - 2;
float y0 = y + 1; float y0 = y() + 1;
float y1 = y + height - 2; float y1 = y() + height - 2;
int color = (click_state == click_type::release) ? highlight_color : highlight_click_color;
quad_type_0(writer, quad_type_0(writer,
{x0, y0, highlight_depth}, {x0, y0, highlight_depth},
{x1, y0, highlight_depth}, {x1, y0, highlight_depth},
{x1, y1, highlight_depth}, {x1, y1, highlight_depth},
{x0, y1, highlight_depth}, {x0, y1, highlight_depth},
highlight_color); color);
} }
void button::draw_background(ta_parameter_writer& writer) void button::draw_background(ta_parameter_writer& writer)
{ {
float x0 = x + 2; float x0 = x() + 2;
float x1 = x + width - 2; float x1 = x() + width - 2;
float y0 = y + 2; float y0 = y() + 2;
float y1 = y + height - 2; float y1 = y() + height - 2;
quad_type_0(writer, quad_type_0(writer,
{x0, y0, background_depth}, {x0, y0, background_depth},
{x1, y0, background_depth}, {x1, y0, background_depth},
@ -92,8 +96,10 @@ namespace widget {
void button::draw_label(ta_parameter_writer& writer) void button::draw_label(ta_parameter_writer& writer)
{ {
float cx = x + width / 2 - (glyph::hori_advance * label_length) / 2; float y_offset = (float)(click_state != click_type::release);
float cy = y + height / 2 - glyph::vert_advance / 2;
float cx = x() + width / 2 - (glyph::hori_advance * label_length) / 2;
float cy = y() + height / 2 - glyph::vert_advance / 2 + y_offset;
transfer_string(writer, label, cx, cy, label_depth, label_color); transfer_string(writer, label, cx, cy, label_depth, label_color);
} }
@ -115,5 +121,15 @@ namespace widget {
transfer_global_polygon_glyph(multi.pt); transfer_global_polygon_glyph(multi.pt);
draw_label(multi.pt); draw_label(multi.pt);
widget::draw(multi);
}
void button::click()
{
if (click_state == click_type::release && on_click != nullptr)
on_click();
widget::click();
} }
} }

View File

@ -2,7 +2,7 @@
#include "holly/ta_parameter.hpp" #include "holly/ta_parameter.hpp"
#include "ta_multiwriter.hpp" #include "ta_multiwriter.hpp"
#include "widget/bounding_box.hpp" #include "widget/widget.hpp"
namespace widget { namespace widget {
@ -15,20 +15,34 @@ namespace widget {
return l; return l;
} }
struct button : bounding_box { struct button : widget {
const char * const label; const char * const label;
const int label_length; const int label_length;
void (* const on_click)();
button(float _x, float _y, float _width, float _height, const char * _label) inline button(float _width, float _height, const char * _label)
: bounding_box(_x, _y, _width, _height), label(_label), label_length(str_length(_label)) : widget(0, 0, _width, _height), label(_label), label_length(str_length(_label)), on_click(nullptr)
{ { }
}
inline button(float _width, float _height, const char * _label, void (* const _on_click)())
: widget(0, 0, _width, _height), label(_label), label_length(str_length(_label)), on_click(_on_click)
{ }
inline button(float _x, float _y, float _width, float _height, const char * _label)
: widget(_x, _y, _width, _height), label(_label), label_length(str_length(_label)), on_click(nullptr)
{ }
inline button(float _x, float _y, float _width, float _height, const char * _label, void (* const _on_click)())
: widget(_x, _y, _width, _height), label(_label), label_length(str_length(_label)), on_click(_on_click)
{ }
void draw_shadow(ta_parameter_writer& writer); void draw_shadow(ta_parameter_writer& writer);
void draw_lowlight(ta_parameter_writer& writer); void draw_lowlight(ta_parameter_writer& writer);
void draw_highlight(ta_parameter_writer& writer); void draw_highlight(ta_parameter_writer& writer);
void draw_background(ta_parameter_writer& writer); void draw_background(ta_parameter_writer& writer);
void draw_label(ta_parameter_writer& writer); void draw_label(ta_parameter_writer& writer);
void draw(ta_multiwriter& multi); void draw(ta_multiwriter& multi) override;
void click() override;
}; };
} }

47
src/widget/container.hpp Normal file
View File

@ -0,0 +1,47 @@
#pragma once
#include "printf/printf.h"
namespace widget {
struct container : widget {
widget ** children;
int length;
inline container(float _x, float _y, float _width, float _height,
widget ** _children, int _length)
: widget(_x, _y, _width, _height), children(_children), length(_length)
{}
inline void freeze(float _dx, float _dy)
{
dx = _dx;
dy = _dy;
for (int i = 0; i < length; i++) {
children[i]->freeze(x(), y());
}
}
void draw(ta_multiwriter& multi)
{
for (int i = 0; i < length; i++) {
children[i]->draw(multi);
}
}
inline widget * pick(float _x, float _y)
{
if (!inside(_x, _y))
return nullptr;
for (int i = 0; i < length; i++) {
widget * w = children[i]->pick(_x, _y);
if (w != nullptr)
return w;
}
return nullptr;
}
};
}

View File

@ -0,0 +1,23 @@
#pragma once
#include "widget/container.hpp"
namespace widget {
struct left_aligned : container {
inline left_aligned(float _x, float _y, float gap, widget ** _children, int _length)
: container(_x, _y, 0, 0, _children, _length)
{
float xi = 0;
for (int i = 0; i < length; i++) {
children[i]->_x = xi;
children[i]->_y = 0;
xi += children[i]->width + gap;
if (children[i]->height > height)
height = children[i]->height;
}
width = xi;
}
};
}

View File

@ -0,0 +1,23 @@
#pragma once
#include "widget/container.hpp"
namespace widget {
struct top_aligned : container {
inline top_aligned(float _x, float _y, float gap, widget ** _children, int _length)
: container(_x, _y, 0, 0, _children, _length)
{
float yi = 0;
for (int i = 0; i < length; i++) {
children[i]->_x = 0;
children[i]->_y = yi;
yi += children[i]->height + gap;
if (children[i]->width > width)
width = children[i]->width;
}
height = yi;
}
};
}

50
src/widget/widget.hpp Normal file
View File

@ -0,0 +1,50 @@
#include "widget/bounding_box.hpp"
#include "ta_multiwriter.hpp"
#include "printf/printf.h"
namespace widget {
enum class click_type {
press,
down,
release,
};
struct widget : bounding_box {
protected:
click_type click_state;
public:
inline widget(float _x, float _y, float _width, float _height)
: bounding_box(_x, _y, _width, _height), click_state(click_type::release)
{ }
inline virtual void draw(ta_multiwriter& multi)
{
if (click_state == click_type::press)
click_state = click_type::down;
else if (click_state == click_type::down)
click_state = click_type::release;
}
inline virtual void freeze(float _dx, float _dy)
{
dx = _dx;
dy = _dy;
}
inline virtual widget * pick(float _x, float _y)
{
if (inside(_x, _y))
return this;
else
return nullptr;
}
inline virtual void click()
{
click_state = click_type::press;
}
};
}