mirror of
https://github.com/aseprite/aseprite.git
synced 2025-02-18 21:40:46 +00:00
Fix several issues locating windows with multiple UI windows
We've refactored the code to support locating windows (and popups windows + hot regions) correctly in both modes: with one ui::Display and with multiple ui::Displays. For this we've added a new ui::fit_bounds() function that works in both modes.
This commit is contained in:
parent
7079801697
commit
bcd69495ce
2
laf
2
laf
@ -1 +1 @@
|
||||
Subproject commit d290eaf37fcb1a48cee433e6b9a1b73854671df0
|
||||
Subproject commit 1106d7488dcf1410815601c9eaa38407bc243893
|
@ -342,12 +342,17 @@ void CanvasSizeCommand::onExecute(Context* context)
|
||||
|
||||
// Find best position for the window on the editor
|
||||
if (DocView* docView = static_cast<UIContext*>(context)->activeView()) {
|
||||
window->positionWindow(
|
||||
docView->bounds().x2() - window->bounds().w,
|
||||
docView->bounds().y);
|
||||
Display* display = ui::Manager::getDefault()->display();
|
||||
ui::fit_bounds(display,
|
||||
window.get(),
|
||||
gfx::Rect(docView->bounds().x2() - window->bounds().w,
|
||||
docView->bounds().y,
|
||||
window->bounds().w,
|
||||
window->bounds().h));
|
||||
}
|
||||
else
|
||||
else {
|
||||
window->centerWindow();
|
||||
}
|
||||
|
||||
load_window_pos(window.get(), "CanvasSize");
|
||||
window->setVisible(true);
|
||||
|
@ -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
|
||||
@ -246,10 +246,7 @@ public:
|
||||
advancedCheck()->Click.connect(
|
||||
[this](ui::Event&){
|
||||
advanced()->setVisible(advancedCheck()->isSelected());
|
||||
|
||||
const gfx::Rect origBounds = bounds();
|
||||
setBounds(gfx::Rect(bounds().origin(), sizeHint()));
|
||||
manager()->invalidateRect(origBounds);
|
||||
expandWindow(sizeHint());
|
||||
});
|
||||
}
|
||||
else {
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "base/string.h"
|
||||
#include "fmt/format.h"
|
||||
#include "ui/alert.h"
|
||||
#include "ui/fit_bounds.h"
|
||||
#include "ui/graphics.h"
|
||||
#include "ui/listitem.h"
|
||||
#include "ui/message.h"
|
||||
@ -882,11 +883,19 @@ void KeyboardShortcutsCommand::onExecute(Context* context)
|
||||
std::string neededSearchCopy = m_search;
|
||||
KeyboardShortcutsWindow window(keys, menuKeys, neededSearchCopy);
|
||||
|
||||
gfx::Size displaySize = ui::get_desktop_size();
|
||||
window.setBounds(gfx::Rect(0, 0, displaySize.w*3/4, displaySize.h*3/4));
|
||||
ui::Display* mainDisplay = Manager::getDefault()->display();
|
||||
ui::fit_bounds(mainDisplay, &window,
|
||||
gfx::Rect(mainDisplay->size()),
|
||||
[](const gfx::Rect& workarea,
|
||||
gfx::Rect& bounds,
|
||||
std::function<gfx::Rect(Widget*)> getWidgetBounds) {
|
||||
gfx::Point center = bounds.center();
|
||||
bounds.setSize(workarea.size()*3/4);
|
||||
bounds.setOrigin(center - gfx::Point(bounds.size()/2));
|
||||
});
|
||||
|
||||
window.loadLayout();
|
||||
|
||||
window.centerWindow();
|
||||
window.setVisible(true);
|
||||
window.openWindowInForeground();
|
||||
|
||||
|
@ -124,11 +124,7 @@ private:
|
||||
}
|
||||
|
||||
if (!m_fontPopup->isVisible()) {
|
||||
gfx::Size displaySize = manager()->display()->size();
|
||||
gfx::Rect bounds = fontFace()->bounds();
|
||||
m_fontPopup->showPopup(
|
||||
gfx::Rect(bounds.x, bounds.y+bounds.h,
|
||||
displaySize.w/2, displaySize.h/2));
|
||||
m_fontPopup->showPopup(display(), fontFace()->bounds());
|
||||
}
|
||||
else {
|
||||
m_fontPopup->closeWindow(NULL);
|
||||
|
@ -71,14 +71,15 @@ public:
|
||||
void centerConsole() {
|
||||
initTheme();
|
||||
|
||||
remapWindow();
|
||||
Display* display = ui::Manager::getDefault()->display();
|
||||
const gfx::Rect displayRc = display->bounds();
|
||||
gfx::Rect rc;
|
||||
rc.w = displayRc.w*9/10;
|
||||
rc.h = displayRc.h*6/10;
|
||||
rc.x = displayRc.x + displayRc.w/2 - rc.w/2;
|
||||
rc.y = displayRc.y + displayRc.h/2 - rc.h/2;
|
||||
|
||||
// TODO center to main window or screen workspace
|
||||
gfx::Size displaySize = manager()->display()->size();
|
||||
setBounds(gfx::Rect(0, 0, displaySize.w*9/10, displaySize.h*6/10));
|
||||
|
||||
centerWindow();
|
||||
invalidate();
|
||||
ui::fit_bounds(display, this, rc);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -693,11 +693,15 @@ void CustomizedGuiManager::onInitTheme(InitThemeEvent& ev)
|
||||
void CustomizedGuiManager::onNewDisplayConfiguration(Display* display)
|
||||
{
|
||||
Manager::onNewDisplayConfiguration(display);
|
||||
save_gui_config();
|
||||
|
||||
// TODO Should we provide a more generic way for all ui::Window to
|
||||
// detect the os::Window (or UI Screen Scaling) change?
|
||||
Console::notifyNewDisplayConfiguration();
|
||||
// Only whne the main display/window is modified
|
||||
if (display == this->display()) {
|
||||
save_gui_config();
|
||||
|
||||
// TODO Should we provide a more generic way for all ui::Window to
|
||||
// detect the os::Window (or UI Screen Scaling) change?
|
||||
Console::notifyNewDisplayConfiguration();
|
||||
}
|
||||
}
|
||||
|
||||
std::string CustomizedGuiManager::loadLayout(Widget* widget)
|
||||
|
@ -589,7 +589,7 @@ void BrowserView::onTabPopup(Workspace* workspace)
|
||||
if (!menu)
|
||||
return;
|
||||
|
||||
menu->showPopup(mousePosInDisplay());
|
||||
menu->showPopup(mousePosInDisplay(), display());
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
@ -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
|
||||
@ -36,6 +36,7 @@
|
||||
#include "os/surface.h"
|
||||
#include "os/system.h"
|
||||
#include "ui/button.h"
|
||||
#include "ui/fit_bounds.h"
|
||||
#include "ui/link_label.h"
|
||||
#include "ui/listitem.h"
|
||||
#include "ui/menu.h"
|
||||
@ -52,22 +53,24 @@ using namespace ui;
|
||||
|
||||
namespace {
|
||||
|
||||
void show_popup_menu(PopupWindow* popupWindow, Menu* popupMenu,
|
||||
const gfx::Point& pt)
|
||||
void show_popup_menu(PopupWindow* popupWindow,
|
||||
Menu* popupMenu,
|
||||
const gfx::Point& pt,
|
||||
Display* display)
|
||||
{
|
||||
// Here we make the popup window temporaly floating, so it's
|
||||
// not closed by the popup menu.
|
||||
popupWindow->makeFloating();
|
||||
|
||||
popupMenu->showPopup(pt);
|
||||
popupMenu->showPopup(pt, display);
|
||||
|
||||
// Add the menu popup region to the window popup hot region so it's
|
||||
// not closed after we close the menu.
|
||||
popupWindow->makeFixed();
|
||||
|
||||
gfx::Region rgn;
|
||||
rgn.createUnion(gfx::Region(popupWindow->bounds()),
|
||||
gfx::Region(popupMenu->bounds()));
|
||||
rgn.createUnion(gfx::Region(popupWindow->boundsOnScreen()),
|
||||
gfx::Region(popupMenu->boundsOnScreen()));
|
||||
popupWindow->setHotRegion(rgn);
|
||||
}
|
||||
|
||||
@ -194,7 +197,8 @@ private:
|
||||
|
||||
m_changeFlags = true;
|
||||
show_popup_menu(m_popup, &menu,
|
||||
gfx::Point(origin().x, origin().y+bounds().h));
|
||||
gfx::Point(origin().x, origin().y+bounds().h),
|
||||
display());
|
||||
|
||||
if (m_changeFlags) {
|
||||
brush = m_brushes.getBrushSlot(m_slot);
|
||||
@ -299,8 +303,10 @@ private:
|
||||
params.shade()->setSelected(saveBrush.shade());
|
||||
params.pixelPerfect()->setSelected(saveBrush.pixelPerfect());
|
||||
|
||||
show_popup_menu(static_cast<PopupWindow*>(window()), &menu,
|
||||
gfx::Point(origin().x, origin().y+bounds().h));
|
||||
show_popup_menu(static_cast<PopupWindow*>(window()),
|
||||
&menu,
|
||||
gfx::Point(origin().x, origin().y+bounds().h),
|
||||
display());
|
||||
|
||||
// Save preferences
|
||||
if (saveBrush.brushType() != params.brushType()->isSelected())
|
||||
@ -384,7 +390,8 @@ void BrushPopup::setBrush(Brush* brush)
|
||||
}
|
||||
}
|
||||
|
||||
void BrushPopup::regenerate(const gfx::Rect& box)
|
||||
void BrushPopup::regenerate(ui::Display* display,
|
||||
const gfx::Point& pos)
|
||||
{
|
||||
auto& brushSlots = App::instance()->brushes().getBrushSlots();
|
||||
|
||||
@ -425,8 +432,8 @@ void BrushPopup::regenerate(const gfx::Rect& box)
|
||||
m_box.addChild(m_customBrushes);
|
||||
|
||||
// Resize the window and change the hot region.
|
||||
setBounds(gfx::Rect(box.origin(), sizeHint()));
|
||||
setHotRegion(gfx::Region(bounds()));
|
||||
fit_bounds(display, this, gfx::Rect(pos, sizeHint()));
|
||||
setHotRegion(gfx::Region(boundsOnScreen()));
|
||||
}
|
||||
|
||||
void BrushPopup::onBrushChanges()
|
||||
@ -435,7 +442,9 @@ void BrushPopup::onBrushChanges()
|
||||
gfx::Region rgn;
|
||||
getDrawableRegion(rgn, kCutTopWindowsAndUseChildArea);
|
||||
|
||||
regenerate(bounds());
|
||||
Display* mainDisplay = manager()->display();
|
||||
regenerate(mainDisplay,
|
||||
mainDisplay->nativeWindow()->pointFromScreen(boundsOnScreen().origin()));
|
||||
invalidate();
|
||||
|
||||
parent()->invalidateRegion(rgn);
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -21,7 +21,8 @@ namespace app {
|
||||
BrushPopup();
|
||||
|
||||
void setBrush(doc::Brush* brush);
|
||||
void regenerate(const gfx::Rect& box);
|
||||
void regenerate(ui::Display* display,
|
||||
const gfx::Point& pos);
|
||||
|
||||
static os::SurfaceRef createSurfaceForBrush(const doc::BrushRef& brush);
|
||||
|
||||
|
@ -1868,7 +1868,7 @@ void ColorBar::showPaletteSortOptions()
|
||||
asc.Click.connect([this]{ setAscending(true); });
|
||||
des.Click.connect([this]{ setAscending(false); });
|
||||
|
||||
menu.showPopup(gfx::Point(bounds.x, bounds.y+bounds.h));
|
||||
menu.showPopup(gfx::Point(bounds.x, bounds.y2()), display());
|
||||
}
|
||||
|
||||
void ColorBar::showPalettePresets()
|
||||
@ -1884,16 +1884,13 @@ void ColorBar::showPalettePresets()
|
||||
}
|
||||
|
||||
if (!m_palettePopup->isVisible()) {
|
||||
gfx::Size displaySize = ui::get_desktop_size();
|
||||
gfx::Rect bounds = m_buttons.getItem(
|
||||
static_cast<int>(PalButton::PRESETS))->bounds();
|
||||
|
||||
m_palettePopup->showPopup(
|
||||
gfx::Rect(bounds.x, bounds.y+bounds.h,
|
||||
displaySize.w/2, displaySize.h*3/4));
|
||||
m_palettePopup->showPopup(display(), bounds);
|
||||
}
|
||||
else {
|
||||
m_palettePopup->closeWindow(NULL);
|
||||
m_palettePopup->closeWindow(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1904,7 +1901,7 @@ void ColorBar::showPaletteOptions()
|
||||
gfx::Rect bounds = m_buttons.getItem(
|
||||
static_cast<int>(PalButton::OPTIONS))->bounds();
|
||||
|
||||
menu->showPopup(gfx::Point(bounds.x, bounds.y+bounds.h));
|
||||
menu->showPopup(gfx::Point(bounds.x, bounds.y2()), display());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,6 +53,7 @@ ColorButton::ColorButton(const app::Color& color,
|
||||
, m_color(color)
|
||||
, m_pixelFormat(pixelFormat)
|
||||
, m_window(nullptr)
|
||||
, m_desktopCoords(false)
|
||||
, m_dependOnLayer(false)
|
||||
, m_options(options)
|
||||
{
|
||||
@ -306,9 +307,12 @@ void ColorButton::onLoadLayout(ui::LoadLayoutEvent& ev)
|
||||
{
|
||||
if (canPin()) {
|
||||
bool pinned = false;
|
||||
|
||||
m_desktopCoords = false;
|
||||
ev.stream() >> pinned;
|
||||
if (ev.stream() && pinned)
|
||||
ev.stream() >> m_windowDefaultBounds;
|
||||
ev.stream() >> m_windowDefaultBounds
|
||||
>> m_desktopCoords;
|
||||
|
||||
m_hiddenPopupBounds = m_windowDefaultBounds;
|
||||
}
|
||||
@ -316,8 +320,12 @@ void ColorButton::onLoadLayout(ui::LoadLayoutEvent& ev)
|
||||
|
||||
void ColorButton::onSaveLayout(ui::SaveLayoutEvent& ev)
|
||||
{
|
||||
if (canPin() && m_window && m_window->isPinned())
|
||||
ev.stream() << 1 << ' ' << m_window->bounds();
|
||||
if (canPin() && m_window && m_window->isPinned()) {
|
||||
if (m_desktopCoords)
|
||||
ev.stream() << 1 << ' ' << m_window->lastNativeFrame() << ' ' << 1;
|
||||
else
|
||||
ev.stream() << 1 << ' ' << m_window->bounds() << ' ' << 0;
|
||||
}
|
||||
else
|
||||
ev.stream() << 0;
|
||||
}
|
||||
@ -339,37 +347,39 @@ void ColorButton::openPopup(const bool forcePinned)
|
||||
}
|
||||
|
||||
m_window->setColor(m_color, ColorPopup::ChangeType);
|
||||
m_window->remapWindow();
|
||||
|
||||
fit_bounds(
|
||||
display(),
|
||||
m_window,
|
||||
gfx::Rect(m_window->sizeHint()),
|
||||
[this, pinned, forcePinned](const gfx::Rect& workarea,
|
||||
gfx::Rect& winBounds,
|
||||
std::function<gfx::Rect(Widget*)> getWidgetBounds) {
|
||||
if (!pinned || (forcePinned && m_hiddenPopupBounds.isEmpty())) {
|
||||
gfx::Rect bounds = getWidgetBounds(this);
|
||||
|
||||
winBounds.x = base::clamp(bounds.x, workarea.x, workarea.x2()-winBounds.w);
|
||||
if (bounds.y2()+winBounds.h <= workarea.y2())
|
||||
winBounds.y = std::max(0, bounds.y2());
|
||||
else
|
||||
winBounds.y = std::max(0, bounds.y-winBounds.h);
|
||||
}
|
||||
else if (forcePinned) {
|
||||
winBounds = convertBounds(m_hiddenPopupBounds);
|
||||
}
|
||||
else {
|
||||
winBounds = convertBounds(m_windowDefaultBounds);
|
||||
}
|
||||
});
|
||||
|
||||
m_window->openWindow();
|
||||
|
||||
gfx::Size displaySize = ui::get_desktop_size();
|
||||
gfx::Rect winBounds;
|
||||
if (!pinned || (forcePinned && m_hiddenPopupBounds.isEmpty())) {
|
||||
winBounds = gfx::Rect(m_window->bounds().origin(),
|
||||
m_window->sizeHint());
|
||||
winBounds.x = base::clamp(bounds().x, 0, displaySize.w-winBounds.w);
|
||||
if (bounds().y2() <= displaySize.h-winBounds.h)
|
||||
winBounds.y = std::max(0, bounds().y2());
|
||||
else
|
||||
winBounds.y = std::max(0, bounds().y-winBounds.h);
|
||||
}
|
||||
else if (forcePinned) {
|
||||
winBounds = m_hiddenPopupBounds;
|
||||
}
|
||||
else {
|
||||
winBounds = m_windowDefaultBounds;
|
||||
}
|
||||
winBounds.x = base::clamp(winBounds.x, 0, displaySize.w-winBounds.w);
|
||||
winBounds.y = base::clamp(winBounds.y, 0, displaySize.h-winBounds.h);
|
||||
m_window->setBounds(winBounds);
|
||||
|
||||
m_window->manager()->dispatchMessages();
|
||||
m_window->layout();
|
||||
|
||||
m_window->setPinned(pinned);
|
||||
|
||||
// Add the ColorButton area to the ColorPopup hot-region
|
||||
if (!pinned) {
|
||||
gfx::Rect rc = bounds().createUnion(m_window->bounds());
|
||||
gfx::Rect rc = boundsOnScreen().createUnion(m_window->boundsOnScreen());
|
||||
rc.enlarge(8);
|
||||
gfx::Region rgn(rc);
|
||||
static_cast<PopupWindow*>(m_window)->setHotRegion(rgn);
|
||||
@ -386,7 +396,14 @@ void ColorButton::closePopup()
|
||||
|
||||
void ColorButton::onWindowClose(ui::CloseEvent& ev)
|
||||
{
|
||||
m_hiddenPopupBounds = m_window->bounds();
|
||||
if (get_multiple_displays()) {
|
||||
m_desktopCoords = true;
|
||||
m_hiddenPopupBounds = m_window->lastNativeFrame();
|
||||
}
|
||||
else {
|
||||
m_desktopCoords = false;
|
||||
m_hiddenPopupBounds = m_window->bounds();
|
||||
}
|
||||
}
|
||||
|
||||
void ColorButton::onWindowColorChange(const app::Color& color)
|
||||
@ -418,4 +435,23 @@ void ColorButton::onActiveSiteChange(const Site& site)
|
||||
}
|
||||
}
|
||||
|
||||
gfx::Rect ColorButton::convertBounds(const gfx::Rect& bounds) const
|
||||
{
|
||||
// Convert to desktop
|
||||
if (get_multiple_displays() && !m_desktopCoords) {
|
||||
auto nativeWindow = display()->nativeWindow();
|
||||
return gfx::Rect(nativeWindow->pointToScreen(bounds.origin()),
|
||||
nativeWindow->pointToScreen(bounds.point2()));
|
||||
}
|
||||
// Convert to display
|
||||
else if (!get_multiple_displays() && m_desktopCoords) {
|
||||
auto nativeWindow = display()->nativeWindow();
|
||||
return gfx::Rect(nativeWindow->pointFromScreen(bounds.origin()),
|
||||
nativeWindow->pointFromScreen(bounds.point2()));
|
||||
}
|
||||
// No conversion is required
|
||||
else
|
||||
return bounds;
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2021 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -68,11 +69,17 @@ namespace app {
|
||||
void onWindowColorChange(const app::Color& color);
|
||||
bool canPin() const { return m_options.canPinSelector; }
|
||||
|
||||
// Used to convert saved bounds (m_window/hiddenDefaultBounds,
|
||||
// which can be relative to the display or relative to the screen)
|
||||
// to the current system of coordinates.
|
||||
gfx::Rect convertBounds(const gfx::Rect& bounds) const;
|
||||
|
||||
app::Color m_color;
|
||||
PixelFormat m_pixelFormat;
|
||||
ColorPopup* m_window;
|
||||
gfx::Rect m_windowDefaultBounds;
|
||||
gfx::Rect m_hiddenPopupBounds;
|
||||
bool m_desktopCoords; // True if m_windowDefault/hiddenPopupBounds are screen coordinates
|
||||
bool m_dependOnLayer;
|
||||
ColorButtonOptions m_options;
|
||||
};
|
||||
|
@ -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
|
||||
@ -412,7 +412,7 @@ void ColorWheel::onOptions()
|
||||
}
|
||||
|
||||
gfx::Rect rc = m_options.bounds();
|
||||
menu.showPopup(gfx::Point(rc.x+rc.w, rc.y));
|
||||
menu.showPopup(gfx::Point(rc.x2(), rc.y), display());
|
||||
}
|
||||
|
||||
int ColorWheel::convertHueAngle(int hue, int dir) const
|
||||
|
@ -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,6 +66,7 @@
|
||||
#include "render/ordered_dither.h"
|
||||
#include "ui/button.h"
|
||||
#include "ui/combobox.h"
|
||||
#include "ui/fit_bounds.h"
|
||||
#include "ui/int_entry.h"
|
||||
#include "ui/label.h"
|
||||
#include "ui/listbox.h"
|
||||
@ -209,20 +210,19 @@ protected:
|
||||
private:
|
||||
// Returns a little rectangle that can be used by the popup as the
|
||||
// first brush position.
|
||||
gfx::Rect getPopupBox() {
|
||||
gfx::Point popupPosCandidate() const {
|
||||
Rect rc = bounds();
|
||||
rc.y += rc.h - 2*guiscale();
|
||||
rc.setSize(sizeHint());
|
||||
return rc;
|
||||
return rc.origin();
|
||||
}
|
||||
|
||||
void openPopup() {
|
||||
doc::BrushRef brush = m_owner->activeBrush();
|
||||
|
||||
m_popupWindow.regenerate(getPopupBox());
|
||||
m_popupWindow.regenerate(display(), popupPosCandidate());
|
||||
m_popupWindow.setBrush(brush.get());
|
||||
|
||||
Region rgn(m_popupWindow.bounds().createUnion(bounds()));
|
||||
Region rgn(m_popupWindow.boundsOnScreen().createUnion(boundsOnScreen()));
|
||||
m_popupWindow.setHotRegion(rgn);
|
||||
|
||||
m_popupWindow.openWindow();
|
||||
@ -450,7 +450,8 @@ protected:
|
||||
}
|
||||
});
|
||||
|
||||
menu.showPopup(gfx::Point(bounds.x, bounds.y+bounds.h));
|
||||
menu.showPopup(gfx::Point(bounds.x, bounds.y2()),
|
||||
display());
|
||||
deselectItems();
|
||||
}
|
||||
|
||||
@ -502,7 +503,8 @@ protected:
|
||||
|
||||
AppMenus::instance()
|
||||
->getInkPopupMenu()
|
||||
->showPopup(gfx::Point(bounds.x, bounds.y+bounds.h));
|
||||
->showPopup(gfx::Point(bounds.x, bounds.y2()),
|
||||
display());
|
||||
|
||||
deselectItems();
|
||||
}
|
||||
@ -627,7 +629,8 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
menu.showPopup(gfx::Point(bounds.x, bounds.y+bounds.h));
|
||||
menu.showPopup(gfx::Point(bounds.x, bounds.y2()),
|
||||
display());
|
||||
m_button.invalidate();
|
||||
}
|
||||
|
||||
@ -808,7 +811,8 @@ private:
|
||||
masked.Click.connect([this]{ setOpaque(false); });
|
||||
automatic.Click.connect([this]{ onAutomatic(); });
|
||||
|
||||
menu.showPopup(gfx::Point(bounds.x, bounds.y+bounds.h));
|
||||
menu.showPopup(gfx::Point(bounds.x, bounds.y2()),
|
||||
display());
|
||||
}
|
||||
|
||||
void onChangeColor() {
|
||||
@ -905,7 +909,8 @@ private:
|
||||
app::gen::PivotPosition(buttonset.selectedItem()));
|
||||
});
|
||||
|
||||
menu.showPopup(gfx::Point(bounds.x, bounds.y+bounds.h));
|
||||
menu.showPopup(gfx::Point(bounds.x, bounds.y2()),
|
||||
display());
|
||||
}
|
||||
|
||||
void onPivotChange() {
|
||||
@ -1151,8 +1156,10 @@ public:
|
||||
|
||||
const gfx::Rect bounds = this->bounds();
|
||||
m_popup->remapWindow();
|
||||
m_popup->positionWindow(bounds.x, bounds.y+bounds.h);
|
||||
m_popup->setHotRegion(gfx::Region(m_popup->bounds()));
|
||||
fit_bounds(display(), m_popup.get(),
|
||||
gfx::Rect(gfx::Point(bounds.x, bounds.y2()),
|
||||
m_popup->sizeHint()));
|
||||
m_popup->setHotRegion(gfx::Region(m_popup->boundsOnScreen()));
|
||||
m_popup->openWindow();
|
||||
}
|
||||
|
||||
@ -1436,7 +1443,8 @@ private:
|
||||
doc->notifyGeneralUpdate();
|
||||
});
|
||||
|
||||
menu.showPopup(gfx::Point(bounds.x, bounds.y+bounds.h));
|
||||
menu.showPopup(gfx::Point(bounds.x, bounds.y2()),
|
||||
display());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -413,7 +413,7 @@ void DataRecoveryView::onTabPopup(Workspace* workspace)
|
||||
if (!menu)
|
||||
return;
|
||||
|
||||
menu->showPopup(mousePosInDisplay());
|
||||
menu->showPopup(mousePosInDisplay(), display());
|
||||
}
|
||||
|
||||
void DataRecoveryView::onOpen()
|
||||
@ -461,7 +461,7 @@ void DataRecoveryView::onOpenMenu()
|
||||
rawFrames.Click.connect([this]{ onOpenRaw(crash::RawImagesAs::kFrames); });
|
||||
rawLayers.Click.connect([this]{ onOpenRaw(crash::RawImagesAs::kLayers); });
|
||||
|
||||
menu.showPopup(gfx::Point(bounds.x, bounds.y+bounds.h));
|
||||
menu.showPopup(gfx::Point(bounds.x, bounds.y+bounds.h), display());
|
||||
}
|
||||
|
||||
void DataRecoveryView::onDelete()
|
||||
|
@ -140,7 +140,7 @@ void DevConsoleView::onTabPopup(Workspace* workspace)
|
||||
if (!menu)
|
||||
return;
|
||||
|
||||
menu->showPopup(mousePosInDisplay());
|
||||
menu->showPopup(mousePosInDisplay(), display());
|
||||
}
|
||||
|
||||
bool DevConsoleView::onProcessMessage(Message* msg)
|
||||
|
@ -362,7 +362,7 @@ void DocView::onTabPopup(Workspace* workspace)
|
||||
ctx->setActiveView(this);
|
||||
ctx->updateFlags();
|
||||
|
||||
menu->showPopup(mousePosInDisplay());
|
||||
menu->showPopup(mousePosInDisplay(), display());
|
||||
}
|
||||
|
||||
bool DocView::onProcessMessage(Message* msg)
|
||||
|
@ -370,15 +370,10 @@ void DynamicsPopup::onValuesChange(ButtonSet::Item* item)
|
||||
m_dynamics->velocityLabel()->setVisible(hasVelocity);
|
||||
m_dynamics->velocityPlaceholder()->setVisible(hasVelocity);
|
||||
|
||||
auto oldBounds = bounds();
|
||||
layout();
|
||||
setBounds(gfx::Rect(origin(), sizeHint()));
|
||||
expandWindow(sizeHint());
|
||||
|
||||
m_hotRegion |= gfx::Region(bounds());
|
||||
m_hotRegion |= gfx::Region(boundsOnScreen());
|
||||
setHotRegion(m_hotRegion);
|
||||
|
||||
if (isVisible())
|
||||
manager()->invalidateRect(oldBounds);
|
||||
}
|
||||
|
||||
void DynamicsPopup::updateFromToText()
|
||||
@ -400,7 +395,7 @@ bool DynamicsPopup::onProcessMessage(Message* msg)
|
||||
switch (msg->type()) {
|
||||
|
||||
case kOpenMessage:
|
||||
m_hotRegion = gfx::Region(bounds());
|
||||
m_hotRegion = gfx::Region(boundsOnScreen());
|
||||
setHotRegion(m_hotRegion);
|
||||
manager()->addMessageFilter(kMouseMoveMessage, this);
|
||||
manager()->addMessageFilter(kMouseDownMessage, this);
|
||||
@ -442,8 +437,13 @@ bool DynamicsPopup::onProcessMessage(Message* msg)
|
||||
}
|
||||
|
||||
case kMouseDownMessage: {
|
||||
if (!msg->display())
|
||||
break;
|
||||
|
||||
os::Window* nativeWindow = msg->display()->nativeWindow();
|
||||
auto mouseMsg = static_cast<MouseMessage*>(msg);
|
||||
auto picked = manager()->pick(mouseMsg->position());
|
||||
auto screenPos = nativeWindow->pointToScreen(mouseMsg->position());
|
||||
auto picked = manager()->pickFromScreenPos(screenPos);
|
||||
if ((picked == nullptr) ||
|
||||
(picked->window() != this &&
|
||||
picked->window() != m_ditheringSel->getWindowWidget())) {
|
||||
@ -451,6 +451,7 @@ bool DynamicsPopup::onProcessMessage(Message* msg)
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return PopupWindow::onProcessMessage(msg);
|
||||
}
|
||||
|
@ -2754,7 +2754,7 @@ void Editor::showAnimationSpeedMultiplierPopup(Option<bool>& playOnce,
|
||||
menu.addChild(item);
|
||||
}
|
||||
|
||||
menu.showPopup(mousePosInDisplay());
|
||||
menu.showPopup(mousePosInDisplay(), display());
|
||||
|
||||
if (isPlaying()) {
|
||||
// Re-play
|
||||
|
@ -256,7 +256,7 @@ bool StandbyState::onMouseDown(Editor* editor, MouseMessage* msg)
|
||||
if (!editor->hasSelectedSlices())
|
||||
params.set("id", base::convert_to<std::string>(hit.slice()->id()).c_str());
|
||||
AppMenuItem::setContextParams(params);
|
||||
popupMenu->showPopup(msg->position());
|
||||
popupMenu->showPopup(msg->position(), editor->display());
|
||||
AppMenuItem::setContextParams(Params());
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
@ -29,6 +29,7 @@
|
||||
#include "os/system.h"
|
||||
#include "ui/box.h"
|
||||
#include "ui/button.h"
|
||||
#include "ui/fit_bounds.h"
|
||||
#include "ui/graphics.h"
|
||||
#include "ui/listitem.h"
|
||||
#include "ui/paint_event.h"
|
||||
@ -183,15 +184,23 @@ FontPopup::FontPopup()
|
||||
m_listBox.addChild(new ListItem("No system fonts were found"));
|
||||
}
|
||||
|
||||
void FontPopup::showPopup(const gfx::Rect& bounds)
|
||||
void FontPopup::showPopup(Display* display,
|
||||
const gfx::Rect& buttonBounds)
|
||||
{
|
||||
m_popup->loadFont()->setEnabled(false);
|
||||
m_listBox.selectChild(NULL);
|
||||
|
||||
moveWindow(bounds);
|
||||
ui::fit_bounds(display, this,
|
||||
gfx::Rect(buttonBounds.x, buttonBounds.y2(), 32, 32),
|
||||
[](const gfx::Rect& workarea,
|
||||
gfx::Rect& bounds,
|
||||
std::function<gfx::Rect(Widget*)> getWidgetBounds) {
|
||||
bounds.w = workarea.w / 2;
|
||||
bounds.h = workarea.h / 2;
|
||||
});
|
||||
|
||||
// Setup the hot-region
|
||||
setHotRegion(gfx::Region(gfx::Rect(bounds).enlarge(32 * guiscale())));
|
||||
setHotRegion(gfx::Region(gfx::Rect(boundsOnScreen()).enlarge(32*guiscale()*display->scale())));
|
||||
|
||||
openWindow();
|
||||
}
|
||||
|
@ -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
|
||||
@ -26,7 +27,8 @@ namespace app {
|
||||
public:
|
||||
FontPopup();
|
||||
|
||||
void showPopup(const gfx::Rect& bounds);
|
||||
void showPopup(ui::Display* display,
|
||||
const gfx::Rect& buttonBounds);
|
||||
|
||||
obs::signal<void(const std::string&)> Load;
|
||||
|
||||
|
@ -136,7 +136,7 @@ void HomeView::onTabPopup(Workspace* workspace)
|
||||
if (!menu)
|
||||
return;
|
||||
|
||||
menu->showPopup(mousePosInDisplay());
|
||||
menu->showPopup(mousePosInDisplay(), display());
|
||||
}
|
||||
|
||||
void HomeView::onWorkspaceViewSelected()
|
||||
|
@ -40,7 +40,6 @@
|
||||
#include "app/ui_context.h"
|
||||
#include "base/fs.h"
|
||||
#include "os/system.h"
|
||||
#include "os/window.h"
|
||||
#include "ui/message.h"
|
||||
#include "ui/splitter.h"
|
||||
#include "ui/system.h"
|
||||
@ -368,13 +367,12 @@ void MainWindow::onResize(ui::ResizeEvent& ev)
|
||||
{
|
||||
app::gen::MainWindow::onResize(ev);
|
||||
|
||||
gfx::Size desktopSize = ui::get_desktop_size();
|
||||
ui::Display* display = this->display();
|
||||
if ((display) &&
|
||||
(display->nativeWindow()->scale()*ui::guiscale() > 2) &&
|
||||
(display->scale()*ui::guiscale() > 2) &&
|
||||
(!m_scalePanic) &&
|
||||
(desktopSize.w/ui::guiscale() < 320 ||
|
||||
desktopSize.h/ui::guiscale() < 260)) {
|
||||
(display->size().w / ui::guiscale() < 320 ||
|
||||
display->size().h / ui::guiscale() < 260)) {
|
||||
showNotification(m_scalePanic = new ScreenScalePanic);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2020 Igara Studio S.A.
|
||||
// Copyright (C) 2020-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -76,9 +76,11 @@ void Notifications::onClick(ui::Event& ev)
|
||||
invalidate();
|
||||
|
||||
gfx::Rect bounds = this->bounds();
|
||||
m_popup.showPopup(gfx::Point(
|
||||
m_popup.showPopup(
|
||||
gfx::Point(
|
||||
bounds.x - m_popup.sizeHint().w,
|
||||
bounds.y + bounds.h));
|
||||
bounds.y2()),
|
||||
display());
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
@ -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
|
||||
@ -22,6 +22,7 @@
|
||||
#include "app/ui_context.h"
|
||||
#include "ui/box.h"
|
||||
#include "ui/button.h"
|
||||
#include "ui/fit_bounds.h"
|
||||
#include "ui/scale.h"
|
||||
#include "ui/theme.h"
|
||||
#include "ui/view.h"
|
||||
@ -58,13 +59,21 @@ PalettePopup::PalettePopup()
|
||||
initTheme();
|
||||
}
|
||||
|
||||
void PalettePopup::showPopup(const gfx::Rect& bounds)
|
||||
void PalettePopup::showPopup(ui::Display* display,
|
||||
const gfx::Rect& buttonPos)
|
||||
{
|
||||
m_popup->loadPal()->setEnabled(false);
|
||||
m_popup->openFolder()->setEnabled(false);
|
||||
m_paletteListBox.selectChild(NULL);
|
||||
|
||||
moveWindow(bounds);
|
||||
fit_bounds(display, this,
|
||||
gfx::Rect(buttonPos.x, buttonPos.y2(), 32, 32),
|
||||
[](const gfx::Rect& workarea,
|
||||
gfx::Rect& bounds,
|
||||
std::function<gfx::Rect(Widget*)> getWidgetBounds) {
|
||||
bounds.w = workarea.w/2;
|
||||
bounds.h = workarea.h*3/4;
|
||||
});
|
||||
|
||||
openWindowInForeground();
|
||||
}
|
||||
|
@ -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
|
||||
@ -26,7 +27,8 @@ namespace app {
|
||||
public:
|
||||
PalettePopup();
|
||||
|
||||
void showPopup(const gfx::Rect& bounds);
|
||||
void showPopup(ui::Display* display,
|
||||
const gfx::Rect& buttonPos);
|
||||
|
||||
protected:
|
||||
void onPalChange(doc::Palette* palette);
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2020 Igara Studio S.A.
|
||||
// Copyright (C) 2020-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -40,8 +40,8 @@ void PopupWindowPin::setPinned(const bool pinned)
|
||||
if (m_pinned)
|
||||
makeFloating();
|
||||
else {
|
||||
gfx::Rect rc = bounds();
|
||||
rc.enlarge(8);
|
||||
gfx::Rect rc = boundsOnScreen();
|
||||
rc.enlarge(8 * guiscale());
|
||||
setHotRegion(gfx::Region(rc));
|
||||
makeFixed();
|
||||
}
|
||||
|
@ -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
|
||||
@ -33,6 +33,7 @@
|
||||
#include "ui/base.h"
|
||||
#include "ui/button.h"
|
||||
#include "ui/close_event.h"
|
||||
#include "ui/fit_bounds.h"
|
||||
#include "ui/message.h"
|
||||
#include "ui/system.h"
|
||||
|
||||
@ -219,25 +220,27 @@ bool PreviewEditorWindow::onProcessMessage(ui::Message* msg)
|
||||
{
|
||||
switch (msg->type()) {
|
||||
|
||||
case kOpenMessage:
|
||||
{
|
||||
SkinTheme* theme = SkinTheme::instance();
|
||||
case kOpenMessage: {
|
||||
Manager* manager = this->manager();
|
||||
Display* mainDisplay = manager->display();
|
||||
|
||||
// Default bounds
|
||||
gfx::Size desktopSize = ui::get_desktop_size();
|
||||
const int width = desktopSize.w/4;
|
||||
const int height = desktopSize.h/4;
|
||||
int extra = 2*theme->dimensions.miniScrollbarSize();
|
||||
setBounds(
|
||||
gfx::Rect(
|
||||
desktopSize.w - width - ToolBar::instance()->bounds().w - extra,
|
||||
desktopSize.h - height - StatusBar::instance()->bounds().h - extra,
|
||||
width, height));
|
||||
gfx::Rect defaultBounds(mainDisplay->size() / 4);
|
||||
SkinTheme* theme = SkinTheme::instance();
|
||||
gfx::Rect mainWindow = manager->bounds();
|
||||
|
||||
load_window_pos(this, "MiniEditor", false);
|
||||
invalidate();
|
||||
int extra = theme->dimensions.miniScrollbarSize();
|
||||
if (get_multiple_displays()) {
|
||||
extra *= mainDisplay->scale();
|
||||
}
|
||||
defaultBounds.x = mainWindow.x2() - ToolBar::instance()->sizeHint().w - defaultBounds.w - extra;
|
||||
defaultBounds.y = mainWindow.y2() - StatusBar::instance()->sizeHint().h - defaultBounds.h - extra;
|
||||
|
||||
fit_bounds(mainDisplay, this, defaultBounds);
|
||||
|
||||
load_window_pos(this, "MiniEditor", false);
|
||||
invalidate();
|
||||
break;
|
||||
}
|
||||
|
||||
case kCloseMessage:
|
||||
save_window_pos(this, "MiniEditor");
|
||||
|
@ -878,6 +878,8 @@ void StatusBar::showSnapToGridWarning(bool state)
|
||||
if (!m_snapToGridWindow)
|
||||
m_snapToGridWindow = new SnapToGridWindow;
|
||||
|
||||
m_snapToGridWindow->setDisplay(display(), false);
|
||||
|
||||
if (!m_snapToGridWindow->isVisible()) {
|
||||
m_snapToGridWindow->openWindow();
|
||||
m_snapToGridWindow->remapWindow();
|
||||
|
@ -1243,12 +1243,12 @@ bool Timeline::onProcessMessage(Message* msg)
|
||||
if (!m_confPopup->isVisible()) {
|
||||
gfx::Rect bounds = m_confPopup->bounds();
|
||||
ui::fit_bounds(display(), BOTTOM, gearBounds, bounds);
|
||||
|
||||
m_confPopup->moveWindow(bounds);
|
||||
ui::fit_bounds(display(), m_confPopup, bounds);
|
||||
m_confPopup->openWindow();
|
||||
}
|
||||
else
|
||||
m_confPopup->closeWindow(NULL);
|
||||
else {
|
||||
m_confPopup->closeWindow(nullptr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1258,7 +1258,7 @@ bool Timeline::onProcessMessage(Message* msg)
|
||||
if (m_clk.frame == m_hot.frame) {
|
||||
Menu* popupMenu = AppMenus::instance()->getFramePopupMenu();
|
||||
if (popupMenu) {
|
||||
popupMenu->showPopup(mouseMsg->position());
|
||||
popupMenu->showPopup(mouseMsg->position(), display());
|
||||
|
||||
m_state = STATE_STANDBY;
|
||||
invalidate();
|
||||
@ -1273,7 +1273,7 @@ bool Timeline::onProcessMessage(Message* msg)
|
||||
if (m_clk.layer == m_hot.layer) {
|
||||
Menu* popupMenu = AppMenus::instance()->getLayerPopupMenu();
|
||||
if (popupMenu) {
|
||||
popupMenu->showPopup(mouseMsg->position());
|
||||
popupMenu->showPopup(mouseMsg->position(), display());
|
||||
|
||||
m_state = STATE_STANDBY;
|
||||
invalidate();
|
||||
@ -1293,7 +1293,7 @@ bool Timeline::onProcessMessage(Message* msg)
|
||||
AppMenus::instance()->getCelMovementPopupMenu():
|
||||
AppMenus::instance()->getCelPopupMenu();
|
||||
if (popupMenu) {
|
||||
popupMenu->showPopup(mouseMsg->position());
|
||||
popupMenu->showPopup(mouseMsg->position(), display());
|
||||
|
||||
// Do not drop in this function, the drop is done from
|
||||
// the menu in case we've used the
|
||||
@ -1321,7 +1321,7 @@ bool Timeline::onProcessMessage(Message* msg)
|
||||
Menu* popupMenu = AppMenus::instance()->getTagPopupMenu();
|
||||
if (popupMenu) {
|
||||
AppMenuItem::setContextParams(params);
|
||||
popupMenu->showPopup(mouseMsg->position());
|
||||
popupMenu->showPopup(mouseMsg->position(), display());
|
||||
AppMenuItem::setContextParams(Params());
|
||||
|
||||
m_state = STATE_STANDBY;
|
||||
|
@ -376,7 +376,7 @@ bool ComboBox::onProcessMessage(Message* msg)
|
||||
|
||||
MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
|
||||
Widget* pick = manager()->pickFromScreenPos(
|
||||
display()->nativeWindow()->pointFromScreen(mouseMsg->position()));
|
||||
mouseMsg->display()->nativeWindow()->pointFromScreen(mouseMsg->position()));
|
||||
if (pick && pick->hasAncestor(this))
|
||||
return true;
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ namespace ui {
|
||||
os::Window* nativeWindow() { return m_nativeWindow.get(); }
|
||||
os::Surface* surface() const;
|
||||
|
||||
int scale() const { return m_nativeWindow->scale(); }
|
||||
gfx::Size size() const;
|
||||
gfx::Rect bounds() const { return gfx::Rect(size()); }
|
||||
|
||||
|
@ -819,7 +819,7 @@ void Entry::showEditPopupMenu(const gfx::Point& pt)
|
||||
paste.setEnabled(false);
|
||||
}
|
||||
|
||||
menu.showPopup(pt);
|
||||
menu.showPopup(pt, display());
|
||||
}
|
||||
|
||||
class Entry::CalcBoxesTextDelegate : public os::DrawTextDelegate {
|
||||
|
@ -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-2016 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -16,6 +16,7 @@
|
||||
#include "ui/base.h"
|
||||
#include "ui/display.h"
|
||||
#include "ui/system.h"
|
||||
#include "ui/window.h"
|
||||
|
||||
namespace ui {
|
||||
|
||||
@ -87,4 +88,50 @@ int fit_bounds(Display* display, int arrowAlign, const gfx::Rect& target, gfx::R
|
||||
return arrowAlign;
|
||||
}
|
||||
|
||||
void fit_bounds(Display* parentDisplay,
|
||||
Window* window,
|
||||
const gfx::Rect& candidateBoundsRelativeToParentDisplay,
|
||||
std::function<void(const gfx::Rect& workarea,
|
||||
gfx::Rect& bounds,
|
||||
std::function<gfx::Rect(Widget*)> getWidgetBounds)> fitLogic)
|
||||
{
|
||||
gfx::Point pos = candidateBoundsRelativeToParentDisplay.origin();
|
||||
|
||||
if (get_multiple_displays() && window->shouldCreateNativeWindow()) {
|
||||
const os::Window* nativeWindow = parentDisplay->nativeWindow();
|
||||
const gfx::Rect workarea = nativeWindow->screen()->workarea();
|
||||
const int scale = nativeWindow->scale();
|
||||
|
||||
// Screen frame bounds
|
||||
gfx::Rect frame(
|
||||
nativeWindow->pointToScreen(pos),
|
||||
candidateBoundsRelativeToParentDisplay.size() * scale);
|
||||
|
||||
if (fitLogic)
|
||||
fitLogic(workarea, frame, [](Widget* widget){ return widget->boundsOnScreen(); });
|
||||
|
||||
frame.x = base::clamp(frame.x, workarea.x, workarea.x2() - frame.w);
|
||||
frame.y = base::clamp(frame.y, workarea.y, workarea.y2() - frame.h);
|
||||
|
||||
// Set frame bounds directly
|
||||
window->setBounds(gfx::Rect(0, 0, frame.w / scale, frame.h / scale));
|
||||
window->loadNativeFrame(frame);
|
||||
|
||||
if (window->isVisible())
|
||||
window->expandWindow(frame.size() / scale);
|
||||
}
|
||||
else {
|
||||
const gfx::Rect displayBounds(parentDisplay->size());
|
||||
gfx::Rect frame(candidateBoundsRelativeToParentDisplay);
|
||||
|
||||
if (fitLogic)
|
||||
fitLogic(displayBounds, frame, [](Widget* widget){ return widget->bounds(); });
|
||||
|
||||
frame.x = base::clamp(frame.x, 0, displayBounds.w - frame.w);
|
||||
frame.y = base::clamp(frame.y, 0, displayBounds.h - frame.h);
|
||||
|
||||
window->setBounds(frame);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ui
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite UI Library
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2016 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -11,12 +11,32 @@
|
||||
|
||||
#include "gfx/fwd.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace ui {
|
||||
|
||||
class Display;
|
||||
class Widget;
|
||||
class Window;
|
||||
|
||||
int fit_bounds(Display* display, int arrowAlign, const gfx::Rect& target, gfx::Rect& bounds);
|
||||
|
||||
// Fits a possible rectangle for the given window fitting it with a
|
||||
// special logic. It works for both cases:
|
||||
// 1. With multiple windows (so the limit is the parentDisplay screen workarea)
|
||||
// 2. Or with one window (so the limit is the just display area)
|
||||
//
|
||||
// The getWidgetBounds() can be used to get other widgets positions
|
||||
// in the "fitLogic" (the bounds will be relative to the screen or
|
||||
// to the display depending if get_multiple_displays() is true or
|
||||
// false).
|
||||
void fit_bounds(Display* parentDisplay,
|
||||
Window* window,
|
||||
const gfx::Rect& candidateBoundsRelativeToParentDisplay,
|
||||
std::function<void(const gfx::Rect& workarea,
|
||||
gfx::Rect& bounds,
|
||||
std::function<gfx::Rect(Widget*)> getWidgetBounds)> fitLogic = nullptr);
|
||||
|
||||
} // namespace ui
|
||||
|
||||
#endif
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "gfx/rect.h"
|
||||
#include "gfx/region.h"
|
||||
#include "os/font.h"
|
||||
#include "ui/fit_bounds.h"
|
||||
#include "ui/manager.h"
|
||||
#include "ui/message.h"
|
||||
#include "ui/popup_window.h"
|
||||
@ -182,20 +183,28 @@ void IntEntry::openPopup()
|
||||
m_popupWindow->addChild(&m_slider);
|
||||
m_popupWindow->Close.connect(&IntEntry::onPopupClose, this);
|
||||
|
||||
Rect rc = bounds();
|
||||
gfx::Size sz = m_popupWindow->sizeHint();
|
||||
gfx::Size displaySize = display()->size();
|
||||
rc.w = 128*guiscale();
|
||||
if (rc.x+rc.w > displaySize.w)
|
||||
rc.x = rc.x-rc.w+bounds().w;
|
||||
if (rc.y+rc.h+sz.h < displaySize.h)
|
||||
rc.y += rc.h;
|
||||
else
|
||||
rc.y -= sz.h;
|
||||
m_popupWindow->setBounds(rc);
|
||||
fit_bounds(
|
||||
display(),
|
||||
m_popupWindow,
|
||||
gfx::Rect(0, 0, 128*guiscale(), m_popupWindow->sizeHint().h),
|
||||
[this](const gfx::Rect& workarea,
|
||||
gfx::Rect& rc,
|
||||
std::function<gfx::Rect(Widget*)> getWidgetBounds) {
|
||||
Rect entryBounds = getWidgetBounds(this);
|
||||
|
||||
Region rgn(rc.createUnion(bounds()));
|
||||
rgn.createUnion(rgn, Region(bounds()));
|
||||
rc.x = entryBounds.x;
|
||||
rc.y = entryBounds.y2();
|
||||
|
||||
if (rc.x2() > workarea.x2())
|
||||
rc.x = rc.x-rc.w+entryBounds.w;
|
||||
|
||||
if (rc.y2() > workarea.y2())
|
||||
rc.y = entryBounds.y-entryBounds.h;
|
||||
|
||||
m_popupWindow->setBounds(rc);
|
||||
});
|
||||
|
||||
Region rgn(m_popupWindow->boundsOnScreen().createUnion(boundsOnScreen()));
|
||||
m_popupWindow->setHotRegion(rgn);
|
||||
|
||||
m_popupWindow->openWindow();
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "base/time.h"
|
||||
#include "os/event.h"
|
||||
#include "os/event_queue.h"
|
||||
#include "os/screen.h"
|
||||
#include "os/surface.h"
|
||||
#include "os/system.h"
|
||||
#include "os/window.h"
|
||||
@ -1132,6 +1133,21 @@ void Manager::removeMessagesForTimer(Timer* timer)
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::removeMessagesForDisplay(Display* display)
|
||||
{
|
||||
#ifdef DEBUG_UI_THREADS
|
||||
ASSERT(manager_thread == base::this_thread::native_id());
|
||||
#endif
|
||||
|
||||
for (Message* msg : msg_queue)
|
||||
if (msg->display() == display)
|
||||
msg->removeRecipient(msg->recipient());
|
||||
|
||||
for (Message* msg : used_msg_queue)
|
||||
if (msg->display() == display)
|
||||
msg->removeRecipient(msg->recipient());
|
||||
}
|
||||
|
||||
void Manager::removePaintMessagesForDisplay(Display* display)
|
||||
{
|
||||
#ifdef DEBUG_UI_THREADS
|
||||
@ -1141,7 +1157,7 @@ void Manager::removePaintMessagesForDisplay(Display* display)
|
||||
for (auto it=msg_queue.begin(); it != msg_queue.end(); ) {
|
||||
Message* msg = *it;
|
||||
if (msg->type() == kPaintMessage &&
|
||||
static_cast<PaintMessage*>(msg)->display() == display) {
|
||||
msg->display() == display) {
|
||||
delete msg;
|
||||
it = msg_queue.erase(it);
|
||||
}
|
||||
@ -1269,22 +1285,18 @@ void Manager::_openWindow(Window* window, bool center)
|
||||
|
||||
// Relayout
|
||||
if (center)
|
||||
window->centerWindow();
|
||||
window->centerWindow(parentDisplay);
|
||||
else
|
||||
window->layout();
|
||||
|
||||
// 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) {
|
||||
if (!window->hasDisplaySet()) {
|
||||
// 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
|
||||
) {
|
||||
&& window->shouldCreateNativeWindow()) {
|
||||
const int scale = parentDisplay->nativeWindow()->scale();
|
||||
|
||||
os::WindowSpec spec;
|
||||
@ -1298,6 +1310,31 @@ void Manager::_openWindow(Window* window, bool center)
|
||||
frame *= scale;
|
||||
frame.offset(relativeToFrame.origin());
|
||||
}
|
||||
|
||||
// Limit window position using the union of all workareas
|
||||
//
|
||||
// TODO at least the title bar should be visible so we can
|
||||
// resize it, because workareas can form an irregular shape
|
||||
// (not rectangular) the calculation is a little more
|
||||
// complex
|
||||
{
|
||||
gfx::Region wa;
|
||||
os::ScreenList screens;
|
||||
os::instance()->listScreens(screens);
|
||||
for (const auto& screen : screens)
|
||||
wa |= gfx::Region(screen->workarea());
|
||||
|
||||
// TODO use a "visibleFrameRegion = frame & wa" to check the
|
||||
// visible regions and calculate if we should move the frame
|
||||
// position
|
||||
|
||||
gfx::Rect waBounds = wa.bounds();
|
||||
if (frame.x < waBounds.x) frame.x = waBounds.x;
|
||||
if (frame.y < waBounds.y) frame.y = waBounds.y;
|
||||
if (frame.x2() > waBounds.x2()) frame.w -= frame.x2() - waBounds.x2();
|
||||
if (frame.y2() > waBounds.y2()) frame.h -= frame.y2() - waBounds.y2();
|
||||
}
|
||||
|
||||
spec.position(os::WindowSpec::Position::Frame);
|
||||
spec.frame(frame);
|
||||
spec.scale(scale);
|
||||
@ -1374,8 +1411,8 @@ void Manager::_closeWindow(Window* window, bool redraw_background)
|
||||
ASSERT(windowDisplay);
|
||||
ASSERT(windowDisplay != this->display());
|
||||
|
||||
// Remove all paint messages for this display.
|
||||
removePaintMessagesForDisplay(windowDisplay);
|
||||
// Remove all messages for this display.
|
||||
removeMessagesForDisplay(windowDisplay);
|
||||
|
||||
window->setDisplay(nullptr, false);
|
||||
windowDisplay->nativeWindow()->setUserData<void*>(nullptr);
|
||||
|
@ -80,6 +80,7 @@ namespace ui {
|
||||
void removeMessagesFor(Widget* widget);
|
||||
void removeMessagesFor(Widget* widget, MessageType type);
|
||||
void removeMessagesForTimer(Timer* timer);
|
||||
void removeMessagesForDisplay(Display* display);
|
||||
void removePaintMessagesForDisplay(Display* display);
|
||||
|
||||
void addMessageFilter(int message, Widget* widget);
|
||||
|
@ -292,7 +292,8 @@ bool MenuItem::hasSubmenu() const
|
||||
return (m_submenu && !m_submenu->children().empty());
|
||||
}
|
||||
|
||||
void Menu::showPopup(const gfx::Point& pos)
|
||||
void Menu::showPopup(const gfx::Point& pos,
|
||||
Display* parentDisplay)
|
||||
{
|
||||
// Generally, when we call showPopup() the menu shouldn't contain a
|
||||
// parent menu-box, because we're filtering kMouseDownMessage to
|
||||
@ -322,11 +323,9 @@ void Menu::showPopup(const gfx::Point& pos)
|
||||
|
||||
window->remapWindow();
|
||||
|
||||
// Menubox position
|
||||
gfx::Size displaySize = display()->size();
|
||||
window->positionWindow(
|
||||
base::clamp(pos.x, 0, displaySize.w - window->bounds().w),
|
||||
base::clamp(pos.y, 0, displaySize.h - window->bounds().h));
|
||||
fit_bounds(parentDisplay,
|
||||
window.get(),
|
||||
gfx::Rect(pos, window->size()));
|
||||
|
||||
add_scrollbars_if_needed(window.get());
|
||||
|
||||
@ -442,20 +441,20 @@ bool MenuBox::onProcessMessage(Message* msg)
|
||||
|
||||
case kMouseDownMessage:
|
||||
case kDoubleClickMessage:
|
||||
if (menu) {
|
||||
if (menu && msg->display()) {
|
||||
ASSERT(menu->parent() == this);
|
||||
|
||||
if (get_base(this)->is_processing)
|
||||
break;
|
||||
|
||||
gfx::Point mousePos = static_cast<MouseMessage*>(msg)->position();
|
||||
const gfx::Point mousePos = static_cast<MouseMessage*>(msg)->position();
|
||||
const gfx::Point screenPos = msg->display()->nativeWindow()->pointToScreen(mousePos);
|
||||
|
||||
// Here we catch the filtered messages (menu-bar or the
|
||||
// popuped menu-box) to detect if the user press outside of
|
||||
// the widget
|
||||
if (msg->type() == kMouseDownMessage && m_base != nullptr) {
|
||||
Widget* picked = manager()->pickFromScreenPos(
|
||||
display()->nativeWindow()->pointToScreen(mousePos));
|
||||
Widget* picked = manager()->pickFromScreenPos(screenPos);
|
||||
|
||||
// If one of these conditions are accomplished we have to
|
||||
// close all menus (back to menu-bar or close the popuped
|
||||
@ -466,16 +465,17 @@ bool MenuBox::onProcessMessage(Message* msg)
|
||||
(get_base_menubox(picked) != this ||
|
||||
(this->type() == kMenuBarWidget &&
|
||||
picked->type() == kMenuWidget))) {
|
||||
|
||||
// The user click outside all the menu-box/menu-items, close all
|
||||
menu->closeAll();
|
||||
|
||||
// Change to "return false" if you want to send the click
|
||||
// to the window after closing all menus.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the widget below the mouse cursor
|
||||
Widget* picked = menu->pick(mousePos);
|
||||
if (picked) {
|
||||
if (Widget* picked = menu->pickFromScreenPos(screenPos)) {
|
||||
if ((picked->type() == kMenuItemWidget) &&
|
||||
!(picked->hasFlags(DISABLED))) {
|
||||
MenuItem* pickedItem = static_cast<MenuItem*>(picked);
|
||||
@ -814,9 +814,6 @@ bool MenuItem::onProcessMessage(Message* msg)
|
||||
ASSERT(base->is_processing);
|
||||
ASSERT(hasSubmenu());
|
||||
|
||||
Rect old_pos = window()->bounds();
|
||||
old_pos.w -= 1*guiscale();
|
||||
|
||||
MenuBox* menubox = new MenuBox();
|
||||
m_submenu_menubox = menubox;
|
||||
menubox->setMenu(m_submenu);
|
||||
@ -824,42 +821,47 @@ bool MenuItem::onProcessMessage(Message* msg)
|
||||
// New window and new menu-box
|
||||
auto window = new MenuBoxWindow(menubox);
|
||||
|
||||
// Menubox position
|
||||
Rect pos = window->bounds();
|
||||
Size displaySize = display()->size();
|
||||
fit_bounds(
|
||||
display(), window, window->bounds(),
|
||||
[this](const gfx::Rect& workarea,
|
||||
gfx::Rect& pos,
|
||||
std::function<gfx::Rect(Widget*)> getWidgetBounds){
|
||||
Rect parentPos = getWidgetBounds(this->window());
|
||||
Rect bounds = getWidgetBounds(this);
|
||||
|
||||
if (inBar()) {
|
||||
pos.x = base::clamp(bounds().x, 0, displaySize.w-pos.w);
|
||||
pos.y = std::max(0, bounds().y2());
|
||||
}
|
||||
else {
|
||||
int x_left = old_pos.x - pos.w;
|
||||
int x_right = old_pos.x2();
|
||||
int x, y = bounds().y-3*guiscale();
|
||||
Rect r1(0, 0, pos.w, pos.h), r2(0, 0, pos.w, pos.h);
|
||||
if (inBar()) {
|
||||
pos.x = base::clamp(bounds.x, workarea.x, workarea.x2()-pos.w);
|
||||
pos.y = std::max(workarea.y, bounds.y2());
|
||||
}
|
||||
else {
|
||||
int x_left = parentPos.x - pos.w + 1*guiscale();
|
||||
int x_right = parentPos.x2() - 1*guiscale();
|
||||
int x, y = bounds.y-3*guiscale();
|
||||
Rect r1(0, 0, pos.w, pos.h);
|
||||
Rect r2(0, 0, pos.w, pos.h);
|
||||
|
||||
r1.x = x_left = base::clamp(x_left, 0, displaySize.w-pos.w);
|
||||
r2.x = x_right = base::clamp(x_right, 0, displaySize.w-pos.w);
|
||||
r1.y = r2.y = y = base::clamp(y, 0, displaySize.h-pos.h);
|
||||
r1.x = x_left = base::clamp(x_left, 0, workarea.w-pos.w);
|
||||
r2.x = x_right = base::clamp(x_right, 0, workarea.w-pos.w);
|
||||
r1.y = r2.y = y = base::clamp(y, 0, workarea.h-pos.h);
|
||||
|
||||
// Calculate both intersections
|
||||
gfx::Rect s1 = r1.createIntersection(old_pos);
|
||||
gfx::Rect s2 = r2.createIntersection(old_pos);
|
||||
// Calculate both intersections
|
||||
const gfx::Rect s1 = r1.createIntersection(parentPos);
|
||||
const gfx::Rect s2 = r2.createIntersection(parentPos);
|
||||
|
||||
if (s2.isEmpty())
|
||||
x = x_right; // Use the right because there aren't intersection with it
|
||||
else if (s1.isEmpty())
|
||||
x = x_left; // Use the left because there are not intersection
|
||||
else if (r2.w*r2.h <= r1.w*r1.h)
|
||||
x = x_right; // Use the right because there are less intersection area
|
||||
else
|
||||
x = x_left; // Use the left because there are less intersection area
|
||||
if (s2.isEmpty())
|
||||
x = x_right; // Use the right because there aren't intersection with it
|
||||
else if (s1.isEmpty())
|
||||
x = x_left; // Use the left because there are not intersection
|
||||
else if (s2.w*s2.h <= s1.w*s1.h)
|
||||
x = x_right; // Use the right because there are less intersection area
|
||||
else
|
||||
x = x_left; // Use the left because there are less intersection area
|
||||
|
||||
pos.x = x;
|
||||
pos.y = y;
|
||||
}
|
||||
pos.x = x;
|
||||
pos.y = y;
|
||||
}
|
||||
});
|
||||
|
||||
window->positionWindow(pos.x, pos.y);
|
||||
add_scrollbars_if_needed(window);
|
||||
|
||||
// Set the focus to the new menubox
|
||||
@ -1133,7 +1135,7 @@ void Menu::unhighlightItem()
|
||||
highlightItem(nullptr, false, false, false);
|
||||
}
|
||||
|
||||
bool MenuItem::inBar()
|
||||
bool MenuItem::inBar() const
|
||||
{
|
||||
return
|
||||
(parent() &&
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite UI Library
|
||||
// Copyright (C) 2020 Igara Studio S.A.
|
||||
// Copyright (C) 2020-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -28,7 +28,8 @@ namespace ui {
|
||||
Menu();
|
||||
~Menu();
|
||||
|
||||
void showPopup(const gfx::Point& pos);
|
||||
void showPopup(const gfx::Point& pos,
|
||||
Display* parentDisplay);
|
||||
Widget* findItemById(const char* id);
|
||||
|
||||
// Returns the MenuItem that has as submenu this menu.
|
||||
@ -141,7 +142,7 @@ namespace ui {
|
||||
virtual void onClick();
|
||||
virtual void onValidate();
|
||||
|
||||
bool inBar();
|
||||
bool inBar() const;
|
||||
|
||||
private:
|
||||
void openSubmenu(bool select_first);
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite UI Library
|
||||
// Copyright (C) 2020 Igara Studio S.A.
|
||||
// Copyright (C) 2020-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -27,8 +27,6 @@ PopupWindow::PopupWindow(const std::string& text,
|
||||
: Window(text.empty() ? WithoutTitleBar: WithTitleBar, text)
|
||||
, m_clickBehavior(clickBehavior)
|
||||
, m_enterBehavior(enterBehavior)
|
||||
, m_filtering(false)
|
||||
, m_fixed(false)
|
||||
{
|
||||
setSizeable(false);
|
||||
setMoveable(false);
|
||||
@ -53,11 +51,11 @@ PopupWindow::~PopupWindow()
|
||||
stopFilteringMessages();
|
||||
}
|
||||
|
||||
void PopupWindow::setHotRegion(const gfx::Region& region)
|
||||
void PopupWindow::setHotRegion(const gfx::Region& screenRegion)
|
||||
{
|
||||
startFilteringMessages();
|
||||
|
||||
m_hotRegion = region;
|
||||
m_hotRegion = screenRegion;
|
||||
}
|
||||
|
||||
void PopupWindow::setClickBehavior(ClickBehavior behavior)
|
||||
@ -137,26 +135,30 @@ bool PopupWindow::onProcessMessage(Message* msg)
|
||||
|
||||
case kMouseDownMessage:
|
||||
if (m_filtering &&
|
||||
manager()->getTopWindow() == this) {
|
||||
manager()->getTopWindow() == this &&
|
||||
msg->display()) {
|
||||
gfx::Point mousePos = static_cast<MouseMessage*>(msg)->position();
|
||||
gfx::Point screenPos = msg->display()->nativeWindow()->pointToScreen(mousePos);
|
||||
|
||||
switch (m_clickBehavior) {
|
||||
|
||||
// If the user click outside the window, we have to close
|
||||
// the tooltip window.
|
||||
case ClickBehavior::CloseOnClickInOtherWindow: {
|
||||
Widget* picked = pick(mousePos);
|
||||
Widget* picked = pickFromScreenPos(screenPos);
|
||||
if (!picked || picked->window() != this) {
|
||||
closeWindow(nullptr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ClickBehavior::CloseOnClickOutsideHotRegion:
|
||||
if (!m_hotRegion.contains(mousePos)) {
|
||||
case ClickBehavior::CloseOnClickOutsideHotRegion: {
|
||||
// Convert the mousePos from display() coordinates to screen
|
||||
if (!m_hotRegion.contains(screenPos)) {
|
||||
closeWindow(nullptr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -164,12 +166,14 @@ bool PopupWindow::onProcessMessage(Message* msg)
|
||||
case kMouseMoveMessage:
|
||||
if (m_fixed &&
|
||||
!m_hotRegion.isEmpty() &&
|
||||
manager()->getCapture() == nullptr) {
|
||||
manager()->getCapture() == nullptr &&
|
||||
msg->display()) {
|
||||
gfx::Point mousePos = static_cast<MouseMessage*>(msg)->position();
|
||||
gfx::Point screenPos = msg->display()->nativeWindow()->pointToScreen(mousePos);
|
||||
|
||||
// If the mouse is outside the hot-region we have to close the
|
||||
// window.
|
||||
if (!m_hotRegion.contains(mousePos))
|
||||
if (!m_hotRegion.contains(screenPos))
|
||||
closeWindow(nullptr);
|
||||
}
|
||||
break;
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite UI Library
|
||||
// Copyright (C) 2021 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -33,7 +34,10 @@ namespace ui {
|
||||
|
||||
// Sets the hot region. This region indicates the area where the
|
||||
// mouse can be located and the window will be kept open.
|
||||
void setHotRegion(const gfx::Region& region);
|
||||
//
|
||||
// The screenRegion must be specified in native screen coordinates.
|
||||
void setHotRegion(const gfx::Region& screenRegion);
|
||||
|
||||
void setClickBehavior(ClickBehavior behavior);
|
||||
void setEnterBehavior(EnterBehavior behavior);
|
||||
|
||||
@ -54,8 +58,8 @@ namespace ui {
|
||||
ClickBehavior m_clickBehavior;
|
||||
EnterBehavior m_enterBehavior;
|
||||
gfx::Region m_hotRegion;
|
||||
bool m_filtering;
|
||||
bool m_fixed;
|
||||
bool m_filtering = false;
|
||||
bool m_fixed = false;
|
||||
};
|
||||
|
||||
class TransparentPopupWindow : public PopupWindow {
|
||||
|
@ -698,6 +698,16 @@ Rect Widget::clientChildrenBounds() const
|
||||
m_bounds.h - border().height());
|
||||
}
|
||||
|
||||
gfx::Rect Widget::boundsOnScreen() const
|
||||
{
|
||||
gfx::Rect rc = bounds();
|
||||
os::Window* nativeWindow = display()->nativeWindow();
|
||||
rc = gfx::Rect(
|
||||
nativeWindow->pointToScreen(rc.origin()),
|
||||
nativeWindow->pointToScreen(rc.point2()));
|
||||
return rc;
|
||||
}
|
||||
|
||||
void Widget::setBounds(const Rect& rc)
|
||||
{
|
||||
ResizeEvent ev(this, rc);
|
||||
|
@ -242,6 +242,9 @@ namespace ui {
|
||||
gfx::Rect childrenBounds() const;
|
||||
gfx::Rect clientChildrenBounds() const;
|
||||
|
||||
// Bounds of this widget or window on native screen/desktop coordinates.
|
||||
gfx::Rect boundsOnScreen() const;
|
||||
|
||||
// Sets the bounds of the widget generating a onResize() event.
|
||||
void setBounds(const gfx::Rect& rc);
|
||||
|
||||
|
@ -309,19 +309,24 @@ void Window::remapWindow()
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void Window::centerWindow()
|
||||
void Window::centerWindow(Display* parentDisplay)
|
||||
{
|
||||
Widget* manager = this->manager();
|
||||
|
||||
if (m_isAutoRemap)
|
||||
remapWindow();
|
||||
|
||||
positionWindow(manager->bounds().w/2 - bounds().w/2,
|
||||
manager->bounds().h/2 - bounds().h/2);
|
||||
if (!parentDisplay)
|
||||
parentDisplay = manager()->getDefault()->display();
|
||||
|
||||
gfx::Size displaySize = parentDisplay->size();
|
||||
positionWindow(displaySize.w/2 - bounds().w/2,
|
||||
displaySize.h/2 - bounds().h/2);
|
||||
}
|
||||
|
||||
void Window::positionWindow(int x, int y)
|
||||
{
|
||||
// TODO don't use in ownDisplay() windows
|
||||
ASSERT(!ownDisplay());
|
||||
|
||||
if (m_isAutoRemap)
|
||||
remapWindow();
|
||||
|
||||
@ -437,6 +442,12 @@ bool Window::onProcessMessage(Message* msg)
|
||||
}
|
||||
if (action != os::WindowAction::Cancel) {
|
||||
display()->nativeWindow()->performWindowAction(action, nullptr);
|
||||
|
||||
// As Window::moveWindow() will not be called, we have to
|
||||
// call onWindowMovement() event from here.
|
||||
if (action == os::WindowAction::Move)
|
||||
onWindowMovement();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ namespace ui {
|
||||
bool ownDisplay() const { return m_ownDisplay; }
|
||||
Display* display() const;
|
||||
void setDisplay(Display* display, const bool own);
|
||||
bool hasDisplaySet() const { return m_display != nullptr; }
|
||||
|
||||
Widget* closer() const { return m_closer; }
|
||||
|
||||
@ -41,7 +42,7 @@ namespace ui {
|
||||
void setWantFocus(bool state);
|
||||
|
||||
void remapWindow();
|
||||
void centerWindow();
|
||||
void centerWindow(Display* parentDisplay = nullptr);
|
||||
void positionWindow(int x, int y);
|
||||
void moveWindow(const gfx::Rect& rect);
|
||||
|
||||
@ -60,6 +61,11 @@ namespace ui {
|
||||
bool isSizeable() const { return m_isSizeable; }
|
||||
bool isMoveable() const { return m_isMoveable; }
|
||||
|
||||
bool shouldCreateNativeWindow() const {
|
||||
return (!isDesktop() &&
|
||||
!isTransparent());
|
||||
}
|
||||
|
||||
HitTest hitTest(const gfx::Point& point);
|
||||
|
||||
// Last native window frame bounds. Saved just before we close the
|
||||
|
Loading…
x
Reference in New Issue
Block a user