Files
Webcam/include/engine/ui/ui_cursor.cpp

302 lines
9.3 KiB
C++

/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include <float.h>
#include "ui/ui_cursor.h"
#include "ui/ui.h"
#include "ui/ui_window.h"
#include "script/script_engine_types.h"
#include "script/script_variant.h"
#include "log/log.h"
using namespace GS;
using namespace GS::S2D;
//------------------------------------------------------------------------------
bool Scene::CallEventHandler(Cursor *cursor, EventCode event_code, EventTable *event_table)
{
EventHandler *handler = event_table ? event_table->GetHandler(event_code) : NULL;
if (!handler)
return false;
if (vm->SetupFunctionCall(NULL, handler->GetHandler(), handler->GetContext()))
{
AutoPtr <Script::Object> table_object(vm->CreateTable());
table_object->Set("sprite", Script::Variant(cursor->current_state.item, Script::typetag_Window));
table_object->Set("window", Script::Variant(cursor->current_state.item, Script::typetag_Window));
table_object->Set("widget", Script::Variant(cursor->current_state.widget, Script::typetag_Widget));
if (cursor->current_state.widget)
table_object->Set("id", Script::Variant(cursor->current_state.widget->GetId()));
table_object->Set("cursor_id", cursor->id);
table_object->Set("x", cursor->current_state.x);
table_object->Set("y", cursor->current_state.y);
table_object->Set("dx", cursor->current_state.x - cursor->previous_state.x);
table_object->Set("dy", cursor->current_state.y - cursor->previous_state.y);
table_object->Set("down", cursor->current_state.down);
// Cursor position in sprite.
if (cursor->current_state.item)
{
Vector2 c_pos = cursor->current_state.item->ScreenToLocal(Vector2(cursor->current_state.x, cursor->current_state.y));
table_object->Set("local_x", c_pos.x);
table_object->Set("local_y", c_pos.y);
if (cursor->previous_state.item == cursor->current_state.item)
{
Vector2 p_pos = cursor->previous_state.item->ScreenToLocal(Vector2(cursor->previous_state.x, cursor->previous_state.y));
table_object->Set("local_dx", c_pos.x - p_pos.x);
table_object->Set("local_dy", c_pos.y - p_pos.y);
}
else
{
table_object->Set("local_dx", 0);
table_object->Set("local_dy", 0);
}
}
vm->PushArgument(event_code);
vm->PushArgument(table_object.c_ptr());
if (!vm->DoFunctionCall())
__ERR__(__LOG_E__ << "Event handler (" << event_code << ") call failed. The handler parameters should be (event, table).\n", false)
return true;
}
return false;
}
void Scene::CallEventHandler(Cursor *cursor, Widget *widget, EventCode event_code, bool can_propagate)
{
for (Widget *base = widget; base; base = base->GetParent())
{
if (CallEventHandler(cursor, event_code, base->GetEventTable()))
return;
if (!can_propagate)
break;
}
// Try the sprite event handler.
if (can_propagate && cursor->current_state.item.IsValid())
CallEventHandler(cursor, event_code, cursor->current_state.item->GetEventTable());
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Widget *Scene::RecurseWidgetBelowCursor(Window *window, Widget *widget, int mx, int my)
{
if (!window || !widget)
return NULL;
ListForeachPtr(Widget *, c, widget->GetChildren())
{
Rect <int> rect(c->GetRect());
if (!c->IsHidden() && window->LocalToScreen(rect).Inside(mx, my))
{
Widget *sub_w = RecurseWidgetBelowCursor(window, c, mx, my);
return sub_w ? sub_w : c;
}
}
return widget;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Scene::ProcessCursorEnterLeaveWidget(Cursor *cursor, Window *window, Widget *widget)
{
if (widget && !widget->IsHidden())
{
// Process on widget.
iRect screen_rect = window->LocalToScreen(widget->GetRect());
if (screen_rect.Inside((int)cursor->current_state.x, (int)cursor->current_state.y))
{
if (!screen_rect.Inside((int)cursor->previous_state.x, (int)cursor->previous_state.y))
CallEventHandler(cursor, widget, Event_CursorEnter, false);
}
else
if (screen_rect.Inside((int)cursor->previous_state.x, (int)cursor->previous_state.y))
CallEventHandler(cursor, widget, Event_CursorLeave, false);
// Process on widget children.
ListForeachPtr(Widget *, c, widget->GetChildren())
ProcessCursorEnterLeaveWidget(cursor, window, c);
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Scene::UpdateCursor(Cursor *cursor)
{
Cursor::State &p_state = cursor->previous_state,
&c_state = cursor->current_state,
&down_state = cursor->down_state;
// Assert lock sprite validity.
if (lock && !item_list.Find(lock))
lock = NULL;
// Move cursor position in system reference.
Vector4 c_ui = screen_to_ui * Vector4(c_state.x, c_state.y, 1);
// __LOG__ << "x: " << c_ui.x << ", y: " << c_ui.y << "\n";
c_state.x = c_ui.x;
c_state.y = c_ui.y;
// Determine the current sprite under the cursor.
if (lock)
c_state.item = lock;
else
{
float min_z_order = FLT_MAX;
c_state.item = NULL;
for (List <Item *> ::Item *e = item_list.GetLast(); e; e = e->Previous())
{
Item *i = e->Object();
switch (i->GetItemType())
{
case Item::Type_Sprite:
case Item::Type_Window:
{
Sprite *s = (Sprite *)i;
if (s->opacity == 0.0)
break;
if (s->sprite_flags.IsSet(Sprite::FlagNonSensitive))
break;
Rect <int> wrect(s->GetRect());
if (s->LocalToScreen(wrect).Inside((int)c_state.x, (int)c_state.y) && (min_z_order > s->GetZOrder()))
{
min_z_order = s->GetZOrder();
c_state.item = s;
}
}
break;
}
}
}
// Determine the current widget under the cursor.
c_state.widget = NULL;
if (c_state.item && (c_state.item->GetItemType() == Item::Type_Window))
{
Window *w = (Window *)c_state.item.c_ptr();
c_state.widget = RecurseWidgetBelowCursor(w, w->GetBaseWidget(), (int)c_state.x, (int)c_state.y);
}
// State must be complete from here on.
// Store down state.
if (c_state.down && !p_state.down)
down_state = c_state;
// Handle cursor up event (done here so that the down_state widget/sprite will always catch the event).
if (p_state.down && !c_state.down)
{
if (down_state.widget)
CallEventHandler(cursor, down_state.widget, Event_CursorUp);
else if (down_state.item)
CallEventHandler(cursor, Event_CursorUp, down_state.item->GetEventTable());
}
// Handle hit/down/move cursor events.
if (c_state.widget)
{
if (p_state.down && !c_state.down)
{
if (c_state.widget == down_state.widget)
CallEventHandler(cursor, c_state.widget, Event_CursorHit);
}
if (!p_state.down && c_state.down)
CallEventHandler(cursor, c_state.widget, Event_CursorDown);
if ((c_state.widget == p_state.widget) && ((c_state.x != p_state.x) || (c_state.y != p_state.y)))
CallEventHandler(cursor, c_state.widget, Event_CursorMove);
}
else
if (c_state.item)
{
if (p_state.down && !c_state.down)
{
if (c_state.item == down_state.item)
CallEventHandler(cursor, Event_CursorHit, c_state.item->GetEventTable());
}
if (!p_state.down && c_state.down)
CallEventHandler(cursor, Event_CursorDown, c_state.item->GetEventTable());
if ((c_state.item == p_state.item) && ((c_state.x != p_state.x) || (c_state.y != p_state.y)))
CallEventHandler(cursor, Event_CursorMove, c_state.item->GetEventTable());
}
// Handle enter/leave cursor events.
if (c_state.item)
{
if (c_state.item->GetItemType() == Item::Type_Window)
{
Window *w = (Window *)c_state.item.c_ptr();
ProcessCursorEnterLeaveWidget(cursor, w, w->GetBaseWidget());
}
if (c_state.item != p_state.item)
CallEventHandler(cursor, Event_CursorEnter, c_state.item->GetEventTable());
}
if (p_state.item)
{
if (p_state.item->GetItemType() == Item::Type_Window)
{
Window *w = (Window *)p_state.item.c_ptr();
ProcessCursorEnterLeaveWidget(cursor, w, w->GetBaseWidget());
}
if (p_state.item != c_state.item)
CallEventHandler(cursor, Event_CursorLeave, p_state.item->GetEventTable());
}
#if 0
if ((c_state.x != p_state.x) || (c_state.y != p_state.y))
{
__LOG__ << "CURSOR ID = " << cursor->id << "\n";
__LOG__ << "\n";
__LOG__ << "X = " << c_state.x << ", Y = " << c_state.y << "\n";
if (c_state.item)
__LOG__ << "PX = " << c_state.item->GetPosition().x << ", PY = " << c_state.item->GetPosition().y << "\n";
if (Sprite *sprite = (Sprite *)c_state.item)
{
__LOG__ << "SPRITE = ";
if (sprite)
__LOG__ << (int)sprite;
else
__LOG__ << "None";
}
__LOG__ << ", WIDGET = ";
if (c_state.widget)
{
__LOG__ << (int)c_state.widget << " (Id = " << c_state.widget->GetId() << "), type = " << c_state.widget->GetType() << "\n";
nRect <int> rect = c_state.widget->GetRect();
__LOG__ << "SX = " << rect.sx << ", SY = " << rect.sy << ", W = " << rect.GetWidth() << ", EY = " << rect.GetHeight() << "\n";
}
else
__LOG__ << "None";
__LOG__ << "\n";
}
#endif
p_state = c_state;
}
//------------------------------------------------------------------------------