summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Aaron Giles <aaron@aarongiles.com>2021-06-04 07:29:56 -0700
committer Aaron Giles <aaron@aarongiles.com>2021-06-04 07:29:56 -0700
commit43a5da3703baf8ab37a2ef29d6f5791d2db385bd (patch)
treed1560a73d5a677389fc97539217e0122c524e07f
parent3f3e0eda38bc08c9ad67ae46543ff7a0f45a856e (diff)
Add support for dragging position-animated layout items.draggable-layout
-rw-r--r--src/emu/ioport.cpp2
-rw-r--r--src/emu/render.cpp31
-rw-r--r--src/emu/render.h6
-rw-r--r--src/emu/rendlay.cpp55
-rw-r--r--src/emu/rendlay.h7
-rw-r--r--src/emu/uiinput.cpp54
-rw-r--r--src/emu/uiinput.h7
7 files changed, 141 insertions, 21 deletions
diff --git a/src/emu/ioport.cpp b/src/emu/ioport.cpp
index 4f3d5b2c7ac..6df457d65f6 100644
--- a/src/emu/ioport.cpp
+++ b/src/emu/ioport.cpp
@@ -656,6 +656,8 @@ void ioport_field::set_value(ioport_value value)
{
if (is_analog())
live().analog->set_value(s32(value));
+ else if (type() == IPT_ADJUSTER)
+ live().value = s32(value);
else
m_digital_value = value != 0;
}
diff --git a/src/emu/render.cpp b/src/emu/render.cpp
index b7a66b7bd2a..640e100653b 100644
--- a/src/emu/render.cpp
+++ b/src/emu/render.cpp
@@ -1493,7 +1493,7 @@ bool render_target::map_point_container(s32 target_x, s32 target_y, render_conta
// field, if possible
//-------------------------------------------------
-bool render_target::map_point_input(s32 target_x, s32 target_y, ioport_port *&input_port, ioport_value &input_mask, float &input_x, float &input_y)
+bool render_target::map_point_input(s32 target_x, s32 target_y, ioport_port *&input_port, ioport_value &input_mask, item_handle &input_item, float &input_x, float &input_y)
{
std::pair<float, float> target_f(map_point_internal(target_x, target_y));
if (m_orientation & ORIENTATION_FLIP_X)
@@ -1535,8 +1535,9 @@ bool render_target::map_point_input(s32 target_x, s32 target_y, ioport_port *&in
{
// point successfully mapped
std::tie(input_port, input_mask) = item.input_tag_and_mask();
- input_x = (target_f.first - bounds.x0) / bounds.width();
- input_y = (target_f.second - bounds.y0) / bounds.height();
+ input_x = target_f.first - ((bounds.x0 + bounds.x1) / 2);
+ input_y = target_f.second - ((bounds.y0 + bounds.y1) / 2);
+ input_item = reinterpret_cast<item_handle>(&item);
return true;
}
else
@@ -1551,11 +1552,35 @@ bool render_target::map_point_input(s32 target_x, s32 target_y, ioport_port *&in
input_port = nullptr;
input_mask = 0;
input_x = input_y = -1.0f;
+ input_item = nullptr;
return false;
}
//-------------------------------------------------
+// interpolated_value - return the interpolated
+// value of an item given x,y coordinates and
+// an x,y offset from the item's center
+//-------------------------------------------------
+
+ioport_value render_target::interpolated_value(s32 target_x, s32 target_y, item_handle item, float xoffs, float yoffs)
+{
+ std::pair<float, float> target_f(map_point_internal(target_x, target_y));
+ if (m_orientation & ORIENTATION_FLIP_X)
+ target_f.first = 1.0f - target_f.first;
+ if (m_orientation & ORIENTATION_FLIP_Y)
+ target_f.second = 1.0f - target_f.second;
+ if (m_orientation & ORIENTATION_SWAP_XY)
+ std::swap(target_f.first, target_f.second);
+
+ target_f.first -= xoffs;
+ target_f.second -= yoffs;
+
+ return reinterpret_cast<layout_view::item *>(item)->state_from_position(target_f.first, target_f.second);
+}
+
+
+//-------------------------------------------------
// invalidate_all - if any of our primitive lists
// contain a reference to the given pointer,
// clear them
diff --git a/src/emu/render.h b/src/emu/render.h
index a372da7f5c5..4c58a47b919 100644
--- a/src/emu/render.h
+++ b/src/emu/render.h
@@ -509,6 +509,9 @@ class render_target
~render_target();
public:
+ // abstraction of layout_view::item for hit testing
+ using item_handle = void *;
+
// getters
render_target *next() const { return m_next; }
render_manager &manager() const { return m_manager; }
@@ -562,7 +565,8 @@ public:
// hit testing
bool map_point_container(s32 target_x, s32 target_y, render_container &container, float &container_x, float &container_y);
- bool map_point_input(s32 target_x, s32 target_y, ioport_port *&input_port, ioport_value &input_mask, float &input_x, float &input_y);
+ bool map_point_input(s32 target_x, s32 target_y, ioport_port *&input_port, ioport_value &input_mask, item_handle &input_item, float &input_x, float &input_y);
+ ioport_value interpolated_value(s32 target_x, s32 target_y, item_handle item, float xoffs, float yoffs);
// reference tracking
void invalidate_all(void *refptr);
diff --git a/src/emu/rendlay.cpp b/src/emu/rendlay.cpp
index 789c7c15a7c..0541b41d07e 100644
--- a/src/emu/rendlay.cpp
+++ b/src/emu/rendlay.cpp
@@ -1052,6 +1052,50 @@ inline render_bounds interpolate_bounds(emu::render::detail::bounds_vector const
}
}
+int uninterpolate_bounds(emu::render::detail::bounds_vector const &steps, float x, float y)
+{
+ float smallest_distance = 1e10;
+ int state = 0;
+
+ auto first(steps.begin());
+ auto second(first);
+ while (steps.end() != ++second)
+ {
+ // create a line between the center of the first and the center of the second
+ float x0 = (first->bounds.x0 + first->bounds.x1) / 2;
+ float y0 = (first->bounds.y0 + first->bounds.y1) / 2;
+ float x1 = (second->bounds.x0 + second->bounds.x1) / 2;
+ float y1 = (second->bounds.y0 + second->bounds.y1) / 2;
+ float length = sqrtf((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0));
+
+ // determine the distance to that line; if it's not the smallest so far, continue
+ float distance = fabsf((x1 - x0) * (y0 - y) - (x0 - x) * (y1 - y0)) / length;
+ if (distance > smallest_distance)
+ continue;
+ smallest_distance = distance;
+
+ // handle out of bounds
+ if (((x0 < x1 && x < x0) || (x0 > x1 && x > x0) || x0 == x1) && ((y0 < y1 && y < y0) || (y0 > y1 && y > y1) || y0 == y1))
+ state = first->state;
+ else if (((x1 < x0 && x < x1) || (x1 > x0 && x > x1) || x0 == x1) && ((y1 < y0 && y < y1) || (y1 > y0 && y > y0) || y0 == y1))
+ state = second->state;
+ else
+ {
+ // compute the distance from our point to the first center
+ float dist_to_first = sqrtf((x - x0) * (x - x0) + (y - y0) * (y - y0));
+
+ // using that, compute the fractional distance along the line
+ float dist_along_line = sqrtf(dist_to_first * dist_to_first - distance * distance) / length;
+
+ // clamp to max, else interpolate
+ if (dist_along_line > 1.0)
+ state = second->state;
+ else
+ state = first->state + (second->state - first->state) * dist_along_line;
+ }
+ }
+ return state;
+}
bool add_color_step(emu::render::detail::layout_environment &env, emu::render::detail::color_vector &steps, util::xml::data_node const &node)
{
@@ -4682,6 +4726,17 @@ void layout_view::item::resolve_tags()
//-------------------------------------------------
+// state_from_position - given a position,
+// compute the effective state
+//-------------------------------------------------
+
+ioport_value layout_view::item::state_from_position(float x, float y)
+{
+ return uninterpolate_bounds(m_bounds, x, y);
+}
+
+
+//-------------------------------------------------
// default_get_elem_state - get default element
// state handler
//-------------------------------------------------
diff --git a/src/emu/rendlay.h b/src/emu/rendlay.h
index fb7871bd0ef..c364a0921fa 100644
--- a/src/emu/rendlay.h
+++ b/src/emu/rendlay.h
@@ -288,8 +288,8 @@ public:
render_container *screen_container() const { return m_screen ? &m_screen->container() : nullptr; }
// interactivity
- bool has_input() const { return bool(m_input_port); }
- std::pair<ioport_port *, ioport_value> input_tag_and_mask() const { return std::make_pair(m_input_port, m_input_mask); };
+ bool has_input() const { return bool(m_input_port) || (bounds_animated() && bool(m_animinput_port)); }
+ std::pair<ioport_port *, ioport_value> input_tag_and_mask() const { return m_animinput_port ? std::make_pair(m_animinput_port, m_animmask) : std::make_pair(m_input_port, m_input_mask); };
bool clickthrough() const { return m_clickthrough; }
// fetch state based on configured source
@@ -308,6 +308,9 @@ public:
// resolve tags, if any
void resolve_tags();
+ // return the best state relative to a point at the given position
+ ioport_value state_from_position(float x, float y);
+
private:
using bounds_vector = emu::render::detail::bounds_vector;
using color_vector = emu::render::detail::color_vector;
diff --git a/src/emu/uiinput.cpp b/src/emu/uiinput.cpp
index d1398591687..3c2b5e2422a 100644
--- a/src/emu/uiinput.cpp
+++ b/src/emu/uiinput.cpp
@@ -41,6 +41,9 @@ ui_input_manager::ui_input_manager(running_machine &machine)
, m_current_mouse_y(-1)
, m_current_mouse_down(false)
, m_current_mouse_field(nullptr)
+ , m_current_mouse_drag_item(nullptr)
+ , m_current_mouse_target_dx(0)
+ , m_current_mouse_target_dy(0)
, m_events_start(0)
, m_events_end(0)
{
@@ -81,20 +84,44 @@ void ui_input_manager::frame_update()
}
}
- // perform mouse hit testing
- ioport_field *mouse_field = m_current_mouse_down ? find_mouse_field() : nullptr;
- if (m_current_mouse_field != mouse_field)
+ // if dragging, update based solely on position
+ if (m_current_mouse_down && m_current_mouse_drag_item != nullptr)
{
- // clear the old field if there was one
- if (m_current_mouse_field != nullptr)
- m_current_mouse_field->set_value(0);
+ m_current_mouse_field->set_value(m_current_mouse_target->interpolated_value(m_current_mouse_x, m_current_mouse_y, m_current_mouse_drag_item, m_current_mouse_target_dx, m_current_mouse_target_dy));
+ }
+ else
+ {
+ // perform mouse hit testing
+ float xoffs = 0, yoffs = 0;
+ render_target::item_handle item = nullptr;
+ ioport_field *mouse_field = m_current_mouse_down ? find_mouse_field(xoffs, yoffs, item) : nullptr;
+ if (m_current_mouse_field != mouse_field)
+ {
+ // clear the old field if there was one
+ if (m_current_mouse_field != nullptr && !m_current_mouse_field->is_analog() && m_current_mouse_field->type() != IPT_ADJUSTER)
+ m_current_mouse_field->set_value(0);
+ m_current_mouse_drag_item = nullptr;
- // set the new field if it exists and isn't already being pressed
- if (mouse_field != nullptr && !mouse_field->digital_value())
- mouse_field->set_value(1);
+ if (mouse_field != nullptr)
+ {
+ if (!mouse_field->is_analog() && mouse_field->type() != IPT_ADJUSTER)
+ {
+ // set the new field if it exists and isn't already being pressed
+ if (!mouse_field->digital_value())
+ mouse_field->set_value(1);
+ }
+ else
+ {
+ // if analog, treat as the start of a dragging operation
+ m_current_mouse_drag_item = item;
+ m_current_mouse_target_dx = xoffs;
+ m_current_mouse_target_dy = yoffs;
+ }
+ }
- // update internal state
- m_current_mouse_field = mouse_field;
+ // update internal state
+ m_current_mouse_field = mouse_field;
+ }
}
}
@@ -208,15 +235,14 @@ render_target *ui_input_manager::find_mouse(s32 *x, s32 *y, bool *button) const
the mouse is currently pointing at
-------------------------------------------------*/
-ioport_field *ui_input_manager::find_mouse_field() const
+ioport_field *ui_input_manager::find_mouse_field(float &xoffs, float &yoffs, render_target::item_handle &item) const
{
// map the point and determine what was hit
if (m_current_mouse_target != nullptr)
{
ioport_port *port = nullptr;
ioport_value mask;
- float x, y;
- if (m_current_mouse_target->map_point_input(m_current_mouse_x, m_current_mouse_y, port, mask, x, y))
+ if (m_current_mouse_target->map_point_input(m_current_mouse_x, m_current_mouse_y, port, mask, item, xoffs, yoffs))
{
if (port != nullptr)
return port->field(mask);
diff --git a/src/emu/uiinput.h b/src/emu/uiinput.h
index 29b18d06d30..a69abc07c6b 100644
--- a/src/emu/uiinput.h
+++ b/src/emu/uiinput.h
@@ -13,6 +13,8 @@
#pragma once
+#include "render.h"
+
/***************************************************************************
TYPE DEFINITIONS
@@ -70,7 +72,7 @@ public:
// retrieves the current location of the mouse
render_target *find_mouse(s32 *x, s32 *y, bool *button) const;
- ioport_field *find_mouse_field() const;
+ ioport_field *find_mouse_field(float &xoffs, float &yoffs, render_target::item_handle &item) const;
// return true if a key down for the given user interface sequence is detected
bool pressed(int code);
@@ -119,6 +121,9 @@ private:
s32 m_current_mouse_y;
bool m_current_mouse_down;
ioport_field * m_current_mouse_field;
+ render_target::item_handle m_current_mouse_drag_item;
+ float m_current_mouse_target_dx;
+ float m_current_mouse_target_dy;
// popped states; ring buffer of ui_events
ui_event m_events[EVENT_QUEUE_SIZE];