mirror of
https://github.com/aseprite/aseprite.git
synced 2025-02-28 16:11:35 +00:00
Avoid capturing the mouse from widgets in background windows
This avoids clicking buttons that are not in the foreground/modal window. At the same time the onBroadcastMouseMessage() functionality was expanded in such a way that added widgets to the broadcast are the only ones allowed to re-capture the mouse (even if they are not in the current foreground window). This is required so the Editor can be scrolled when we are visualizing a Filter window with preview. New functions added to simplify some code: * Manager::transferAsMouseDownMessage() * Manager::allowCapture() * base::contains() Related to #4963 and #4973.
This commit is contained in:
parent
6c69840184
commit
d5738fb492
2
laf
2
laf
@ -1 +1 @@
|
|||||||
Subproject commit 339a0fa13584853bda8559de486e715e743a5763
|
Subproject commit 65829107c838817987f3cf6374cc68c583e5d538
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (c) 2024 Igara Studio S.A.
|
// Copyright (c) 2024-2025 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.
|
||||||
@ -51,18 +51,12 @@ bool FontEntry::FontFace::onProcessMessage(Message* msg)
|
|||||||
MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
|
MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
|
||||||
const gfx::Point screenPos = mouseMsg->display()->nativeWindow()->pointToScreen(
|
const gfx::Point screenPos = mouseMsg->display()->nativeWindow()->pointToScreen(
|
||||||
mouseMsg->position());
|
mouseMsg->position());
|
||||||
Widget* pick = manager()->pickFromScreenPos(screenPos);
|
Manager* mgr = manager();
|
||||||
|
Widget* pick = mgr->pickFromScreenPos(screenPos);
|
||||||
Widget* target = m_popup->getListBox();
|
Widget* target = m_popup->getListBox();
|
||||||
|
|
||||||
if (pick && (pick == target || pick->hasAncestor(target))) {
|
if (pick && (pick == target || pick->hasAncestor(target))) {
|
||||||
releaseMouse();
|
mgr->transferAsMouseDownMessage(this, pick, mouseMsg);
|
||||||
|
|
||||||
MouseMessage mouseMsg2(kMouseDownMessage,
|
|
||||||
*mouseMsg,
|
|
||||||
mouseMsg->positionForDisplay(pick->display()));
|
|
||||||
mouseMsg2.setRecipient(pick);
|
|
||||||
mouseMsg2.setDisplay(pick->display());
|
|
||||||
pick->sendMessage(&mouseMsg2);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
// Copyright (C) 2018-2025 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -266,17 +266,10 @@ bool ToolBar::onProcessMessage(Message* msg)
|
|||||||
// mouse over the ToolBar.
|
// mouse over the ToolBar.
|
||||||
if (hasCapture()) {
|
if (hasCapture()) {
|
||||||
MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
|
MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
|
||||||
Widget* pick = manager()->pickFromScreenPos(mouseMsg->screenPosition());
|
Manager* mgr = manager();
|
||||||
|
Widget* pick = mgr->pickFromScreenPos(mouseMsg->screenPosition());
|
||||||
if (ToolStrip* strip = dynamic_cast<ToolStrip*>(pick)) {
|
if (ToolStrip* strip = dynamic_cast<ToolStrip*>(pick)) {
|
||||||
releaseMouse();
|
mgr->transferAsMouseDownMessage(this, strip, mouseMsg);
|
||||||
|
|
||||||
MouseMessage* mouseMsg2 = new MouseMessage(
|
|
||||||
kMouseDownMessage,
|
|
||||||
*mouseMsg,
|
|
||||||
mouseMsg->positionForDisplay(strip->display()));
|
|
||||||
mouseMsg2->setRecipient(strip);
|
|
||||||
mouseMsg2->setDisplay(strip->display());
|
|
||||||
manager()->enqueueMessage(mouseMsg2);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -755,16 +748,10 @@ bool ToolBar::ToolStrip::onProcessMessage(Message* msg)
|
|||||||
if (m_hotTool)
|
if (m_hotTool)
|
||||||
m_toolbar->selectTool(m_hotTool);
|
m_toolbar->selectTool(m_hotTool);
|
||||||
|
|
||||||
Widget* pick = manager()->pickFromScreenPos(mouseMsg->screenPosition());
|
Manager* mgr = manager();
|
||||||
|
Widget* pick = mgr->pickFromScreenPos(mouseMsg->screenPosition());
|
||||||
if (ToolBar* bar = dynamic_cast<ToolBar*>(pick)) {
|
if (ToolBar* bar = dynamic_cast<ToolBar*>(pick)) {
|
||||||
releaseMouse();
|
mgr->transferAsMouseDownMessage(this, bar, mouseMsg);
|
||||||
|
|
||||||
MouseMessage* mouseMsg2 = new MouseMessage(kMouseDownMessage,
|
|
||||||
*mouseMsg,
|
|
||||||
mouseMsg->positionForDisplay(pick->display()));
|
|
||||||
mouseMsg2->setRecipient(bar);
|
|
||||||
mouseMsg2->setDisplay(pick->display());
|
|
||||||
manager()->enqueueMessage(mouseMsg2);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite UI Library
|
// Aseprite UI Library
|
||||||
// Copyright (C) 2018-2023 Igara Studio S.A.
|
// Copyright (C) 2018-2025 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.
|
||||||
@ -503,18 +503,17 @@ bool ComboBoxEntry::onProcessMessage(Message* msg)
|
|||||||
MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
|
MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
|
||||||
gfx::Point screenPos = mouseMsg->display()->nativeWindow()->pointToScreen(
|
gfx::Point screenPos = mouseMsg->display()->nativeWindow()->pointToScreen(
|
||||||
mouseMsg->position());
|
mouseMsg->position());
|
||||||
Widget* pick = manager()->pickFromScreenPos(screenPos);
|
Manager* mgr = manager();
|
||||||
|
Widget* pick = mgr->pickFromScreenPos(screenPos);
|
||||||
Widget* listbox = m_comboBox->m_listbox;
|
Widget* listbox = m_comboBox->m_listbox;
|
||||||
|
|
||||||
if (pick != nullptr && (pick == listbox || pick->hasAncestor(listbox))) {
|
if (pick != nullptr && (pick == listbox || pick->hasAncestor(listbox))) {
|
||||||
releaseMouse();
|
mgr->transferAsMouseDownMessage(this,
|
||||||
|
pick,
|
||||||
MouseMessage mouseMsg2(kMouseDownMessage,
|
mouseMsg,
|
||||||
*mouseMsg,
|
// Send the message right now, if we enqueue
|
||||||
mouseMsg->positionForDisplay(pick->display()));
|
// the message the popup window is closed.
|
||||||
mouseMsg2.setRecipient(pick);
|
true);
|
||||||
mouseMsg2.setDisplay(pick->display());
|
|
||||||
pick->sendMessage(&mouseMsg2);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite UI Library
|
// Aseprite UI Library
|
||||||
// Copyright (C) 2019-2022 Igara Studio S.A.
|
// Copyright (C) 2019-2025 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.
|
||||||
@ -89,17 +89,11 @@ bool IntEntry::onProcessMessage(Message* msg)
|
|||||||
case kMouseMoveMessage:
|
case kMouseMoveMessage:
|
||||||
if (hasCapture()) {
|
if (hasCapture()) {
|
||||||
MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
|
MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
|
||||||
Widget* pick = manager()->pickFromScreenPos(
|
Manager* mgr = manager();
|
||||||
|
Widget* pick = mgr->pickFromScreenPos(
|
||||||
display()->nativeWindow()->pointToScreen(mouseMsg->position()));
|
display()->nativeWindow()->pointToScreen(mouseMsg->position()));
|
||||||
if (pick == m_slider.get()) {
|
if (pick == m_slider.get()) {
|
||||||
releaseMouse();
|
mgr->transferAsMouseDownMessage(this, pick, mouseMsg);
|
||||||
|
|
||||||
MouseMessage mouseMsg2(kMouseDownMessage,
|
|
||||||
*mouseMsg,
|
|
||||||
mouseMsg->positionForDisplay(pick->display()));
|
|
||||||
mouseMsg2.setRecipient(pick);
|
|
||||||
mouseMsg2.setDisplay(pick->display());
|
|
||||||
pick->sendMessage(&mouseMsg2);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite UI Library
|
// Aseprite UI Library
|
||||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
// Copyright (C) 2018-2025 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.
|
||||||
@ -13,6 +13,7 @@
|
|||||||
// #define DEBUG_PAINT_MESSAGES 1
|
// #define DEBUG_PAINT_MESSAGES 1
|
||||||
// #define LIMIT_DISPATCH_TIME 1
|
// #define LIMIT_DISPATCH_TIME 1
|
||||||
#define GARBAGE_TRACE(...) // TRACE(__VA_ARGS__)
|
#define GARBAGE_TRACE(...) // TRACE(__VA_ARGS__)
|
||||||
|
#define CAPTURE_TRACE(...) // TRACE(__VA_ARGS__)
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@ -21,6 +22,8 @@
|
|||||||
#include "ui/manager.h"
|
#include "ui/manager.h"
|
||||||
|
|
||||||
#include "base/concurrent_queue.h"
|
#include "base/concurrent_queue.h"
|
||||||
|
#include "base/contains.h"
|
||||||
|
#include "base/remove_from_container.h"
|
||||||
#include "base/scoped_value.h"
|
#include "base/scoped_value.h"
|
||||||
#include "base/thread.h"
|
#include "base/thread.h"
|
||||||
#include "base/time.h"
|
#include "base/time.h"
|
||||||
@ -183,8 +186,7 @@ os::Hit handle_native_hittest(os::Window* osWindow, const gfx::Point& pos)
|
|||||||
bool Manager::widgetAssociatedToManager(Widget* widget)
|
bool Manager::widgetAssociatedToManager(Widget* widget)
|
||||||
{
|
{
|
||||||
return (focus_widget == widget || mouse_widget == widget || capture_widget == widget ||
|
return (focus_widget == widget || mouse_widget == widget || capture_widget == widget ||
|
||||||
std::find(mouse_widgets_list.begin(), mouse_widgets_list.end(), widget) !=
|
base::contains(mouse_widgets_list, widget));
|
||||||
mouse_widgets_list.end());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Manager::Manager(const os::WindowRef& nativeWindow)
|
Manager::Manager(const os::WindowRef& nativeWindow)
|
||||||
@ -889,12 +891,12 @@ void Manager::enqueueMessage(Message* msg)
|
|||||||
concurrent_msg_queue.push(msg);
|
concurrent_msg_queue.push(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
Window* Manager::getTopWindow()
|
Window* Manager::getTopWindow() const
|
||||||
{
|
{
|
||||||
return static_cast<Window*>(UI_FIRST_WIDGET(children()));
|
return static_cast<Window*>(UI_FIRST_WIDGET(children()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Window* Manager::getDesktopWindow()
|
Window* Manager::getDesktopWindow() const
|
||||||
{
|
{
|
||||||
for (auto child : children()) {
|
for (auto child : children()) {
|
||||||
Window* window = static_cast<Window*>(child);
|
Window* window = static_cast<Window*>(child);
|
||||||
@ -904,7 +906,7 @@ Window* Manager::getDesktopWindow()
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Window* Manager::getForegroundWindow()
|
Window* Manager::getForegroundWindow() const
|
||||||
{
|
{
|
||||||
for (auto child : children()) {
|
for (auto child : children()) {
|
||||||
Window* window = static_cast<Window*>(child);
|
Window* window = static_cast<Window*>(child);
|
||||||
@ -1033,8 +1035,33 @@ void Manager::setMouse(Widget* widget)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::setCapture(Widget* widget)
|
void Manager::setCapture(Widget* widget, bool force)
|
||||||
{
|
{
|
||||||
|
ASSERT(widget);
|
||||||
|
if (!widget)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CAPTURE_TRACE("Manager::setCapture %s\n", typeid(*widget).name());
|
||||||
|
if (!force &&
|
||||||
|
// The given "widget" cannot capture the mouse if it's not
|
||||||
|
// "clickable". The definition of "clickable" generally means
|
||||||
|
// that the widget is in the current foreground/modal window, or
|
||||||
|
// in the desktop window (or in any floating non-modal window).
|
||||||
|
// But it can also be in a top window, e.g. a combobox popup.
|
||||||
|
!isWidgetClickable(widget) &&
|
||||||
|
// In some special cases, a widget transfers a mouse message to
|
||||||
|
// another widget which doesn't belong to the current foreground
|
||||||
|
// modal window, this is done using onBroadcastMouseMessage()
|
||||||
|
// and/or transferAsMouseDownMessage(), so here we allow capturing
|
||||||
|
// the mouse from widgets inside the "mouse_widgets_list"
|
||||||
|
// (widgets that are allowed to capture the mouse / added with
|
||||||
|
// allowCapture() function).
|
||||||
|
(widget != mouse_widget && !base::contains(mouse_widgets_list, widget))) {
|
||||||
|
CAPTURE_TRACE("-> FILTERED!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CAPTURE_TRACE("-> OK\n");
|
||||||
|
|
||||||
// To set the capture, we set first the mouse_widget (because
|
// To set the capture, we set first the mouse_widget (because
|
||||||
// mouse_widget shouldn't be != capture_widget)
|
// mouse_widget shouldn't be != capture_widget)
|
||||||
setMouse(widget);
|
setMouse(widget);
|
||||||
@ -1048,6 +1075,13 @@ void Manager::setCapture(Widget* widget)
|
|||||||
display->nativeWindow()->captureMouse();
|
display->nativeWindow()->captureMouse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Manager::allowCapture(Widget* widget)
|
||||||
|
{
|
||||||
|
ASSERT(widget);
|
||||||
|
if (!base::contains(mouse_widgets_list, widget))
|
||||||
|
mouse_widgets_list.push_back(widget);
|
||||||
|
}
|
||||||
|
|
||||||
// Sets the focus to the "magnetic" widget inside the window
|
// Sets the focus to the "magnetic" widget inside the window
|
||||||
void Manager::attractFocus(Widget* widget)
|
void Manager::attractFocus(Widget* widget)
|
||||||
{
|
{
|
||||||
@ -1082,6 +1116,8 @@ void Manager::freeMouse()
|
|||||||
void Manager::freeCapture()
|
void Manager::freeCapture()
|
||||||
{
|
{
|
||||||
if (capture_widget) {
|
if (capture_widget) {
|
||||||
|
CAPTURE_TRACE("Manager::freeCapture() %s\n", typeid(*capture_widget).name());
|
||||||
|
|
||||||
Display* display = capture_widget->display();
|
Display* display = capture_widget->display();
|
||||||
|
|
||||||
capture_widget->disableFlags(HAS_CAPTURE);
|
capture_widget->disableFlags(HAS_CAPTURE);
|
||||||
@ -1113,9 +1149,7 @@ void Manager::freeWidget(Widget* widget)
|
|||||||
if (widget->hasMouse() || (widget == mouse_widget))
|
if (widget->hasMouse() || (widget == mouse_widget))
|
||||||
freeMouse();
|
freeMouse();
|
||||||
|
|
||||||
auto it = std::find(mouse_widgets_list.begin(), mouse_widgets_list.end(), widget);
|
base::remove_from_container(mouse_widgets_list, widget);
|
||||||
if (it != mouse_widgets_list.end())
|
|
||||||
mouse_widgets_list.erase(it);
|
|
||||||
|
|
||||||
ASSERT(!Manager::widgetAssociatedToManager(widget));
|
ASSERT(!Manager::widgetAssociatedToManager(widget));
|
||||||
}
|
}
|
||||||
@ -1279,6 +1313,53 @@ Widget* Manager::pickFromScreenPos(const gfx::Point& screenPos) const
|
|||||||
return Widget::pickFromScreenPos(screenPos);
|
return Widget::pickFromScreenPos(screenPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Manager::transferAsMouseDownMessage(Widget* from,
|
||||||
|
Widget* to,
|
||||||
|
const MouseMessage* mouseMsg,
|
||||||
|
const bool sendNow)
|
||||||
|
{
|
||||||
|
ASSERT(to);
|
||||||
|
ASSERT(from);
|
||||||
|
|
||||||
|
// Remove the capture from the "from" widget.
|
||||||
|
if (from->hasCapture())
|
||||||
|
from->releaseMouse();
|
||||||
|
|
||||||
|
// Allow the "to" widget to re-capture the mouse.
|
||||||
|
allowCapture(to);
|
||||||
|
|
||||||
|
// We enqueue a copy of the mouse message but as a kMouseDownMessage.
|
||||||
|
auto mouseMsg2 = std::make_unique<MouseMessage>(kMouseDownMessage,
|
||||||
|
*mouseMsg,
|
||||||
|
mouseMsg->positionForDisplay(to->display()));
|
||||||
|
mouseMsg2->setRecipient(to);
|
||||||
|
mouseMsg2->setDisplay(to->display());
|
||||||
|
|
||||||
|
if (sendNow)
|
||||||
|
to->sendMessage(mouseMsg2.get());
|
||||||
|
else
|
||||||
|
enqueueMessage(mouseMsg2.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Manager::isWidgetClickable(const Widget* widget) const
|
||||||
|
{
|
||||||
|
Window* widgetWindow = widget->window();
|
||||||
|
if (!widgetWindow)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (auto* child : children()) {
|
||||||
|
Window* window = static_cast<Window*>(child);
|
||||||
|
|
||||||
|
if (widgetWindow == window)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (window->isForeground() || window->isDesktop())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void Manager::_closingAppWithException()
|
void Manager::_closingAppWithException()
|
||||||
{
|
{
|
||||||
redrawState = RedrawState::ClosingApp;
|
redrawState = RedrawState::ClosingApp;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite UI Library
|
// Aseprite UI Library
|
||||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
// Copyright (C) 2018-2025 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.
|
||||||
@ -72,9 +72,9 @@ public:
|
|||||||
void addToGarbage(Widget* widget);
|
void addToGarbage(Widget* widget);
|
||||||
void collectGarbage();
|
void collectGarbage();
|
||||||
|
|
||||||
Window* getTopWindow();
|
Window* getTopWindow() const;
|
||||||
Window* getDesktopWindow();
|
Window* getDesktopWindow() const;
|
||||||
Window* getForegroundWindow();
|
Window* getForegroundWindow() const;
|
||||||
Display* getForegroundDisplay();
|
Display* getForegroundDisplay();
|
||||||
|
|
||||||
Widget* getFocus();
|
Widget* getFocus();
|
||||||
@ -83,7 +83,7 @@ public:
|
|||||||
|
|
||||||
void setFocus(Widget* widget);
|
void setFocus(Widget* widget);
|
||||||
void setMouse(Widget* widget);
|
void setMouse(Widget* widget);
|
||||||
void setCapture(Widget* widget);
|
void setCapture(Widget* widget, bool force = false);
|
||||||
void attractFocus(Widget* widget);
|
void attractFocus(Widget* widget);
|
||||||
void focusFirstChild(Widget* widget);
|
void focusFirstChild(Widget* widget);
|
||||||
void freeFocus();
|
void freeFocus();
|
||||||
@ -107,6 +107,30 @@ public:
|
|||||||
|
|
||||||
Widget* pickFromScreenPos(const gfx::Point& screenPos) const override;
|
Widget* pickFromScreenPos(const gfx::Point& screenPos) const override;
|
||||||
|
|
||||||
|
// Transfers the given MouseMessage received "from" (generally a
|
||||||
|
// kMouseMoveMessage) to the given "to" widget, sending a copy of
|
||||||
|
// the message but changing its type to kMouseDownMessage. By
|
||||||
|
// default it enqueues the message.
|
||||||
|
//
|
||||||
|
// If "from" has the mouse capture, it will be released as it is
|
||||||
|
// highly probable that the "to" widget will recapture the mouse
|
||||||
|
// again.
|
||||||
|
//
|
||||||
|
// This is used in cases were the user presses the mouse button on
|
||||||
|
// one widget, and then drags the mouse to another widget. With this
|
||||||
|
// we can transfer the mouse capture between widgets (from -> to)
|
||||||
|
// simulating a kMouseDownMessage for the new widget "to".
|
||||||
|
void transferAsMouseDownMessage(Widget* from,
|
||||||
|
Widget* to,
|
||||||
|
const MouseMessage* mouseMsg,
|
||||||
|
bool sendNow = false);
|
||||||
|
|
||||||
|
// Returns true if the widget is accessible with the mouse, i.e. the
|
||||||
|
// widget is in the current foreground window (or a top window above
|
||||||
|
// the foreground, e.g. a combobox popup), or there is no foreground
|
||||||
|
// window and the widget is in the desktop window.
|
||||||
|
bool isWidgetClickable(const Widget* widget) const;
|
||||||
|
|
||||||
void _openWindow(Window* window, bool center);
|
void _openWindow(Window* window, bool center);
|
||||||
void _closeWindow(Window* window, bool redraw_background);
|
void _closeWindow(Window* window, bool redraw_background);
|
||||||
void _runModalWindow(Window* window);
|
void _runModalWindow(Window* window);
|
||||||
@ -164,6 +188,7 @@ private:
|
|||||||
const double magnification);
|
const double magnification);
|
||||||
bool handleWindowZOrder();
|
bool handleWindowZOrder();
|
||||||
void updateMouseWidgets(const gfx::Point& mousePos, Display* display);
|
void updateMouseWidgets(const gfx::Point& mousePos, Display* display);
|
||||||
|
void allowCapture(Widget* widget);
|
||||||
|
|
||||||
int pumpQueue();
|
int pumpQueue();
|
||||||
bool sendMessageToWidget(Message* msg, Widget* widget);
|
bool sendMessageToWidget(Message* msg, Widget* widget);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite UI Library
|
// Aseprite UI Library
|
||||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
// Copyright (C) 2018-2025 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.
|
||||||
@ -186,7 +186,7 @@ void View::updateView(const bool restoreScrollPos)
|
|||||||
// Restore the mouse capture if it changed, which means that a
|
// Restore the mouse capture if it changed, which means that a
|
||||||
// scroll bar (when it was temporarily removed) lost the capture.
|
// scroll bar (when it was temporarily removed) lost the capture.
|
||||||
if (man && man->getCapture() != mouseCapture && mouseCapture->isVisible())
|
if (man && man->getCapture() != mouseCapture && mouseCapture->isVisible())
|
||||||
man->setCapture(mouseCapture);
|
man->setCapture(mouseCapture, true); // Force the capture
|
||||||
}
|
}
|
||||||
|
|
||||||
Viewport* View::viewport()
|
Viewport* View::viewport()
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite UI Library
|
// Aseprite UI Library
|
||||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
// Copyright (C) 2018-2025 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.
|
||||||
@ -1507,22 +1507,15 @@ void Widget::releaseMouse()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Widget::offerCapture(ui::MouseMessage* mouseMsg, int widget_type)
|
bool Widget::offerCapture(ui::MouseMessage* mouseMsg, const WidgetType widgetType)
|
||||||
{
|
{
|
||||||
if (hasCapture()) {
|
if (hasCapture()) {
|
||||||
const gfx::Point screenPos = mouseMsg->display()->nativeWindow()->pointToScreen(
|
const gfx::Point screenPos = mouseMsg->display()->nativeWindow()->pointToScreen(
|
||||||
mouseMsg->position());
|
mouseMsg->position());
|
||||||
auto man = manager();
|
Manager* mgr = manager();
|
||||||
Widget* pick = (man ? man->pickFromScreenPos(screenPos) : nullptr);
|
Widget* pick = (mgr ? mgr->pickFromScreenPos(screenPos) : nullptr);
|
||||||
if (pick && pick != this && pick->type() == widget_type) {
|
if (pick && pick != this && pick->type() == widgetType) {
|
||||||
releaseMouse();
|
mgr->transferAsMouseDownMessage(this, pick, mouseMsg);
|
||||||
|
|
||||||
MouseMessage* mouseMsg2 = new MouseMessage(kMouseDownMessage,
|
|
||||||
*mouseMsg,
|
|
||||||
mouseMsg->positionForDisplay(pick->display()));
|
|
||||||
mouseMsg2->setDisplay(pick->display());
|
|
||||||
mouseMsg2->setRecipient(pick);
|
|
||||||
man->enqueueMessage(mouseMsg2);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite UI Library
|
// Aseprite UI Library
|
||||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
// Copyright (C) 2018-2025 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.
|
||||||
@ -336,6 +336,11 @@ public:
|
|||||||
|
|
||||||
void requestFocus();
|
void requestFocus();
|
||||||
void releaseFocus();
|
void releaseFocus();
|
||||||
|
|
||||||
|
// Captures the mouse to continue receiving its messages until we
|
||||||
|
// release the capture. Useful for widgets with painting-like
|
||||||
|
// capabilities, where we want to keep track of the mouse until the
|
||||||
|
// user releases the mouse button, or drag-and-drop behaviors.
|
||||||
void captureMouse();
|
void captureMouse();
|
||||||
void releaseMouse();
|
void releaseMouse();
|
||||||
|
|
||||||
@ -371,9 +376,9 @@ public:
|
|||||||
// the widget bounds.
|
// the widget bounds.
|
||||||
gfx::Point mousePosInClientBounds() const { return toClient(mousePosInDisplay()); }
|
gfx::Point mousePosInClientBounds() const { return toClient(mousePosInDisplay()); }
|
||||||
|
|
||||||
// Offer the capture to widgets of the given type. Returns true if
|
// Offers the capture to widgets of the given type. Returns true if
|
||||||
// the capture was passed to other widget.
|
// the capture was passed to other widget.
|
||||||
bool offerCapture(MouseMessage* mouseMsg, int widget_type);
|
bool offerCapture(MouseMessage* mouseMsg, WidgetType widgetType);
|
||||||
|
|
||||||
// Returns lower-case letter that represet the mnemonic of the widget
|
// Returns lower-case letter that represet the mnemonic of the widget
|
||||||
// (the underscored character, i.e. the letter after & symbol).
|
// (the underscored character, i.e. the letter after & symbol).
|
||||||
|
Loading…
x
Reference in New Issue
Block a user