Skip to content

Commit

Permalink
libtooltipmenu: add font scaling
Browse files Browse the repository at this point in the history
  • Loading branch information
ToxicFrog committed Aug 8, 2022
1 parent c7ff58a commit 13ea974
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 28 deletions.
5 changes: 5 additions & 0 deletions libtooltipmenu/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# 0.2.0

- Fix: tooltip font size now automatically scales based on screen resolution
- New: `TooltipGeometry` allows specifying a font scaling factor

# 0.1.3

- Fix: intermitten array index out of bounds crash when opening the menu
Expand Down
2 changes: 1 addition & 1 deletion libtooltipmenu/Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
NAME=libtooltipmenu
VERSION=0.1.3
VERSION=0.2.0
LUMPS=zscript.txt textures
LUMPS+=*.md
ZSCRIPT=ca.ancilla.libtooltipmenu/*.zsc
Expand Down
17 changes: 12 additions & 5 deletions libtooltipmenu/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,14 +84,21 @@ The default is to place tooltips in the top left corner, with a maximum width of
You can change the size and position of the tooltips with the `TooltipGeometry` directive:

```
// Arguments: X, Y, width, horizontal margin, vertical margin
// Place tooltip in the bottom center with really fat margins.
TooltipGeometry 0.5, 1.0, 1.0, 4.0, 2.0
// Arguments: X, Y, width, horizontal margin, vertical margin, scale
// Place tooltip in the bottom center with really fat margins and 50% larger
// than normal.
TooltipGeometry 0.5, 1.0, 1.0, 4.0, 2.0, 1.5
```

`X` and `Y` determine the positioning of the tooltip, as a proportion of screen size; `0.0, 0.0` places the tooltip in the top left, `1.0, 1.0` in the bottom right, and `0.5, 0.5` in the center of the screen. `width` determines the maximum width of the tooltip, also as a screen proportion; a tooltip longer than this will be wrapped to span multiple lines. The `margin` arguments determine the amount of blank space allotted surrounding the actual text of the tooltip; horizontal is in multiples of em width, and vertical in multiples of line height.
`X` and `Y` determine the positioning of the tooltip, as a proportion of screen size; `0.0, 0.0` places the tooltip in the top left, `1.0, 1.0` in the bottom right, and `0.5, 0.5` in the center of the screen.

You can use as many `TooltipGeometry` directives as you want; each one will affect only the tooltips after it, so you can use this to position different tooltips at different locations. If you want to override only some of the settings, passing `-1` for a setting will leave it unchanged, so (e.g.) `TooltipGeometry -1, -1, -1, 0.0, 0.0` would zero out the margins without affecting the size or position.
`width` determines the maximum width of the tooltip, also as a screen proportion; a tooltip longer than this will be wrapped to span multiple lines.

The `margin` arguments determine the amount of blank space allotted surrounding the actual text of the tooltip; horizontal is in multiples of em width, and vertical in multiples of line height.

`scale` determines the text scale. The default font size is based on CleanYFac_1 and gives a font size comparable to the default option menu; scale values other than 1.0 will shrink or enlarge the font accordingly (and the background image, it given with `TooltipAppearance`, will be scaled to match).

You can use as many `TooltipGeometry` directives as you want; each one will affect only the tooltips after it, so you can use this to position different tooltips at different locations or with different sizes. If you want to override only some of the settings, passing `-1` for a setting will leave it unchanged, so (e.g.) `TooltipGeometry -1, -1, -1, 0.0, 0.0, -1` would zero out the margins without affecting the size or position.

### Configuring tooltip appearance

Expand Down
66 changes: 44 additions & 22 deletions libtooltipmenu/ca.ancilla.libtooltipmenu/TooltipOptionMenu.zsc
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
// For details, see the included README.

class TF_Tooltip : Object ui {
double x, y, w, xpad, ypad; // Geometry
double x, y, w, xpad, ypad, scale; // Geometry
uint first, last; // First and last menuitems this applies to
Font font;
Color colour;
Expand All @@ -21,40 +21,62 @@ class TF_Tooltip : Object ui {
self.w = settings.w;
self.xpad = settings.xpad;
self.ypad = settings.ypad;
self.scale = settings.scale;
self.font = settings.font;
self.colour = settings.colour;
self.texture = settings.texture;
}

int GetX(uint width) {
return (screen.GetWidth() - width) * self.x;
int GetX(uint screen_width, uint width) {
return (screen_width - width) * self.x;
}

int GetY(uint height) {
return (screen.GetHeight() - height) * self.y;
int GetY(uint screen_width, uint height) {
return (screen_width - height) * self.y;
}

void Draw() {
// In order to draw the text readably at high resolutions, we calculate
// everything using a virtual screen size and then tell DrawTexture and
// DrawText to scale appropriately when blitting the background and tooltip
// text to the real screen.
uint virtual_height = screen.GetHeight() / CleanYFac_1 / scale;
let aspect = screen.GetAspectRatio();
let virtual_width = virtual_height * aspect;
// Font metrics: em width and line height.
let em = self.font.GetCharWidth(0x6D);
let lh = self.font.GetHeight();
let nominal_width = screen.GetWidth() * self.w;
// Nominal width is the maximum width of the tooltip based on configuration
// in the MENUDEF.
let nominal_width = virtual_width * self.w;
let lines = self.font.BreakLines(self.text, nominal_width);

// Calculate the real width of the tooltip. This may be less than the
// nominal width if it's a short one-liner.
// nominal width if it's a short one-liner. This is still in virtual screen
// coordinates, not real screen!
uint actual_width = 0;
for (uint i = 0; i < lines.count(); ++i) {
actual_width = max(actual_width, self.font.StringWidth(lines.StringAt(i)));
}
actual_width += self.xpad * 2.0 * em;
// Calculate the actual height based on the number of lines we wrapped it into

// Calculate the real height based on the number of lines we wrapped it into
// and the vertical margins.
uint actual_height = self.font.GetHeight() * (self.ypad * 2.0 + lines.count());

uint x = GetX(actual_width);
uint y = GetY(actual_height);
// Draw the background texture, if defined.
// Get the coordinates of the top left corner of the tooltip's bounding box,
// including padding, in virtual screen coordinates.
uint x = GetX(virtual_width, actual_width);
uint y = GetY(virtual_height, actual_height);

// Draw the background texture, if defined. DTA_Virtual* commands it to scale
// the virtual screen size to match the real screen; DTA_KeepRatio tells it
// to assume the ratio of the virtual screen matches the real screen. (The
// documentation on the wiki is wrong here; leaving it false forces a 4:3
// aspect ratio.)
Screen.DrawTexture(texture, true, x, y,
DTA_VirtualWidthF, virtual_width, DTA_VirtualHeight, virtual_height,
DTA_KeepRatio, true,
DTA_LeftOffset, 0, DTA_TopOffset, 0,
DTA_DestWidth, actual_width, DTA_DestHeight, actual_height);

Expand All @@ -63,7 +85,9 @@ class TF_Tooltip : Object ui {
self.font, self.colour,
x + self.xpad*em,
y + i*lh + self.ypad*lh,
lines.StringAt(i));
lines.StringAt(i),
DTA_VirtualWidthF, virtual_width, DTA_VirtualHeight, virtual_height,
DTA_KeepRatio, true);
}
}
}
Expand All @@ -82,26 +106,21 @@ class TF_TooltipOptionMenu : OptionMenu {
tt.w = 0.3;
tt.xpad = 1.0;
tt.ypad = 0.5;
tt.scale = 1.0;
tt.font = newsmallfont;
tt.colour = Font.CR_WHITE;
return tt;
}

override void Init(Menu parent, OptionMenuDescriptor desc) {
super.Init(parent, desc);
// console.printf("Init menu, items=%d", desc.mItems.size());
let settings = GetDefaults();

// If there's already a TooltipHolder in tail position, we've already been
// initialized and just need to retrieve our saved tooltips from it.
// for (uint i = 0; i < desc.mItems.size(); ++i) {
// console.printf("Item: %s", desc.mItems[i].GetClassName());
// }
let tail = OptionMenuItemTooltipHolder(desc.mItems[desc.mItems.size()-1]);
if (tail) {
tooltips.copy(tail.tooltips);
// console.printf("Cache hit, items=%d, tooltips=%d",
// desc.mItems.size(), tooltips.size());
return;
}

Expand Down Expand Up @@ -143,8 +162,6 @@ class TF_TooltipOptionMenu : OptionMenu {
// Store our tooltips inside the menu descriptor so we can recover them when
// the menu is redisplayed.
desc.mItems.push(new("OptionMenuItemTooltipHolder").Init(tooltips));

// console.printf("Init done, items=%d, tooltips=%d", desc.mItems.size(), tooltips.size());
}

TF_Tooltip AppendableTooltip(uint first, uint last) {
Expand Down Expand Up @@ -213,11 +230,15 @@ class OptionMenuItemTooltip : OptionMenuItem {
}

class OptionMenuItemTooltipGeometry : OptionMenuitem {
double x, y, w, xpad, ypad;
double x, y, w, xpad, ypad, scale;

OptionMenuItemTooltipGeometry Init(double x=-1.0, double y=-1.0, double w=-1.0, double xpad=-1.0, double ypad=-1.0) {
OptionMenuItemTooltipGeometry Init(
double x=-1.0, double y=-1.0, double w=-1.0,
double xpad=-1.0, double ypad=-1.0,
double scale=-1.0) {
self.x = x; self.y = y; self.w = w;
self.xpad = xpad; self.ypad = ypad;
self.scale = scale;
return self;
}

Expand All @@ -227,6 +248,7 @@ class OptionMenuItemTooltipGeometry : OptionMenuitem {
if (self.w >= 0) settings.w = self.w;
if (self.xpad >= 0) settings.xpad = self.xpad;
if (self.ypad >= 0) settings.ypad = self.ypad;
if (self.scale > 0) settings.scale = self.scale;
}
}

Expand Down

0 comments on commit 13ea974

Please sign in to comment.