mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-09-30 02:48:14 +03:00
Merge pull request #329 from kichikuou/drag
PartsEngine: Implement drag-and-drop processing
This commit is contained in:
@@ -172,6 +172,7 @@ void PE_SetPassCursor(int parts_no, bool pass);
|
||||
bool PE_GetPartsPassCursor(int parts_no);
|
||||
void PE_SetClickable(int parts_no, bool clickable);
|
||||
bool PE_GetPartsClickable(int parts_no);
|
||||
void PE_SetDrag(int parts_no, bool enable);
|
||||
void PE_SetPartsGroupDecideOnCursor(int group_no, bool decide_on_cursor);
|
||||
void PE_SetPartsGroupDecideClick(int group_no, bool decide_click);
|
||||
void PE_SetOnCursorShowLinkPartsNumber(int parts_no, int link_parts_no);
|
||||
|
||||
@@ -837,7 +837,7 @@ HLL_LIBRARY(PartsEngine,
|
||||
HLL_EXPORT(Parts_SetPassCursor, PE_SetPassCursor),
|
||||
HLL_EXPORT(Parts_SetClickable, PE_SetClickable),
|
||||
HLL_TODO_EXPORT(Parts_SetResetTimerByChangeInputStatus, PartsEngine_Parts_SetResetTimerByChangeInputStatus),
|
||||
HLL_TODO_EXPORT(Parts_SetDrag, PartsEngine_Parts_SetDrag),
|
||||
HLL_EXPORT(Parts_SetDrag, PE_SetDrag),
|
||||
HLL_EXPORT(Parts_SetParentPartsNumber, PE_SetParentPartsNumber),
|
||||
HLL_EXPORT(Parts_SetInputState, PE_SetInputState),
|
||||
HLL_EXPORT(Parts_SetOnCursorShowLinkPartsNumber, PE_SetOnCursorShowLinkPartsNumber),
|
||||
|
||||
+100
-16
@@ -34,6 +34,13 @@ static int clicked_parts = 0;
|
||||
// the current (partially) clicked parts number
|
||||
static int click_down_parts = 0;
|
||||
|
||||
// drag state
|
||||
static struct parts *drag_parts = NULL;
|
||||
static bool is_dragging = false;
|
||||
static Point drag_initial_pos;
|
||||
static Point drag_start_cursor;
|
||||
static struct parts *drop_target = NULL;
|
||||
|
||||
static bool parts_hittest(struct parts *parts, int state, Point pos)
|
||||
{
|
||||
Rectangle hitbox = parts->states[state].common.hitbox;
|
||||
@@ -44,6 +51,21 @@ static bool parts_hittest(struct parts *parts, int state, Point pos)
|
||||
return SDL_PointInRect(&pos, &hitbox);
|
||||
}
|
||||
|
||||
static void drag_state_reset(void)
|
||||
{
|
||||
drag_parts = NULL;
|
||||
is_dragging = false;
|
||||
drop_target = NULL;
|
||||
}
|
||||
|
||||
void parts_input_reset_drag(struct parts *parts)
|
||||
{
|
||||
if (parts == drag_parts)
|
||||
drag_state_reset();
|
||||
else if (parts == drop_target)
|
||||
drop_target = NULL;
|
||||
}
|
||||
|
||||
static void parts_update_mouse(struct parts *parts, Point cur_pos, bool cur_clicking,
|
||||
int passed_time, bool *hover_consumed, bool *click_consumed)
|
||||
{
|
||||
@@ -66,25 +88,22 @@ static void parts_update_mouse(struct parts *parts, Point cur_pos, bool cur_clic
|
||||
return;
|
||||
|
||||
if (is_hovered && !was_hovered) {
|
||||
parts_msg_push(parts->no, parts->delegate_index,
|
||||
PARTS_MSG_MOUSE_ENTER, "ii", cur_pos.x, cur_pos.y);
|
||||
parts_msg_push(parts, PARTS_MSG_MOUSE_ENTER, "ii", cur_pos.x, cur_pos.y);
|
||||
parts->hover_time = 0;
|
||||
}
|
||||
if (!is_hovered && was_hovered) {
|
||||
parts_msg_push(parts->no, parts->delegate_index,
|
||||
PARTS_MSG_MOUSE_LEAVE, "ii", cur_pos.x, cur_pos.y);
|
||||
parts_msg_push(parts, PARTS_MSG_MOUSE_LEAVE, "ii", cur_pos.x, cur_pos.y);
|
||||
}
|
||||
|
||||
if (is_hovered) {
|
||||
// MOUSE_ON message fires every frame while hovering
|
||||
parts_msg_push(parts->no, parts->delegate_index,
|
||||
PARTS_MSG_MOUSE_ON, "iii", cur_pos.x, cur_pos.y, parts->hover_time);
|
||||
parts_msg_push(parts, PARTS_MSG_MOUSE_ON,
|
||||
"iii", cur_pos.x, cur_pos.y, parts->hover_time);
|
||||
parts->hover_time += passed_time;
|
||||
|
||||
// MOUSE_MOVE message fires when cursor moves while hovering
|
||||
if (cur_pos.x != parts_prev_pos.x || cur_pos.y != parts_prev_pos.y) {
|
||||
parts_msg_push(parts->no, parts->delegate_index,
|
||||
PARTS_MSG_MOUSE_MOVE, "ii", cur_pos.x, cur_pos.y);
|
||||
parts_msg_push(parts, PARTS_MSG_MOUSE_MOVE, "ii", cur_pos.x, cur_pos.y);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,15 +125,17 @@ static void parts_update_mouse(struct parts *parts, Point cur_pos, bool cur_clic
|
||||
click_down_parts = parts->no;
|
||||
*click_consumed = true;
|
||||
|
||||
drag_parts = parts;
|
||||
drag_initial_pos = parts->local.pos;
|
||||
drag_start_cursor = cur_pos;
|
||||
|
||||
// KEY_TRIGGER message fires on press transition
|
||||
parts_msg_push(parts->no, parts->delegate_index,
|
||||
PARTS_MSG_KEY_TRIGGER, "i", VK_LBUTTON);
|
||||
parts_msg_push(parts, PARTS_MSG_KEY_TRIGGER, "i", VK_LBUTTON);
|
||||
}
|
||||
|
||||
// KEY_DOWN message fires every frame while held (not first frame)
|
||||
if (prev_clicking && cur_clicking && click_down_parts == parts->no) {
|
||||
parts_msg_push(parts->no, parts->delegate_index,
|
||||
PARTS_MSG_KEY_DOWN, "i", VK_LBUTTON);
|
||||
parts_msg_push(parts, PARTS_MSG_KEY_DOWN, "i", VK_LBUTTON);
|
||||
}
|
||||
|
||||
if (cur_clicking && click_down_parts == parts->no) {
|
||||
@@ -132,10 +153,9 @@ static void parts_update_mouse(struct parts *parts, Point cur_pos, bool cur_clic
|
||||
audio_play_sound(parts->on_click_sound);
|
||||
clicked_parts = parts->no;
|
||||
|
||||
parts_msg_push(parts->no, parts->delegate_index,
|
||||
PARTS_MSG_MOUSE_CLICK, "iii", cur_pos.x, cur_pos.y, VK_LBUTTON);
|
||||
parts_msg_push(parts->no, parts->delegate_index,
|
||||
PARTS_MSG_KEY_UP, "i", VK_LBUTTON);
|
||||
parts_msg_push(parts, PARTS_MSG_MOUSE_CLICK,
|
||||
"iii", cur_pos.x, cur_pos.y, VK_LBUTTON);
|
||||
parts_msg_push(parts, PARTS_MSG_KEY_UP, "i", VK_LBUTTON);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,7 +174,65 @@ void PE_UpdateInputState(int passed_time)
|
||||
&hover_consumed, &click_consumed);
|
||||
}
|
||||
|
||||
// Drag movement processing
|
||||
if (drag_parts && cur_clicking) {
|
||||
bool cursor_moved = (cur_pos.x != parts_prev_pos.x ||
|
||||
cur_pos.y != parts_prev_pos.y);
|
||||
if (cursor_moved && drag_parts->draggable) {
|
||||
Point new_pos = {
|
||||
drag_initial_pos.x + (cur_pos.x - drag_start_cursor.x),
|
||||
drag_initial_pos.y + (cur_pos.y - drag_start_cursor.y)
|
||||
};
|
||||
parts_set_pos(drag_parts, new_pos);
|
||||
if (!is_dragging) {
|
||||
parts_msg_push(drag_parts, PARTS_MSG_DRAG_BEGIN, "");
|
||||
}
|
||||
parts_msg_push(drag_parts, PARTS_MSG_DRAGGING, "iiii",
|
||||
drag_start_cursor.x, drag_start_cursor.y, cur_pos.x, cur_pos.y);
|
||||
is_dragging = true;
|
||||
}
|
||||
|
||||
// Drop target tracking
|
||||
if (cursor_moved && is_dragging) {
|
||||
struct parts *new_drop = NULL;
|
||||
PARTS_LIST_FOREACH_REVERSE(parts) {
|
||||
if (parts == drag_parts)
|
||||
continue;
|
||||
if (parts_hittest(parts, PARTS_STATE_DEFAULT, cur_pos)) {
|
||||
new_drop = parts;
|
||||
if (!parts->pass_cursor)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (new_drop != drop_target) {
|
||||
if (drop_target) {
|
||||
parts_msg_push(drop_target, PARTS_MSG_DROP_LEAVE,
|
||||
"i", drag_parts->no);
|
||||
}
|
||||
if (new_drop) {
|
||||
parts_msg_push(new_drop, PARTS_MSG_DROP_ENTER,
|
||||
"i", drag_parts->no);
|
||||
}
|
||||
drop_target = new_drop;
|
||||
} else if (drop_target) {
|
||||
parts_msg_push(drop_target, PARTS_MSG_DROP_ON,
|
||||
"iii", drag_parts->no, cur_pos.x, cur_pos.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Release handling
|
||||
if (prev_clicking && !cur_clicking) {
|
||||
if (is_dragging && drag_parts && drag_parts->draggable) {
|
||||
parts_msg_push(drag_parts, PARTS_MSG_DRAG_END, "");
|
||||
}
|
||||
if (drop_target && drag_parts) {
|
||||
parts_msg_push(drop_target, PARTS_MSG_DROPPED,
|
||||
"iii", drag_parts->no, cur_pos.x, cur_pos.y);
|
||||
parts_msg_push(drop_target, PARTS_MSG_DROP_LEAVE, "i", drag_parts->no);
|
||||
}
|
||||
drag_state_reset();
|
||||
|
||||
if (!click_down_parts) {
|
||||
// TODO: play misclick sound
|
||||
}
|
||||
@@ -247,6 +325,12 @@ void PE_EndInput(void)
|
||||
{
|
||||
parts_began_click = false;
|
||||
clicked_parts = 0;
|
||||
drag_state_reset();
|
||||
}
|
||||
|
||||
void PE_SetDrag(int parts_no, bool enable)
|
||||
{
|
||||
parts_get(parts_no)->draggable = !!enable;
|
||||
}
|
||||
|
||||
int PE_GetClickPartsNumber(void)
|
||||
|
||||
+3
-3
@@ -39,15 +39,15 @@ struct parts_message {
|
||||
static STAILQ_HEAD(, parts_message) msg_queue =
|
||||
STAILQ_HEAD_INITIALIZER(msg_queue);
|
||||
|
||||
void parts_msg_push(int parts_no, int delegate_index, int type, const char *fmt, ...)
|
||||
void parts_msg_push(struct parts* parts, int type, const char *fmt, ...)
|
||||
{
|
||||
// Message system is introduced in Rance 9
|
||||
if (!parts_multi_controller)
|
||||
return;
|
||||
|
||||
struct parts_message *msg = xmalloc(sizeof(*msg));
|
||||
msg->parts_no = parts_no;
|
||||
msg->delegate_index = delegate_index;
|
||||
msg->parts_no = parts->no;
|
||||
msg->delegate_index = parts->delegate_index;
|
||||
msg->type = type;
|
||||
msg->nr_variables = 0;
|
||||
|
||||
|
||||
@@ -970,6 +970,7 @@ void parts_release(int parts_no)
|
||||
return;
|
||||
|
||||
struct parts *parts = slot->value;
|
||||
parts_input_reset_drag(parts);
|
||||
parts_clear_motion(parts);
|
||||
for (int i = 0; i < PARTS_NR_STATES; i++) {
|
||||
parts_state_free(&parts->states[i]);
|
||||
|
||||
@@ -393,6 +393,7 @@ struct parts {
|
||||
bool pass_cursor;
|
||||
bool lock_input_state;
|
||||
bool want_save;
|
||||
bool draggable;
|
||||
int on_cursor_sound;
|
||||
int on_click_sound;
|
||||
int origin_mode;
|
||||
@@ -500,6 +501,7 @@ void parts_add_motion(struct parts *parts, struct parts_motion *motion);
|
||||
|
||||
// input.c
|
||||
extern bool parts_began_click;
|
||||
void parts_input_reset_drag(struct parts *parts);
|
||||
|
||||
// message.c
|
||||
enum parts_message_type {
|
||||
@@ -512,12 +514,16 @@ enum parts_message_type {
|
||||
PARTS_MSG_DRAG_BEGIN = 7,
|
||||
PARTS_MSG_DRAGGING = 8,
|
||||
PARTS_MSG_DRAG_END = 9,
|
||||
PARTS_MSG_DROP_ENTER = 10,
|
||||
PARTS_MSG_DROP_ON = 11,
|
||||
PARTS_MSG_DROPPED = 12,
|
||||
PARTS_MSG_DROP_LEAVE = 13,
|
||||
PARTS_MSG_KEY_TRIGGER = 14,
|
||||
PARTS_MSG_KEY_DOWN = 15,
|
||||
PARTS_MSG_KEY_UP = 17,
|
||||
};
|
||||
|
||||
void parts_msg_push(int parts_no, int delegate_index, int type, const char *fmt, ...);
|
||||
void parts_msg_push(struct parts* parts, int type, const char *fmt, ...);
|
||||
|
||||
// construction.c
|
||||
void parts_cp_op_free(struct parts_cp_op *op);
|
||||
|
||||
@@ -570,6 +570,7 @@ static void save_parts(struct iarray_writer *w, struct parts *parts)
|
||||
iarray_write(w, parts->margin_bottom);
|
||||
iarray_write(w, parts->margin_left);
|
||||
iarray_write(w, parts->margin_right);
|
||||
iarray_write(w, parts->draggable);
|
||||
}
|
||||
|
||||
unsigned motion_count_pos = iarray_writer_pos(w);
|
||||
@@ -620,6 +621,7 @@ static void load_parts(struct iarray_reader *r, int version)
|
||||
parts->margin_bottom = iarray_read(r);
|
||||
parts->margin_left = iarray_read(r);
|
||||
parts->margin_right = iarray_read(r);
|
||||
parts->draggable = iarray_read(r);
|
||||
}
|
||||
|
||||
int motion_count = iarray_read(r);
|
||||
|
||||
Reference in New Issue
Block a user