mirror of
https://github.com/aseprite/aseprite.git
synced 2025-04-16 05:42:32 +00:00
Process os::Event::MouseEnter/Leave in correct order
When we received a MouseEnter/Leave, we were processing those laf-os events immediately without taking care of all the MouseMove/Down/Up events in the middle. Now we enqueue all the events as messages (MouseEnter -> MouseMove/Down/Up -> MouseLeave). This is important because when we process MouseLeave we are calling setMouse(nullptr), which resets the mouse widget HAS_MOUSE flag, and some widgets needs to know if they have the mouse above before the MouseUp event. With this change we can remove the Widget::hasMouseOver() function (that was checking the global ui::get_mouse_position() instead of the HAS_MOUSE flag directly). Another change was introduced to keep the old behavior now that hasMouseOver() is not available: the ui::Manager doesn't assign the HAS_MOUSE flag if the mouse is captured (it only assign the HAS_MOUSE to the widget with the mouse captured, or to no widget, at least until the capture is released).
This commit is contained in:
parent
48275d51c2
commit
bd91a6430f
@ -277,7 +277,7 @@ void ColorButton::onPaint(PaintEvent& ev)
|
|||||||
draw_color_button(g, rc,
|
draw_color_button(g, rc,
|
||||||
color,
|
color,
|
||||||
(doc::ColorMode)m_pixelFormat,
|
(doc::ColorMode)m_pixelFormat,
|
||||||
hasMouseOver(), false);
|
hasMouse(), false);
|
||||||
|
|
||||||
// Draw text
|
// Draw text
|
||||||
std::string str = m_color.toHumanReadableString(m_pixelFormat,
|
std::string str = m_color.toHumanReadableString(m_pixelFormat,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2022 Igara Studio S.A.
|
// Copyright (C) 2022-2023 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2017 David Capello
|
// Copyright (C) 2001-2017 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -56,7 +56,7 @@ void IconButton::onPaint(PaintEvent& ev)
|
|||||||
fg = theme->colors.menuitemHighlightText();
|
fg = theme->colors.menuitemHighlightText();
|
||||||
bg = theme->colors.menuitemHighlightFace();
|
bg = theme->colors.menuitemHighlightFace();
|
||||||
}
|
}
|
||||||
else if (isEnabled() && hasMouseOver()) {
|
else if (isEnabled() && hasMouse()) {
|
||||||
fg = theme->colors.menuitemHotText();
|
fg = theme->colors.menuitemHotText();
|
||||||
bg = theme->colors.menuitemHotFace();
|
bg = theme->colors.menuitemHotFace();
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ void Notifications::onPaint(PaintEvent& ev)
|
|||||||
Graphics* g = ev.graphics();
|
Graphics* g = ev.graphics();
|
||||||
|
|
||||||
PaintWidgetPartInfo info;
|
PaintWidgetPartInfo info;
|
||||||
if (hasMouseOver()) info.styleFlags |= ui::Style::Layer::kMouse;
|
if (hasMouse()) info.styleFlags |= ui::Style::Layer::kMouse;
|
||||||
if (m_red) info.styleFlags |= ui::Style::Layer::kFocus;
|
if (m_red) info.styleFlags |= ui::Style::Layer::kFocus;
|
||||||
if (isSelected()) info.styleFlags |= ui::Style::Layer::kSelected;
|
if (isSelected()) info.styleFlags |= ui::Style::Layer::kSelected;
|
||||||
|
|
||||||
|
@ -1489,16 +1489,16 @@ void SkinTheme::paintSlider(PaintEvent& ev)
|
|||||||
SkinPartPtr empty_part;
|
SkinPartPtr empty_part;
|
||||||
|
|
||||||
if (isMiniLook) {
|
if (isMiniLook) {
|
||||||
full_part = widget->hasMouseOver() ? parts.miniSliderFullFocused():
|
full_part = (widget->hasMouse() ? parts.miniSliderFullFocused():
|
||||||
parts.miniSliderFull();
|
parts.miniSliderFull());
|
||||||
empty_part = widget->hasMouseOver() ? parts.miniSliderEmptyFocused():
|
empty_part = (widget->hasMouse() ? parts.miniSliderEmptyFocused():
|
||||||
parts.miniSliderEmpty();
|
parts.miniSliderEmpty());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
full_part = widget->hasFocus() ? parts.sliderFullFocused():
|
full_part = (widget->hasFocus() ? parts.sliderFullFocused():
|
||||||
parts.sliderFull();
|
parts.sliderFull());
|
||||||
empty_part = widget->hasFocus() ? parts.sliderEmptyFocused():
|
empty_part = (widget->hasFocus() ? parts.sliderEmptyFocused():
|
||||||
parts.sliderEmpty();
|
parts.sliderEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value == min)
|
if (value == min)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2018-2022 Igara Studio S.A.
|
// Copyright (C) 2018-2023 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2017 David Capello
|
// Copyright (C) 2001-2017 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -1042,7 +1042,7 @@ void Tabs::updateDragTabIndexes(int mouseX, bool startAni)
|
|||||||
startAni = true;
|
startAni = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (hasMouseOver()) {
|
else if (hasMouse()) {
|
||||||
i = std::clamp(i, 0, int(m_list.size())-1);
|
i = std::clamp(i, 0, int(m_list.size())-1);
|
||||||
if (i != m_dragTabIndex) {
|
if (i != m_dragTabIndex) {
|
||||||
m_list.erase(m_list.begin()+m_dragTabIndex);
|
m_list.erase(m_list.begin()+m_dragTabIndex);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (c) 2020-2022 Igara Studio S.A.
|
// Copyright (c) 2020-2023 Igara Studio S.A.
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
// the End-User License Agreement for Aseprite.
|
// the End-User License Agreement for Aseprite.
|
||||||
@ -164,7 +164,7 @@ void TileButton::onPaint(PaintEvent& ev)
|
|||||||
Site site = UIContext::instance()->activeSite();
|
Site site = UIContext::instance()->activeSite();
|
||||||
draw_tile_button(g, rc,
|
draw_tile_button(g, rc,
|
||||||
site, m_tile,
|
site, m_tile,
|
||||||
hasMouseOver(), false);
|
hasMouse(), false);
|
||||||
|
|
||||||
// Draw text
|
// Draw text
|
||||||
if (m_tile != doc::notile) {
|
if (m_tile != doc::notile) {
|
||||||
|
@ -3241,7 +3241,7 @@ void Timeline::updateScrollBars()
|
|||||||
void Timeline::updateByMousePos(ui::Message* msg, const gfx::Point& mousePos)
|
void Timeline::updateByMousePos(ui::Message* msg, const gfx::Point& mousePos)
|
||||||
{
|
{
|
||||||
Hit hit = hitTest(msg, mousePos);
|
Hit hit = hitTest(msg, mousePos);
|
||||||
if (hasMouseOver())
|
if (hasMouse())
|
||||||
setCursor(msg, hit);
|
setCursor(msg, hit);
|
||||||
setHot(hit);
|
setHot(hit);
|
||||||
}
|
}
|
||||||
|
@ -204,7 +204,7 @@ bool ButtonBase::onProcessMessage(Message* msg)
|
|||||||
if (hasCapture()) {
|
if (hasCapture()) {
|
||||||
releaseMouse();
|
releaseMouse();
|
||||||
|
|
||||||
if (hasMouseOver()) {
|
if (hasMouse()) {
|
||||||
switch (m_behaviorType) {
|
switch (m_behaviorType) {
|
||||||
|
|
||||||
case kButtonWidget:
|
case kButtonWidget:
|
||||||
@ -270,7 +270,7 @@ void ButtonBase::onStartDrag()
|
|||||||
|
|
||||||
void ButtonBase::onSelectWhenDragging()
|
void ButtonBase::onSelectWhenDragging()
|
||||||
{
|
{
|
||||||
bool hasMouse = hasMouseOver();
|
const bool hasMouse = this->hasMouse();
|
||||||
|
|
||||||
// Switch state when the mouse go out
|
// Switch state when the mouse go out
|
||||||
if ((hasMouse && isSelected() != m_pressedStatus) ||
|
if ((hasMouse && isSelected() != m_pressedStatus) ||
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite UI Library
|
// Aseprite UI Library
|
||||||
// Copyright (C) 2018 Igara Studio S.A.
|
// Copyright (C) 2018-2023 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2017 David Capello
|
// Copyright (C) 2001-2017 David Capello
|
||||||
//
|
//
|
||||||
// This file is released under the terms of the MIT license.
|
// This file is released under the terms of the MIT license.
|
||||||
@ -48,7 +48,7 @@ bool LinkLabel::onProcessMessage(Message* msg)
|
|||||||
|
|
||||||
case kSetCursorMessage:
|
case kSetCursorMessage:
|
||||||
// TODO theme stuff
|
// TODO theme stuff
|
||||||
if (isEnabled() && hasMouseOver()) {
|
if (isEnabled() && hasMouse()) {
|
||||||
set_mouse_cursor(kHandCursor);
|
set_mouse_cursor(kHandCursor);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -66,7 +66,7 @@ bool LinkLabel::onProcessMessage(Message* msg)
|
|||||||
|
|
||||||
case kMouseMoveMessage:
|
case kMouseMoveMessage:
|
||||||
if (isEnabled() && hasCapture())
|
if (isEnabled() && hasCapture())
|
||||||
setSelected(hasMouseOver());
|
setSelected(hasMouse());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kMouseDownMessage:
|
case kMouseDownMessage:
|
||||||
@ -83,7 +83,7 @@ bool LinkLabel::onProcessMessage(Message* msg)
|
|||||||
setSelected(false);
|
setSelected(false);
|
||||||
invalidate(); // TODO theme specific
|
invalidate(); // TODO theme specific
|
||||||
|
|
||||||
if (hasMouseOver())
|
if (hasMouse())
|
||||||
onClick();
|
onClick();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -496,30 +496,37 @@ void Manager::generateMessagesFromOSEvents()
|
|||||||
}
|
}
|
||||||
|
|
||||||
case os::Event::MouseEnter: {
|
case os::Event::MouseEnter: {
|
||||||
if (get_multiple_displays()) {
|
auto msg = new CallbackMessage([osEvent, display]{
|
||||||
if (osEvent.window()) {
|
if (get_multiple_displays()) {
|
||||||
ASSERT(display != nullptr);
|
if (osEvent.window()) {
|
||||||
_internal_set_mouse_display(display);
|
ASSERT(display != nullptr);
|
||||||
|
_internal_set_mouse_display(display);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
set_mouse_cursor(kArrowCursor);
|
||||||
set_mouse_cursor(kArrowCursor);
|
mouse_display = display;
|
||||||
|
});
|
||||||
|
enqueueMessage(msg);
|
||||||
lastMouseMoveEvent = osEvent;
|
lastMouseMoveEvent = osEvent;
|
||||||
mouse_display = display;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case os::Event::MouseLeave: {
|
case os::Event::MouseLeave: {
|
||||||
if (mouse_display == display) {
|
auto msg = new CallbackMessage([this, display]{
|
||||||
set_mouse_cursor(kOutsideDisplay);
|
if (mouse_display == display) {
|
||||||
setMouse(nullptr);
|
set_mouse_cursor(kOutsideDisplay);
|
||||||
|
setMouse(nullptr);
|
||||||
|
|
||||||
_internal_no_mouse_position();
|
_internal_no_mouse_position();
|
||||||
mouse_display = nullptr;
|
mouse_display = nullptr;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// To avoid calling kSetCursorMessage when the mouse leaves
|
enqueueMessage(msg);
|
||||||
// the window.
|
|
||||||
lastMouseMoveEvent = os::Event();
|
// To avoid calling kSetCursorMessage when the mouse leaves
|
||||||
}
|
// the window.
|
||||||
|
lastMouseMoveEvent = os::Event();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1000,54 +1007,61 @@ void Manager::setMouse(Widget* widget)
|
|||||||
(widget ? widget->id(): ""));
|
(widget ? widget->id(): ""));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ((mouse_widget != widget) && (!capture_widget)) {
|
if (mouse_widget == widget)
|
||||||
Widget* commonAncestor = findLowestCommonAncestor(mouse_widget, widget);
|
return;
|
||||||
|
|
||||||
// Fetch the mouse
|
Widget* commonAncestor = findLowestCommonAncestor(mouse_widget, widget);
|
||||||
if (mouse_widget && mouse_widget != commonAncestor) {
|
|
||||||
auto msg = new Message(kMouseLeaveMessage);
|
|
||||||
msg->setRecipient(mouse_widget);
|
|
||||||
msg->setPropagateToParent(true);
|
|
||||||
msg->setCommonAncestor(commonAncestor);
|
|
||||||
enqueueMessage(msg);
|
|
||||||
|
|
||||||
// Remove HAS_MOUSE from all the hierarchy
|
// Fetch the mouse
|
||||||
auto a = mouse_widget;
|
if (mouse_widget && mouse_widget != commonAncestor) {
|
||||||
while (a && a != commonAncestor) {
|
auto msg = new Message(kMouseLeaveMessage);
|
||||||
a->disableFlags(HAS_MOUSE);
|
msg->setRecipient(mouse_widget);
|
||||||
a = a->parent();
|
msg->setPropagateToParent(true);
|
||||||
}
|
msg->setCommonAncestor(commonAncestor);
|
||||||
|
enqueueMessage(msg);
|
||||||
|
|
||||||
|
// Remove HAS_MOUSE from all the hierarchy
|
||||||
|
auto a = mouse_widget;
|
||||||
|
while (a && a != commonAncestor) {
|
||||||
|
a->disableFlags(HAS_MOUSE);
|
||||||
|
a = a->parent();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Put the mouse
|
// If the mouse is captured, we can just put the HAS_MOUSE flag in
|
||||||
mouse_widget = widget;
|
// the captured widget (or in none).
|
||||||
if (widget) {
|
if (capture_widget && capture_widget != widget) {
|
||||||
Display* display = mouse_widget->display();
|
widget = nullptr;
|
||||||
gfx::Point mousePos = display->nativeWindow()->pointFromScreen(get_mouse_position());
|
}
|
||||||
|
|
||||||
auto msg = newMouseMessage(
|
// Put the mouse
|
||||||
kMouseEnterMessage,
|
mouse_widget = widget;
|
||||||
display, nullptr,
|
if (widget) {
|
||||||
mousePos,
|
Display* display = mouse_widget->display();
|
||||||
PointerType::Unknown,
|
gfx::Point mousePos = display->nativeWindow()->pointFromScreen(get_mouse_position());
|
||||||
m_mouseButton,
|
|
||||||
kKeyUninitializedModifier);
|
|
||||||
|
|
||||||
msg->setRecipient(widget);
|
auto msg = newMouseMessage(
|
||||||
msg->setPropagateToParent(true);
|
kMouseEnterMessage,
|
||||||
msg->setCommonAncestor(commonAncestor);
|
display, nullptr,
|
||||||
enqueueMessage(msg);
|
mousePos,
|
||||||
generateSetCursorMessage(display,
|
PointerType::Unknown,
|
||||||
mousePos,
|
m_mouseButton,
|
||||||
kKeyUninitializedModifier,
|
kKeyUninitializedModifier);
|
||||||
PointerType::Unknown);
|
|
||||||
|
|
||||||
// Add HAS_MOUSE to all the hierarchy
|
msg->setRecipient(widget);
|
||||||
auto a = mouse_widget;
|
msg->setPropagateToParent(true);
|
||||||
while (a && a != commonAncestor) {
|
msg->setCommonAncestor(commonAncestor);
|
||||||
a->enableFlags(HAS_MOUSE);
|
enqueueMessage(msg);
|
||||||
a = a->parent();
|
generateSetCursorMessage(display,
|
||||||
}
|
mousePos,
|
||||||
|
kKeyUninitializedModifier,
|
||||||
|
PointerType::Unknown);
|
||||||
|
|
||||||
|
// Add HAS_MOUSE to all the hierarchy
|
||||||
|
auto a = mouse_widget;
|
||||||
|
while (a && a != commonAncestor) {
|
||||||
|
a->enableFlags(HAS_MOUSE);
|
||||||
|
a = a->parent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1929,9 +1943,10 @@ bool Manager::sendMessageToWidget(Message* msg, Widget* widget)
|
|||||||
"kSetCursorMessage",
|
"kSetCursorMessage",
|
||||||
"kMouseWheelMessage",
|
"kMouseWheelMessage",
|
||||||
"kTouchMagnifyMessage",
|
"kTouchMagnifyMessage",
|
||||||
|
"kCallbackMessage",
|
||||||
};
|
};
|
||||||
static_assert(kOpenMessage == 0 &&
|
static_assert(kOpenMessage == 0 &&
|
||||||
kTouchMagnifyMessage == sizeof(msg_name)/sizeof(const char*)-1,
|
kCallbackMessage == sizeof(msg_name)/sizeof(const char*)-1,
|
||||||
"MessageType enum has changed");
|
"MessageType enum has changed");
|
||||||
const char* string =
|
const char* string =
|
||||||
(msg->type() >= 0 &&
|
(msg->type() >= 0 &&
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite UI Library
|
// Aseprite UI Library
|
||||||
// Copyright (C) 2018-2022 Igara Studio S.A.
|
// Copyright (C) 2018-2023 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This file is released under the terms of the MIT license.
|
// This file is released under the terms of the MIT license.
|
||||||
@ -18,6 +18,8 @@
|
|||||||
#include "ui/mouse_button.h"
|
#include "ui/mouse_button.h"
|
||||||
#include "ui/pointer_type.h"
|
#include "ui/pointer_type.h"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
class Display;
|
class Display;
|
||||||
@ -81,6 +83,18 @@ namespace ui {
|
|||||||
KeyModifiers m_modifiers; // Key modifiers pressed when message was created
|
KeyModifiers m_modifiers; // Key modifiers pressed when message was created
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CallbackMessage : public Message {
|
||||||
|
public:
|
||||||
|
CallbackMessage(std::function<void()>&& callback)
|
||||||
|
: Message(kCallbackMessage)
|
||||||
|
, m_callback(std::move(callback)) { }
|
||||||
|
void call() {
|
||||||
|
m_callback();
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::function<void()> m_callback;
|
||||||
|
};
|
||||||
|
|
||||||
class KeyMessage : public Message {
|
class KeyMessage : public Message {
|
||||||
public:
|
public:
|
||||||
KeyMessage(MessageType type,
|
KeyMessage(MessageType type,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite UI Library
|
// Aseprite UI Library
|
||||||
// Copyright (C) 2019 Igara Studio S.A.
|
// Copyright (C) 2019-2023 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This file is released under the terms of the MIT license.
|
// This file is released under the terms of the MIT license.
|
||||||
@ -45,6 +45,11 @@ namespace ui {
|
|||||||
// TODO Drag'n'drop messages...
|
// TODO Drag'n'drop messages...
|
||||||
// k...DndMessage
|
// k...DndMessage
|
||||||
|
|
||||||
|
// Call a generic function when we are processing the queue of
|
||||||
|
// messages. Used to process an laf-os event in the same order
|
||||||
|
// they were received in some cases (e.g. mouse leave/enter).
|
||||||
|
kCallbackMessage,
|
||||||
|
|
||||||
// User widgets.
|
// User widgets.
|
||||||
kFirstRegisteredMessage,
|
kFirstRegisteredMessage,
|
||||||
kLastRegisteredMessage = 0x7fffffff
|
kLastRegisteredMessage = 0x7fffffff
|
||||||
|
@ -1496,11 +1496,6 @@ bool Widget::offerCapture(ui::MouseMessage* mouseMsg, int widget_type)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Widget::hasMouseOver() const
|
|
||||||
{
|
|
||||||
return (this == pickFromScreenPos(get_mouse_position()));
|
|
||||||
}
|
|
||||||
|
|
||||||
gfx::Point Widget::mousePosInDisplay() const
|
gfx::Point Widget::mousePosInDisplay() const
|
||||||
{
|
{
|
||||||
return display()->nativeWindow()->pointFromScreen(get_mouse_position());
|
return display()->nativeWindow()->pointFromScreen(get_mouse_position());
|
||||||
|
@ -349,12 +349,29 @@ namespace ui {
|
|||||||
void captureMouse();
|
void captureMouse();
|
||||||
void releaseMouse();
|
void releaseMouse();
|
||||||
|
|
||||||
|
// True when the widget has the keyboard focus (only widgets with
|
||||||
|
// FOCUS_STOP flag will receive the HAS_FOCUS flag/receive the
|
||||||
|
// focus when the user press the tab key to navigate widgets).
|
||||||
bool hasFocus() const { return hasFlags(HAS_FOCUS); }
|
bool hasFocus() const { return hasFlags(HAS_FOCUS); }
|
||||||
bool hasMouse() const { return hasFlags(HAS_MOUSE); }
|
|
||||||
bool hasCapture() const { return hasFlags(HAS_CAPTURE); }
|
|
||||||
|
|
||||||
// Checking if the mouse is currently above the widget.
|
// True when the widget has the mouse above. If the mouse leaves
|
||||||
bool hasMouseOver() const;
|
// the widget, the widget will lose the HAS_MOUSE flag. If some
|
||||||
|
// widget captures the mouse, no other widget will have this flag,
|
||||||
|
// so in this case there are just two options:
|
||||||
|
//
|
||||||
|
// 1) The widget with the capture (hasCapture()) will has the
|
||||||
|
// mouse flag too.
|
||||||
|
// 2) Or no other widget will have the mouse flag until the widget
|
||||||
|
// releases the capture (releaseCapture())
|
||||||
|
bool hasMouse() const { return hasFlags(HAS_MOUSE); }
|
||||||
|
|
||||||
|
// True when the widget has captured the mouse, e.g. generally
|
||||||
|
// when the user press a mouse button above a clickeable widget
|
||||||
|
// (e.g. ui::Button), the widget will capture the mouse
|
||||||
|
// temporarily until the mouse button is released. If a widget
|
||||||
|
// captures the mouse, it will receive all mouse events until it
|
||||||
|
// release (even if the mouse moves outside the widget).
|
||||||
|
bool hasCapture() const { return hasFlags(HAS_CAPTURE); }
|
||||||
|
|
||||||
// Returns the mouse position relative to the top-left corner of
|
// Returns the mouse position relative to the top-left corner of
|
||||||
// the ui::Display's client area/content rect.
|
// the ui::Display's client area/content rect.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user