mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-02 22:13:32 +00:00
Each ui::Window now can have a related native os::Window. This connection is done through the ui::Display class added recently in c3d52f0bbe5242923c9e38495e1be1135ca0934f.
This commit is contained in:
parent
74961f58c0
commit
8034b0cbcc
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Aseprite -->
|
||||
<!-- Copyright (C) 2018-2020 Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2018-2021 Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2014-2018 David Capello -->
|
||||
<preferences>
|
||||
|
||||
@ -203,6 +203,7 @@
|
||||
<option id="api" type="std::string" />
|
||||
</section>
|
||||
<section id="experimental" text="Experimental">
|
||||
<option id="multiple_windows" type="bool" default="true" />
|
||||
<option id="new_render_engine" type="bool" default="true" />
|
||||
<option id="new_blend" type="bool" default="true" />
|
||||
<option id="use_native_clipboard" type="bool" default="true" />
|
||||
|
@ -1336,6 +1336,7 @@ disable_extension = &Disable
|
||||
uninstall_extension = &Uninstall
|
||||
open_extension_folder = Open &Folder
|
||||
user_interface = User Interface
|
||||
multiple_windows = UI with multiple windows
|
||||
new_blend = New layer blending method
|
||||
new_render_engine = New render engine for sprite editor
|
||||
native_clipboard = Use native clipboard
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!-- Aseprite -->
|
||||
<!-- Copyright (C) 2018-2020 Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2018-2021 Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2001-2018 David Capello -->
|
||||
<gui>
|
||||
<window id="options" text="@.title">
|
||||
@ -484,6 +484,8 @@
|
||||
<!-- Experimental -->
|
||||
<vbox id="section_experimental">
|
||||
<separator text="@.user_interface" horizontal="true" />
|
||||
<check id="multiple_windows" text="@.multiple_windows"
|
||||
pref="experimental.multiple_windows" />
|
||||
<hbox>
|
||||
<check text="@.new_render_engine"
|
||||
pref="experimental.new_render_engine" />
|
||||
|
2
laf
2
laf
@ -1 +1 @@
|
||||
Subproject commit b2c8b1e63dec366439d78d304f3ce48803eb1fd6
|
||||
Subproject commit 60d8b87ce826dc52651154bcd90c4251b69cbdb8
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -142,8 +142,9 @@ protected:
|
||||
updateEditorBoxFromRect();
|
||||
}
|
||||
|
||||
virtual void onBroadcastMouseMessage(WidgetsList& targets) override {
|
||||
Window::onBroadcastMouseMessage(targets);
|
||||
virtual void onBroadcastMouseMessage(const gfx::Point& screenPos,
|
||||
WidgetsList& targets) override {
|
||||
Window::onBroadcastMouseMessage(screenPos, targets);
|
||||
|
||||
// Add the editor as receptor of mouse events too.
|
||||
targets.push_back(View::getView(m_editor));
|
||||
|
@ -550,8 +550,9 @@ private:
|
||||
return Window::onProcessMessage(msg);
|
||||
}
|
||||
|
||||
void onBroadcastMouseMessage(WidgetsList& targets) override {
|
||||
Window::onBroadcastMouseMessage(targets);
|
||||
void onBroadcastMouseMessage(const gfx::Point& screenPos,
|
||||
WidgetsList& targets) override {
|
||||
Window::onBroadcastMouseMessage(screenPos, targets);
|
||||
|
||||
// Add the editor as receptor of mouse events too.
|
||||
if (m_editor)
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2020 Igara Studio S.A.
|
||||
// Copyright (C) 2020-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -186,12 +186,16 @@ void EyedropperCommand::onLoadParams(const Params& params)
|
||||
void EyedropperCommand::onExecute(Context* context)
|
||||
{
|
||||
gfx::Point mousePos = ui::get_mouse_position();
|
||||
Widget* widget = ui::Manager::getDefault()->pick(mousePos);
|
||||
Widget* widget = ui::Manager::getDefault()->pickFromScreenPos(mousePos);
|
||||
if (!widget || widget->type() != Editor::Type())
|
||||
return;
|
||||
|
||||
Editor* editor = static_cast<Editor*>(widget);
|
||||
executeOnMousePos(context, editor, mousePos, !m_background);
|
||||
executeOnMousePos(
|
||||
context,
|
||||
editor,
|
||||
editor->display()->nativeWindow()->pointFromScreen(mousePos),
|
||||
!m_background);
|
||||
}
|
||||
|
||||
void EyedropperCommand::executeOnMousePos(Context* context,
|
||||
|
@ -74,7 +74,7 @@ public:
|
||||
gfx::Rect vp = view->viewportBounds();
|
||||
gfx::Point scroll = view->viewScroll();
|
||||
|
||||
m_oldMousePos = ui::get_mouse_position();
|
||||
m_oldMousePos = mousePosInDisplay();
|
||||
m_pos.x = -scroll.x + vp.x + editor->padding().x;
|
||||
m_pos.y = -scroll.y + vp.y + editor->padding().y;
|
||||
|
||||
|
@ -195,8 +195,9 @@ protected:
|
||||
return Window::onProcessMessage(msg);
|
||||
}
|
||||
|
||||
void onBroadcastMouseMessage(WidgetsList& targets) override {
|
||||
Window::onBroadcastMouseMessage(targets);
|
||||
void onBroadcastMouseMessage(const gfx::Point& screenPos,
|
||||
WidgetsList& targets) override {
|
||||
Window::onBroadcastMouseMessage(screenPos, targets);
|
||||
|
||||
// Add the editor as receptor of mouse events too.
|
||||
if (m_editor)
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2019 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2015-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -82,7 +82,7 @@ void SelectTileCommand::onExecute(Context* ctx)
|
||||
|
||||
{
|
||||
gfx::Rect gridBounds = writer.site()->gridBounds();
|
||||
gfx::Point pos = current_editor->screenToEditor(ui::get_mouse_position());
|
||||
gfx::Point pos = current_editor->screenToEditor(current_editor->mousePosInDisplay());
|
||||
pos = snap_to_grid(gridBounds, pos, PreferSnapTo::BoxOrigin);
|
||||
gridBounds.setOrigin(pos);
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2021 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -83,7 +84,7 @@ void ZoomCommand::onExecute(Context* context)
|
||||
gfx::Point mousePos = ui::get_mouse_position();
|
||||
|
||||
// Try to use the editor above the mouse.
|
||||
ui::Widget* pick = ui::Manager::getDefault()->pick(mousePos);
|
||||
ui::Widget* pick = ui::Manager::getDefault()->pickFromScreenPos(mousePos);
|
||||
if (pick && pick->type() == Editor::Type())
|
||||
editor = static_cast<Editor*>(pick);
|
||||
|
||||
@ -112,7 +113,8 @@ void ZoomCommand::onExecute(Context* context)
|
||||
}
|
||||
|
||||
editor->setZoomAndCenterInMouse(
|
||||
zoom, mousePos,
|
||||
zoom,
|
||||
editor->display()->nativeWindow()->pointFromScreen(mousePos),
|
||||
(focus == Focus::Center ? Editor::ZoomBehavior::CENTER:
|
||||
Editor::ZoomBehavior::MOUSE));
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -71,12 +71,12 @@ bool ColorCurveEditor::onProcessMessage(Message* msg)
|
||||
switch (static_cast<KeyMessage*>(msg)->scancode()) {
|
||||
|
||||
case kKeyInsert: {
|
||||
addPoint(screenToView(get_mouse_position()));
|
||||
addPoint(screenToView(mousePosInDisplay()));
|
||||
break;
|
||||
}
|
||||
|
||||
case kKeyDel: {
|
||||
if (gfx::Point* point = getClosestPoint(screenToView(get_mouse_position())))
|
||||
if (gfx::Point* point = getClosestPoint(screenToView(mousePosInDisplay())))
|
||||
removePoint(*point);
|
||||
break;
|
||||
}
|
||||
|
@ -219,7 +219,7 @@ int init_module_gui()
|
||||
Message* msg = new Message(kResizeDisplayMessage);
|
||||
msg->setDisplay(display);
|
||||
msg->setRecipient(manager);
|
||||
msg->setPropagateToChildren(true);
|
||||
msg->setPropagateToChildren(false);
|
||||
|
||||
manager->enqueueMessage(msg);
|
||||
manager->dispatchMessages();
|
||||
@ -295,6 +295,8 @@ static void load_gui_config(int& w, int& h, bool& maximized,
|
||||
h = get_config_int("GfxMode", "Height", defSize.h);
|
||||
maximized = get_config_bool("GfxMode", "Maximized", false);
|
||||
windowLayout = get_config_string("GfxMode", "WindowLayout", "");
|
||||
|
||||
ui::set_multiple_displays(Preferences::instance().experimental.multipleWindows());
|
||||
}
|
||||
|
||||
static void save_gui_config()
|
||||
@ -331,21 +333,20 @@ void update_screen_for_document(const Doc* document)
|
||||
}
|
||||
}
|
||||
|
||||
void load_window_pos(Widget* window, const char* section,
|
||||
void load_window_pos(Window* window, const char* section,
|
||||
const bool limitMinSize)
|
||||
{
|
||||
Size desktopSize = ui::get_desktop_size();
|
||||
|
||||
// Default position
|
||||
Rect orig_pos = window->bounds();
|
||||
Rect pos = orig_pos;
|
||||
Rect origPos = window->bounds();
|
||||
|
||||
// Load configurated position
|
||||
pos = get_config_rect(section, "WindowPos", pos);
|
||||
Rect pos = get_config_rect(section, "WindowPos", origPos);
|
||||
|
||||
if (limitMinSize) {
|
||||
pos.w = base::clamp(pos.w, orig_pos.w, desktopSize.w);
|
||||
pos.h = base::clamp(pos.h, orig_pos.h, desktopSize.h);
|
||||
pos.w = base::clamp(pos.w, origPos.w, desktopSize.w);
|
||||
pos.h = base::clamp(pos.h, origPos.h, desktopSize.h);
|
||||
}
|
||||
else {
|
||||
pos.w = std::min(pos.w, desktopSize.w);
|
||||
@ -356,11 +357,36 @@ void load_window_pos(Widget* window, const char* section,
|
||||
base::clamp(pos.y, 0, desktopSize.h-pos.h)));
|
||||
|
||||
window->setBounds(pos);
|
||||
|
||||
if (get_multiple_displays()) {
|
||||
Rect frame = get_config_rect(section, "WindowFrame", gfx::Rect());
|
||||
if (!frame.isEmpty()) {
|
||||
// TODO limit window area to current workspace / all available screen limits (?)
|
||||
window->loadNativeFrame(frame);
|
||||
}
|
||||
}
|
||||
else {
|
||||
del_config_value(section, "WindowFrame");
|
||||
}
|
||||
}
|
||||
|
||||
void save_window_pos(Widget* window, const char *section)
|
||||
void save_window_pos(Window* window, const char *section)
|
||||
{
|
||||
set_config_rect(section, "WindowPos", window->bounds());
|
||||
gfx::Rect rc;
|
||||
|
||||
if (!window->lastNativeFrame().isEmpty()) {
|
||||
os::Window* mainNativeWindow = manager->display()->nativeWindow();
|
||||
int scale = mainNativeWindow->scale();
|
||||
rc = window->lastNativeFrame();
|
||||
set_config_rect(section, "WindowFrame", rc);
|
||||
rc.offset(-mainNativeWindow->frame().origin());
|
||||
rc /= scale;
|
||||
}
|
||||
else {
|
||||
rc = window->bounds();
|
||||
}
|
||||
|
||||
set_config_rect(section, "WindowPos", rc);
|
||||
}
|
||||
|
||||
// TODO Replace this with new theme styles
|
||||
@ -405,12 +431,15 @@ bool CustomizedGuiManager::onProcessMessage(Message* msg)
|
||||
|
||||
switch (msg->type()) {
|
||||
|
||||
case kCloseDisplayMessage: {
|
||||
// Execute the "Exit" command.
|
||||
Command* command = Commands::instance()->byId(CommandId::Exit());
|
||||
UIContext::instance()->executeCommandFromMenuOrShortcut(command);
|
||||
case kCloseDisplayMessage:
|
||||
// When the main display is closed...
|
||||
if (msg->display() == this->display()) {
|
||||
// Execute the "Exit" command.
|
||||
Command* command = Commands::instance()->byId(CommandId::Exit());
|
||||
UIContext::instance()->executeCommandFromMenuOrShortcut(command);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case kDropFilesMessage:
|
||||
// Files are processed only when the main window is the current
|
||||
@ -580,7 +609,7 @@ bool CustomizedGuiManager::onProcessDevModeKeyDown(KeyMessage* msg)
|
||||
return true; // This line should not be executed anyway
|
||||
}
|
||||
|
||||
// F1 switches screen/UI scaling
|
||||
// Ctrl+F1 switches screen/UI scaling
|
||||
if (msg->ctrlPressed() &&
|
||||
msg->scancode() == kKeyF1) {
|
||||
try {
|
||||
|
@ -38,9 +38,9 @@ namespace app {
|
||||
void update_windows_color_profile_from_preferences();
|
||||
void update_screen_for_document(const Doc* document);
|
||||
|
||||
void load_window_pos(ui::Widget* window, const char* section,
|
||||
void load_window_pos(ui::Window* window, const char* section,
|
||||
const bool limitMinSize = true);
|
||||
void save_window_pos(ui::Widget* window, const char* section);
|
||||
void save_window_pos(ui::Window* window, const char* section);
|
||||
|
||||
ui::Widget* setup_mini_font(ui::Widget* widget);
|
||||
ui::Widget* setup_mini_look(ui::Widget* widget);
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2020 Igara Studio S.A.
|
||||
// Copyright (C) 2020-2021 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -27,7 +27,7 @@ void VelocitySensor::reset()
|
||||
m_velocity = Vec2(0.0f, 0.0f);
|
||||
}
|
||||
|
||||
void VelocitySensor::updateWithScreenPoint(const gfx::Point& screenPoint)
|
||||
void VelocitySensor::updateWithDisplayPoint(const gfx::Point& screenPoint)
|
||||
{
|
||||
const base::tick_t t = base::current_tick();
|
||||
const base::tick_t dt = t - m_lastUpdate;
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2020 Igara Studio S.A.
|
||||
// Copyright (C) 2020-2021 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -34,7 +34,7 @@ public:
|
||||
|
||||
const Vec2& velocity() const { return m_velocity; }
|
||||
|
||||
void updateWithScreenPoint(const gfx::Point& screenPoint);
|
||||
void updateWithDisplayPoint(const gfx::Point& screenPoint);
|
||||
|
||||
private:
|
||||
bool m_firstPoint;
|
||||
|
@ -589,7 +589,7 @@ void BrowserView::onTabPopup(Workspace* workspace)
|
||||
if (!menu)
|
||||
return;
|
||||
|
||||
menu->showPopup(ui::get_mouse_position());
|
||||
menu->showPopup(mousePosInDisplay());
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
@ -145,6 +145,7 @@ bool ColorButton::onProcessMessage(Message* msg)
|
||||
break;
|
||||
|
||||
case kMouseMoveMessage:
|
||||
// TODO code similar to TileButton::onProcessMessage()
|
||||
if (hasCapture()) {
|
||||
gfx::Point mousePos = static_cast<MouseMessage*>(msg)->position();
|
||||
app::Color color = m_color;
|
||||
@ -157,7 +158,7 @@ bool ColorButton::onProcessMessage(Message* msg)
|
||||
// surface, and finally from the desktop. The desktop must be
|
||||
// a last resource method, because in macOS it will ask for
|
||||
// permissions to record the screen.
|
||||
if (!colorSource) {
|
||||
if (!colorSource && get_multiple_displays()) {
|
||||
os::Window* nativeWindow = display()->nativeWindow();
|
||||
gfx::Point screenPos = nativeWindow->pointToScreen(mousePos);
|
||||
|
||||
|
@ -413,7 +413,7 @@ void DataRecoveryView::onTabPopup(Workspace* workspace)
|
||||
if (!menu)
|
||||
return;
|
||||
|
||||
menu->showPopup(ui::get_mouse_position());
|
||||
menu->showPopup(mousePosInDisplay());
|
||||
}
|
||||
|
||||
void DataRecoveryView::onOpen()
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2020 Igara Studio S.A.
|
||||
// Copyright (C) 2020-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -140,7 +140,7 @@ void DevConsoleView::onTabPopup(Workspace* workspace)
|
||||
if (!menu)
|
||||
return;
|
||||
|
||||
menu->showPopup(ui::get_mouse_position());
|
||||
menu->showPopup(mousePosInDisplay());
|
||||
}
|
||||
|
||||
bool DevConsoleView::onProcessMessage(Message* msg)
|
||||
|
@ -128,7 +128,7 @@ protected:
|
||||
PointerType::Unknown,
|
||||
(lmb->isPressed(msg, *keys) ? kButtonLeft: kButtonRight),
|
||||
msg->modifiers(),
|
||||
ui::get_mouse_position());
|
||||
mousePosInDisplay());
|
||||
|
||||
sendMessage(&mouseMsg);
|
||||
return true;
|
||||
@ -362,7 +362,7 @@ void DocView::onTabPopup(Workspace* workspace)
|
||||
ctx->setActiveView(this);
|
||||
ctx->updateFlags();
|
||||
|
||||
menu->showPopup(ui::get_mouse_position());
|
||||
menu->showPopup(mousePosInDisplay());
|
||||
}
|
||||
|
||||
bool DocView::onProcessMessage(Message* msg)
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2020 Igara Studio S.A.
|
||||
// Copyright (C) 2020-2021 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -430,7 +430,7 @@ bool DynamicsPopup::onProcessMessage(Message* msg)
|
||||
}
|
||||
|
||||
if (m_dynamics->velocityPlaceholder()->isVisible()) {
|
||||
m_velocity.updateWithScreenPoint(mouseMsg->position());
|
||||
m_velocity.updateWithDisplayPoint(mouseMsg->position());
|
||||
|
||||
float v = m_velocity.velocity().magnitude()
|
||||
/ tools::VelocitySensor::kScreenPixelsForFullVelocity;
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -214,7 +214,7 @@ bool DrawingState::onMouseMove(Editor* editor, MouseMessage* msg)
|
||||
false, m_processScrollChange);
|
||||
|
||||
// Update velocity sensor.
|
||||
m_velocity.updateWithScreenPoint(msg->position());
|
||||
m_velocity.updateWithDisplayPoint(msg->position());
|
||||
|
||||
// The autoScroll() function controls the "infinite scroll" when we
|
||||
// touch the viewport borders.
|
||||
@ -279,10 +279,10 @@ bool DrawingState::onKeyUp(Editor* editor, KeyMessage* msg)
|
||||
bool DrawingState::onScrollChange(Editor* editor)
|
||||
{
|
||||
if (m_processScrollChange) {
|
||||
gfx::Point mousePos = ui::get_mouse_position();
|
||||
gfx::Point mousePos = editor->mousePosInDisplay();
|
||||
|
||||
// Update velocity sensor.
|
||||
m_velocity.updateWithScreenPoint(mousePos); // TODO add scroll as velocity?
|
||||
m_velocity.updateWithDisplayPoint(mousePos); // TODO add scroll as velocity?
|
||||
|
||||
handleMouseMovement(
|
||||
tools::Pointer(editor->screenToEditor(mousePos),
|
||||
|
@ -301,7 +301,7 @@ void Editor::setStateInternal(const EditorStatePtr& newState)
|
||||
invalidate();
|
||||
|
||||
// Setup the new mouse cursor
|
||||
setCursor(ui::get_mouse_position());
|
||||
setCursor(mousePosInDisplay());
|
||||
|
||||
updateStatusBar();
|
||||
}
|
||||
@ -539,7 +539,7 @@ void Editor::setEditorScroll(const gfx::Point& scroll)
|
||||
void Editor::setEditorZoom(const render::Zoom& zoom)
|
||||
{
|
||||
setZoomAndCenterInMouse(
|
||||
zoom, ui::get_mouse_position(),
|
||||
zoom, mousePosInDisplay(),
|
||||
Editor::ZoomBehavior::CENTER);
|
||||
}
|
||||
|
||||
@ -1402,7 +1402,8 @@ gfx::Point Editor::autoScroll(MouseMessage* msg, AutoScroll dir)
|
||||
setEditorScroll(scroll);
|
||||
|
||||
mousePos -= delta;
|
||||
ui::set_mouse_position(mousePos);
|
||||
ui::set_mouse_position(mousePos,
|
||||
display());
|
||||
|
||||
m_oldPos = mousePos;
|
||||
mousePos = gfx::Point(
|
||||
@ -1976,7 +1977,7 @@ bool Editor::onProcessMessage(Message* msg)
|
||||
updateAutoCelGuides(msg);
|
||||
if (hasMouse()) {
|
||||
updateQuicktool();
|
||||
setCursor(ui::get_mouse_position());
|
||||
setCursor(mousePosInDisplay());
|
||||
}
|
||||
|
||||
if (used)
|
||||
@ -1993,7 +1994,7 @@ bool Editor::onProcessMessage(Message* msg)
|
||||
updateAutoCelGuides(msg);
|
||||
if (hasMouse()) {
|
||||
updateQuicktool();
|
||||
setCursor(ui::get_mouse_position());
|
||||
setCursor(mousePosInDisplay());
|
||||
}
|
||||
|
||||
if (used)
|
||||
@ -2040,7 +2041,7 @@ bool Editor::onProcessMessage(Message* msg)
|
||||
// (e.g. in the case of the Eraser tool).
|
||||
m_document->setExtraCel(ExtraCelRef(nullptr));
|
||||
|
||||
showBrushPreview(ui::get_mouse_position());
|
||||
showBrushPreview(mousePosInDisplay());
|
||||
}
|
||||
else {
|
||||
m_document->setExtraCel(ExtraCelRef(nullptr));
|
||||
@ -2174,7 +2175,7 @@ void Editor::onActiveToolChange(tools::Tool* tool)
|
||||
m_state->onActiveToolChange(this, tool);
|
||||
if (hasMouse()) {
|
||||
updateStatusBar();
|
||||
setCursor(ui::get_mouse_position());
|
||||
setCursor(mousePosInDisplay());
|
||||
}
|
||||
}
|
||||
|
||||
@ -2277,15 +2278,15 @@ void Editor::onRemoveSlice(DocEvent& ev)
|
||||
}
|
||||
}
|
||||
|
||||
void Editor::setCursor(const gfx::Point& mouseScreenPos)
|
||||
void Editor::setCursor(const gfx::Point& mouseDisplayPos)
|
||||
{
|
||||
Rect vp = View::getView(this)->viewportBounds();
|
||||
if (!vp.contains(mouseScreenPos))
|
||||
if (!vp.contains(mouseDisplayPos))
|
||||
return;
|
||||
|
||||
bool used = false;
|
||||
if (m_sprite)
|
||||
used = m_state->onSetCursor(this, mouseScreenPos);
|
||||
used = m_state->onSetCursor(this, mouseDisplayPos);
|
||||
|
||||
if (!used)
|
||||
showMouseCursor(kArrowCursor);
|
||||
@ -2302,7 +2303,7 @@ bool Editor::canDraw()
|
||||
|
||||
bool Editor::isInsideSelection()
|
||||
{
|
||||
gfx::Point spritePos = screenToEditor(ui::get_mouse_position());
|
||||
gfx::Point spritePos = screenToEditor(mousePosInDisplay());
|
||||
spritePos -= mainTilePosition();
|
||||
|
||||
KeyAction action = m_customizationDelegate->getPressedKeyAction(KeyContext::SelectionTool);
|
||||
@ -2617,7 +2618,7 @@ void Editor::notifyScrollChanged()
|
||||
// Update status bar and mouse cursor
|
||||
if (hasMouse()) {
|
||||
updateStatusBar();
|
||||
setCursor(ui::get_mouse_position());
|
||||
setCursor(mousePosInDisplay());
|
||||
}
|
||||
}
|
||||
|
||||
@ -2753,7 +2754,7 @@ void Editor::showAnimationSpeedMultiplierPopup(Option<bool>& playOnce,
|
||||
menu.addChild(item);
|
||||
}
|
||||
|
||||
menu.showPopup(ui::get_mouse_position());
|
||||
menu.showPopup(mousePosInDisplay());
|
||||
|
||||
if (isPlaying()) {
|
||||
// Re-play
|
||||
@ -2916,7 +2917,7 @@ void Editor::updateAutoCelGuides(ui::Message* msg)
|
||||
ColorPicker picker;
|
||||
picker.pickColor(getSite(),
|
||||
screenToEditorF(mouseMsg ? mouseMsg->position():
|
||||
ui::get_mouse_position()),
|
||||
mousePosInDisplay()),
|
||||
m_proj, ColorPicker::FromComposition);
|
||||
m_showGuidesThisCel = (picker.layer() ? picker.layer()->cel(m_frame):
|
||||
nullptr);
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -172,6 +172,11 @@ namespace app {
|
||||
|
||||
void flashCurrentLayer();
|
||||
|
||||
// Convert ui::Display coordinates (pixel relative to the top-left
|
||||
// corner of the in the display content bounds) from/to
|
||||
// editor/sprite coordinates (pixel in the canvas).
|
||||
//
|
||||
// TODO we should rename these functions to displayToEditor() and editorToDisplay()
|
||||
gfx::Point screenToEditor(const gfx::Point& pt);
|
||||
gfx::PointF screenToEditorF(const gfx::Point& pt);
|
||||
gfx::Point editorToScreen(const gfx::Point& pt);
|
||||
@ -368,7 +373,7 @@ namespace app {
|
||||
const int dottedY);
|
||||
gfx::Rect getCelScreenBounds(const Cel* cel);
|
||||
|
||||
void setCursor(const gfx::Point& mouseScreenPos);
|
||||
void setCursor(const gfx::Point& mouseDisplayPos);
|
||||
|
||||
// Draws the specified portion of sprite in the editor. Warning:
|
||||
// You should setup the clip of the screen before calling this
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -66,7 +66,6 @@
|
||||
#include "os/system.h"
|
||||
#include "ui/alert.h"
|
||||
#include "ui/message.h"
|
||||
#include "ui/system.h"
|
||||
#include "ui/view.h"
|
||||
|
||||
#include <cmath>
|
||||
@ -527,7 +526,7 @@ bool StandbyState::onUpdateStatusBar(Editor* editor)
|
||||
tools::Ink* ink = editor->getCurrentEditorInk();
|
||||
const Sprite* sprite = editor->sprite();
|
||||
gfx::PointF spritePos =
|
||||
editor->screenToEditorF(ui::get_mouse_position())
|
||||
editor->screenToEditorF(editor->mousePosInDisplay())
|
||||
- gfx::PointF(editor->mainTilePosition());
|
||||
|
||||
if (!sprite) {
|
||||
@ -680,7 +679,7 @@ bool StandbyState::checkStartDrawingStraightLine(Editor* editor,
|
||||
if (drawingState) {
|
||||
drawingState->sendMovementToToolLoop(
|
||||
tools::Pointer(
|
||||
pointer ? pointer->point(): editor->screenToEditor(ui::get_mouse_position()),
|
||||
pointer ? pointer->point(): editor->screenToEditor(editor->mousePosInDisplay()),
|
||||
tools::Vec2(0.0f, 0.0f),
|
||||
pointerButton,
|
||||
pointer ? pointer->type(): tools::Pointer::Type::Unknown,
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -136,7 +136,7 @@ void HomeView::onTabPopup(Workspace* workspace)
|
||||
if (!menu)
|
||||
return;
|
||||
|
||||
menu->showPopup(ui::get_mouse_position());
|
||||
menu->showPopup(mousePosInDisplay());
|
||||
}
|
||||
|
||||
void HomeView::onWorkspaceViewSelected()
|
||||
|
@ -728,7 +728,7 @@ void Tabs::calculateHot()
|
||||
|
||||
gfx::Rect rect = bounds();
|
||||
gfx::Rect box(rect.x+m_border*guiscale(), rect.y, 0, rect.h-1);
|
||||
gfx::Point mousePos = ui::get_mouse_position();
|
||||
gfx::Point mousePos = mousePosInDisplay();
|
||||
TabPtr hot(nullptr);
|
||||
bool hotCloseButton = false;
|
||||
|
||||
@ -1040,7 +1040,7 @@ void Tabs::updateDragCopyCursor(ui::Message* msg)
|
||||
(tab && m_delegate && m_delegate->canCloneTab(this, tab->view)));
|
||||
|
||||
if (oldDragCopy != m_dragCopy) {
|
||||
updateDragTabIndexes(get_mouse_position().x, true);
|
||||
updateDragTabIndexes(mousePosInDisplay().x, true);
|
||||
updateMouseCursor();
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (c) 2020 Igara Studio S.A.
|
||||
// Copyright (c) 2020-2021 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -20,6 +20,7 @@
|
||||
#include "ui/paint_event.h"
|
||||
#include "ui/size_hint_event.h"
|
||||
#include "ui/system.h"
|
||||
#include "ui/window.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
@ -88,18 +89,34 @@ bool TileButton::onProcessMessage(Message* msg)
|
||||
break;
|
||||
|
||||
case kMouseMoveMessage:
|
||||
// TODO code similar to ColorButton::onProcessMessage()
|
||||
if (hasCapture()) {
|
||||
gfx::Point mousePos = static_cast<MouseMessage*>(msg)->position();
|
||||
Widget* picked = manager()->pick(mousePos);
|
||||
doc::tile_t tile = m_tile;
|
||||
|
||||
if (picked && picked != this) {
|
||||
// Pick a tile from a ITileSource
|
||||
if (ITileSource* tileSource = dynamic_cast<ITileSource*>(picked)) {
|
||||
tile = tileSource->getTileByPosition(mousePos);
|
||||
// Pick a tile from a ITileSource
|
||||
Widget* picked = window()->pick(mousePos);
|
||||
ITileSource* tileSource = (picked != this ? dynamic_cast<ITileSource*>(picked): nullptr);
|
||||
|
||||
// If there is no tile source in this window, try to get the
|
||||
// tile from other display, i.e. and editor in other native
|
||||
// window.
|
||||
if (!tileSource && get_multiple_displays()) {
|
||||
os::Window* nativeWindow = display()->nativeWindow();
|
||||
gfx::Point screenPos = nativeWindow->pointToScreen(mousePos);
|
||||
|
||||
picked = manager()->pickFromScreenPos(screenPos);
|
||||
tileSource = (picked != this ? dynamic_cast<ITileSource*>(picked): nullptr);
|
||||
if (tileSource) {
|
||||
nativeWindow = picked->display()->nativeWindow();
|
||||
mousePos = nativeWindow->pointFromScreen(screenPos);
|
||||
}
|
||||
}
|
||||
|
||||
if (tileSource) {
|
||||
tile = tileSource->getTileByPosition(mousePos);
|
||||
}
|
||||
|
||||
// Did the tile change?
|
||||
if (tile != m_tile) {
|
||||
setTile(tile);
|
||||
|
@ -888,7 +888,7 @@ bool Timeline::onProcessMessage(Message* msg)
|
||||
m_state = STATE_COLLAPSING_LAYERS;
|
||||
|
||||
setLayerCollapsedFlag(m_clk.layer, m_state == STATE_COLLAPSING_LAYERS);
|
||||
updateByMousePos(msg, ui::get_mouse_position() - bounds().origin());
|
||||
updateByMousePos(msg, mousePosInClientBounds());
|
||||
|
||||
// The m_clk might have changed because we've
|
||||
// expanded/collapsed a group just right now (i.e. we've
|
||||
@ -1075,7 +1075,7 @@ bool Timeline::onProcessMessage(Message* msg)
|
||||
m_clk = hit;
|
||||
if (hit.part == PART_ROW_CONTINUOUS_ICON) {
|
||||
setLayerCollapsedFlag(hit.layer, m_state == STATE_COLLAPSING_LAYERS);
|
||||
updateByMousePos(msg, ui::get_mouse_position() - bounds().origin());
|
||||
updateByMousePos(msg, mousePosInClientBounds());
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1483,7 +1483,7 @@ bool Timeline::onProcessMessage(Message* msg)
|
||||
}
|
||||
}
|
||||
|
||||
updateByMousePos(msg, ui::get_mouse_position() - bounds().origin());
|
||||
updateByMousePos(msg, mousePosInClientBounds());
|
||||
if (used)
|
||||
return true;
|
||||
|
||||
@ -1502,7 +1502,7 @@ bool Timeline::onProcessMessage(Message* msg)
|
||||
}
|
||||
}
|
||||
|
||||
updateByMousePos(msg, ui::get_mouse_position() - bounds().origin());
|
||||
updateByMousePos(msg, mousePosInClientBounds());
|
||||
if (used)
|
||||
return true;
|
||||
|
||||
|
@ -375,7 +375,8 @@ bool ComboBox::onProcessMessage(Message* msg)
|
||||
closeListBox();
|
||||
|
||||
MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
|
||||
Widget* pick = manager()->pick(mouseMsg->position());
|
||||
Widget* pick = manager()->pickFromScreenPos(
|
||||
display()->nativeWindow()->pointFromScreen(mouseMsg->position()));
|
||||
if (pick && pick->hasAncestor(this))
|
||||
return true;
|
||||
}
|
||||
@ -503,7 +504,8 @@ bool ComboBoxEntry::onProcessMessage(Message* msg)
|
||||
case kMouseMoveMessage:
|
||||
if (hasCapture()) {
|
||||
MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
|
||||
Widget* pick = manager()->pick(mouseMsg->position());
|
||||
Widget* pick = manager()->pickFromScreenPos(
|
||||
display()->nativeWindow()->pointToScreen(mouseMsg->position()));
|
||||
Widget* listbox = m_comboBox->m_listbox;
|
||||
|
||||
if (pick != nullptr &&
|
||||
@ -615,7 +617,7 @@ void ComboBox::openListBox()
|
||||
View* view = new View();
|
||||
m_listbox = new ComboBoxListBox(this);
|
||||
// TODO create a real native window for comboboxes
|
||||
m_window->setDisplay(display());
|
||||
m_window->setDisplay(display(), false);
|
||||
m_window->setOnTop(true);
|
||||
m_window->setWantFocus(false);
|
||||
m_window->setSizeable(false);
|
||||
@ -667,6 +669,7 @@ void ComboBox::closeListBox()
|
||||
|
||||
m_window->closeWindow(this);
|
||||
delete m_window; // window, frame
|
||||
|
||||
m_window = nullptr;
|
||||
m_listbox = nullptr;
|
||||
|
||||
|
@ -18,9 +18,11 @@
|
||||
|
||||
namespace ui {
|
||||
|
||||
Display::Display(const os::WindowRef& nativeWindow,
|
||||
Display::Display(Display* parentDisplay,
|
||||
const os::WindowRef& nativeWindow,
|
||||
Widget* containedWidget)
|
||||
: m_nativeWindow(nativeWindow)
|
||||
: m_parentDisplay(parentDisplay)
|
||||
, m_nativeWindow(nativeWindow)
|
||||
, m_containedWidget(containedWidget)
|
||||
{
|
||||
ASSERT(m_nativeWindow);
|
||||
@ -46,7 +48,7 @@ gfx::Size Display::size() const
|
||||
|
||||
void Display::dirtyRect(const gfx::Rect& bounds)
|
||||
{
|
||||
m_dirtyRegion.createUnion(m_dirtyRegion, gfx::Region(bounds));
|
||||
m_dirtyRegion |= gfx::Region(bounds);
|
||||
}
|
||||
|
||||
void Display::flipDisplay()
|
||||
|
@ -25,9 +25,11 @@ namespace ui {
|
||||
// (tooltips?)
|
||||
class Display {
|
||||
public:
|
||||
Display(const os::WindowRef& nativeWindow,
|
||||
Display(Display* parentDisplay,
|
||||
const os::WindowRef& nativeWindow,
|
||||
Widget* containedWidget);
|
||||
|
||||
Display* parentDisplay() { return m_parentDisplay; }
|
||||
os::Window* nativeWindow() { return m_nativeWindow.get(); }
|
||||
os::Surface* surface() const;
|
||||
|
||||
@ -71,6 +73,7 @@ namespace ui {
|
||||
const std::vector<Window*>& getWindows() const { return m_windows; }
|
||||
|
||||
private:
|
||||
Display* m_parentDisplay;
|
||||
os::WindowRef m_nativeWindow;
|
||||
Widget* m_containedWidget; // A ui::Manager or a ui::Window
|
||||
std::vector<Window*> m_windows; // Sub-windows in this display
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite UI Library
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -90,7 +90,8 @@ bool IntEntry::onProcessMessage(Message* msg)
|
||||
case kMouseMoveMessage:
|
||||
if (hasCapture()) {
|
||||
MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
|
||||
Widget* pick = manager()->pick(mouseMsg->position());
|
||||
Widget* pick = manager()->pickFromScreenPos(
|
||||
display()->nativeWindow()->pointToScreen(mouseMsg->position()));
|
||||
if (pick == &m_slider) {
|
||||
releaseMouse();
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "os/surface.h"
|
||||
#include "os/system.h"
|
||||
#include "os/window.h"
|
||||
#include "os/window_spec.h"
|
||||
#include "ui/intern.h"
|
||||
#include "ui/ui.h"
|
||||
|
||||
@ -91,6 +92,16 @@ static base::concurrent_queue<Message*> concurrent_msg_queue;
|
||||
static Filters msg_filters[NFILTERS]; // Filters for every enqueued message
|
||||
static int filter_locks = 0;
|
||||
|
||||
// Current display with the mouse, used to avoid processing a
|
||||
// os::Event::MouseLeave of the non-current display/window as when we
|
||||
// move the mouse between two windows we can receive:
|
||||
//
|
||||
// 1. A os::Event::MouseEnter of the new window
|
||||
// 2. A os::Event::MouseLeave of the old window
|
||||
//
|
||||
// Instead of the MouseLeave event of the old window first.
|
||||
static Display* mouse_display = nullptr;
|
||||
|
||||
static Widget* focus_widget; // The widget with the focus
|
||||
static Widget* mouse_widget; // The widget with the mouse
|
||||
static Widget* capture_widget; // The widget that captures the mouse
|
||||
@ -164,7 +175,7 @@ bool Manager::widgetAssociatedToManager(Widget* widget)
|
||||
|
||||
Manager::Manager(const os::WindowRef& nativeWindow)
|
||||
: Widget(kManagerWidget)
|
||||
, m_display(nativeWindow, this)
|
||||
, m_display(nullptr, nativeWindow, this)
|
||||
, m_eventQueue(os::instance()->eventQueue())
|
||||
, m_lockedWindow(nullptr)
|
||||
, m_mouseButton(kButtonNone)
|
||||
@ -264,6 +275,13 @@ void Manager::flipAllDisplays()
|
||||
overlays->drawOverlays();
|
||||
|
||||
m_display.flipDisplay();
|
||||
if (get_multiple_displays()) {
|
||||
for (auto child : children()) {
|
||||
auto window = static_cast<Window*>(child);
|
||||
if (window->ownDisplay())
|
||||
window->display()->flipDisplay();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::updateAllDisplaysWithNewScale(int scale)
|
||||
@ -271,6 +289,17 @@ void Manager::updateAllDisplaysWithNewScale(int scale)
|
||||
os::Window* nativeWindow = m_display.nativeWindow();
|
||||
nativeWindow->setScale(scale);
|
||||
|
||||
if (get_multiple_displays()) {
|
||||
for (auto child : children()) {
|
||||
auto window = static_cast<Window*>(child);
|
||||
if (window->ownDisplay()) {
|
||||
Display* display = static_cast<Window*>(child)->display();
|
||||
display->nativeWindow()->setScale(scale);
|
||||
onNewDisplayConfiguration(display);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onNewDisplayConfiguration(&m_display);
|
||||
}
|
||||
|
||||
@ -403,7 +432,7 @@ void Manager::generateMessagesFromOSEvents()
|
||||
Message* msg = new Message(kResizeDisplayMessage);
|
||||
msg->setDisplay(display);
|
||||
msg->setRecipient(this);
|
||||
msg->setPropagateToChildren(true);
|
||||
msg->setPropagateToChildren(false);
|
||||
enqueueMessage(msg);
|
||||
break;
|
||||
}
|
||||
@ -438,26 +467,34 @@ void Manager::generateMessagesFromOSEvents()
|
||||
}
|
||||
|
||||
case os::Event::MouseEnter: {
|
||||
_internal_set_mouse_position(osEvent.position());
|
||||
if (get_multiple_displays()) {
|
||||
if (osEvent.window()) {
|
||||
ASSERT(display != nullptr);
|
||||
_internal_set_mouse_display(display);
|
||||
}
|
||||
}
|
||||
set_mouse_cursor(kArrowCursor);
|
||||
lastMouseMoveEvent = osEvent;
|
||||
mouse_display = display;
|
||||
break;
|
||||
}
|
||||
|
||||
case os::Event::MouseLeave: {
|
||||
set_mouse_cursor(kOutsideDisplay);
|
||||
setMouse(nullptr);
|
||||
if (mouse_display == display) {
|
||||
set_mouse_cursor(kOutsideDisplay);
|
||||
setMouse(nullptr);
|
||||
|
||||
_internal_no_mouse_position();
|
||||
_internal_no_mouse_position();
|
||||
mouse_display = nullptr;
|
||||
|
||||
// To avoid calling kSetCursorMessage when the mouse leaves
|
||||
// the window.
|
||||
lastMouseMoveEvent = os::Event();
|
||||
// To avoid calling kSetCursorMessage when the mouse leaves
|
||||
// the window.
|
||||
lastMouseMoveEvent = os::Event();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case os::Event::MouseMove: {
|
||||
_internal_set_mouse_position(osEvent.position());
|
||||
handleMouseMove(
|
||||
display,
|
||||
osEvent.position(),
|
||||
@ -510,8 +547,6 @@ void Manager::generateMessagesFromOSEvents()
|
||||
}
|
||||
|
||||
case os::Event::TouchMagnify: {
|
||||
_internal_set_mouse_position(osEvent.position());
|
||||
|
||||
handleTouchMagnify(display,
|
||||
osEvent.position(),
|
||||
osEvent.modifiers(),
|
||||
@ -549,7 +584,7 @@ void Manager::handleMouseMove(Display* display,
|
||||
const PointerType pointerType,
|
||||
const float pressure)
|
||||
{
|
||||
updateMouseWidgets(mousePos);
|
||||
updateMouseWidgets(mousePos, display);
|
||||
|
||||
// Send the mouse movement message
|
||||
Widget* dst = (capture_widget ? capture_widget: mouse_widget);
|
||||
@ -669,6 +704,8 @@ void Manager::handleWindowZOrder()
|
||||
if ((window) &&
|
||||
// We cannot change Z-order of desktop windows
|
||||
(!window->isDesktop()) &&
|
||||
// We cannot change window order of native windows (they are handled by the OS)
|
||||
(!window->ownDisplay()) &&
|
||||
// We cannot change Z order of foreground windows because a
|
||||
// foreground window can launch other background windows
|
||||
// which should be kept on top of the foreground one.
|
||||
@ -705,16 +742,44 @@ void Manager::handleWindowZOrder()
|
||||
setFocus(mouse_widget);
|
||||
}
|
||||
|
||||
void Manager::updateMouseWidgets(const gfx::Point& mousePos)
|
||||
// If display is nullptr, mousePos is in screen coordinates, if not,
|
||||
// it's relative to the display content rect.
|
||||
void Manager::updateMouseWidgets(const gfx::Point& mousePos,
|
||||
Display* display)
|
||||
{
|
||||
gfx::Point screenPos = (display ? display->nativeWindow()->pointToScreen(mousePos):
|
||||
mousePos);
|
||||
|
||||
// Get the list of widgets to send mouse messages.
|
||||
mouse_widgets_list.clear();
|
||||
broadcastMouseMessage(mouse_widgets_list);
|
||||
broadcastMouseMessage(screenPos,
|
||||
mouse_widgets_list);
|
||||
|
||||
// Get the widget under the mouse
|
||||
Widget* widget = nullptr;
|
||||
for (auto mouseWidget : mouse_widgets_list) {
|
||||
widget = mouseWidget->pick(mousePos);
|
||||
if (get_multiple_displays()) {
|
||||
gfx::Point displayPos;
|
||||
if (display) {
|
||||
if (display != mouseWidget->display()) {
|
||||
displayPos = mouseWidget->display()->nativeWindow()->pointFromScreen(screenPos);
|
||||
widget = mouseWidget->display()->containedWidget()->pick(displayPos);
|
||||
}
|
||||
else {
|
||||
widget = mouseWidget->pick(mousePos);
|
||||
}
|
||||
}
|
||||
else {
|
||||
displayPos = mouseWidget->display()->nativeWindow()->pointFromScreen(screenPos);
|
||||
widget = mouseWidget->display()->containedWidget()->pick(displayPos);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (display)
|
||||
widget = mouseWidget->pick(mousePos);
|
||||
else
|
||||
widget = mouseWidget->pickFromScreenPos(screenPos);
|
||||
}
|
||||
if (widget) {
|
||||
// Get the first ancestor of the picked widget that doesn't
|
||||
// ignore mouse events.
|
||||
@ -726,10 +791,12 @@ void Manager::updateMouseWidgets(const gfx::Point& mousePos)
|
||||
|
||||
// Fixup "mouse" flag
|
||||
if (widget != mouse_widget) {
|
||||
if (!widget)
|
||||
if (!widget) {
|
||||
freeMouse();
|
||||
else
|
||||
}
|
||||
else {
|
||||
setMouse(widget);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -793,6 +860,16 @@ Window* Manager::getForegroundWindow()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Display* Manager::getForegroundDisplay()
|
||||
{
|
||||
if (get_multiple_displays()) {
|
||||
Window* window = getForegroundWindow();
|
||||
if (window)
|
||||
return window->display();
|
||||
}
|
||||
return &m_display;
|
||||
}
|
||||
|
||||
Widget* Manager::getFocus()
|
||||
{
|
||||
return focus_widget;
|
||||
@ -885,11 +962,12 @@ void Manager::setMouse(Widget* widget)
|
||||
mouse_widget = widget;
|
||||
if (widget) {
|
||||
Display* display = mouse_widget->display();
|
||||
gfx::Point mousePos = display->nativeWindow()->pointFromScreen(get_mouse_position());
|
||||
|
||||
auto msg = newMouseMessage(
|
||||
kMouseEnterMessage,
|
||||
display, nullptr,
|
||||
get_mouse_position(),
|
||||
mousePos,
|
||||
PointerType::Unknown,
|
||||
m_mouseButton,
|
||||
kKeyUninitializedModifier);
|
||||
@ -899,7 +977,7 @@ void Manager::setMouse(Widget* widget)
|
||||
msg->setCommonAncestor(commonAncestor);
|
||||
enqueueMessage(msg);
|
||||
generateSetCursorMessage(display,
|
||||
get_mouse_position(),
|
||||
mousePos,
|
||||
kKeyUninitializedModifier,
|
||||
PointerType::Unknown);
|
||||
|
||||
@ -1050,6 +1128,24 @@ void Manager::removeMessagesForTimer(Timer* timer)
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::removePaintMessagesForDisplay(Display* display)
|
||||
{
|
||||
#ifdef DEBUG_UI_THREADS
|
||||
ASSERT(manager_thread == base::this_thread::native_id());
|
||||
#endif
|
||||
|
||||
for (auto it=msg_queue.begin(); it != msg_queue.end(); ) {
|
||||
Message* msg = *it;
|
||||
if (msg->type() == kPaintMessage &&
|
||||
static_cast<PaintMessage*>(msg)->display() == display) {
|
||||
delete msg;
|
||||
it = msg_queue.erase(it);
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::addMessageFilter(int message, Widget* widget)
|
||||
{
|
||||
#ifdef DEBUG_UI_THREADS
|
||||
@ -1116,12 +1212,37 @@ bool Manager::isFocusMovementMessage(Message* msg)
|
||||
|
||||
Widget* Manager::pickFromScreenPos(const gfx::Point& screenPos) const
|
||||
{
|
||||
return pick(gfx::Point(screenPos) - display()->nativeWindow()->contentRect().origin());
|
||||
Display* mainDisplay = display();
|
||||
|
||||
if (get_multiple_displays()) {
|
||||
for (auto child : children()) {
|
||||
auto window = static_cast<Window*>(child);
|
||||
if (window->ownDisplay() ||
|
||||
window->display() != mainDisplay) {
|
||||
os::Window* nativeWindow = window->display()->nativeWindow();
|
||||
if (nativeWindow->frame().contains(screenPos))
|
||||
return window->pick(nativeWindow->pointFromScreen(screenPos));
|
||||
}
|
||||
}
|
||||
|
||||
gfx::Point displayPos = display()->nativeWindow()->pointFromScreen(screenPos);
|
||||
for (auto child : children()) {
|
||||
auto window = static_cast<Window*>(child);
|
||||
if (window->display() == mainDisplay) {
|
||||
if (auto picked = window->pick(displayPos))
|
||||
return picked;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Widget::pickFromScreenPos(screenPos);
|
||||
}
|
||||
|
||||
// Configures the window for begin the loop
|
||||
void Manager::_openWindow(Window* window)
|
||||
void Manager::_openWindow(Window* window, bool center)
|
||||
{
|
||||
Display* parentDisplay = getForegroundDisplay();
|
||||
ASSERT(parentDisplay);
|
||||
|
||||
// Free all widgets of special states.
|
||||
if (window->isWantFocus()) {
|
||||
freeCapture();
|
||||
@ -1139,10 +1260,79 @@ void Manager::_openWindow(Window* window)
|
||||
}
|
||||
|
||||
// Relayout
|
||||
window->layout();
|
||||
if (center)
|
||||
window->centerWindow();
|
||||
else
|
||||
window->layout();
|
||||
|
||||
// Same display as the manager.
|
||||
window->setDisplay(this->display());
|
||||
// If the window already was set a display, we don't setup it
|
||||
// (i.e. in the case of combobox popup/window the display field is
|
||||
// set to the same display where the ComboBox widget is located)
|
||||
if (window->display() == &m_display) {
|
||||
// In other case, we can try to create a display/native window for
|
||||
// the UI window.
|
||||
if (get_multiple_displays()
|
||||
&& !window->isDesktop()
|
||||
#if 1 // TODO Add support for menuboxes and tooltips with native windows
|
||||
&& window->isSizeable()
|
||||
#endif
|
||||
) {
|
||||
const int scale = parentDisplay->nativeWindow()->scale();
|
||||
|
||||
os::WindowSpec spec;
|
||||
gfx::Rect frame;
|
||||
if (!window->lastNativeFrame().isEmpty()) {
|
||||
frame = window->lastNativeFrame();
|
||||
}
|
||||
else {
|
||||
gfx::Rect relativeToFrame = parentDisplay->nativeWindow()->contentRect();
|
||||
frame = window->bounds();
|
||||
frame *= scale;
|
||||
frame.offset(relativeToFrame.origin());
|
||||
}
|
||||
spec.position(os::WindowSpec::Position::Frame);
|
||||
spec.frame(frame);
|
||||
spec.scale(scale);
|
||||
// Only desktop will have the real native window title bar
|
||||
// TODO in the future other windows could use the native title bar
|
||||
// when there are no special decorators (or we could just add
|
||||
// the possibility to create new buttons in the native window
|
||||
// title bar)
|
||||
spec.titled(window->isDesktop());
|
||||
spec.floating(!window->isDesktop());
|
||||
spec.resizable(window->isDesktop() || window->isSizeable());
|
||||
spec.maximizable(spec.resizable());
|
||||
spec.minimizable(window->isDesktop());
|
||||
spec.borderless(!window->isDesktop());
|
||||
|
||||
if (!window->isDesktop()) {
|
||||
spec.parent(parentDisplay->nativeWindow());
|
||||
}
|
||||
|
||||
os::WindowRef newNativeWindow = os::instance()->makeWindow(spec);
|
||||
ui::Display* newDisplay = new ui::Display(parentDisplay, newNativeWindow, window);
|
||||
|
||||
newNativeWindow->setUserData(newDisplay);
|
||||
window->setDisplay(newDisplay, true);
|
||||
|
||||
// Set native title bar text
|
||||
newNativeWindow->setTitle(window->text());
|
||||
|
||||
// Activate only non-floating windows
|
||||
if (!spec.floating())
|
||||
newNativeWindow->activate();
|
||||
else
|
||||
m_display.nativeWindow()->activate();
|
||||
|
||||
// Move all widgets to the os::Display origin (0,0)
|
||||
window->offsetWidgets(-window->origin().x, -window->origin().y);
|
||||
}
|
||||
else {
|
||||
// Same display for desktop window or when multiple displays is
|
||||
// disabled.
|
||||
window->setDisplay(this->display(), false);
|
||||
}
|
||||
}
|
||||
|
||||
// Dirty the entire window and show it
|
||||
window->setVisible(true);
|
||||
@ -1160,19 +1350,51 @@ void Manager::_openWindow(Window* window)
|
||||
|
||||
// Update mouse widget (as it can be a widget below the
|
||||
// recently opened window).
|
||||
updateMouseWidgets(ui::get_mouse_position());
|
||||
updateMouseWidgets(ui::get_mouse_position(), nullptr);
|
||||
}
|
||||
|
||||
void Manager::_closeWindow(Window* window, bool redraw_background)
|
||||
{
|
||||
window->setDisplay(nullptr);
|
||||
Display* windowDisplay = window->display();
|
||||
Display* parentDisplay;
|
||||
|
||||
if (// The display can be nullptr if the window was not opened or
|
||||
// was closed before.
|
||||
window->ownDisplay()) {
|
||||
parentDisplay = windowDisplay->parentDisplay();
|
||||
ASSERT(parentDisplay);
|
||||
ASSERT(windowDisplay);
|
||||
ASSERT(windowDisplay != this->display());
|
||||
|
||||
// Remove all paint messages for this display.
|
||||
removePaintMessagesForDisplay(windowDisplay);
|
||||
|
||||
window->setDisplay(nullptr, false);
|
||||
windowDisplay->nativeWindow()->setUserData<void*>(nullptr);
|
||||
|
||||
// Remove the mouse cursor from the display that we are going to
|
||||
// delete.
|
||||
_internal_set_mouse_display(parentDisplay);
|
||||
|
||||
// The ui::Display should destroy the os::Window
|
||||
delete windowDisplay;
|
||||
|
||||
// Activate main windows
|
||||
parentDisplay->nativeWindow()->activate();
|
||||
}
|
||||
else {
|
||||
parentDisplay = windowDisplay;
|
||||
window->setDisplay(nullptr, false);
|
||||
}
|
||||
|
||||
if (!hasChild(window))
|
||||
return;
|
||||
|
||||
gfx::Region reg1;
|
||||
if (redraw_background)
|
||||
window->getRegion(reg1);
|
||||
if (!window->ownDisplay()) {
|
||||
if (redraw_background)
|
||||
window->getRegion(reg1);
|
||||
}
|
||||
|
||||
// Close all windows to this desktop
|
||||
if (window->isDesktop()) {
|
||||
@ -1183,7 +1405,7 @@ void Manager::_closeWindow(Window* window, bool redraw_background)
|
||||
else {
|
||||
gfx::Region reg2;
|
||||
window->getRegion(reg2);
|
||||
reg1.createUnion(reg1, reg2);
|
||||
reg1 |= reg2;
|
||||
|
||||
_closeWindow(child, false);
|
||||
}
|
||||
@ -1213,15 +1435,22 @@ void Manager::_closeWindow(Window* window, bool redraw_background)
|
||||
removeChild(window);
|
||||
|
||||
// Redraw background.
|
||||
invalidateRegion(reg1);
|
||||
parentDisplay->containedWidget()->invalidateRegion(reg1);
|
||||
|
||||
// Update mouse widget (as it can be a widget below the
|
||||
// recently closed window).
|
||||
updateMouseWidgets(ui::get_mouse_position());
|
||||
updateMouseWidgets(ui::get_mouse_position(), nullptr);
|
||||
|
||||
redrawState = RedrawState::AWindowHasJustBeenClosed;
|
||||
}
|
||||
|
||||
void Manager::_runModalWindow(Window* window)
|
||||
{
|
||||
MessageLoop loop(manager());
|
||||
while (!window->hasFlags(HIDDEN))
|
||||
loop.pumpMessages();
|
||||
}
|
||||
|
||||
bool Manager::onProcessMessage(Message* msg)
|
||||
{
|
||||
switch (msg->type()) {
|
||||
@ -1234,6 +1463,15 @@ bool Manager::onProcessMessage(Message* msg)
|
||||
// finally closed.)
|
||||
return true;
|
||||
|
||||
case kCloseDisplayMessage: {
|
||||
if (msg->display() != &m_display) {
|
||||
if (Window* window = dynamic_cast<Window*>(msg->display()->containedWidget())) {
|
||||
window->closeWindow(this);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case kResizeDisplayMessage:
|
||||
onNewDisplayConfiguration(msg->display());
|
||||
break;
|
||||
@ -1291,6 +1529,9 @@ void Manager::onResize(ResizeEvent& ev)
|
||||
|
||||
for (auto child : children()) {
|
||||
Window* window = static_cast<Window*>(child);
|
||||
if (window->ownDisplay())
|
||||
continue;
|
||||
|
||||
if (window->isDesktop()) {
|
||||
window->setBounds(new_pos);
|
||||
break;
|
||||
@ -1329,13 +1570,14 @@ void Manager::onResize(ResizeEvent& ev)
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::onBroadcastMouseMessage(WidgetsList& targets)
|
||||
void Manager::onBroadcastMouseMessage(const gfx::Point& screenPos,
|
||||
WidgetsList& targets)
|
||||
{
|
||||
// Ask to the first window in the "children" list to know how to
|
||||
// propagate mouse messages.
|
||||
Widget* widget = UI_FIRST_WIDGET(children());
|
||||
if (widget)
|
||||
widget->broadcastMouseMessage(targets);
|
||||
widget->broadcastMouseMessage(screenPos, targets);
|
||||
}
|
||||
|
||||
void Manager::onInitTheme(InitThemeEvent& ev)
|
||||
@ -1382,7 +1624,7 @@ void Manager::onNewDisplayConfiguration(Display* display)
|
||||
|
||||
_internal_set_mouse_display(display);
|
||||
container->invalidate();
|
||||
flushRedraw();
|
||||
container->flushRedraw();
|
||||
}
|
||||
|
||||
void Manager::onSizeHint(SizeHintEvent& ev)
|
||||
@ -1576,15 +1818,13 @@ bool Manager::sendMessageToWidget(Message* msg, Widget* widget)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (surface) {
|
||||
// Call the message handler
|
||||
used = widget->sendMessage(msg);
|
||||
|
||||
// Restore clip region for paint messages.
|
||||
surface->restoreClip();
|
||||
}
|
||||
// Call the message handler
|
||||
used = widget->sendMessage(msg);
|
||||
}
|
||||
|
||||
// Restore clip region for paint messages.
|
||||
surface->restoreClip();
|
||||
|
||||
// As this kPaintMessage's rectangle was updated, we can
|
||||
// remove it from "m_invalidRegion".
|
||||
paintMsg->display()->subtractInvalidRegion(gfx::Region(paintMsg->rect()));
|
||||
@ -1600,6 +1840,8 @@ bool Manager::sendMessageToWidget(Message* msg, Widget* widget)
|
||||
// It's like Widget::onInvalidateRegion() but optimized for the
|
||||
// Manager (as we know that all children in a Manager will be windows,
|
||||
// we can use this knowledge to avoid some calculations).
|
||||
//
|
||||
// TODO similar to Window::onInvalidateRegion
|
||||
void Manager::onInvalidateRegion(const gfx::Region& region)
|
||||
{
|
||||
if (!isVisible() || region.contains(bounds()) == gfx::Region::Out)
|
||||
@ -1619,6 +1861,11 @@ void Manager::onInvalidateRegion(const gfx::Region& region)
|
||||
ASSERT(child->type() == kWindowWidget);
|
||||
Window* window = static_cast<Window*>(child);
|
||||
|
||||
// Invalidating the manager only works for the main display, to
|
||||
// invalidate windows you have to invalidate them.
|
||||
if (window->ownDisplay())
|
||||
continue;
|
||||
|
||||
// Invalidate regions of this window
|
||||
window->invalidateRegion(reg1);
|
||||
|
||||
|
@ -62,6 +62,7 @@ namespace ui {
|
||||
|
||||
Window* getTopWindow();
|
||||
Window* getForegroundWindow();
|
||||
Display* getForegroundDisplay();
|
||||
|
||||
Widget* getFocus();
|
||||
Widget* getMouse();
|
||||
@ -79,6 +80,7 @@ namespace ui {
|
||||
void removeMessagesFor(Widget* widget);
|
||||
void removeMessagesFor(Widget* widget, MessageType type);
|
||||
void removeMessagesForTimer(Timer* timer);
|
||||
void removePaintMessagesForDisplay(Display* display);
|
||||
|
||||
void addMessageFilter(int message, Widget* widget);
|
||||
void removeMessageFilter(int message, Widget* widget);
|
||||
@ -89,17 +91,19 @@ namespace ui {
|
||||
bool isFocusMovementMessage(Message* msg);
|
||||
bool processFocusMovementMessage(Message* msg);
|
||||
|
||||
Widget* pickFromScreenPos(const gfx::Point& screenPos) const;
|
||||
Widget* pickFromScreenPos(const gfx::Point& screenPos) const override;
|
||||
|
||||
void _openWindow(Window* window);
|
||||
void _openWindow(Window* window, bool center);
|
||||
void _closeWindow(Window* window, bool redraw_background);
|
||||
void _runModalWindow(Window* window);
|
||||
|
||||
protected:
|
||||
bool onProcessMessage(Message* msg) override;
|
||||
void onInvalidateRegion(const gfx::Region& region) override;
|
||||
void onResize(ResizeEvent& ev) override;
|
||||
void onSizeHint(SizeHintEvent& ev) override;
|
||||
void onBroadcastMouseMessage(WidgetsList& targets) override;
|
||||
void onBroadcastMouseMessage(const gfx::Point& screenPos,
|
||||
WidgetsList& targets) override;
|
||||
void onInitTheme(InitThemeEvent& ev) override;
|
||||
virtual LayoutIO* onGetLayoutIO();
|
||||
virtual void onNewDisplayConfiguration(Display* display);
|
||||
@ -142,7 +146,8 @@ namespace ui {
|
||||
const KeyModifiers modifiers,
|
||||
const double magnification);
|
||||
void handleWindowZOrder();
|
||||
void updateMouseWidgets(const gfx::Point& mousePos);
|
||||
void updateMouseWidgets(const gfx::Point& mousePos,
|
||||
Display* display);
|
||||
|
||||
int pumpQueue();
|
||||
bool sendMessageToWidget(Message* msg, Widget* widget);
|
||||
|
@ -454,7 +454,8 @@ bool MenuBox::onProcessMessage(Message* msg)
|
||||
// popuped menu-box) to detect if the user press outside of
|
||||
// the widget
|
||||
if (msg->type() == kMouseDownMessage && m_base != nullptr) {
|
||||
Widget* picked = manager()->pick(mousePos);
|
||||
Widget* picked = manager()->pickFromScreenPos(
|
||||
display()->nativeWindow()->pointToScreen(mousePos));
|
||||
|
||||
// If one of these conditions are accomplished we have to
|
||||
// close all menus (back to menu-bar or close the popuped
|
||||
|
@ -35,6 +35,9 @@ namespace ui {
|
||||
// thread. (Which might be catastrofic.)
|
||||
base::thread::native_id_type main_gui_thread;
|
||||
|
||||
// Multiple displays (create one os::Window for each ui::Window)
|
||||
bool multi_displays = false;
|
||||
|
||||
// Current mouse cursor type.
|
||||
static CursorType mouse_cursor_type = kOutsideDisplay;
|
||||
static const Cursor* mouse_cursor_custom = nullptr;
|
||||
@ -44,10 +47,8 @@ static OverlayRef mouse_cursor_overlay = nullptr;
|
||||
static bool use_native_mouse_cursor = true;
|
||||
static bool support_native_custom_cursor = false;
|
||||
|
||||
// Mouse information (button and position).
|
||||
static gfx::Point m_mouse_pos;
|
||||
// Mouse information
|
||||
static int mouse_cursor_scale = 1;
|
||||
|
||||
static int mouse_scares = 0;
|
||||
|
||||
static void update_mouse_overlay(const Cursor* cursor)
|
||||
@ -60,7 +61,7 @@ static void update_mouse_overlay(const Cursor* cursor)
|
||||
mouse_cursor_overlay = base::make_ref<Overlay>(
|
||||
mouse_display,
|
||||
mouse_cursor->getSurface(),
|
||||
get_mouse_position(),
|
||||
mouse_display->nativeWindow()->pointFromScreen(get_mouse_position()),
|
||||
Overlay::MouseZOrder);
|
||||
|
||||
OverlayManager::instance()->addOverlay(mouse_cursor_overlay);
|
||||
@ -77,17 +78,14 @@ static void update_mouse_overlay(const Cursor* cursor)
|
||||
}
|
||||
}
|
||||
|
||||
static bool update_custom_native_cursor(const Cursor* cursor)
|
||||
static bool set_native_cursor_on_all_displays(Display* display,
|
||||
const Cursor* cursor)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
// Check if we can use a custom native mouse in this platform
|
||||
if (support_native_custom_cursor &&
|
||||
mouse_display) {
|
||||
os::Window* nativeWindow = mouse_display->nativeWindow();
|
||||
|
||||
while (display) {
|
||||
os::Window* nativeWindow = display->nativeWindow();
|
||||
if (cursor) {
|
||||
result = nativeWindow->setNativeMouseCursor(
|
||||
result |= nativeWindow->setNativeMouseCursor(
|
||||
// The surface is already scaled by guiscale()
|
||||
cursor->getSurface().get(),
|
||||
cursor->getFocus(),
|
||||
@ -95,11 +93,41 @@ static bool update_custom_native_cursor(const Cursor* cursor)
|
||||
nativeWindow->scale() * mouse_cursor_scale);
|
||||
}
|
||||
else if (mouse_cursor_type == kOutsideDisplay) {
|
||||
result = nativeWindow->setNativeMouseCursor(os::NativeCursor::Arrow);
|
||||
result |= nativeWindow->setNativeMouseCursor(os::NativeCursor::Arrow);
|
||||
}
|
||||
else {
|
||||
result = nativeWindow->setNativeMouseCursor(os::NativeCursor::Hidden);
|
||||
result |= nativeWindow->setNativeMouseCursor(os::NativeCursor::Hidden);
|
||||
}
|
||||
display = display->parentDisplay();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool set_native_cursor_on_all_displays(Display* display,
|
||||
const os::NativeCursor cursor)
|
||||
{
|
||||
bool result = false;
|
||||
while (display) {
|
||||
os::Window* nativeWindow = display->nativeWindow();
|
||||
if (mouse_cursor_type == kOutsideDisplay) {
|
||||
result |= nativeWindow->setNativeMouseCursor(os::NativeCursor::Arrow);
|
||||
}
|
||||
else {
|
||||
result |= nativeWindow->setNativeMouseCursor(cursor);
|
||||
}
|
||||
display = display->parentDisplay();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool update_custom_native_cursor(const Cursor* cursor)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
// Check if we can use a custom native mouse in this platform
|
||||
if (support_native_custom_cursor &&
|
||||
mouse_display) {
|
||||
result = set_native_cursor_on_all_displays(mouse_display, cursor);
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -149,7 +177,7 @@ static void update_mouse_cursor()
|
||||
|
||||
// Set native cursor
|
||||
if (mouse_display) {
|
||||
bool ok = mouse_display->nativeWindow()->setNativeMouseCursor(nativeCursor);
|
||||
bool ok = set_native_cursor_on_all_displays(mouse_display, nativeCursor);
|
||||
|
||||
// It looks like the specific native cursor is not supported,
|
||||
// so we can should use the internal overlay (even when we
|
||||
@ -227,15 +255,26 @@ void _internal_set_mouse_display(Display* display)
|
||||
set_mouse_cursor(cursor); // Restore mouse cursor
|
||||
}
|
||||
|
||||
void _internal_free_mouse_display(Display* display)
|
||||
void set_multiple_displays(bool multi)
|
||||
{
|
||||
if (mouse_display == display)
|
||||
_internal_set_mouse_display(nullptr);
|
||||
multi_displays = multi;
|
||||
}
|
||||
|
||||
bool get_multiple_displays()
|
||||
{
|
||||
return multi_displays;
|
||||
}
|
||||
|
||||
gfx::Size get_desktop_size()
|
||||
{
|
||||
return Manager::getDefault()->display()->size();
|
||||
if (get_multiple_displays()) {
|
||||
return
|
||||
os::instance()->mainScreen()->workarea().size() /
|
||||
Manager::getDefault()->display()->nativeWindow()->scale();
|
||||
}
|
||||
else {
|
||||
return Manager::getDefault()->display()->size();
|
||||
}
|
||||
}
|
||||
|
||||
void set_clipboard_text(const std::string& text)
|
||||
@ -260,7 +299,8 @@ void update_cursor_overlay()
|
||||
{
|
||||
if (mouse_cursor_overlay != nullptr && mouse_scares == 0) {
|
||||
gfx::Point newPos =
|
||||
get_mouse_position() - mouse_cursor->getFocus();
|
||||
mouse_display->nativeWindow()->pointFromScreen(get_mouse_position())
|
||||
- mouse_cursor->getFocus();
|
||||
|
||||
if (newPos != mouse_cursor_overlay->position()) {
|
||||
mouse_cursor_overlay->moveOverlay(newPos);
|
||||
@ -317,22 +357,21 @@ void _internal_no_mouse_position()
|
||||
update_mouse_overlay(nullptr);
|
||||
}
|
||||
|
||||
void _internal_set_mouse_position(const gfx::Point& newPos)
|
||||
gfx::Point get_mouse_position()
|
||||
{
|
||||
m_mouse_pos = newPos;
|
||||
return os::instance()->mousePosition();
|
||||
}
|
||||
|
||||
const gfx::Point& get_mouse_position()
|
||||
void set_mouse_position(const gfx::Point& newPos,
|
||||
Display* display)
|
||||
{
|
||||
return m_mouse_pos;
|
||||
}
|
||||
if (display && display != mouse_display)
|
||||
_internal_set_mouse_display(display);
|
||||
|
||||
void set_mouse_position(const gfx::Point& newPos)
|
||||
{
|
||||
if (mouse_display)
|
||||
mouse_display->nativeWindow()->setMousePosition(newPos);
|
||||
|
||||
_internal_set_mouse_position(newPos);
|
||||
if (display)
|
||||
display->nativeWindow()->setMousePosition(newPos);
|
||||
else
|
||||
os::instance()->setMousePosition(newPos);
|
||||
}
|
||||
|
||||
void execute_from_ui_thread(std::function<void()>&& func)
|
||||
|
@ -40,6 +40,8 @@ namespace ui {
|
||||
ClipboardDelegate* m_clipboardDelegate;
|
||||
};
|
||||
|
||||
void set_multiple_displays(bool multi);
|
||||
bool get_multiple_displays();
|
||||
gfx::Size get_desktop_size();
|
||||
|
||||
void set_clipboard_text(const std::string& text);
|
||||
@ -60,12 +62,15 @@ namespace ui {
|
||||
void show_mouse_cursor();
|
||||
|
||||
void _internal_set_mouse_display(Display* display);
|
||||
void _internal_free_mouse_display(Display* display);
|
||||
void _internal_no_mouse_position();
|
||||
void _internal_set_mouse_position(const gfx::Point& newPos);
|
||||
|
||||
const gfx::Point& get_mouse_position();
|
||||
void set_mouse_position(const gfx::Point& newPos);
|
||||
// Returns desktop/screen mouse position (relative to no-display)
|
||||
gfx::Point get_mouse_position();
|
||||
|
||||
// Sets the mouse position relative to a specific display (or
|
||||
// relative to the desktop if it's nullptr)
|
||||
void set_mouse_position(const gfx::Point& newPos,
|
||||
Display* display);
|
||||
|
||||
void execute_from_ui_thread(std::function<void()>&& func);
|
||||
bool is_ui_thread();
|
||||
|
@ -120,13 +120,13 @@ void TooltipManager::onTick()
|
||||
int arrowAlign = m_target.tipInfo.arrowAlign;
|
||||
gfx::Rect target = m_target.widget->bounds();
|
||||
if (!arrowAlign)
|
||||
target.setOrigin(ui::get_mouse_position()+12*guiscale());
|
||||
target.setOrigin(m_target.widget->mousePosInDisplay()+12*guiscale());
|
||||
|
||||
if (m_tipWindow->pointAt(arrowAlign,
|
||||
target,
|
||||
m_target.widget->display())) {
|
||||
// TODO create a native transparent window for the tooltip
|
||||
m_tipWindow->setDisplay(m_target.widget->display());
|
||||
m_tipWindow->setDisplay(m_target.widget->display(), false);
|
||||
m_tipWindow->openWindow();
|
||||
}
|
||||
else {
|
||||
|
@ -499,6 +499,11 @@ Widget* Widget::pick(const gfx::Point& pt,
|
||||
return const_cast<Widget*>(picked);
|
||||
}
|
||||
|
||||
Widget* Widget::pickFromScreenPos(const gfx::Point& screenPos) const
|
||||
{
|
||||
return pick(display()->nativeWindow()->pointFromScreen(screenPos));
|
||||
}
|
||||
|
||||
bool Widget::hasChild(Widget* child)
|
||||
{
|
||||
ASSERT_VALID_WIDGET(child);
|
||||
@ -762,13 +767,13 @@ void Widget::getRegion(gfx::Region& region)
|
||||
|
||||
void Widget::getDrawableRegion(gfx::Region& region, DrawableRegionFlags flags)
|
||||
{
|
||||
Window* window = this->window();
|
||||
Display* display = this->display();
|
||||
|
||||
getRegion(region);
|
||||
|
||||
// Cut the top windows areas
|
||||
if (flags & kCutTopWindows) {
|
||||
Window* window = this->window();
|
||||
Display* display = this->display();
|
||||
|
||||
const auto& uiWindows = display->getWindows();
|
||||
|
||||
// Reverse iterator
|
||||
@ -815,7 +820,7 @@ void Widget::getDrawableRegion(gfx::Region& region, DrawableRegionFlags flags)
|
||||
// Intersect with the parent area
|
||||
if (!hasFlags(DECORATIVE)) {
|
||||
Widget* p = this->parent();
|
||||
while (p) {
|
||||
while (p && p->type() != kManagerWidget) {
|
||||
region &= Region(p->childrenBounds());
|
||||
p = p->parent();
|
||||
}
|
||||
@ -827,25 +832,15 @@ void Widget::getDrawableRegion(gfx::Region& region, DrawableRegionFlags flags)
|
||||
}
|
||||
}
|
||||
|
||||
// Limit to the manager area
|
||||
{
|
||||
Window* window = this->window();
|
||||
Manager* manager = (window ? window->manager(): nullptr);
|
||||
while (manager) {
|
||||
View* view = View::getView(manager);
|
||||
// Limit to the displayable area
|
||||
View* view = View::getView(display->containedWidget());
|
||||
Rect cpos;
|
||||
if (view)
|
||||
cpos = static_cast<View*>(view)->viewportBounds();
|
||||
else
|
||||
cpos = display->containedWidget()->bounds();
|
||||
|
||||
Rect cpos;
|
||||
if (view)
|
||||
cpos = static_cast<View*>(view)->viewportBounds();
|
||||
else
|
||||
cpos = manager->childrenBounds();
|
||||
|
||||
region &= Region(cpos);
|
||||
|
||||
window = manager->window();
|
||||
manager = (window ? window->manager(): nullptr);
|
||||
}
|
||||
}
|
||||
region &= Region(cpos);
|
||||
}
|
||||
|
||||
int Widget::textWidth() const
|
||||
@ -982,7 +977,6 @@ void Widget::flushRedraw()
|
||||
processing.push(this);
|
||||
}
|
||||
|
||||
Display* display = this->display();
|
||||
Manager* manager = this->manager();
|
||||
ASSERT(manager);
|
||||
if (!manager)
|
||||
@ -1017,6 +1011,7 @@ void Widget::flushRedraw()
|
||||
Region::const_iterator it = widget->m_updateRegion.begin();
|
||||
|
||||
// Draw the widget
|
||||
Display* display = widget->display();
|
||||
int count = nrects-1;
|
||||
for (c=0; c<nrects; ++c, ++it, --count) {
|
||||
// Create the draw message
|
||||
@ -1094,23 +1089,28 @@ bool Widget::paintEvent(Graphics* graphics,
|
||||
|
||||
enableFlags(HIDDEN);
|
||||
|
||||
if (parent()) {
|
||||
if (parent()->display() == display()) {
|
||||
gfx::Region rgn(parent()->bounds());
|
||||
rgn &= gfx::Region(
|
||||
graphics->getClipBounds().offset(
|
||||
graphics->getInternalDeltaX(),
|
||||
graphics->getInternalDeltaY()));
|
||||
parent()->paint(graphics, rgn, true);
|
||||
}
|
||||
else {
|
||||
// TODO clear surface with transparent color, the following
|
||||
// line doesn't work because we have to specify the
|
||||
// SkBlendMode::kSrc mode instead of
|
||||
// SkBlendMode::kSrcOver
|
||||
Widget* parentWidget;
|
||||
if (type() == kWindowWidget) {
|
||||
parentWidget = display()->containedWidget();
|
||||
}
|
||||
else {
|
||||
parentWidget = parent();
|
||||
}
|
||||
if (parentWidget) {
|
||||
gfx::Region rgn(parentWidget->bounds());
|
||||
rgn &= gfx::Region(
|
||||
graphics->getClipBounds().offset(
|
||||
graphics->getInternalDeltaX(),
|
||||
graphics->getInternalDeltaY()));
|
||||
parentWidget->paint(graphics, rgn, true);
|
||||
}
|
||||
else {
|
||||
// TODO clear surface with transparent color, the following
|
||||
// line doesn't work because we have to specify the
|
||||
// SkBlendMode::kSrc mode instead of
|
||||
// SkBlendMode::kSrcOver
|
||||
|
||||
//graphics->fillRect(gfx::rgba(0, 0, 0, 0), clientBounds());
|
||||
}
|
||||
//graphics->fillRect(gfx::rgba(0, 0, 0, 0), clientBounds());
|
||||
}
|
||||
|
||||
disableFlags(HIDDEN);
|
||||
@ -1231,9 +1231,10 @@ void Widget::closeWindow()
|
||||
w->closeWindow(this);
|
||||
}
|
||||
|
||||
void Widget::broadcastMouseMessage(WidgetsList& targets)
|
||||
void Widget::broadcastMouseMessage(const gfx::Point& screenPos,
|
||||
WidgetsList& targets)
|
||||
{
|
||||
onBroadcastMouseMessage(targets);
|
||||
onBroadcastMouseMessage(screenPos, targets);
|
||||
}
|
||||
|
||||
// ===============================================================
|
||||
@ -1384,7 +1385,12 @@ bool Widget::offerCapture(ui::MouseMessage* mouseMsg, int widget_type)
|
||||
|
||||
bool Widget::hasMouseOver() const
|
||||
{
|
||||
return (this == pick(get_mouse_position()));
|
||||
return (this == pickFromScreenPos(get_mouse_position()));
|
||||
}
|
||||
|
||||
gfx::Point Widget::mousePosInDisplay() const
|
||||
{
|
||||
return display()->nativeWindow()->pointFromScreen(get_mouse_position());
|
||||
}
|
||||
|
||||
void Widget::setMnemonic(int mnemonic)
|
||||
@ -1566,7 +1572,8 @@ void Widget::onPaint(PaintEvent& ev)
|
||||
clientBounds());
|
||||
}
|
||||
|
||||
void Widget::onBroadcastMouseMessage(WidgetsList& targets)
|
||||
void Widget::onBroadcastMouseMessage(const gfx::Point& screenPos,
|
||||
WidgetsList& targets)
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
@ -185,6 +185,8 @@ namespace ui {
|
||||
|
||||
Widget* pick(const gfx::Point& pt,
|
||||
const bool checkParentsVisibility = true) const;
|
||||
virtual Widget* pickFromScreenPos(const gfx::Point& screenPos) const;
|
||||
|
||||
bool hasChild(Widget* child);
|
||||
bool hasAncestor(Widget* ancestor);
|
||||
Widget* findChild(const char* id);
|
||||
@ -318,7 +320,8 @@ namespace ui {
|
||||
bool sendMessage(Message* msg);
|
||||
void closeWindow();
|
||||
|
||||
void broadcastMouseMessage(WidgetsList& targets);
|
||||
void broadcastMouseMessage(const gfx::Point& screenPos,
|
||||
WidgetsList& targets);
|
||||
|
||||
// ===============================================================
|
||||
// SIZE & POSITION
|
||||
@ -342,8 +345,20 @@ namespace ui {
|
||||
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.
|
||||
bool hasMouseOver() const;
|
||||
|
||||
// Returns the mouse position relative to the top-left corner of
|
||||
// the ui::Display's client area/content rect.
|
||||
gfx::Point mousePosInDisplay() const;
|
||||
|
||||
// Returns the mouse position relative to the top-left cornder of
|
||||
// the widget bounds.
|
||||
gfx::Point mousePosInClientBounds() const {
|
||||
return toClient(mousePosInDisplay());
|
||||
}
|
||||
|
||||
// Offer the capture to widgets of the given type. Returns true if
|
||||
// the capture was passed to other widget.
|
||||
bool offerCapture(ui::MouseMessage* mouseMsg, int widget_type);
|
||||
@ -380,7 +395,8 @@ namespace ui {
|
||||
virtual void onSaveLayout(SaveLayoutEvent& ev);
|
||||
virtual void onResize(ResizeEvent& ev);
|
||||
virtual void onPaint(PaintEvent& ev);
|
||||
virtual void onBroadcastMouseMessage(WidgetsList& targets);
|
||||
virtual void onBroadcastMouseMessage(const gfx::Point& screenPos,
|
||||
WidgetsList& targets);
|
||||
virtual void onInitTheme(InitThemeEvent& ev);
|
||||
virtual void onSetDecorativeWidgetBounds();
|
||||
virtual void onVisible(bool visible);
|
||||
|
@ -112,6 +112,7 @@ Window::Window(Type type, const std::string& text)
|
||||
, m_closer(nullptr)
|
||||
, m_titleLabel(nullptr)
|
||||
, m_closeButton(nullptr)
|
||||
, m_ownDisplay(false)
|
||||
, m_isDesktop(type == DesktopWindow)
|
||||
, m_isMoveable(!m_isDesktop)
|
||||
, m_isSizeable(!m_isDesktop)
|
||||
@ -145,12 +146,16 @@ Display* Window::display() const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Window::setDisplay(Display* display)
|
||||
void Window::setDisplay(Display* display, const bool own)
|
||||
{
|
||||
if (m_display)
|
||||
if (m_display) {
|
||||
if (m_ownDisplay)
|
||||
m_lastFrame = m_display->nativeWindow()->frame();
|
||||
m_display->removeWindow(this);
|
||||
}
|
||||
|
||||
m_display = display;
|
||||
m_ownDisplay = own;
|
||||
|
||||
if (m_display)
|
||||
m_display->addWindow(this);
|
||||
@ -198,7 +203,7 @@ void Window::onHitTest(HitTestEvent& ev)
|
||||
{
|
||||
HitTest ht = HitTestNowhere;
|
||||
|
||||
// If this window is not movable or we are not completely visible.
|
||||
// If this window is not movable
|
||||
if (!m_isMoveable) {
|
||||
ev.setHit(ht);
|
||||
return;
|
||||
@ -207,7 +212,7 @@ void Window::onHitTest(HitTestEvent& ev)
|
||||
// TODO check why this is necessary, there should be a bug in
|
||||
// the manager where we are receiving mouse events and are not
|
||||
// the top most window.
|
||||
Widget* picked = manager()->pick(ev.point());
|
||||
Widget* picked = pick(ev.point());
|
||||
if (picked &&
|
||||
picked != this &&
|
||||
picked->type() != kWindowTitleLabelWidget) {
|
||||
@ -230,6 +235,14 @@ void Window::onHitTest(HitTestEvent& ev)
|
||||
}
|
||||
// Resize
|
||||
else if (m_isSizeable) {
|
||||
#ifdef __APPLE__
|
||||
// TODO on macOS we cannot start resize actions on native windows
|
||||
if (ownDisplay()) {
|
||||
ev.setHit(ht);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((x >= pos.x) && (x < cpos.x)) {
|
||||
if ((y >= pos.y) && (y < cpos.y))
|
||||
ht = HitTestBorderNW;
|
||||
@ -326,19 +339,28 @@ void Window::expandWindow(const gfx::Size& size)
|
||||
{
|
||||
const gfx::Rect oldBounds = bounds();
|
||||
|
||||
setBounds(gfx::Rect(bounds().origin(), size));
|
||||
if (ownDisplay()) {
|
||||
os::Window* nativeWindow = display()->nativeWindow();
|
||||
const int scale = nativeWindow->scale();
|
||||
gfx::Rect frame = nativeWindow->frame();
|
||||
frame.setSize(size * scale);
|
||||
nativeWindow->setFrame(frame);
|
||||
|
||||
layout();
|
||||
manager()->invalidateRect(oldBounds);
|
||||
layout();
|
||||
invalidate();
|
||||
}
|
||||
else {
|
||||
setBounds(gfx::Rect(bounds().origin(), size));
|
||||
|
||||
layout();
|
||||
manager()->invalidateRect(oldBounds);
|
||||
}
|
||||
}
|
||||
|
||||
void Window::openWindow()
|
||||
{
|
||||
if (!parent()) {
|
||||
if (m_isAutoRemap)
|
||||
centerWindow();
|
||||
|
||||
Manager::getDefault()->_openWindow(this);
|
||||
Manager::getDefault()->_openWindow(this, m_isAutoRemap);
|
||||
}
|
||||
}
|
||||
|
||||
@ -348,9 +370,7 @@ void Window::openWindowInForeground()
|
||||
|
||||
openWindow();
|
||||
|
||||
MessageLoop loop(manager());
|
||||
while (!hasFlags(HIDDEN))
|
||||
loop.pumpMessages();
|
||||
Manager::getDefault()->_runModalWindow(this);
|
||||
|
||||
m_isForeground = false;
|
||||
}
|
||||
@ -401,6 +421,26 @@ bool Window::onProcessMessage(Message* msg)
|
||||
else
|
||||
*clickedWindowPos = bounds();
|
||||
|
||||
// Handle native window action
|
||||
if (ownDisplay()) {
|
||||
os::WindowAction action = os::WindowAction::Cancel;
|
||||
switch (m_hitTest) {
|
||||
case HitTestCaption: action = os::WindowAction::Move; break;
|
||||
case HitTestBorderNW: action = os::WindowAction::ResizeFromTopLeft; break;
|
||||
case HitTestBorderN: action = os::WindowAction::ResizeFromTop; break;
|
||||
case HitTestBorderNE: action = os::WindowAction::ResizeFromTopRight; break;
|
||||
case HitTestBorderW: action = os::WindowAction::ResizeFromLeft; break;
|
||||
case HitTestBorderE: action = os::WindowAction::ResizeFromRight; break;
|
||||
case HitTestBorderSW: action = os::WindowAction::ResizeFromBottomLeft; break;
|
||||
case HitTestBorderS: action = os::WindowAction::ResizeFromBottom; break;
|
||||
case HitTestBorderSE: action = os::WindowAction::ResizeFromBottomRight; break;
|
||||
}
|
||||
if (action != os::WindowAction::Cancel) {
|
||||
display()->nativeWindow()->performWindowAction(action, nullptr);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
captureMouse();
|
||||
return true;
|
||||
}
|
||||
@ -521,6 +561,50 @@ bool Window::onProcessMessage(Message* msg)
|
||||
return Widget::onProcessMessage(msg);
|
||||
}
|
||||
|
||||
// TODO similar to Manager::onInvalidateRegion
|
||||
void Window::onInvalidateRegion(const gfx::Region& region)
|
||||
{
|
||||
if (!ownDisplay()) {
|
||||
Widget::onInvalidateRegion(region);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isVisible() || region.contains(bounds()) == gfx::Region::Out)
|
||||
return;
|
||||
|
||||
Display* display = this->display();
|
||||
|
||||
// Intersect only with window bounds, we don't need to use
|
||||
// getDrawableRegion() because each sub-window in the display will
|
||||
// be processed in the following for() loop
|
||||
gfx::Region reg1;
|
||||
reg1.createIntersection(region, gfx::Region(bounds()));
|
||||
|
||||
// Redraw windows from top to background.
|
||||
for (auto window : display->getWindows()) {
|
||||
// Invalidating the manager only works for the main display, to
|
||||
// invalidate windows you have to invalidate them.
|
||||
if (window->ownDisplay()) {
|
||||
ASSERT(this == window);
|
||||
break;
|
||||
}
|
||||
|
||||
// Invalidate regions of this window
|
||||
window->invalidateRegion(reg1);
|
||||
|
||||
// Clip this window area for the next window.
|
||||
gfx::Region reg2;
|
||||
window->getRegion(reg2);
|
||||
reg1 -= reg2;
|
||||
}
|
||||
|
||||
// TODO we should be able to modify m_updateRegion directly here,
|
||||
// so we avoid the getDrawableRegion() call from
|
||||
// Widget::onInvalidateRegion().
|
||||
if (!reg1.isEmpty())
|
||||
Widget::onInvalidateRegion(reg1);
|
||||
}
|
||||
|
||||
void Window::onResize(ResizeEvent& ev)
|
||||
{
|
||||
windowSetPosition(ev.bounds());
|
||||
@ -555,9 +639,11 @@ void Window::onSizeHint(SizeHintEvent& ev)
|
||||
}
|
||||
}
|
||||
|
||||
void Window::onBroadcastMouseMessage(WidgetsList& targets)
|
||||
void Window::onBroadcastMouseMessage(const gfx::Point& screenPos,
|
||||
WidgetsList& targets)
|
||||
{
|
||||
targets.push_back(this);
|
||||
if (!ownDisplay() || display()->nativeWindow()->frame().contains(screenPos))
|
||||
targets.push_back(this);
|
||||
|
||||
// Continue sending the message to siblings windows until a desktop
|
||||
// or foreground window.
|
||||
@ -566,7 +652,7 @@ void Window::onBroadcastMouseMessage(WidgetsList& targets)
|
||||
|
||||
Widget* sibling = nextSibling();
|
||||
if (sibling)
|
||||
sibling->broadcastMouseMessage(targets);
|
||||
sibling->broadcastMouseMessage(screenPos, targets);
|
||||
}
|
||||
|
||||
void Window::onSetText()
|
||||
|
@ -28,8 +28,9 @@ namespace ui {
|
||||
explicit Window(Type type, const std::string& text = "");
|
||||
~Window();
|
||||
|
||||
bool ownDisplay() const { return m_ownDisplay; }
|
||||
Display* display() const;
|
||||
void setDisplay(Display* display);
|
||||
void setDisplay(Display* display, const bool own);
|
||||
|
||||
Widget* closer() const { return m_closer; }
|
||||
|
||||
@ -61,14 +62,22 @@ namespace ui {
|
||||
|
||||
HitTest hitTest(const gfx::Point& point);
|
||||
|
||||
// Last native window frame bounds. Saved just before we close the
|
||||
// native window so we can save this information in the
|
||||
// configuration file.
|
||||
gfx::Rect lastNativeFrame() const { return m_lastFrame; }
|
||||
void loadNativeFrame(const gfx::Rect& frame) { m_lastFrame = frame; }
|
||||
|
||||
// Signals
|
||||
obs::signal<void (CloseEvent&)> Close;
|
||||
|
||||
protected:
|
||||
virtual bool onProcessMessage(Message* msg) override;
|
||||
virtual void onInvalidateRegion(const gfx::Region& region) override;
|
||||
virtual void onResize(ResizeEvent& ev) override;
|
||||
virtual void onSizeHint(SizeHintEvent& ev) override;
|
||||
virtual void onBroadcastMouseMessage(WidgetsList& targets) override;
|
||||
virtual void onBroadcastMouseMessage(const gfx::Point& screenPos,
|
||||
WidgetsList& targets) override;
|
||||
virtual void onSetText() override;
|
||||
|
||||
// New events
|
||||
@ -88,6 +97,7 @@ namespace ui {
|
||||
Widget* m_closer;
|
||||
Label* m_titleLabel;
|
||||
ButtonBase* m_closeButton;
|
||||
bool m_ownDisplay : 1;
|
||||
bool m_isDesktop : 1;
|
||||
bool m_isMoveable : 1;
|
||||
bool m_isSizeable : 1;
|
||||
@ -96,6 +106,7 @@ namespace ui {
|
||||
bool m_isForeground : 1;
|
||||
bool m_isAutoRemap : 1;
|
||||
int m_hitTest;
|
||||
gfx::Rect m_lastFrame;
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
|
Loading…
x
Reference in New Issue
Block a user