mirror of
https://github.com/edubart/otclient.git
synced 2025-10-15 20:14:54 +02:00
rework walk
This commit is contained in:
@@ -26,6 +26,11 @@
|
||||
#include <framework/global.h>
|
||||
|
||||
class Module;
|
||||
class Event;
|
||||
class ScheduledEvent;
|
||||
|
||||
typedef std::shared_ptr<Module> ModulePtr;
|
||||
typedef std::shared_ptr<Event> EventPtr;
|
||||
typedef std::shared_ptr<ScheduledEvent> ScheduledEventPtr;
|
||||
|
||||
#endif
|
||||
|
@@ -37,29 +37,34 @@ void EventDispatcher::flush()
|
||||
void EventDispatcher::poll()
|
||||
{
|
||||
while(!m_scheduledEventList.empty()) {
|
||||
if(g_clock.ticks() < m_scheduledEventList.top().ticks)
|
||||
ScheduledEventPtr scheduledEvent = m_scheduledEventList.top();
|
||||
if(scheduledEvent->reamaningTicks() > 0)
|
||||
break;
|
||||
SimpleCallback callback = std::move(m_scheduledEventList.top().callback);
|
||||
m_scheduledEventList.pop();
|
||||
callback();
|
||||
scheduledEvent->execute();
|
||||
}
|
||||
|
||||
while(!m_eventList.empty()) {
|
||||
m_eventList.front()();
|
||||
EventPtr event = m_eventList.front();
|
||||
m_eventList.pop_front();
|
||||
event->execute();
|
||||
}
|
||||
}
|
||||
|
||||
void EventDispatcher::scheduleEvent(const SimpleCallback& callback, int delay)
|
||||
ScheduledEventPtr EventDispatcher::scheduleEvent(const SimpleCallback& callback, int delay)
|
||||
{
|
||||
assert(delay >= 0);
|
||||
m_scheduledEventList.push(ScheduledEvent(g_clock.ticksFor(delay), callback));
|
||||
ScheduledEventPtr scheduledEvent(new ScheduledEvent(callback, delay));
|
||||
m_scheduledEventList.push(scheduledEvent);
|
||||
return scheduledEvent;
|
||||
}
|
||||
|
||||
void EventDispatcher::addEvent(const SimpleCallback& callback, bool pushFront)
|
||||
EventPtr EventDispatcher::addEvent(const SimpleCallback& callback, bool pushFront)
|
||||
{
|
||||
EventPtr event(new Event(callback));
|
||||
if(pushFront)
|
||||
m_eventList.push_front(callback);
|
||||
m_eventList.push_front(event);
|
||||
else
|
||||
m_eventList.push_back(callback);
|
||||
m_eventList.push_back(event);
|
||||
return event;
|
||||
}
|
||||
|
@@ -24,12 +24,49 @@
|
||||
#define EVENTDISPATCHER_H
|
||||
|
||||
#include "declarations.h"
|
||||
#include "clock.h"
|
||||
#include <framework/luascript/luaobject.h>
|
||||
|
||||
struct ScheduledEvent {
|
||||
ScheduledEvent(ticks_t ticks, const SimpleCallback& callback) : ticks(ticks), callback(callback) { }
|
||||
bool operator<(const ScheduledEvent& other) const { return ticks > other.ticks; }
|
||||
ticks_t ticks;
|
||||
SimpleCallback callback;
|
||||
class Event : public LuaObject
|
||||
{
|
||||
public:
|
||||
Event(const SimpleCallback& callback) : m_callback(callback), m_canceled(false), m_executed(false) { }
|
||||
|
||||
void execute() {
|
||||
if(!m_canceled) {
|
||||
m_callback();
|
||||
m_executed = true;
|
||||
}
|
||||
}
|
||||
void cancel() { m_canceled = true; }
|
||||
|
||||
bool isCanceled() { return m_canceled; }
|
||||
bool isExecuted() { return m_executed; }
|
||||
|
||||
protected:
|
||||
SimpleCallback m_callback;
|
||||
bool m_canceled;
|
||||
bool m_executed;
|
||||
};
|
||||
|
||||
class ScheduledEvent : public Event
|
||||
{
|
||||
public:
|
||||
ScheduledEvent(const SimpleCallback& callback, int delay) : Event(callback) {
|
||||
m_ticks = g_clock.ticksFor(delay);
|
||||
}
|
||||
|
||||
int ticks() const { return m_ticks; }
|
||||
int reamaningTicks() const { return m_ticks - g_clock.ticks(); }
|
||||
|
||||
private:
|
||||
ticks_t m_ticks;
|
||||
};
|
||||
|
||||
struct lessScheduledEvent : std::binary_function<ScheduledEventPtr, ScheduledEventPtr&, bool> {
|
||||
bool operator()(const ScheduledEventPtr& a, const ScheduledEventPtr& b) const {
|
||||
return b->ticks() < a->ticks();
|
||||
}
|
||||
};
|
||||
|
||||
class EventDispatcher
|
||||
@@ -38,12 +75,12 @@ public:
|
||||
void flush();
|
||||
void poll();
|
||||
|
||||
void addEvent(const SimpleCallback& callback, bool pushFront = false);
|
||||
void scheduleEvent(const SimpleCallback& callback, int delay);
|
||||
EventPtr addEvent(const SimpleCallback& callback, bool pushFront = false);
|
||||
ScheduledEventPtr scheduleEvent(const SimpleCallback& callback, int delay);
|
||||
|
||||
private:
|
||||
std::list<SimpleCallback> m_eventList;
|
||||
std::priority_queue<ScheduledEvent> m_scheduledEventList;
|
||||
std::list<EventPtr> m_eventList;
|
||||
std::priority_queue<ScheduledEventPtr, std::vector<ScheduledEventPtr>, lessScheduledEvent> m_scheduledEventList;
|
||||
};
|
||||
|
||||
extern EventDispatcher g_dispatcher;
|
||||
|
@@ -43,6 +43,14 @@ void Application::registerLuaFunctions()
|
||||
g_lua.bindGlobalFunction("colortostring", [](const Color& v) { return Fw::tostring(v); });
|
||||
g_lua.bindGlobalFunction("sizetostring", [](const Size& v) { return Fw::tostring(v); });
|
||||
|
||||
// Event
|
||||
g_lua.registerClass<Event>();
|
||||
g_lua.bindClassMemberFunction<Event>("isCanceled", &Event::isCanceled);
|
||||
g_lua.bindClassMemberFunction<Event>("isExecuted", &Event::isExecuted);
|
||||
|
||||
// ScheduledEvent
|
||||
g_lua.registerClass<ScheduledEvent, Event>();
|
||||
|
||||
// UIWidget
|
||||
g_lua.registerClass<UIWidget>();
|
||||
g_lua.bindClassStaticFunction<UIWidget>("create", []{ return UIWidgetPtr(new UIWidget); });
|
||||
|
@@ -119,4 +119,4 @@ T LuaObject::getLuaField(const std::string& key) {
|
||||
return g_lua.polymorphicPop<T>();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
@@ -351,16 +351,12 @@ void *WIN32Window::getExtensionProcAddress(const char *ext)
|
||||
|
||||
void WIN32Window::move(const Point& pos)
|
||||
{
|
||||
RECT windowRect = {pos.x, pos.y, m_pos.x + m_size.width(), m_pos.y + m_size.height()};
|
||||
AdjustWindowRectEx(&windowRect, WS_OVERLAPPEDWINDOW, FALSE, WS_EX_APPWINDOW | WS_EX_WINDOWEDGE);
|
||||
MoveWindow(m_window, windowRect.left, windowRect.top, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, TRUE);
|
||||
MoveWindow(m_window, pos.x, pos.y, m_size.width(), m_size.height(), TRUE);
|
||||
}
|
||||
|
||||
void WIN32Window::resize(const Size& size)
|
||||
{
|
||||
RECT windowRect = {m_pos.x, m_pos.y, m_pos.x + size.width(), m_pos.y + size.height()};
|
||||
AdjustWindowRectEx(&windowRect, WS_OVERLAPPEDWINDOW, FALSE, WS_EX_APPWINDOW | WS_EX_WINDOWEDGE);
|
||||
MoveWindow(m_window, windowRect.left, windowRect.top, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, TRUE);
|
||||
MoveWindow(m_window, m_pos.x, m_pos.y, size.width(), size.height(), TRUE);
|
||||
}
|
||||
|
||||
void WIN32Window::show()
|
||||
@@ -400,7 +396,6 @@ void WIN32Window::poll()
|
||||
|
||||
LRESULT WIN32Window::windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
m_inputEvent.reset();
|
||||
switch(uMsg)
|
||||
{
|
||||
case WM_ACTIVATE: {
|
||||
@@ -411,6 +406,8 @@ LRESULT WIN32Window::windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar
|
||||
if(wParam >= 32 && wParam <= 255) {
|
||||
m_inputEvent.reset(Fw::KeyTextInputEvent);
|
||||
m_inputEvent.keyText = wParam;
|
||||
if(m_onInputEvent)
|
||||
m_onInputEvent(m_inputEvent);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -429,31 +426,43 @@ LRESULT WIN32Window::windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar
|
||||
case WM_LBUTTONDOWN: {
|
||||
m_inputEvent.reset(Fw::MousePressInputEvent);
|
||||
m_inputEvent.mouseButton = Fw::MouseLeftButton;
|
||||
if(m_onInputEvent)
|
||||
m_onInputEvent(m_inputEvent);
|
||||
break;
|
||||
}
|
||||
case WM_LBUTTONUP: {
|
||||
m_inputEvent.reset(Fw::MouseReleaseInputEvent);
|
||||
m_inputEvent.mouseButton = Fw::MouseLeftButton;
|
||||
if(m_onInputEvent)
|
||||
m_onInputEvent(m_inputEvent);
|
||||
break;
|
||||
}
|
||||
case WM_MBUTTONDOWN: {
|
||||
m_inputEvent.reset(Fw::MousePressInputEvent);
|
||||
m_inputEvent.mouseButton = Fw::MouseMidButton;
|
||||
if(m_onInputEvent)
|
||||
m_onInputEvent(m_inputEvent);
|
||||
break;
|
||||
}
|
||||
case WM_MBUTTONUP: {
|
||||
m_inputEvent.reset(Fw::MouseReleaseInputEvent);
|
||||
m_inputEvent.mouseButton = Fw::MouseMidButton;
|
||||
if(m_onInputEvent)
|
||||
m_onInputEvent(m_inputEvent);
|
||||
break;
|
||||
}
|
||||
case WM_RBUTTONDOWN: {
|
||||
m_inputEvent.reset(Fw::MousePressInputEvent);
|
||||
m_inputEvent.mouseButton = Fw::MouseRightButton;
|
||||
if(m_onInputEvent)
|
||||
m_onInputEvent(m_inputEvent);
|
||||
break;
|
||||
}
|
||||
case WM_RBUTTONUP: {
|
||||
m_inputEvent.reset(Fw::MouseReleaseInputEvent);
|
||||
m_inputEvent.mouseButton = Fw::MouseRightButton;
|
||||
if(m_onInputEvent)
|
||||
m_onInputEvent(m_inputEvent);
|
||||
break;
|
||||
}
|
||||
case WM_MOUSEMOVE: {
|
||||
@@ -461,11 +470,15 @@ LRESULT WIN32Window::windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar
|
||||
Point newMousePos(LOWORD(lParam), HIWORD(lParam));
|
||||
m_inputEvent.mouseMoved = newMousePos - m_inputEvent.mousePos;
|
||||
m_inputEvent.mousePos = newMousePos;
|
||||
if(m_onInputEvent)
|
||||
m_onInputEvent(m_inputEvent);
|
||||
break;
|
||||
}
|
||||
case WM_MOUSEWHEEL: {
|
||||
m_inputEvent.mouseButton = Fw::MouseMidButton;
|
||||
m_inputEvent.wheelDirection = HIWORD(wParam) > 0 ? Fw::MouseWheelUp : Fw::MouseWheelDown;
|
||||
if(m_onInputEvent)
|
||||
m_onInputEvent(m_inputEvent);
|
||||
break;
|
||||
}
|
||||
case WM_MOVE: {
|
||||
@@ -494,8 +507,6 @@ LRESULT WIN32Window::windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar
|
||||
return DefWindowProc(hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
if(m_onInputEvent && m_inputEvent.type != Fw::NoInputEvent)
|
||||
m_onInputEvent(m_inputEvent);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -193,26 +193,27 @@ void UIWidget::removeChild(const UIWidgetPtr& child)
|
||||
|
||||
void UIWidget::focusChild(const UIWidgetPtr& child, Fw::FocusReason reason)
|
||||
{
|
||||
if(child == m_focusedChild)
|
||||
return;
|
||||
|
||||
if(child && !hasChild(child)) {
|
||||
logError("Attempt to focus an unknown child in a UIWidget");
|
||||
logError("attempt to focus an unknown child in a UIWidget");
|
||||
return;
|
||||
}
|
||||
|
||||
if(child != m_focusedChild) {
|
||||
UIWidgetPtr oldFocused = m_focusedChild;
|
||||
m_focusedChild = child;
|
||||
UIWidgetPtr oldFocused = m_focusedChild;
|
||||
m_focusedChild = child;
|
||||
|
||||
if(child) {
|
||||
child->setLastFocusReason(reason);
|
||||
child->updateState(Fw::FocusState);
|
||||
child->updateState(Fw::ActiveState);
|
||||
}
|
||||
if(child) {
|
||||
child->setLastFocusReason(reason);
|
||||
child->updateState(Fw::FocusState);
|
||||
child->updateState(Fw::ActiveState);
|
||||
}
|
||||
|
||||
if(oldFocused) {
|
||||
oldFocused->setLastFocusReason(reason);
|
||||
oldFocused->updateState(Fw::FocusState);
|
||||
oldFocused->updateState(Fw::ActiveState);
|
||||
}
|
||||
if(oldFocused) {
|
||||
oldFocused->setLastFocusReason(reason);
|
||||
oldFocused->updateState(Fw::FocusState);
|
||||
oldFocused->updateState(Fw::ActiveState);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -389,6 +390,8 @@ void UIWidget::addAnchor(Fw::AnchorEdge anchoredEdge, const std::string& hookedW
|
||||
{
|
||||
if(UIAnchorLayoutPtr anchorLayout = getAnchoredLayout())
|
||||
anchorLayout->addAnchor(asUIWidget(), anchoredEdge, hookedWidgetId, hookedEdge);
|
||||
else
|
||||
logError("cannot add anchors to widget ", m_id, ": the parent doesn't use anchors layout");
|
||||
}
|
||||
|
||||
void UIWidget::centerIn(const std::string& hookedWidgetId)
|
||||
@@ -396,7 +399,8 @@ void UIWidget::centerIn(const std::string& hookedWidgetId)
|
||||
if(UIAnchorLayoutPtr anchorLayout = getAnchoredLayout()) {
|
||||
anchorLayout->addAnchor(asUIWidget(), Fw::AnchorHorizontalCenter, hookedWidgetId, Fw::AnchorHorizontalCenter);
|
||||
anchorLayout->addAnchor(asUIWidget(), Fw::AnchorVerticalCenter, hookedWidgetId, Fw::AnchorVerticalCenter);
|
||||
}
|
||||
} else
|
||||
logError("cannot add anchors to widget ", m_id, ": the parent doesn't use anchors layout");
|
||||
}
|
||||
|
||||
void UIWidget::fill(const std::string& hookedWidgetId)
|
||||
@@ -406,7 +410,8 @@ void UIWidget::fill(const std::string& hookedWidgetId)
|
||||
anchorLayout->addAnchor(asUIWidget(), Fw::AnchorRight, hookedWidgetId, Fw::AnchorRight);
|
||||
anchorLayout->addAnchor(asUIWidget(), Fw::AnchorTop, hookedWidgetId, Fw::AnchorTop);
|
||||
anchorLayout->addAnchor(asUIWidget(), Fw::AnchorBottom, hookedWidgetId, Fw::AnchorBottom);
|
||||
}
|
||||
} else
|
||||
logError("cannot add anchors to widget ", m_id, ": the parent doesn't use anchors layout");
|
||||
}
|
||||
|
||||
void UIWidget::breakAnchors()
|
||||
@@ -732,17 +737,10 @@ Rect UIWidget::getChildrenRect()
|
||||
UIAnchorLayoutPtr UIWidget::getAnchoredLayout()
|
||||
{
|
||||
UIWidgetPtr parent = getParent();
|
||||
if(!parent) {
|
||||
logError("cannot add anchors to widget ", m_id, ": there is no parent");
|
||||
if(!parent)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
UIAnchorLayoutPtr anchorLayout = parent->getLayout()->asUIAnchorLayout();
|
||||
if(!anchorLayout) {
|
||||
logError("cannot add anchors to widget ", m_id, ": the parent doesn't use anchors layout");
|
||||
return nullptr;
|
||||
}
|
||||
return anchorLayout;
|
||||
return parent->getLayout()->asUIAnchorLayout();
|
||||
}
|
||||
|
||||
UIWidgetPtr UIWidget::getRootParent()
|
||||
@@ -1190,38 +1188,38 @@ bool UIWidget::propagateOnKeyUp(uchar keyCode, int keyboardModifiers)
|
||||
bool UIWidget::propagateOnMousePress(const Point& mousePos, Fw::MouseButton button)
|
||||
{
|
||||
// do a backup of children list, because it may change while looping it
|
||||
UIWidgetList children;
|
||||
UIWidgetPtr clickedChild;
|
||||
for(const UIWidgetPtr& child : m_children) {
|
||||
// events on hidden or disabled widgets are discarded
|
||||
if(!child->isExplicitlyEnabled() || !child->isExplicitlyVisible())
|
||||
continue;
|
||||
|
||||
// mouse press events only go to children that contains the mouse position
|
||||
if(child->containsPoint(mousePos) && child == getChildByPos(mousePos))
|
||||
children.push_back(child);
|
||||
if(child->containsPoint(mousePos) && child == getChildByPos(mousePos)) {
|
||||
clickedChild = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for(const UIWidgetPtr& child : children) {
|
||||
// when a focusable item is focused it must gain focus
|
||||
if(child->isFocusable())
|
||||
focusChild(child, Fw::MouseFocusReason);
|
||||
if(clickedChild) {
|
||||
// focusable child gains focus when clicked
|
||||
if(clickedChild->isFocusable())
|
||||
focusChild(clickedChild, Fw::MouseFocusReason);
|
||||
|
||||
bool mustEnd = child->propagateOnMousePress(mousePos, button);
|
||||
|
||||
if(button == Fw::MouseLeftButton && !child->isPressed()) {
|
||||
UIWidgetPtr clickedChild = child->getChildByPos(mousePos);
|
||||
if(!clickedChild || clickedChild->isPhantom())
|
||||
child->setPressed(true);
|
||||
}
|
||||
|
||||
if(mustEnd)
|
||||
// stop propagating if the child accept the event
|
||||
if(clickedChild->propagateOnMousePress(mousePos, button))
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!isPhantom())
|
||||
return onMousePress(mousePos, button);
|
||||
else
|
||||
return false;
|
||||
// only non phatom widgets receives mouse press events
|
||||
if(!isPhantom()) {
|
||||
onMousePress(mousePos, button);
|
||||
if(button == Fw::MouseLeftButton && !isPressed())
|
||||
setPressed(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void UIWidget::propagateOnMouseRelease(const Point& mousePos, Fw::MouseButton button)
|
||||
@@ -1239,12 +1237,12 @@ void UIWidget::propagateOnMouseRelease(const Point& mousePos, Fw::MouseButton bu
|
||||
|
||||
for(const UIWidgetPtr& child : children) {
|
||||
child->propagateOnMouseRelease(mousePos, button);
|
||||
|
||||
if(child->isPressed() && button == Fw::MouseLeftButton)
|
||||
child->setPressed(false);
|
||||
}
|
||||
|
||||
onMouseRelease(mousePos, button);
|
||||
|
||||
if(isPressed() && button == Fw::MouseLeftButton)
|
||||
setPressed(false);
|
||||
}
|
||||
|
||||
bool UIWidget::propagateOnMouseMove(const Point& mousePos, const Point& mouseMoved)
|
||||
|
Reference in New Issue
Block a user