Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add visual layout debugging features #2856

Open
hyuri opened this issue Sep 17, 2024 · 14 comments
Open

Add visual layout debugging features #2856

hyuri opened this issue Sep 17, 2024 · 14 comments
Labels
enhancement New features, or improvements to existing features.

Comments

@hyuri
Copy link

hyuri commented Sep 17, 2024

What is the problem or limitation you are having?

Currently, we don't have an easy way to visualize and debut our layouts. So the only way to do that is by changing the background colors of different boxes, buttons and labels. That way we can visually see how the widgets are relating to each other. But it's manual, messy and tedious.

Describe the solution you'd like

Add a sort of debug "layout wireframes" property to App, that, when True, renders all widgets with a bounding box/border around them.

Going even further, another debug property can be added: "layout depth", that turns off all colors and instead assigns a different shade of gray to each widget based on its depth in the hierarchy. The main window black, with inner widgets in progressively lighter shades of gray, all the way to the top elements like buttons and labels.

So we would be able to easily visualize boxes inside of boxes and how they relate to each other.

That way, we have an easy way of visualizing what's going on in the layout and can spot bugs — especially some that are hard to catch unless you visualize how the widgets are glueing together.

Describe alternatives you've considered

None

Additional context

No response

@hyuri hyuri added the enhancement New features, or improvements to existing features. label Sep 17, 2024
@hyuri hyuri changed the title Add layout debug wireframes Add visual layout debugging features Sep 17, 2024
@freakboy3742
Copy link
Member

There's definitely an idea in here worth pursuing. I agree that layout issues can be difficult to resolve, and I'll openly admit that manually setting background colors is my go-to technique for debugging layout issues (along with a couple of others).

The broader concept of "app debug mode" is also something that has come up on a couple of occasions. For example, having exceptions pop up as dialogs might be nice for production apps, but that would be a bit distracting when doing app development.

Some implementation questions:

  1. How do we turn on debug mode? A TOGA_DEBUG environment variable (or similar) would be the obvious choice, but I'm open to other suggestions. Would debug mode automatically turn on layout helpers, or just enable a "develop" menu that exposes options like toggling layout helpers? Or would TOGA_DEBUG_LAYOUT be a separate setting?

  2. What would the exact manifestation of layout backgrounds be? I'm not sure borders would be a good idea, as they could easily alter layout (pushing everything by a pixel); colors introduce an accessibility angle - subtle shades of grey in particular would be indistinguishable by my son, for example. I'd suggest cycling between 3-4 colors, specifically selected from a colorblind-aware palette - https://davidmathlogic.com/colorblind/ has a couple of candidate palettes (although we possibly want to use lightened variants, rather than strong bold backgrounds).

  3. How would "debug" backgrounds interact with explicitly specified background colors? An override? A color mix?

  4. Would layout helper background colors apply to all widgets? Or just widgets where physical extents aren't necessarily obvious (Box obviously, but others like TextInput and Switch would also be candidates)

@hyuri
Copy link
Author

hyuri commented Sep 18, 2024

The broader concept of "app debug mode" is also something that has come up on a couple of occasions. For example, having exceptions pop up as dialogs might be nice for production apps, but that would be a bit distracting when doing app development.

These exception dialogs for production would be a great addition indeed.

How do we turn on debug mode? A TOGA_DEBUG environment variable (or similar) would be the obvious choice, but I'm open to other suggestions.

The environment variable sounds reasonable. Does a --toga_debug flag to briefcase dev also make sense?

Would debug mode automatically turn on layout helpers, or just enable a "develop" menu that exposes options like toggling layout helpers? Or would TOGA_DEBUG_LAYOUT be a separate setting?

To me, it makes sense to have both settings.

What would the exact manifestation of layout backgrounds be? I'm not sure borders would be a good idea, as they could easily alter layout (pushing everything by a pixel); colors introduce an accessibility angle - subtle shades of grey in particular would be indistinguishable by my son, for example. I'd suggest cycling between 3-4 colors, specifically selected from a colorblind-aware palette - https://davidmathlogic.com/colorblind/ has a couple of candidate palettes (although we possibly want to use lightened variants, rather than strong bold backgrounds).

On borders: When this "debug mode" is active, could widget sizes be reduced by the border size, to compensate for it — so reduce all widgets by 1 pixel if border is 1 px? Or have the border be inwards instead of outwards — in other words: be drawn on top of the widget's outer-most pixels instead of after it?

On colors: Good call. I'm not knowledgeable on this and I don't want to offer mistaken suggestions, so maybe you are better positioned to decide on what the rights colors should be and how they should be used. Would the different shades work in addition to the colors, or should shades be avoided altogether?

How would "debug" backgrounds interact with explicitly specified background colors? An override? A color mix?

How about it overrides all colors by default, but we have a "debug_skip_color" property in Widget to tell the debug mode to not override the colors in that specific widget? Like !important in CSS.

Would layout helper background colors apply to all widgets? Or just widgets where physical extents aren't necessarily obvious (Box obviously, but others like TextInput and Switch would also be candidates)

My intuition says all widgets by default. Could we have an option for that? Like "TOGA_DEBUG_CONTAINERS_ONLY"?.

@freakboy3742
Copy link
Member

The broader concept of "app debug mode" is also something that has come up on a couple of occasions. For example, having exceptions pop up as dialogs might be nice for production apps, but that would be a bit distracting when doing app development.

These exception dialogs for production would be a great addition indeed.

To be clear - Briefcase already does have crash dialogs, but only for exceptions that are true app-crashers. Toga will go to great lengths to not crash, and output to console instead - it's these outputs that I'm suggesting as possible dialogs in non-debug mode.

How do we turn on debug mode? A TOGA_DEBUG environment variable (or similar) would be the obvious choice, but I'm open to other suggestions.

The environment variable sounds reasonable. Does a --toga_debug flag to briefcase dev also make sense?

I'd rather not add Toga specific flags to Briefcase - while the two tools work well together, we're deliberately trying to keep them decoupled. However, a generic --debug/DEBUG flag/envvar might be acceptable.,

Would debug mode automatically turn on layout helpers, or just enable a "develop" menu that exposes options like toggling layout helpers? Or would TOGA_DEBUG_LAYOUT be a separate setting?

To me, it makes sense to have both settings.

The more I think about it, I think a "debug" menu makes more sense. Having layout debug permanently on is going to be a distraction; being able to toggle it is going to be useful. I can also think of any number of things that we might want to include as debug utilities, like a widget tree inspector, or maybe even a performance monitor. Having a menu item that is added in case of debug makes all these possible, rather than an explosion of environment variables.

What would the exact manifestation of layout backgrounds be? I'm not sure borders would be a good idea, as they could easily alter layout (pushing everything by a pixel); colors introduce an accessibility angle - subtle shades of grey in particular would be indistinguishable by my son, for example. I'd suggest cycling between 3-4 colors, specifically selected from a colorblind-aware palette - https://davidmathlogic.com/colorblind/ has a couple of candidate palettes (although we possibly want to use lightened variants, rather than strong bold backgrounds).

On borders: When this "debug mode" is active, could widget sizes be reduced by the border size, to compensate for it — so reduce all widgets by 1 pixel if border is 1 px? Or have the border be inwards instead of outwards — in other words: be drawn on top of the widget's outer-most pixels instead of after it?

Oh sure - could be... but then we've got to debug our debug code... and that's complexity I'd rather avoid.

On colors: Good call. I'm not knowledgeable on this and I don't want to offer mistaken suggestions, so maybe you are better positioned to decide on what the rights colors should be and how they should be used. Would the different shades work in addition to the colors, or should shades be avoided altogether?

The biggest concern from an accessibility standpoint is that telling 2 subtly different shades of yellow apart is hard even if you do have good eyesight. I think the best we're going to be able to do is make the colors as distinct as possible, and cycle as often as possible. We might need to make the periodicity of colors cycline configurable to avoid issues where the exact depth of a widget heirarchy matches the color cycle, obscuring the diagnostic assistance. Which... is another argument for a debug menu, as we could control the cycle size there.

How would "debug" backgrounds interact with explicitly specified background colors? An override? A color mix?

How about it overrides all colors by default, but we have a "debug_skip_color" property in Widget to tell the debug mode to not override the colors in that specific widget? Like !important in CSS.

I'm not wild about the prospect of writing user-space code that has to account for debug properties.

Would layout helper background colors apply to all widgets? Or just widgets where physical extents aren't necessarily obvious (Box obviously, but others like TextInput and Switch would also be candidates)

My intuition says all widgets by default. Could we have an option for that? Like "TOGA_DEBUG_CONTAINERS_ONLY"?.

The problem here is that some widgets (e.g., Table) use background color for a purpose that won't shed any light on layout problems. Table will always fill the allocated space, in both axes; and the boundaries of the widget is obvious. It's only the box/label/switch style widgets where there's ambiguity.

@hyuri
Copy link
Author

hyuri commented Sep 19, 2024

The more I think about it, I think a "debug" menu makes more sense. Having layout debug permanently on is going to be a distraction; being able to toggle it is going to be useful. I can also think of any number of things that we might want to include as debug utilities, like a widget tree inspector, or maybe even a performance monitor. Having a menu item that is added in case of debug makes all these possible, rather than an explosion of environment variables.

Great. But, to be clear, would the "debug layout" toggle, accessible in this debug menu, preserve state between runs until we flick it again?
When debugging the layout, we might go back and forth multiple times between tweaking the code and running to see results, so having to access the menu and toggle it on every time will probably quickly get annoying.

The biggest concern from an accessibility standpoint is that telling 2 subtly different shades of yellow apart is hard even if you do have good eyesight. I think the best we're going to be able to do is make the colors as distinct as possible, and cycle as often as possible. We might need to make the periodicity of colors cycline configurable to avoid issues where the exact depth of a widget heirarchy matches the color cycle, obscuring the diagnostic assistance. Which... is another argument for a debug menu, as we could control the cycle size there.

Got it. Extra: What if the colors are configurable as well? Or maybe only a handful of presets, like "full spectrum/rainbow", "gray scale", "green-red", "yellow-blue"? Or other presets that better serve different people with different needs, as it seems there are different cases with different sensitivities.

The problem here is that some widgets (e.g., Table) use background color for a purpose that won't shed any light on layout problems. Table will always fill the allocated space, in both axes; and the boundaries of the widget is obvious. It's only the box/label/switch style widgets where there's ambiguity.

Right. So maybe only things like boxes, labels, buttons and switches — at least as a first step?

@hyuri
Copy link
Author

hyuri commented Sep 19, 2024

Another idea: Overlay diagonal lines in padding areas, so we can visualize padding as well.

@freakboy3742
Copy link
Member

Great. But, to be clear, would the "debug layout" toggle, accessible in this debug menu, preserve state between runs until we flick it again? When debugging the layout, we might go back and forth multiple times between tweaking the code and running to see results, so having to access the menu and toggle it on every time will probably quickly get annoying.

I hadn't considered whether the option would be persistent... I guess it could be, though. There's an interesting overlap here with #90 - that feature request requires a generic mechanism for storing user settings; and the enable/disable state of layout debug would probably fit into that territory.

It would also benefit from the addition of menu items that support toggle behaviours (i.e., the 'tick' marker next to the menu item indicating something is enabled).

The biggest concern from an accessibility standpoint is that telling 2 subtly different shades of yellow apart is hard even if you do have good eyesight. I think the best we're going to be able to do is make the colors as distinct as possible, and cycle as often as possible. We might need to make the periodicity of colors cycline configurable to avoid issues where the exact depth of a widget heirarchy matches the color cycle, obscuring the diagnostic assistance. Which... is another argument for a debug menu, as we could control the cycle size there.

Got it. Extra: What if the colors are configurable as well? Or maybe only a handful of presets, like "full spectrum/rainbow", "gray scale", "green-red", "yellow-blue"? Or other presets that better serve different people with different needs, as it seems there are different cases with different sensitivities.

It's not that difficult to pick a palette that is differentiable by all forms of color blindness. It takes some care, to be sure - but it's not impossible.

Another idea: Overlay diagonal lines in padding areas, so we can visualize padding as well.

At that point, we're getting into the territory where the complexity of implementation should be starting to become a concern. If there's a simple way to do it... maybe - but carrying around a bunch of heavyweight code for debugging purposes isn't especially desirable.

@hyuri
Copy link
Author

hyuri commented Sep 21, 2024

At that point, we're getting into the territory where the complexity of implementation should be starting to become a concern. If there's a simple way to do it... maybe - but carrying around a bunch of heavyweight code for debugging purposes isn't especially desirable.

True. What about a much darker shade of the same hue? Since it would only be 2 shades of the same color — one for total widget area, and one for padding —, they can be pushed towards extremes and not be subtle. Would that work for color blindness?

@freakboy3742
Copy link
Member

True. What about a much darker shade of the same hue? Since it would only be 2 shades of the same color — one for total widget area, and one for padding —, they can be pushed towards extremes and not be subtle. Would that work for color blindness?

Relying on the ability to distinguish shades generally isn't a good idea.

However, again, the question is how to implement this easily. "Override the background color" is a simple change. "Completely alter how the widgets are rendered so we can render a debug helper" isn't.

@aerickson
Copy link

I wanted this exact feature, so I hacked it up.

features:

  • randomized background color (using colors optimized for color-blindness) for boxes
  • enabled via TOGA_DEBUG_LAYOUT env var

diff:
main...aerickson:toga:debug_mode_alternating_bg

# using
TOGA_DEBUG_LAYOUT=1 briefcase dev

without:
plain
with:
debug

@HalfWhitt
Copy link
Contributor

That's awesome! Quick-and-dirty, but exciting to see! It seems to me there might be times one would want it applied only to containers (Box as here, plus ScrollContainer, SplitContainer, and OptionContainer), and times when it would be nice to apply it to all widgets — not sure what the best way would be to select that.

Would you be interested in fleshing this out into a PR? The docs have a section on how to do so.

@freakboy3742
Copy link
Member

That's awesome! Quick-and-dirty, but exciting to see!

Adding my +1 to this - definitely looks like a good start.

It seems to me there might be times one would want it applied only to containers (Box as here, plus ScrollContainer, SplitContainer, and OptionContainer), and times when it would be nice to apply it to all widgets — not sure what the best way would be to select that.

My immediate thought is that having this as a capability on the base Widget, enabled by a flag on the widget - so, Box, and any other widgets where it's appropriate, would have _USE_DEBUG_BACKGROUND=True (or similar) defined.

The other thought is how this interacts with user-specified colors. The debug logic is setting style.background_color... my immediate reaction was that I wasn't certain we can guarantee that style has been defined at that point in the code - or, if it has, that the end-user hasn't manually defined a background color of their own. I'm not 100% sure what the right behavior here should be - does the debug color or the manual color take precedence? Or should the color be mixed so it's a "manual color with debug tint"? PR #2484 is in-flight, but it has some logic to perform color mixing that would make sense as a general utility.

@aerickson
Copy link

That's awesome! Quick-and-dirty, but exciting to see!

Adding my +1 to this - definitely looks like a good start.

Yay. :)

It seems to me there might be times one would want it applied only to containers (Box as here, plus ScrollContainer, SplitContainer, and OptionContainer), and times when it would be nice to apply it to all widgets — not sure what the best way would be to select that.

My immediate thought is that having this as a capability on the base Widget, enabled by a flag on the widget - so, Box, and any other widgets where it's appropriate, would have _USE_DEBUG_BACKGROUND=True (or similar) defined.

Yeah, it makes sense to place the functionality on Widget.

The other thought is how this interacts with user-specified colors. The debug logic is setting style.background_color... my immediate reaction was that I wasn't certain we can guarantee that style has been defined at that point in the code - or, if it has, that the end-user hasn't manually defined a background color of their own. I'm not 100% sure what the right behavior here should be - does the debug color or the manual color take precedence? Or should the color be mixed so it's a "manual color with debug tint"? PR #2484 is in-flight, but it has some logic to perform color mixing that would make sense as a general utility.

For me, when I'm using this, I don't expect the UI's colors to look anything like normal (I'm purely debugging layout)... I think it's fine to not honor any background color the widget may already set, but doing some mixing could definitely be a next evolution of the feature. Is mixing a must have?

Happy to work on a PR, just want to get the details worked out before starting.

@HalfWhitt
Copy link
Contributor

For me, when I'm using this, I don't expect the UI's colors to look anything like normal (I'm purely debugging layout)... I think it's fine to not honor any background color the widget may already set, but doing some mixing could definitely be a next evolution of the feature. Is mixing a must have?

My vote is to completely override it, and ignore any setting of background color through the normal mechanism. I think it'll be simpler to do, too... if you want blending, you'd need to keep a record of the debug color, and mix into it any time the user changes the color.

@freakboy3742
Copy link
Member

For me, when I'm using this, I don't expect the UI's colors to look anything like normal (I'm purely debugging layout)... I think it's fine to not honor any background color the widget may already set, but doing some mixing could definitely be a next evolution of the feature. Is mixing a must have?

My vote is to completely override it, and ignore any setting of background color through the normal mechanism. I think it'll be simpler to do, too... if you want blending, you'd need to keep a record of the debug color, and mix into it any time the user changes the color.

I concur. Color mixing would be nice to have, but isn't essential. Overriding user-provided background colors seems entirely reasonable as a first implementation. Otherwise, a user who manually specified every background color (🤮) wouldn't see anything in debug mode.

Plus - this is a debug feature; so if it turns out we need to modify the behavior, we can modify or improve it over time without any backwards compatibility risk (which is something that the documentation of the new feature should highlight).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New features, or improvements to existing features.
Projects
None yet
Development

No branches or pull requests

4 participants