Skip to content

Add inline color pickers to script editor #105724

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

dugramen
Copy link
Contributor

Implements godotengine/godot-proposals#6653

image

The proposal already had a linked PR which added color buttons to the gutter.
This PR instead adds color buttons directly in the text area, and supports multiple colors per line, like in VSCode. Had to make some text_server_adv fixes to support objects with 0 span length.

The following constructors are supported:

  • Color() (Empty, an html color string, or 3-4 rgba values)
  • Color.from_hsv()
  • Color.from_rgba8()
  • Color.from_ok_hsl

The mode / format of the constructor will match which mode is selected in the color picker. Video demo:

script_editor_color_picker.mp4

@JekSun97
Copy link
Contributor

I think we should have a corresponding setting in the editor settings to turn this display mode on and off

bruvzg

This comment was marked as outdated.

@bruvzg
Copy link
Member

bruvzg commented Apr 24, 2025

Also, 0 size spans should not exist and can properly work, at least one replacement character is needed for BiDi.

Actually it's probably fine, but a note should be added to the documentation to mention that if it's 0 size it is attached to the previous character.

@dugramen dugramen force-pushed the recovery/split-commit branch from 7a046ab to 06e3ad7 Compare April 24, 2025 23:17
@dugramen dugramen requested a review from a team as a code owner April 24, 2025 23:17
@dugramen
Copy link
Contributor Author

dugramen commented Apr 24, 2025

Ok I applied all the changes by @bruvzg, and added an editor setting to enable / disable this. Also rebased just in case. (Also the parse and string functions were moved upwards to be available in ScriptTextEditor::update_settings)

inline_color_start = i_start;
inline_color_end = i_end;

Vector2 xf_mpos = mb->get_global_position();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Vector2 xf_mpos = mb->get_global_position();
Vector2 xf_mpos = mb->get_position() + get_screen_position();

Or it will be off if the editor window is not maximized/not on the primary screen.

Copy link
Member

@Mickeon Mickeon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what I know, this looks to be the first feature that makes it so that what is displayed in the TextEdit does not exactly match its underlying text.
This could open the door for more personalized displays, such as parameter names, akin to other IDEs. There was a proposal about this but I cannot find it at the moment.

Either way, I think this is a bit too niche to be exposed to the scripting API, and it's a good thing it's not in this PR...
Isn't the code for this too invasive? It affects TextEdit directly for no justifiable reason, I feel.

@@ -1216,6 +1216,9 @@
<member name="text_editor/appearance/caret/type" type="int" setter="" getter="">
The shape of the caret to use in the script editor. [b]Line[/b] displays a vertical line to the left of the current character, whereas [b]Block[/b] displays an outline over the current character.
</member>
<member name="text_editor/appearance/enable_inline_color_picker" type="bool" setter="" getter="">
If [code]true[/code], colored buttons will appear before color constructors. Clicking them will popup a color picker for visually editing the color's parameters.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A link to the Color Variant type is important, I feel.

Suggested change
If [code]true[/code], colored buttons will appear before color constructors. Clicking them will popup a color picker for visually editing the color's parameters.
If [code]true[/code], displays a colored button before any [Color] constructor in the script editor. Clicking on them allows the color to be modified through a color picker.

Perhaps ColorPicker, too, but not as much, and it does not parse right for localization.

@dugramen
Copy link
Contributor Author

dugramen commented Apr 30, 2025

It affects TextEdit directly for no justifiable reason, I feel.

Well all TextServer access happens in TextEdit, so objects need to be added in there. But I get what you mean that its weird for color picker code to be in TextEdit. Maybe I can generalize it a bit and move the color related stuff into ScriptTextEditor or CodeEdit, and have TextEdit only call it through Callables

Is it possible to move the ColorPicker to ScriptTextEditor? The TextEdit doesn't use it on its own.

Yeah I'll move color picker to that or CodeEdit too

@dugramen dugramen force-pushed the recovery/split-commit branch 2 times, most recently from 1e90fb9 to f99a6f3 Compare May 1, 2025 13:29
@dugramen
Copy link
Contributor Author

dugramen commented May 1, 2025

Ok I generalized everything in TextEdit, so it can be used for adding any inline objects with 0 span. All color related functionality was moved to ScriptTextEditor. I added enums and validation functions to make it easier to understand & build off of in the future. Also applied the suggestions.

(I'm not sure why the tests are failing. That line passed before and I haven't changed anything in color_picker.h or color_picker.cpp)

@kitbdev
Copy link
Contributor

kitbdev commented May 1, 2025

It looks like in #105892 ColorPicker's _text_type_toggled was put in tools only ifdefs, so you should wrap the methods you added to ColorPicker in #ifdef TOOLS_ENABLED too.

@dugramen dugramen force-pushed the recovery/split-commit branch 2 times, most recently from c380b1f to a921f7e Compare May 1, 2025 14:09
@dugramen
Copy link
Contributor Author

dugramen commented May 1, 2025

Ok that worked. Thanks!

Copy link
Contributor

@kitbdev kitbdev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally the color parsing and text replacing would be separated to GDScript ScriptLanguage or somewhere, but there are lots of other GDScript specific things in the script editor, so it's fine for now.

Parsing should make sure that it only gets color constructors and not functions that end with Color:

image

The mouse cursor should change to indicate the color box can be clicked.

Selecting color objects should probably show the selection background behind it.

Comment on lines 125 to 130
enum InlineInfo {
INFO_LINE,
INFO_COLUMN,
INFO_WIDTH_RATIO, // Used to determine the object's width given a line height.
INFO_MAX
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if we use enums like these very often, as array indexes.
Its probably better to use a Dictionary instead of Array.

Copy link
Member

@Mickeon Mickeon May 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not odd. If you think about it this is akin to the constants used for PopupMenu items. Not sure of the context here, though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PopupMenu constants are used to distinguish which action to do based on the button, so only one callback is needed, but here it's used to transfer data generically in an Array with various types.

Like this:

Array color_info;
color_info.resize(INFO_COLOR_MAX);
color_info[TextEdit::INFO_LINE] = p_line;
color_info[TextEdit::INFO_COLUMN] = i_start;
color_info[TextEdit::INFO_WIDTH_RATIO] = 1.0;
color_info[INFO_COLOR_END] = i_par_end;

color_info[INFO_COLOR] = Color(color_string);

So it's already basically being used like a dictionary.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it even have to be either one of the two? Can it not be a struct here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It has to be a variant to be added as a object to TextServer. A struct can't do that (as far as I know)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my opinion using Arrays here is okay, as a strictly "server-sided" operation. It occupies less memory and doesn't need to be dynamic. It reminds me of the way ArrayMesh works.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine with either if array is better for memory / performance, though I did already transition to Dictionary locally. It might also be better in case it gets exposed in the future

@KoBeWi
Copy link
Member

KoBeWi commented May 2, 2025

There is another syntax supported for Colors, but it's probably the least used - integer colors, e.g. Color(0xff0000ff).

@Mickeon
Copy link
Member

Mickeon commented May 2, 2025

There is another syntax supported for Colors, but it's probably the least used - integer colors, e.g. Color(0xff0000ff).

Still, if not supported it may be deemed to be a bug down the line.

@kitbdev
Copy link
Contributor

kitbdev commented May 2, 2025

There is another syntax supported for Colors, but it's probably the least used - integer colors, e.g. Color(0xff0000ff).

Still, if not supported it may be deemed to be a bug down the line.

There's more constructors that aren't supported, I thought it was intentional. Color.hex, Color.hex64, Color.html, Color.from_rgb9995, Color(code, alpha).
Do they all need to be supported in this PR? Since they aren't as common I figured they could be added later, if wanted.

@dugramen
Copy link
Contributor Author

dugramen commented May 2, 2025

I have an updated commit ready for all kitbdev's fixes, but my wifi is out so I'll have to push tomorrow or something

There is another syntax supported for Colors, but it's probably the least used - integer colors, e.g. Color(0xff0000ff).

The way I have it set up now, the used syntax is just whatever tab is selected in the color picker, and if the hex toggle is enabled it uses a hex string. But that limits it to just those 4 constructors.

Would it be better to just ignore the tab, and instead repurpose the hex button to cycle between all the constructors. I think vscode does that

@dugramen dugramen force-pushed the recovery/split-commit branch from a921f7e to 12e9f9f Compare May 2, 2025 16:22
@dugramen
Copy link
Contributor Author

dugramen commented May 2, 2025

Alright wifi came back. Summary of fixes:

  • Switched to using dictionaries (willing to switch back if arrays are better for performance)
  • Fixed drawing bugs, and added transparent checker image for translucent colors
  • Prevent functions that end with "color" from showing a color button
  • Draw selection background for objects
  • Changed cursor to pointer when hovering an object

If this is called when the picker is already open, it gets called before _picker_closed and causes the symbol tooltip on hover to stay off.

It seems that ScriptTextEditor already forces hover tooltip to enabled anyways (not based on some setting like I thought), so I got rid of previous_tooltip_enabled and just enabled / disabled it when the popup opens / closes

Copy link
Contributor

@kitbdev kitbdev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previous issues are fixed.

When using word wrap and a line with a color object is wrapped, I get this error:
ERROR: modules\text_server_adv\text_server_adv.cpp:7137 - Condition "!sd->objects.has(p_key)" is true. Returning: Rect2()

@dugramen dugramen force-pushed the recovery/split-commit branch from 12e9f9f to 09f31e5 Compare May 5, 2025 01:50
@dugramen
Copy link
Contributor Author

dugramen commented May 5, 2025

Ok new commit implementing the fixes, and added support for hex integers.

I changed it so that you now choose a constructor from a dropdown, rather than it being tied to which tab the color picker is on. This enables any number of constructors in the future. I also simplified the code a bit to make adding & reordering constructors easier. Here's a demo:

2025-05-04.21-17-35.-.Trim.mp4

Also after testing more while considering word wrap, I found a few bugs relating to object hover / click position, so had to rework that a bit. The weird indentation offset code is just how its calculated in other places too

@dugramen dugramen force-pushed the recovery/split-commit branch from 09f31e5 to 5aadb88 Compare May 5, 2025 02:04
@dugramen dugramen force-pushed the recovery/split-commit branch from 5aadb88 to bba34b6 Compare May 5, 2025 19:28
Copy link
Contributor

@kitbdev kitbdev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works well.

Comment on lines 173 to 177
MODE_STRING,
MODE_HEX,
MODE_RGB,
MODE_HSV,
MODE_OKHSL,
MODE_RGB8,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
MODE_STRING,
MODE_HEX,
MODE_RGB,
MODE_HSV,
MODE_OKHSL,
MODE_RGB8,
MODE_RGB,
MODE_STRING,
MODE_HSV,
MODE_OKHSL,
MODE_RGB8,
MODE_HEX,

Or something like this, so the more common ones are first.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Delayed this a bit but I just pushed with the updated order. Also made the option list's font the same as the code editor, for readability

@dugramen dugramen force-pushed the recovery/split-commit branch from bba34b6 to 84b4deb Compare May 11, 2025 23:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants