place a tooltip beside the pointer, not under it
The tooltip's top-left corner sat on the pointer, so the pixel the pointer rested on belonged to the tooltip's own window: the next click on a build button went to the tooltip, which ignores it, and never reached the button. It now stands one pixel to the right of the pointer, flipping to its left where the screen has no room. That clearance is horizontal only, which leaves the tooltip free to shift up as far as it must -- the build button bar sits at the bottom of the view, and clamping its tooltips back onto the screen was pushing them over the pointer again. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ne3mejABZoLWKLh8fgpM3x
This commit is contained in:
@@ -442,7 +442,7 @@ Any ship, module, building, or assembler recipe id that appears in no unlock gro
|
||||
Several UI elements carry a tooltip: the header bar's artifact count (REQ-UI-ARTIFACTS-TOOLTIP), every display that names an item — item chips, inline item values, and recipe summary icons, the header bar's building blocks stock among them (REQ-UI-ITEM-TOOLTIP, REQ-UI-ITEM-VALUE-TOOLTIP), the build button bar's building-type buttons (REQ-UI-BUILD-TOOLTIP) and Deconstruct button (REQ-UI-DECONSTRUCT-BUTTON), the layout configuration dialog's module selection buttons (REQ-MOD-UI-MODULE-TOOLTIP), and the blueprint card's delete icon (REQ-UI-BLUEPRINT-DELETE). Each of those requirements defines what its tooltip says; the first two requirements here define how every one of them is shown and hidden, and the third says which displays carry an item's tooltip without being an item chip. An element not named there describes itself or says nothing: the modal header's close button (REQ-UI-MODAL-CHROME) says what it does by being a close button, and the selection dialog's option buttons describe themselves on their own faces (REQ-UI-SELECT-OPTIONS) — carrying no tooltip of their own, though the items they name still explain themselves (REQ-UI-ITEM-VALUE-TOOLTIP).
|
||||
|
||||
- REQ-UI-TOOLTIP-TRIGGER: A tooltip is shown by **hovering** the element it belongs to, after the usual short hover delay. On an element that has **no click action of its own** it is in addition shown **immediately on left click**, without waiting the delay out. That covers the header bar's building blocks stock display and artifact count and the selection panel's item chips: these display a value and do nothing when clicked, so a click on them is free to mean "tell me what this is", which is quicker than waiting on a hover and is the obvious thing to try. It does not cover elements whose click already does something — the building-type buttons, the Deconstruct button, and the module selection buttons — whose tooltips are reached by hovering alone, so that one gesture never both acts and explains. Nor does it cover an item named on such a control (REQ-UI-ITEM-VALUE-TOOLTIP): the click there belongs to the control, whatever the pointer is resting on. Only the left mouse button shows a tooltip; the right and middle buttons never do. Clicking an element whose tooltip is already up leaves it up.
|
||||
- REQ-UI-TOOLTIP-DISMISS: A tooltip stays visible until the pointer leaves **both the tooltip and the element it belongs to**, however it was triggered. It does **not time out**: there is no display duration after which it vanishes on its own, so a tooltip listing several recipe lines (REQ-UI-ITEM-TOOLTIP) can be read at whatever pace the player needs. The tooltip is itself part of the area that keeps it open — moving the pointer off the element and onto the tooltip does not hide it — which is what fixes where it is placed: its **top-left corner sits at the pointer**, at the position the pointer had the moment the tooltip was triggered. The pointer therefore starts on the tooltip's own corner and reaches the rest of it without crossing a gap. A tooltip that would run off the screen is pushed back onto it, which only moves it further over the pointer. **A tooltip whose element moves goes with it**, holding the place it was given in relation to that element rather than the place it was given on the screen: the expansion button rides the scrolling world (REQ-UI-EXPAND-BUTTON), and a tooltip left standing where the button used to be reads as belonging to nothing. Moving with it is also what ends it, without any rule of its own — the element travels out from under the pointer and takes the tooltip along, and once the pointer is on neither, the tooltip hides. Nothing else dismisses it, and nothing else needs to: a click elsewhere is a click the pointer has already travelled to, so the tooltip is gone before it lands.
|
||||
- REQ-UI-TOOLTIP-DISMISS: A tooltip stays visible until the pointer leaves **both the tooltip and the element it belongs to**, however it was triggered. It does **not time out**: there is no display duration after which it vanishes on its own, so a tooltip listing several recipe lines (REQ-UI-ITEM-TOOLTIP) can be read at whatever pace the player needs. The tooltip is itself part of the area that keeps it open — moving the pointer off the element and onto the tooltip does not hide it — which is what fixes where it is placed: it stands **immediately beside the pointer**, at the position the pointer had the moment the tooltip was triggered — its **top-left corner one pixel to the right of the pointer and level with it**. The pointer therefore reaches the tooltip's own corner without crossing a gap, while the pixel it rests on stays clear: a tooltip is a window in its own right, and one covering that pixel would swallow the next click on the element beneath rather than let it act. A tooltip that would run off the screen is pushed back onto it, and that clearance shapes how: it goes to the **left** of the pointer instead, one pixel clear on that side, where there is no room to its right, and it may shift **up or down** as far as it must — the build button bar sits at the bottom of the view (REQ-UI-BUILD-BAR) and its tooltips shift up — since a tooltip standing clear of the pointer's column cannot come over the pointer by moving vertically. Only a tooltip too wide for the room on either side is pushed over the pointer, being unreadable otherwise. **A tooltip whose element moves goes with it**, holding the place it was given in relation to that element rather than the place it was given on the screen: the expansion button rides the scrolling world (REQ-UI-EXPAND-BUTTON), and a tooltip left standing where the button used to be reads as belonging to nothing. Moving with it is also what ends it, without any rule of its own — the element travels out from under the pointer and takes the tooltip along, and once the pointer is on neither, the tooltip hides. Nothing else dismisses it, and nothing else needs to: a click elsewhere is a click the pointer has already travelled to, so the tooltip is gone before it lands.
|
||||
- REQ-UI-ITEM-VALUE-TOOLTIP: **Wherever the UI names an item, that spot explains the item.** An item is named by its icon, and it is named in three forms (REQ-UI-ITEM-ICON): as an **item chip**, as a **value** — a number followed by the bare inline icon standing in for the item's name — and as an **icon on its colored square within a recipe summary** (REQ-UI-RECIPE-SUMMARY), each with its per-cycle amount. All three show that item's production tooltip (REQ-UI-ITEM-TOOLTIP). The player can therefore ask what an item is wherever it is named, rather than only where it happens to be drawn as a chip.
|
||||
|
||||
The **whole value carries the tooltip** — the amount and the icon together, in every form: the two are one statement, and an icon alone is a target no taller than a line of text. Nothing else on the line is part of it: the caption beside a value (`Remaining`, `Total cost`) describes the number rather than the item, and a recipe summary's arrow, separators and cycle time belong to no item at all. None of these displays has a click action of its own, so a click shows the tooltip at once, as it does on a chip (REQ-UI-TOOLTIP-TRIGGER). This covers the header bar's building blocks stock (REQ-UI-BLOCKS-ICON), the building multi-selection's total cost (REQ-UI-MULTI-SELECTION), the remaining scrap of the debris panel and the field multi-selection (REQ-UI-DEBRIS-PANEL, REQ-UI-FIELD-MULTI-SELECTION), every input and output icon of the selection panel's recipe summary, a Shipyard's schematic materials included (REQ-UI-RECIPE-SUMMARY), and the layout configuration dialog's build cost line, which states a ship's materials in that same form (REQ-MOD-UI-DIALOG). For a value it holds whether or not the icon file exists: where a missing icon leaves the fallback text (`Stock: <n> Blocks`, `Scrap remaining`), the value still states an amount of an item and still explains it.
|
||||
|
||||
@@ -115,17 +115,29 @@ void Tooltip::showAt(const QPoint& globalPos)
|
||||
refreshContent();
|
||||
adjustSize();
|
||||
|
||||
// The top-left corner goes on the pointer, so the pointer starts on the tooltip and
|
||||
// reaches it without crossing a gap (REQ-UI-TOOLTIP-DISMISS). Kept on the screen the
|
||||
// pointer is on: a tooltip near the right or bottom edge would otherwise be cut off.
|
||||
// Clamping keeps the pointer inside the tooltip, since it only ever moves the
|
||||
// tooltip back over the pointer.
|
||||
// Beside the pointer rather than under it: one pixel right of it, level with it
|
||||
// (REQ-UI-TOOLTIP-DISMISS). The one pixel is what leaves the pointer's own column
|
||||
// clear -- a tooltip is a window of its own, so a tooltip covering the pixel the
|
||||
// pointer rests on would take the next click off the element it belongs to -- and it
|
||||
// is only one so that the pointer reaches the tooltip without crossing a gap.
|
||||
const QRect screen = availableScreenRect(globalPos);
|
||||
QPoint topLeft = globalPos;
|
||||
QPoint topLeft(globalPos.x() + 1, globalPos.y());
|
||||
if (screen.isValid())
|
||||
{
|
||||
// Left of the pointer where there is no room to its right, keeping the same one
|
||||
// pixel of clearance: a tooltip near the right edge would otherwise be cut off.
|
||||
if (topLeft.x() + width() - 1 > screen.right())
|
||||
{
|
||||
topLeft.setX(globalPos.x() - width());
|
||||
}
|
||||
// Wider than the room on either side of the pointer: back onto the screen, over
|
||||
// the pointer, since being readable beats being clear of the pointer.
|
||||
topLeft.setX(qMax(screen.left(),
|
||||
qMin(topLeft.x(), screen.right() - width() + 1)));
|
||||
// Vertically it is free to shift as far as it must, which is what the build
|
||||
// button bar's tooltips need, the bar sitting at the bottom of the view
|
||||
// (REQ-UI-BUILD-BAR): the tooltip stands clear of the pointer's column either
|
||||
// way, so no shift up or down can bring it over the pointer.
|
||||
topLeft.setY(qMax(screen.top(),
|
||||
qMin(topLeft.y(), screen.bottom() - height() + 1)));
|
||||
}
|
||||
|
||||
@@ -30,8 +30,9 @@ public:
|
||||
|
||||
// Plain text content, wrapped at a readable measure. Newlines are kept.
|
||||
void setText(const QString& text);
|
||||
// Refreshes the content and shows the tooltip with its top-left corner on the given
|
||||
// screen position, kept inside the screen (REQ-UI-TOOLTIP-DISMISS).
|
||||
// Refreshes the content and shows the tooltip beside the given screen position --
|
||||
// one pixel to its right, or to its left where there is no room -- kept inside the
|
||||
// screen (REQ-UI-TOOLTIP-DISMISS).
|
||||
void showAt(const QPoint& globalPos);
|
||||
bool getContainsGlobalPos(const QPoint& globalPos) const;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user