Table of contents

Highlight Multiline Labels in Dragonruby

The purpose of this post is to highlight a couple of techniques for dealing with multi line labels.

The first being that DragonRuby has a really cool technique for multi-line labels where you increment the anchor_y property. Like so:

Ruby
def tick(args)
  lines = ["line1", "line2", "line3", "line4"]
  labels = lines.map.with_index do |text, index|
    {
      x: 1280 / 2,
      y: 720 / 2,
      text: text,
      anchor_y: index
    }
  end
  args.outputs.labels.concat(labels)
end

By incrementing the anchor_y property by 1 everytime, the labels will be “stacked” on top of each other and you don’t need to do hacky things like guess the label height, or use expensive operations like GTK.calcstringbox(text).

Nope. You just get it for free.

Adding a highlight on the last line

Now this works great. Easy stuff.

However, I wanted to be able to “highlight” a line. Also simple. Clone the label you want, and then

Ruby

This works great! But the highlight is a little tight… what if we added some padding?

Ruby

The anchoring problem

As you saw above, the box gets thrown way out of whack…why is that? Well the reason is fairly straightforward. We changed the x / y values, but kept the same “anchor_y”. By doing so, we totally threw off all the calculations.

I scoured around DragonRuby’s Discord and docs and couldn’t find anything.

The most I found was people using vertical_alignment_enum: 2 which sets anchoring to the top. Yes, labels are anchored to the top-left, while everything else is anchored to bottom left, however that is actually irrelevant here since anchor_(x|y) override the alignment enums.

Finally, I stumbled across a method called #anchor_rect in the docs.

https://docs.dragonruby.org/#/api/geometry?id=anchor_rect

As far as I can tell, what this method will do is take our rectangle or “box”, pass in the appropriate anchors, and it will return a rect with the proper X / Y values based on the anchors, without needing to specify the anchors in the actual rect object.

So what I hoped would work is to remove the padding calculations from the highlight rect, remove the anchor_y from the label merge, calculate the anchor_rect, and then do the padding calculations after the anchoring has been calculated.

Something like this:

Ruby
# Remove any anchors, since they'll be added in the next call.
highlight_box.anchor_x = nil
highlight_box.anchor_y = nil
highlight_box = highlight_box.anchor_rect(last_label.anchor_x || 0, last_label.anchor_y || 0)
highlight_box.tap do |box|
    box.x = box.x - padding_left
    box.y = box.y - padding_bottom
    box.w = box.w + padding_left + padding_right
    box.h = box.h + padding_bottom + padding_top
end

So…let’s try it in action…

Ruby

Gist of code: https://gist.github.com/KonnorRogers/231694893ac2b148b22466594f5c7675

Notice we removed the last_label.merge() because it was passing in the anchor_y which would’ve thrown off our anchor_rect call.

And there we have it! Adding a box around an anchored label in DragonRuby!