@@ -396,8 +396,234 @@ bool ScriptTextEditor::show_members_overview() {
396
396
return true ;
397
397
}
398
398
399
+ bool ScriptTextEditor::_is_valid_color_info (const Dictionary &p_info) {
400
+ if (p_info.get_valid (" color" ).get_type () != Variant::COLOR) {
401
+ return false ;
402
+ }
403
+ if (!p_info.get_valid (" color_end" ).is_num () || !p_info.get_valid (" color_mode" ).is_num ()) {
404
+ return false ;
405
+ }
406
+ return true ;
407
+ }
408
+
409
+ Array ScriptTextEditor::_inline_object_parse (const String &p_text, int p_line) {
410
+ Array result;
411
+ int i_end_previous = 0 ;
412
+ int i_start = p_text.find (" Color" );
413
+
414
+ while (i_start != -1 ) {
415
+ // Ignore words that just have "Color" in them.
416
+ if (i_start == 0 || !(" _" + p_text.substr (i_start - 1 , 1 )).is_valid_ascii_identifier ()) {
417
+ int i_par_start = p_text.find_char (' (' , i_start + 5 );
418
+ if (i_par_start != -1 ) {
419
+ int i_par_end = p_text.find_char (' )' , i_start + 5 );
420
+ if (i_par_end != -1 ) {
421
+ Dictionary color_info;
422
+ color_info[" line" ] = p_line;
423
+ color_info[" column" ] = i_start;
424
+ color_info[" width_ratio" ] = 1.0 ;
425
+ color_info[" color_end" ] = i_par_end;
426
+
427
+ String fn_name = p_text.substr (i_start + 5 , i_par_start - i_start - 5 );
428
+ String s_params = p_text.substr (i_par_start + 1 , i_par_end - i_par_start - 1 );
429
+ bool has_added_color = false ;
430
+
431
+ if (fn_name.is_empty ()) {
432
+ String stripped = s_params.strip_edges (true , true );
433
+ // String constructor.
434
+ if (stripped.length () > 0 && (stripped[0 ] == ' \" ' )) {
435
+ String color_string = stripped.substr (1 , stripped.length () - 2 );
436
+ color_info[" color" ] = Color (color_string);
437
+ color_info[" color_mode" ] = MODE_STRING;
438
+ has_added_color = true ;
439
+ }
440
+ // Hex constructor.
441
+ else if (stripped.length () == 10 && stripped.substr (0 , 2 ) == " 0x" ) {
442
+ color_info[" color" ] = Color (stripped.substr (2 , stripped.length () - 2 ));
443
+ color_info[" color_mode" ] = MODE_HEX;
444
+ has_added_color = true ;
445
+ }
446
+ // Empty Color() constructor.
447
+ else if (stripped.is_empty ()) {
448
+ color_info[" color" ] = Color ();
449
+ color_info[" color_mode" ] = MODE_RGB;
450
+ has_added_color = true ;
451
+ }
452
+ }
453
+ // Float & int parameters.
454
+ if (!has_added_color && s_params.size () > 0 ) {
455
+ PackedFloat64Array params = s_params.split_floats (" ," , false );
456
+ if (params.size () == 3 ) {
457
+ params.resize (4 );
458
+ params.set (3 , 1.0 );
459
+ }
460
+ if (params.size () == 4 ) {
461
+ has_added_color = true ;
462
+ if (fn_name == " .from_ok_hsl" ) {
463
+ color_info[" color" ] = Color::from_ok_hsl (params[0 ], params[1 ], params[2 ], params[3 ]);
464
+ color_info[" color_mode" ] = MODE_OKHSL;
465
+ } else if (fn_name == " .from_hsv" ) {
466
+ color_info[" color" ] = Color::from_hsv (params[0 ], params[1 ], params[2 ], params[3 ]);
467
+ color_info[" color_mode" ] = MODE_HSV;
468
+ } else if (fn_name == " .from_rgba8" ) {
469
+ color_info[" color" ] = Color::from_rgba8 (int (params[0 ]), int (params[1 ]), int (params[2 ]), int (params[3 ]));
470
+ color_info[" color_mode" ] = MODE_RGB8;
471
+ } else if (fn_name.is_empty ()) {
472
+ color_info[" color" ] = Color (params[0 ], params[1 ], params[2 ], params[3 ]);
473
+ color_info[" color_mode" ] = MODE_RGB;
474
+ } else {
475
+ has_added_color = false ;
476
+ }
477
+ }
478
+ }
479
+
480
+ if (has_added_color) {
481
+ result.push_back (color_info);
482
+ i_end_previous = i_par_end + 1 ;
483
+ }
484
+ }
485
+ }
486
+ }
487
+ i_end_previous = MAX (i_end_previous, i_start);
488
+ i_start = p_text.find (" Color" , i_start + 1 );
489
+ }
490
+ return result;
491
+ }
492
+
493
+ void ScriptTextEditor::_inline_object_draw (const Dictionary &p_info, const Rect2 &p_rect) {
494
+ if (_is_valid_color_info (p_info)) {
495
+ Rect2 col_rect = p_rect.grow (-4 );
496
+ if (color_alpha_texture.is_null ()) {
497
+ color_alpha_texture = inline_color_picker->get_theme_icon (" sample_bg" , " ColorPicker" );
498
+ }
499
+ code_editor->get_text_editor ()->draw_texture_rect (color_alpha_texture, col_rect, false );
500
+ code_editor->get_text_editor ()->draw_rect (col_rect, Color (p_info[" color" ]));
501
+ code_editor->get_text_editor ()->draw_rect (col_rect, Color (1 , 1 , 1 ), false , 1 );
502
+ }
503
+ }
504
+
505
+ void ScriptTextEditor::_inline_object_handle_click (const Dictionary &p_info, const Rect2 &p_rect) {
506
+ if (_is_valid_color_info (p_info)) {
507
+ inline_color_picker->set_pick_color (p_info[" color" ]);
508
+ inline_color_line = p_info[" line" ];
509
+ inline_color_start = p_info[" column" ];
510
+ inline_color_end = p_info[" color_end" ];
511
+
512
+ // Reset tooltip hover timer.
513
+ code_editor->get_text_editor ()->set_symbol_tooltip_on_hover_enabled (false );
514
+ code_editor->get_text_editor ()->set_symbol_tooltip_on_hover_enabled (true );
515
+
516
+ _update_color_constructor_options ();
517
+ inline_color_options->select (p_info[" color_mode" ]);
518
+
519
+ // Move popup above the line if it's too low.
520
+ float_t view_h = get_viewport_rect ().size .y ;
521
+ float_t pop_h = inline_color_popup->get_contents_minimum_size ().y ;
522
+ float_t pop_y = p_rect.get_end ().y ;
523
+ float_t pop_x = p_rect.position .x ;
524
+ if (pop_y + pop_h > view_h) {
525
+ pop_y = p_rect.position .y - pop_h;
526
+ }
527
+ // Move popup to the right if it's too high.
528
+ if (pop_y < 0 ) {
529
+ pop_x = p_rect.get_end ().x ;
530
+ }
531
+
532
+ inline_color_popup->popup (Rect2 (pop_x, pop_y, 0 , 0 ));
533
+ }
534
+ }
535
+
536
+ String ScriptTextEditor::_picker_color_stringify (const Color &p_color, COLOR_MODE p_mode) {
537
+ String result;
538
+ String fname;
539
+ Vector<String> str_params;
540
+ switch (p_mode) {
541
+ case ScriptTextEditor::MODE_STRING: {
542
+ str_params.push_back (" \" " + p_color.to_html () + " \" " );
543
+ } break ;
544
+ case ScriptTextEditor::MODE_HEX: {
545
+ str_params.push_back (" 0x" + p_color.to_html ());
546
+ } break ;
547
+ case ScriptTextEditor::MODE_RGB: {
548
+ str_params = {
549
+ String::num (p_color.r , 3 ),
550
+ String::num (p_color.g , 3 ),
551
+ String::num (p_color.b , 3 ),
552
+ String::num (p_color.a , 3 )
553
+ };
554
+ } break ;
555
+ case ScriptTextEditor::MODE_HSV: {
556
+ str_params = {
557
+ String::num (p_color.get_h (), 3 ),
558
+ String::num (p_color.get_s (), 3 ),
559
+ String::num (p_color.get_v (), 3 ),
560
+ String::num (p_color.a , 3 )
561
+ };
562
+ fname = " .from_hsv" ;
563
+ } break ;
564
+ case ScriptTextEditor::MODE_OKHSL: {
565
+ str_params = {
566
+ String::num (p_color.get_ok_hsl_h (), 3 ),
567
+ String::num (p_color.get_ok_hsl_s (), 3 ),
568
+ String::num (p_color.get_ok_hsl_l (), 3 ),
569
+ String::num (p_color.a , 3 )
570
+ };
571
+ fname = " .from_ok_hsl" ;
572
+ } break ;
573
+ case ScriptTextEditor::MODE_RGB8: {
574
+ str_params = {
575
+ itos (p_color.get_r8 ()),
576
+ itos (p_color.get_g8 ()),
577
+ itos (p_color.get_b8 ()),
578
+ itos (p_color.get_a8 ())
579
+ };
580
+ fname = " .from_rgba8" ;
581
+ } break ;
582
+ }
583
+ result = " Color" + fname + " (" + String (" , " ).join (str_params) + " )" ;
584
+ return result;
585
+ }
586
+
587
+ void ScriptTextEditor::_picker_color_changed (const Color &p_color) {
588
+ _update_color_constructor_options ();
589
+ _update_color_text ();
590
+ }
591
+
592
+ void ScriptTextEditor::_update_color_constructor_options () {
593
+ int item_count = inline_color_options->get_item_count ();
594
+ // Update or add each constructor as an option.
595
+ for (int i = 0 ; i < MODE_MAX; i++) {
596
+ String option_text = _picker_color_stringify (inline_color_picker->get_pick_color (), (COLOR_MODE)i);
597
+ if (i >= item_count) {
598
+ inline_color_options->add_item (option_text);
599
+ } else {
600
+ inline_color_options->set_item_text (i, option_text);
601
+ }
602
+ }
603
+ }
604
+
605
+ void ScriptTextEditor::_update_color_text () {
606
+ if (inline_color_line < 0 ) {
607
+ return ;
608
+ }
609
+ String result = inline_color_options->get_item_text (inline_color_options->get_selected_id ());
610
+ code_editor->get_text_editor ()->begin_complex_operation ();
611
+ code_editor->get_text_editor ()->remove_text (inline_color_line, inline_color_start, inline_color_line, inline_color_end + 1 );
612
+ inline_color_end = inline_color_start + result.size () - 2 ;
613
+ code_editor->get_text_editor ()->insert_text (result, inline_color_line, inline_color_start);
614
+ code_editor->get_text_editor ()->end_complex_operation ();
615
+ }
616
+
399
617
void ScriptTextEditor::update_settings () {
400
618
code_editor->get_text_editor ()->set_gutter_draw (connection_gutter, EDITOR_GET (" text_editor/appearance/gutters/show_info_gutter" ));
619
+ if (EDITOR_GET (" text_editor/appearance/enable_inline_color_picker" )) {
620
+ code_editor->get_text_editor ()->set_inline_object_handlers (
621
+ callable_mp (this , &ScriptTextEditor::_inline_object_parse),
622
+ callable_mp (this , &ScriptTextEditor::_inline_object_draw),
623
+ callable_mp (this , &ScriptTextEditor::_inline_object_handle_click));
624
+ } else {
625
+ code_editor->get_text_editor ()->set_inline_object_handlers (Callable (), Callable (), Callable ());
626
+ }
401
627
code_editor->update_editor_settings ();
402
628
}
403
629
@@ -2594,6 +2820,23 @@ ScriptTextEditor::ScriptTextEditor() {
2594
2820
bookmarks_menu = memnew (PopupMenu);
2595
2821
breakpoints_menu = memnew (PopupMenu);
2596
2822
2823
+ inline_color_popup = memnew (PopupPanel);
2824
+ add_child (inline_color_popup);
2825
+
2826
+ inline_color_picker = memnew (ColorPicker);
2827
+ inline_color_picker->set_mouse_filter (MOUSE_FILTER_STOP);
2828
+ inline_color_picker->set_deferred_mode (true );
2829
+ inline_color_picker->set_hex_visible (false );
2830
+ inline_color_picker->connect (" color_changed" , callable_mp (this , &ScriptTextEditor::_picker_color_changed));
2831
+ inline_color_popup->add_child (inline_color_picker);
2832
+
2833
+ inline_color_options = memnew (OptionButton);
2834
+ inline_color_options->set_h_size_flags (SIZE_FILL);
2835
+ inline_color_options->set_text_overrun_behavior (TextServer::OVERRUN_TRIM_ELLIPSIS);
2836
+ inline_color_options->set_fit_to_longest_item (false );
2837
+ inline_color_options->connect (" item_selected" , callable_mp (this , &ScriptTextEditor::_update_color_text).unbind (1 ));
2838
+ inline_color_picker->get_slider (ColorPicker::SLIDER_COUNT)->get_parent ()->add_sibling (inline_color_options);
2839
+
2597
2840
connection_info_dialog = memnew (ConnectionInfoDialog);
2598
2841
2599
2842
SET_DRAG_FORWARDING_GCD (code_editor->get_text_editor (), ScriptTextEditor);
0 commit comments