How to draw a focus indictor on a drawing area

Hello everyone,

I have a custom widget (an image viewer implemented as a GtkDrawingArea subclass) which has some keyboard bindings, so I need a focus indicator.

What’s the best way to do this? Should I use GtkOverlay to float some other widget over my drawing area and rely on that to draw the indicator? What would be the best widget to float on top?

Hi,

gtk3 or gtk4?
Do you want the focus indicator on the whole DrawingArea, or on a smaller element?

Hi @gwllems,

Sorry, gtk4, I should have said.

My image viewer looks like this:

So I’m currently drawing the focus indicator as a thin line just inside the window in my _snapshot() handler. It’d be much better if I could get gtk to draw it for me, of course!

OK, then the easiest way IMHO is to use a custom CSS:

drawingarea:focus {
	outline-color: @theme_selected_bg_color;
	outline-offset: -3px;
	outline-width: 2px;
	outline-style: dotted;
}

Note that for testing, you can launch the gtk inspector with CtrlShiftI and paste the style above in the “CSS” tab.
That’s an easy way to visualize the outcome.

Sorry for the very late reply, it took me ages to get CSS drawing anything on my widget (the trick was to call gtk_widget_class_set_css_name(widget_class, "imagedisplay") in my class init, ooops).

I ended up with:

imagedisplay {
  transition: outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
  border-radius: 7px;
  outline: 2px solid transparent;
  outline-offset: 4px;
}

imagedisplay:focus {
  outline-color: @theme_selected_bg_color;
  outline-offset: -3px;
}

Which kind-a looks a bit like the gtk focus indicator, but it won’t fade away after a while in the way that (for example) the focus ring on the scale widget will.

1 Like

I think you need :focus:focus-visible instead of just :focus for this.

I tried that, but it stopped it working completely :frowning:

Do you know if there’s something I need to call to make my GtkDrawingArea use the focus-visible state? I looked through the gtkscale sources but nothing jumped out at me (probably being dumb).

Weird, that works on my side…

Have you used this?

imagedisplay:focus:focus-visible {
  outline-color: @theme_selected_bg_color;
  outline-offset: -3px;
}

Make sure there are no spaces around the :, that will change the meaning.

Ah! I was testing it by clicking in the drawing area, but nothing happens then. It DOES appear if I tab the focus in and out of the drawingarea, and it does vanish after a few seconds.

Thank you! That was quite a journey.

1 Like

My final solution:

imagedisplay {
  transition-property: outline-offset, outline-color;
  transition-duration: 300ms;
  animation-timing-function: ease-in-out;
  border-radius: 7px;
  outline-offset: 4px;
  outline: 2px solid transparent;
} 

imagedisplay:focus:focus-visible {
  outline-offset: -3px;
  outline-color: @theme_selected_bg_color;
}

Ideally I’d be able to get $focus_border_color for a better match with the rest of gtk, but I think that’s not part of the set of public colors.

1 Like