Fix default menu positions with (and without) multiple windows

This commit is contained in:
David Capello 2021-04-20 18:40:06 -03:00
parent 0d7fea3111
commit 5aa765a942

View File

@ -100,32 +100,67 @@ static MenuItem* check_for_letter(Menu* menu, const KeyMessage* keymsg);
static MenuItem* find_nextitem(Menu* menu, MenuItem* menuitem); static MenuItem* find_nextitem(Menu* menu, MenuItem* menuitem);
static MenuItem* find_previtem(Menu* menu, MenuItem* menuitem); static MenuItem* find_previtem(Menu* menu, MenuItem* menuitem);
static void add_scrollbars_if_needed(Window* window) static void choose_side(gfx::Rect& bounds,
const gfx::Rect& workarea,
const gfx::Rect& parentBounds)
{ {
const gfx::Rect rc0 = window->bounds(); int scale = guiscale();
gfx::Size displaySize = window->display()->size(); if (get_multiple_displays())
gfx::Rect rc = rc0; scale = Manager::getDefault()->display()->scale();
if (rc.x < 0) { int x_left = parentBounds.x - bounds.w + 1*scale;
rc.w += rc.x; int x_right = parentBounds.x2() - 1*scale;
rc.x = 0; int x, y = bounds.y;
Rect r1(0, 0, bounds.w, bounds.h);
Rect r2(0, 0, bounds.w, bounds.h);
r1.x = x_left = base::clamp(x_left, workarea.x, workarea.x2()-bounds.w);
r2.x = x_right = base::clamp(x_right, workarea.x, workarea.x2()-bounds.w);
r1.y = r2.y = y = base::clamp(y, workarea.y, workarea.y2()-bounds.h);
// Calculate both intersections
const gfx::Rect s1 = r1.createIntersection(parentBounds);
const gfx::Rect s2 = r2.createIntersection(parentBounds);
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
bounds.x = x;
bounds.y = y;
}
static void add_scrollbars_if_needed(Window* window,
const gfx::Rect& workarea,
gfx::Rect& bounds)
{
gfx::Rect rc = bounds;
if (rc.x < workarea.x) {
rc.w -= (workarea.x - rc.x);
rc.x = workarea.x;
} }
if (rc.x2() > displaySize.w) { if (rc.x2() > workarea.x2()) {
rc.w = displaySize.w - rc.x; rc.w = workarea.x2() - rc.x;
} }
bool vscrollbarsAdded = false; bool vscrollbarsAdded = false;
if (rc.y < 0) { if (rc.y < workarea.y) {
rc.h += rc.y; rc.h -= (workarea.y - rc.y);
rc.y = 0; rc.y = workarea.y;
vscrollbarsAdded = true; vscrollbarsAdded = true;
} }
if (rc.y2() > displaySize.h) { if (rc.y2() > workarea.y2()) {
rc.h = displaySize.h - rc.y; rc.h = workarea.y2() - rc.y;
vscrollbarsAdded = true; vscrollbarsAdded = true;
} }
if (rc == rc0) if (rc == bounds)
return; return;
Widget* menubox = window->firstChild(); Widget* menubox = window->firstChild();
@ -134,17 +169,22 @@ static void add_scrollbars_if_needed(Window* window)
view->initTheme(); view->initTheme();
if (vscrollbarsAdded) { if (vscrollbarsAdded) {
rc.w += 2*view->verticalBar()->getBarWidth(); int barWidth = view->verticalBar()->getBarWidth();;
if (rc.x2() > displaySize.w) { if (get_multiple_displays())
rc.x = displaySize.w - rc.w; barWidth *= window->display()->scale();
if (rc.x < 0) {
rc.x = 0; rc.w += 2*barWidth;
rc.w = displaySize.w; if (rc.x2() > workarea.x2()) {
rc.x = workarea.x2() - rc.x2();
if (rc.x < workarea.x) {
rc.x = workarea.x;
rc.w = workarea.w;
} }
} }
} }
window->setBounds(rc); // New bounds
bounds = rc;
window->removeChild(menubox); window->removeChild(menubox);
view->attachToView(menubox); view->attachToView(menubox);
@ -325,9 +365,13 @@ void Menu::showPopup(const gfx::Point& pos,
fit_bounds(parentDisplay, fit_bounds(parentDisplay,
window.get(), window.get(),
gfx::Rect(pos, window->size())); gfx::Rect(pos, window->size()),
[&window, pos](const gfx::Rect& workarea,
add_scrollbars_if_needed(window.get()); gfx::Rect& bounds,
std::function<gfx::Rect(Widget*)> getWidgetBounds) {
choose_side(bounds, workarea, gfx::Rect(bounds.x-1, bounds.y, 1, 1));
add_scrollbars_if_needed(window.get(), workarea, bounds);
});
// Set the focus to the new menubox // Set the focus to the new menubox
Manager* manager = Manager::getDefault(); Manager* manager = Manager::getDefault();
@ -823,46 +867,26 @@ bool MenuItem::onProcessMessage(Message* msg)
fit_bounds( fit_bounds(
display(), window, window->bounds(), display(), window, window->bounds(),
[this](const gfx::Rect& workarea, [this, window](const gfx::Rect& workarea,
gfx::Rect& pos, gfx::Rect& bounds,
std::function<gfx::Rect(Widget*)> getWidgetBounds){ std::function<gfx::Rect(Widget*)> getWidgetBounds){
Rect parentPos = getWidgetBounds(this->window()); const gfx::Rect itemBounds = getWidgetBounds(this);
Rect bounds = getWidgetBounds(this);
if (inBar()) { if (inBar()) {
pos.x = base::clamp(bounds.x, workarea.x, workarea.x2()-pos.w); bounds.x = base::clamp(itemBounds.x, workarea.x, workarea.x2()-bounds.w);
pos.y = std::max(workarea.y, bounds.y2()); bounds.y = std::max(workarea.y, itemBounds.y2());
} }
else { else {
int x_left = parentPos.x - pos.w + 1*guiscale(); int scale = guiscale();
int x_right = parentPos.x2() - 1*guiscale(); if (get_multiple_displays())
int x, y = bounds.y-3*guiscale(); scale = display()->scale();
Rect r1(0, 0, pos.w, pos.h);
Rect r2(0, 0, pos.w, pos.h);
r1.x = x_left = base::clamp(x_left, workarea.x, workarea.w-pos.w); const gfx::Rect parentBounds = getWidgetBounds(this->window());
r2.x = x_right = base::clamp(x_right, workarea.x, workarea.w-pos.w); bounds.y = itemBounds.y-3*scale;
r1.y = r2.y = y = base::clamp(y, workarea.y, workarea.h-pos.h); choose_side(bounds, workarea, parentBounds);
// 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 (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;
} }
});
add_scrollbars_if_needed(window); add_scrollbars_if_needed(window, workarea, bounds);
});
// Set the focus to the new menubox // Set the focus to the new menubox
menubox->setFocusMagnet(true); menubox->setFocusMagnet(true);