placeOnScreen
Adjust start rect based on screen and spawner (like a context menu).
When adding a floating widget or window, often we want to guarantee that it is visible. Additionally, if start is logically connected to a spawning rect (like a context menu spawning a submenu), then jump to the opposite side if needed.
Parameters
- screen:Rect.Natural
- Rect.Natural
- spawner:Rect.Natural
- Rect.Natural
- avoid:PlaceOnScreenAvoid
- PlaceOnScreenAvoid
- start:Rect.Natural
- Rect.Natural
Source
Implementation
pub fn placeOnScreen(screen: Rect.Natural, spawner: Rect.Natural, avoid: PlaceOnScreenAvoid, start: Rect.Natural) Rect.Natural {
var r = start;
// first move to avoid spawner
if (!r.intersect(spawner).empty()) {
switch (avoid) {
.none => {},
.horizontal => r.x = spawner.x + spawner.w,
.vertical => r.y = spawner.y + spawner.h,
}
}
// fix up if we ran off right side of screen
switch (avoid) {
.none, .vertical => {
// if off right, move
if ((r.x + r.w) > (screen.x + screen.w)) {
r.x = (screen.x + screen.w) - r.w;
}
// if off left, move
if (r.x < screen.x) {
r.x = screen.x;
}
// if off right, shrink to fit (but not to zero)
// - if we went to zero, then a window could get into a state where you can
// no longer see it or interact with it (like if you resize the OS window
// to zero size and back)
if ((r.x + r.w) > (screen.x + screen.w)) {
r.w = @max(24, (screen.x + screen.w) - r.x);
}
},
.horizontal => {
// if off right, is there more room on left
if ((r.x + r.w) > (screen.x + screen.w)) {
if ((spawner.x - screen.x) > (screen.x + screen.w - (spawner.x + spawner.w))) {
// more room on left, switch
r.x = spawner.x - r.w;
if (r.x < screen.x) {
// off left, shrink
r.x = screen.x;
r.w = spawner.x - screen.x;
}
} else {
// more room on left, shrink
r.w = @max(24, (screen.x + screen.w) - r.x);
}
}
},
}
// fix up if we ran off bottom of screen
switch (avoid) {
.none, .horizontal => {
// if off bottom, first try moving
if ((r.y + r.h) > (screen.y + screen.h)) {
r.y = (screen.y + screen.h) - r.h;
}
// if off top, move
if (r.y < screen.y) {
r.y = screen.y;
}
// if still off bottom, shrink to fit (but not to zero)
if ((r.y + r.h) > (screen.y + screen.h)) {
r.h = @max(24, (screen.y + screen.h) - r.y);
}
},
.vertical => {
// if off bottom, is there more room on top?
if ((r.y + r.h) > (screen.y + screen.h)) {
if ((spawner.y - screen.y) > (screen.y + screen.h - (spawner.y + spawner.h))) {
// more room on top, switch
r.y = spawner.y - r.h;
if (r.y < screen.y) {
// off top, shrink
r.y = screen.y;
r.h = spawner.y - screen.y;
}
} else {
// more room on bottom, shrink
r.h = @max(24, (screen.y + screen.h) - r.y);
}
}
},
}
return r;
}