@@ -396,8 +396,215 @@ bool ScriptTextEditor::show_members_overview() {
396396 return true ;
397397}
398398
399+ bool ScriptTextEditor::_is_valid_color_info (const Array &p_info) {
400+ if (p_info.size () < INFO_COLOR_MAX) {
401+ return false ;
402+ }
403+ if (p_info[INFO_COLOR].get_type () != Variant::COLOR) {
404+ return false ;
405+ }
406+ if (!p_info[INFO_COLOR_END].is_num () || !p_info[INFO_COLOR_MODE].is_num ()) {
407+ return false ;
408+ }
409+ return true ;
410+ }
411+
412+ Array ScriptTextEditor::_inline_object_parse (const String &p_text, int p_line) {
413+ Array result;
414+ int i_end_previous = 0 ;
415+ int i_start = p_text.find (" Color" );
416+
417+ while (i_start != -1 ) {
418+ int i_par_start = p_text.find_char (' (' , i_start + 5 );
419+ if (i_par_start != -1 ) {
420+ int i_par_end = p_text.find_char (' )' , i_start + 5 );
421+ if (i_par_end != -1 ) {
422+ Array color_info;
423+ color_info.resize (INFO_COLOR_MAX);
424+ color_info[TextEdit::INFO_LINE] = p_line;
425+ color_info[TextEdit::INFO_COLUMN] = i_start;
426+ color_info[TextEdit::INFO_WIDTH_RATIO] = 1.0 ;
427+ color_info[INFO_COLOR_END] = i_par_end;
428+
429+ String fn_name = p_text.substr (i_start + 5 , i_par_start - i_start - 5 );
430+ String s_params = p_text.substr (i_par_start + 1 , i_par_end - i_par_start - 1 );
431+ bool has_added_color = false ;
432+
433+ if (fn_name.is_empty () || fn_name == " .from_string" ) {
434+ String stripped = s_params.strip_edges (true , true );
435+ // String parameter.
436+ if (stripped.length () > 0 && (stripped[0 ] == ' \" ' )) {
437+ String color_string = stripped.substr (1 , stripped.length () - 2 );
438+ color_info[INFO_COLOR] = Color (color_string);
439+ color_info[INFO_COLOR_MODE] = -1 ;
440+ has_added_color = true ;
441+ }
442+ // Empty Color() constructor.
443+ else if (stripped.is_empty ()) {
444+ color_info[INFO_COLOR] = Color ();
445+ color_info[INFO_COLOR_MODE] = -1 ;
446+ has_added_color = true ;
447+ }
448+ }
449+ // Float & int parameters.
450+ if (!has_added_color && s_params.size () > 0 ) {
451+ PackedFloat64Array params = s_params.split_floats (" ," , false );
452+ if (params.size () == 3 ) {
453+ params.resize (4 );
454+ params.set (3 , 1.0 );
455+ }
456+ if (params.size () == 4 ) {
457+ has_added_color = true ;
458+ if (fn_name == " .from_ok_hsl" ) {
459+ color_info[INFO_COLOR] = Color::from_ok_hsl (params[0 ], params[1 ], params[2 ], params[3 ]);
460+ color_info[INFO_COLOR_MODE] = ColorPicker::MODE_OKHSL;
461+ } else if (fn_name == " .from_hsv" ) {
462+ color_info[INFO_COLOR] = Color::from_hsv (params[0 ], params[1 ], params[2 ], params[3 ]);
463+ color_info[INFO_COLOR_MODE] = ColorPicker::MODE_HSV;
464+ } else if (fn_name == " .from_rgba8" ) {
465+ color_info[INFO_COLOR] = Color::from_rgba8 (int (params[0 ]), int (params[1 ]), int (params[2 ]), int (params[3 ]));
466+ color_info[INFO_COLOR_MODE] = ColorPicker::MODE_RGB;
467+ } else if (fn_name.is_empty ()) {
468+ color_info[INFO_COLOR] = Color (params[0 ], params[1 ], params[2 ], params[3 ]);
469+ color_info[INFO_COLOR_MODE] = ColorPicker::MODE_RAW;
470+ } else {
471+ has_added_color = false ;
472+ }
473+ }
474+ }
475+
476+ if (has_added_color) {
477+ result.push_back (color_info);
478+ i_end_previous = i_par_end + 1 ;
479+ }
480+ }
481+ }
482+ i_end_previous = MAX (i_end_previous, i_start);
483+ i_start = p_text.find (" Color" , i_start + 1 );
484+ }
485+ return result;
486+ }
487+
488+ void ScriptTextEditor::_inline_object_draw (const Array &p_info, const Rect2 &p_rect) {
489+ if (_is_valid_color_info (p_info)) {
490+ Rect2 col_rect = p_rect.grow (-4 );
491+ code_editor->get_text_editor ()->draw_rect (col_rect, Color (p_info[INFO_COLOR]));
492+ code_editor->get_text_editor ()->draw_rect (col_rect, Color (1 , 1 , 1 ), false , 1 );
493+ }
494+ }
495+
496+ void ScriptTextEditor::_inline_object_handle_click (const Array &p_info, const Rect2 &p_rect) {
497+ if (_is_valid_color_info (p_info)) {
498+ int mode = p_info[INFO_COLOR_MODE];
499+ if (mode < 0 || mode >= ColorPicker::MODE_MAX) {
500+ inline_color_picker->set_using_hex_string (true );
501+ } else {
502+ inline_color_picker->set_using_hex_string (false );
503+ inline_color_picker->set_color_mode ((ColorPicker::ColorModeType)mode);
504+ }
505+
506+ inline_color_picker->set_pick_color (p_info[INFO_COLOR]);
507+ inline_color_line = p_info[TextEdit::INFO_LINE];
508+ inline_color_start = p_info[TextEdit::INFO_COLUMN];
509+ inline_color_end = p_info[INFO_COLOR_END];
510+
511+ // Move popup above the line if it's too low.
512+ float_t view_h = get_viewport_rect ().size .y ;
513+ float_t pop_h = inline_color_popup->get_contents_minimum_size ().y ;
514+ float_t pop_y = p_rect.get_end ().y ;
515+ float_t pop_x = p_rect.position .x ;
516+ if (pop_y + pop_h > view_h) {
517+ pop_y = p_rect.position .y - pop_h;
518+ }
519+ // Move popup to the right if it's too high.
520+ if (pop_y < 0 ) {
521+ pop_x = p_rect.get_end ().x ;
522+ }
523+
524+ inline_color_popup->popup (Rect2 (pop_x, pop_y, 0 , 0 ));
525+ code_editor->get_text_editor ()->set_selection_mode (TextEdit::SelectionMode::SELECTION_MODE_NONE);
526+ }
527+ }
528+
529+ String ScriptTextEditor::_picker_color_stringify (const Color &p_color, int p_mode) {
530+ String result;
531+ String fname;
532+ Vector<String> str_params;
533+ // HTML string.
534+ if (p_mode < 0 ) {
535+ str_params.push_back (" \" " + p_color.to_html () + " \" " );
536+ }
537+ // RGBA int parameters (0-255).
538+ else if (p_mode == ColorPicker::MODE_RGB) {
539+ str_params = {
540+ itos (p_color.get_r8 ()),
541+ itos (p_color.get_g8 ()),
542+ itos (p_color.get_b8 ()),
543+ itos (p_color.get_a8 ())
544+ };
545+ fname = " .from_rgba8" ;
546+ }
547+ // HSL, HSV, and RAW Float parameters.
548+ else {
549+ PackedFloat64Array flt_params;
550+ str_params.resize (4 );
551+ switch (p_mode) {
552+ case ColorPicker::MODE_HSV: {
553+ flt_params = { p_color.get_h (), p_color.get_s (), p_color.get_v (), p_color.a };
554+ fname = " .from_hsv" ;
555+ } break ;
556+ case ColorPicker::MODE_OKHSL: {
557+ flt_params = { p_color.get_ok_hsl_h (), p_color.get_ok_hsl_s (), p_color.get_ok_hsl_l (), p_color.a };
558+ fname = " .from_ok_hsl" ;
559+ } break ;
560+ case ColorPicker::MODE_RAW: {
561+ flt_params = { p_color.r , p_color.g , p_color.b , p_color.a };
562+ fname = " " ;
563+ } break ;
564+ }
565+ for (int ind = 0 ; ind < flt_params.size (); ind++) {
566+ str_params.set (ind, String::num (flt_params[ind], 3 ));
567+ }
568+ }
569+ result = " Color" + fname + " (" + String (" , " ).join (str_params) + " )" ;
570+ return result;
571+ }
572+
573+ void ScriptTextEditor::_picker_color_changed (const Color &p_color) {
574+ if (inline_color_line < 0 ) {
575+ return ;
576+ }
577+ int mode = inline_color_picker->get_color_mode ();
578+ if (inline_color_picker->is_using_hex_string ()) {
579+ mode = -1 ;
580+ }
581+ String result = _picker_color_stringify (p_color, mode);
582+ code_editor->get_text_editor ()->begin_complex_operation ();
583+ code_editor->get_text_editor ()->remove_text (inline_color_line, inline_color_start, inline_color_line, inline_color_end + 1 );
584+ inline_color_end = inline_color_start + result.size () - 2 ;
585+ code_editor->get_text_editor ()->insert_text (result, inline_color_line, inline_color_start);
586+ code_editor->get_text_editor ()->end_complex_operation ();
587+ }
588+
589+ void ScriptTextEditor::_picker_opening () {
590+ previous_tooltip_enabled = code_editor->get_text_editor ()->is_symbol_tooltip_on_hover_enabled ();
591+ code_editor->get_text_editor ()->set_symbol_tooltip_on_hover_enabled (false );
592+ }
593+
594+ void ScriptTextEditor::_picker_closed () {
595+ code_editor->get_text_editor ()->set_symbol_tooltip_on_hover_enabled (previous_tooltip_enabled);
596+ }
597+
399598void ScriptTextEditor::update_settings () {
400599 code_editor->get_text_editor ()->set_gutter_draw (connection_gutter, EDITOR_GET (" text_editor/appearance/gutters/show_info_gutter" ));
600+ if (EDITOR_GET (" text_editor/appearance/enable_inline_color_picker" )) {
601+ code_editor->get_text_editor ()->set_inline_object_handlers (
602+ callable_mp (this , &ScriptTextEditor::_inline_object_parse),
603+ callable_mp (this , &ScriptTextEditor::_inline_object_draw),
604+ callable_mp (this , &ScriptTextEditor::_inline_object_handle_click));
605+ } else {
606+ code_editor->get_text_editor ()->set_inline_object_handlers (Callable (), Callable (), Callable ());
607+ }
401608 code_editor->update_editor_settings ();
402609}
403610
@@ -2594,6 +2801,17 @@ ScriptTextEditor::ScriptTextEditor() {
25942801 bookmarks_menu = memnew (PopupMenu);
25952802 breakpoints_menu = memnew (PopupMenu);
25962803
2804+ inline_color_popup = memnew (PopupPanel);
2805+ inline_color_popup->connect (" about_to_popup" , callable_mp (this , &ScriptTextEditor::_picker_opening));
2806+ inline_color_popup->connect (" popup_hide" , callable_mp (this , &ScriptTextEditor::_picker_closed));
2807+ add_child (inline_color_popup);
2808+
2809+ inline_color_picker = memnew (ColorPicker);
2810+ inline_color_picker->set_mouse_filter (MOUSE_FILTER_STOP);
2811+ inline_color_picker->set_deferred_mode (true );
2812+ inline_color_picker->connect (" color_changed" , callable_mp (this , &ScriptTextEditor::_picker_color_changed));
2813+ inline_color_popup->add_child (inline_color_picker);
2814+
25972815 connection_info_dialog = memnew (ConnectionInfoDialog);
25982816
25992817 SET_DRAG_FORWARDING_GCD (code_editor->get_text_editor (), ScriptTextEditor);
0 commit comments