2025-08-02 20:10:33 +03:00
# include "TextBoxEditTool.hpp"
# include "DrawingProgram.hpp"
# include "../MainProgram.hpp"
# include "../DrawData.hpp"
2025-11-08 20:50:23 +03:00
# include "Helpers/ConvertVec.hpp"
2025-08-02 20:10:33 +03:00
# include "Helpers/SCollision.hpp"
# include <cereal/types/vector.hpp>
2025-11-04 17:31:23 +03:00
# include <include/core/SkFontStyle.h>
2025-11-08 20:50:23 +03:00
# include <modules/skparagraph/include/DartTypes.h>
# include <modules/skparagraph/include/ParagraphStyle.h>
2025-11-09 16:24:40 +03:00
# include <modules/skparagraph/include/TextStyle.h>
2025-11-08 20:50:23 +03:00
# include <modules/skparagraph/src/ParagraphBuilderImpl.h>
# include <modules/skunicode/include/SkUnicode_icu.h>
2025-08-02 20:10:33 +03:00
# include <memory>
# include "EditTool.hpp"
2025-11-10 14:45:51 +03:00
using namespace RichText ;
2025-08-02 20:10:33 +03:00
TextBoxEditTool : : TextBoxEditTool ( DrawingProgram & initDrawP ) :
DrawingProgramEditToolBase ( initDrawP )
{ }
bool TextBoxEditTool : : edit_gui ( const std : : shared_ptr < DrawComponent > & comp ) {
std : : shared_ptr < DrawTextBox > a = std : : static_pointer_cast < DrawTextBox > ( comp ) ;
Toolbar & t = drawP . world . main . toolbar ;
2025-11-05 12:29:31 +03:00
2025-08-02 20:10:33 +03:00
t . gui . push_id ( " edit tool text " ) ;
t . gui . text_label_centered ( " Edit Text " ) ;
2025-11-08 20:50:23 +03:00
t . gui . left_to_right_line_layout ( [ & ] ( ) {
t . gui . text_label ( " Font " ) ;
2025-11-09 16:24:40 +03:00
if ( t . gui . font_picker ( " font picker " , & newFontName ) ) {
currentMods [ TextStyleModifier : : ModifierType : : FONT_FAMILIES ] = std : : make_shared < FontFamiliesTextStyleModifier > ( std : : vector < SkString > { SkString { newFontName . c_str ( ) , newFontName . size ( ) } } ) ;
2025-11-12 14:54:46 +03:00
add_undo_if_selecting_area ( a , [ & ] ( ) { a - > textBox - > set_text_style_modifier_between ( a - > cursor - > selectionBeginPos , a - > cursor - > selectionEndPos , currentMods [ TextStyleModifier : : ModifierType : : FONT_FAMILIES ] ) ; } ) ;
2025-11-09 16:24:40 +03:00
}
2025-11-08 20:50:23 +03:00
} ) ;
2025-11-05 12:29:31 +03:00
2025-11-05 18:21:49 +03:00
t . gui . left_to_right_line_centered_layout ( [ & ] ( ) {
2025-11-09 16:24:40 +03:00
if ( t . gui . svg_icon_button ( " Bold button " , " data/icons/RemixIcon/bold.svg " , newIsBold ) ) {
newIsBold = ! newIsBold ;
currentMods [ TextStyleModifier : : ModifierType : : WEIGHT ] = std : : make_shared < WeightTextStyleModifier > ( newIsBold ? SkFontStyle : : Weight : : kBold_Weight : SkFontStyle : : Weight : : kNormal_Weight ) ;
2025-11-12 14:54:46 +03:00
add_undo_if_selecting_area ( a , [ & ] ( ) { a - > textBox - > set_text_style_modifier_between ( a - > cursor - > selectionBeginPos , a - > cursor - > selectionEndPos , currentMods [ TextStyleModifier : : ModifierType : : WEIGHT ] ) ; } ) ;
2025-11-09 16:24:40 +03:00
}
if ( t . gui . svg_icon_button ( " Italic button " , " data/icons/RemixIcon/italic.svg " , newIsItalic ) ) {
newIsItalic = ! newIsItalic ;
currentMods [ TextStyleModifier : : ModifierType : : SLANT ] = std : : make_shared < SlantTextStyleModifier > ( newIsItalic ? SkFontStyle : : Slant : : kItalic_Slant : SkFontStyle : : Slant : : kUpright_Slant ) ;
2025-11-12 14:54:46 +03:00
add_undo_if_selecting_area ( a , [ & ] ( ) { a - > textBox - > set_text_style_modifier_between ( a - > cursor - > selectionBeginPos , a - > cursor - > selectionEndPos , currentMods [ TextStyleModifier : : ModifierType : : SLANT ] ) ; } ) ;
2025-11-09 16:24:40 +03:00
}
bool decorationEdited = false ;
if ( t . gui . svg_icon_button ( " Underline button " , " data/icons/RemixIcon/underline.svg " , newIsUnderlined ) ) {
newIsUnderlined = ! newIsUnderlined ;
decorationEdited = true ;
}
if ( t . gui . svg_icon_button ( " Strikethrough button " , " data/icons/RemixIcon/strikethrough.svg " , newIsLinethrough ) ) {
newIsLinethrough = ! newIsLinethrough ;
decorationEdited = true ;
}
if ( t . gui . svg_icon_button ( " Overline button " , " data/icons/RemixIcon/overline.svg " , newIsOverline ) ) {
newIsOverline = ! newIsOverline ;
decorationEdited = true ;
}
if ( decorationEdited ) {
currentMods [ TextStyleModifier : : ModifierType : : DECORATION ] = std : : make_shared < DecorationTextStyleModifier > ( get_new_decoration_value ( ) ) ;
2025-11-12 14:54:46 +03:00
add_undo_if_selecting_area ( a , [ & ] ( ) { a - > textBox - > set_text_style_modifier_between ( a - > cursor - > selectionBeginPos , a - > cursor - > selectionEndPos , currentMods [ TextStyleModifier : : ModifierType : : DECORATION ] ) ; } ) ;
2025-11-09 16:24:40 +03:00
}
2025-11-05 18:21:49 +03:00
} ) ;
2025-11-10 16:49:02 +03:00
t . gui . left_to_right_line_centered_layout ( [ & ] ( ) {
if ( t . gui . svg_icon_button ( " Align left button " , " data/icons/RemixIcon/align-left.svg " , currentPStyle . textAlignment = = skia : : textlayout : : TextAlign : : kLeft ) )
2025-11-12 14:54:46 +03:00
add_undo ( [ & ] ( ) { a - > textBox - > set_text_alignment_between ( a - > cursor - > selectionBeginPos . fParagraphIndex , a - > cursor - > selectionEndPos . fParagraphIndex , skia : : textlayout : : TextAlign : : kLeft ) ; } ) ;
2025-11-10 16:49:02 +03:00
if ( t . gui . svg_icon_button ( " Align center button " , " data/icons/RemixIcon/align-center.svg " , currentPStyle . textAlignment = = skia : : textlayout : : TextAlign : : kCenter ) )
2025-11-12 14:54:46 +03:00
add_undo ( [ & ] ( ) { a - > textBox - > set_text_alignment_between ( a - > cursor - > selectionBeginPos . fParagraphIndex , a - > cursor - > selectionEndPos . fParagraphIndex , skia : : textlayout : : TextAlign : : kCenter ) ; } ) ;
2025-11-10 16:49:02 +03:00
if ( t . gui . svg_icon_button ( " Align right button " , " data/icons/RemixIcon/align-right.svg " , currentPStyle . textAlignment = = skia : : textlayout : : TextAlign : : kRight ) )
2025-11-12 14:54:46 +03:00
add_undo ( [ & ] ( ) { a - > textBox - > set_text_alignment_between ( a - > cursor - > selectionBeginPos . fParagraphIndex , a - > cursor - > selectionEndPos . fParagraphIndex , skia : : textlayout : : TextAlign : : kRight ) ; } ) ;
2025-11-10 16:49:02 +03:00
if ( t . gui . svg_icon_button ( " Align justify button " , " data/icons/RemixIcon/align-justify.svg " , currentPStyle . textAlignment = = skia : : textlayout : : TextAlign : : kJustify ) )
2025-11-12 14:54:46 +03:00
add_undo ( [ & ] ( ) { a - > textBox - > set_text_alignment_between ( a - > cursor - > selectionBeginPos . fParagraphIndex , a - > cursor - > selectionEndPos . fParagraphIndex , skia : : textlayout : : TextAlign : : kJustify ) ; } ) ;
2025-11-10 16:49:02 +03:00
if ( t . gui . svg_icon_button ( " Text direction left " , " data/icons/RemixIcon/text-direction-l.svg " , currentPStyle . textDirection = = skia : : textlayout : : TextDirection : : kLtr ) )
2025-11-12 14:54:46 +03:00
add_undo ( [ & ] ( ) { a - > textBox - > set_text_direction_between ( a - > cursor - > selectionBeginPos . fParagraphIndex , a - > cursor - > selectionEndPos . fParagraphIndex , skia : : textlayout : : TextDirection : : kLtr ) ; } ) ;
2025-11-10 16:49:02 +03:00
if ( t . gui . svg_icon_button ( " Text direction right " , " data/icons/RemixIcon/text-direction-r.svg " , currentPStyle . textDirection = = skia : : textlayout : : TextDirection : : kRtl ) )
2025-11-12 14:54:46 +03:00
add_undo ( [ & ] ( ) { a - > textBox - > set_text_direction_between ( a - > cursor - > selectionBeginPos . fParagraphIndex , a - > cursor - > selectionEndPos . fParagraphIndex , skia : : textlayout : : TextDirection : : kRtl ) ; } ) ;
2025-11-10 16:49:02 +03:00
} ) ;
2025-11-09 16:24:40 +03:00
if ( t . gui . slider_scalar_field < uint32_t > ( " Font Size Slider " , " Font Size " , & newFontSize , 3 , 100 ) ) {
2025-11-12 14:54:46 +03:00
hold_undo_data ( " Font Size " , a ) ;
2025-11-09 16:24:40 +03:00
currentMods [ TextStyleModifier : : ModifierType : : SIZE ] = std : : make_shared < SizeTextStyleModifier > ( newFontSize ) ;
a - > textBox - > set_text_style_modifier_between ( a - > cursor - > selectionBeginPos , a - > cursor - > selectionEndPos , currentMods [ TextStyleModifier : : ModifierType : : SIZE ] ) ;
}
2025-11-12 14:54:46 +03:00
else
release_undo_data ( " Font Size " ) ;
2025-11-09 15:01:57 +03:00
2025-11-24 17:45:21 +03:00
// Text color
2025-11-05 18:21:49 +03:00
t . gui . left_to_right_line_layout ( [ & ] ( ) {
CLAY ( { . layout = { . sizing = { . width = CLAY_SIZING_FIXED ( 40 ) , . height = CLAY_SIZING_FIXED ( 40 ) } } } ) {
2025-11-12 14:54:46 +03:00
if ( t . gui . color_button ( " Text Color " , & newTextColor , & newTextColor = = t . colorRight ) )
2025-11-05 18:21:49 +03:00
t . color_selector_right ( & newTextColor = = t . colorRight ? nullptr : & newTextColor ) ;
}
t . gui . text_label ( " Text Color " ) ;
} ) ;
2025-11-12 14:54:46 +03:00
if ( & newTextColor = = t . colorRight )
hold_undo_data ( " Text Color " , a ) ;
else
release_undo_data ( " Text Color " ) ;
2025-11-09 16:24:40 +03:00
if ( ( & newTextColor = = t . colorRight ) & & t . isUpdatingColorRight ) {
currentMods [ TextStyleModifier : : ModifierType : : COLOR ] = std : : make_shared < ColorTextStyleModifier > ( newTextColor ) ;
a - > textBox - > set_text_style_modifier_between ( a - > cursor - > selectionBeginPos , a - > cursor - > selectionEndPos , currentMods [ TextStyleModifier : : ModifierType : : COLOR ] ) ;
}
2025-11-24 17:45:21 +03:00
// Highlight color
t . gui . left_to_right_line_layout ( [ & ] ( ) {
CLAY ( { . layout = { . sizing = { . width = CLAY_SIZING_FIXED ( 40 ) , . height = CLAY_SIZING_FIXED ( 40 ) } } } ) {
if ( t . gui . color_button ( " Highlight Color " , & newHighlightColor , & newHighlightColor = = t . colorRight ) ) {
if ( newHighlightColor . w ( ) = = 0.0f ) // Make highlight appear when the button is pressed
newHighlightColor . w ( ) = 1.0f ;
t . color_selector_right ( & newHighlightColor = = t . colorRight ? nullptr : & newHighlightColor ) ;
}
}
t . gui . text_label ( " Highlight Color " ) ;
2025-11-24 17:57:46 +03:00
if ( newHighlightColor . w ( ) ! = 0.0f ) {
if ( t . gui . svg_icon_button ( " Remove Highlight Color " , " data/icons/close.svg " ) ) {
newHighlightColor = Vector4f { 0.0f , 0.0f , 0.0f , 0.0f } ;
currentMods [ TextStyleModifier : : ModifierType : : HIGHLIGHT_COLOR ] = std : : make_shared < HighlightColorTextStyleModifier > ( newHighlightColor ) ;
add_undo_if_selecting_area ( a , [ & ] ( ) { a - > textBox - > set_text_style_modifier_between ( a - > cursor - > selectionBeginPos , a - > cursor - > selectionEndPos , currentMods [ TextStyleModifier : : ModifierType : : HIGHLIGHT_COLOR ] ) ; } ) ;
}
}
2025-11-24 17:45:21 +03:00
} ) ;
if ( & newHighlightColor = = t . colorRight )
hold_undo_data ( " Highlight Color " , a ) ;
else
release_undo_data ( " Highlight Color " ) ;
if ( ( & newHighlightColor = = t . colorRight ) & & t . isUpdatingColorRight ) {
currentMods [ TextStyleModifier : : ModifierType : : HIGHLIGHT_COLOR ] = std : : make_shared < HighlightColorTextStyleModifier > ( newHighlightColor ) ;
a - > textBox - > set_text_style_modifier_between ( a - > cursor - > selectionBeginPos , a - > cursor - > selectionEndPos , currentMods [ TextStyleModifier : : ModifierType : : HIGHLIGHT_COLOR ] ) ;
}
2025-08-02 20:10:33 +03:00
t . gui . pop_id ( ) ;
2025-10-25 17:31:55 +03:00
2025-11-10 16:49:02 +03:00
if ( a - > textBox - > inputChangedTextBox )
set_styles_at_selection ( a ) ;
2025-11-05 12:29:31 +03:00
// NOTE: There should be a system that periodically sends updates even if no changes are made, since unreliable channels can drop update data
bool oldInputChangedTextBox = a - > textBox - > inputChangedTextBox ;
a - > textBox - > inputChangedTextBox = false ;
return oldInputChangedTextBox ;
2025-08-02 20:10:33 +03:00
}
2025-11-12 14:54:46 +03:00
void TextBoxEditTool : : hold_undo_data ( const std : : string & undoName , const std : : shared_ptr < DrawTextBox > & a ) {
auto it = undoHeldData . find ( undoName ) ;
if ( it ! = undoHeldData . end ( ) ) {
std : : pair < RichText : : TextBox : : Cursor , RichText : : TextData > & undoData = it - > second ;
if ( undoData . first ! = * a - > cursor )
undoHeldData . erase ( it ) ;
}
else if ( a - > cursor - > selectionBeginPos ! = a - > cursor - > selectionEndPos )
undoHeldData . emplace ( undoName , std : : pair < RichText : : TextBox : : Cursor , RichText : : TextData > { * a - > cursor , a - > textBox - > get_rich_text_data ( ) } ) ;
}
void TextBoxEditTool : : release_undo_data ( const std : : string & undoName ) {
auto it = undoHeldData . find ( undoName ) ;
if ( it ! = undoHeldData . end ( ) ) {
std : : pair < RichText : : TextBox : : Cursor , RichText : : TextData > & undoData = it - > second ;
InputManager & input = drawP . world . main . input ;
input . text . add_textbox_undo ( undoData . first , undoData . second ) ;
undoHeldData . erase ( it ) ;
}
}
void TextBoxEditTool : : add_undo_if_selecting_area ( const std : : shared_ptr < DrawTextBox > & a , const std : : function < void ( ) > & func ) {
if ( a - > cursor - > selectionBeginPos = = a - > cursor - > selectionEndPos )
func ( ) ;
else {
InputManager & input = drawP . world . main . input ;
input . text . do_textbox_operation_with_undo ( func ) ;
}
}
void TextBoxEditTool : : add_undo ( const std : : function < void ( ) > & func ) {
InputManager & input = drawP . world . main . input ;
input . text . do_textbox_operation_with_undo ( func ) ;
}
2025-11-09 16:24:40 +03:00
uint8_t TextBoxEditTool : : get_new_decoration_value ( ) {
uint8_t toRet = skia : : textlayout : : TextDecoration : : kNoDecoration ;
if ( newIsUnderlined )
toRet | = skia : : textlayout : : TextDecoration : : kUnderline ;
if ( newIsLinethrough )
toRet | = skia : : textlayout : : TextDecoration : : kLineThrough ;
if ( newIsOverline )
toRet | = skia : : textlayout : : TextDecoration : : kOverline ;
return toRet ;
}
2025-11-10 16:49:02 +03:00
void TextBoxEditTool : : set_styles_at_selection ( const std : : shared_ptr < DrawTextBox > & a ) {
2025-11-10 14:45:51 +03:00
TextPosition start = std : : min ( a - > cursor - > selectionBeginPos , a - > cursor - > selectionEndPos ) ;
TextPosition end = std : : max ( a - > cursor - > selectionBeginPos , a - > cursor - > selectionEndPos ) ;
2025-11-05 14:55:22 +03:00
if ( start = = end )
2025-11-10 14:45:51 +03:00
currentMods = a - > textBox - > get_mods_used_at_pos ( a - > textBox - > move ( TextBox : : Movement : : LEFT , start ) ) ;
2025-11-05 14:55:22 +03:00
else
2025-11-09 16:24:40 +03:00
currentMods = a - > textBox - > get_mods_used_at_pos ( start ) ;
2025-11-10 16:49:02 +03:00
newFontName = std : : static_pointer_cast < FontFamiliesTextStyleModifier > ( currentMods [ TextStyleModifier : : ModifierType : : FONT_FAMILIES ] ) - > get_families ( ) . back ( ) . c_str ( ) ;
newFontSize = std : : static_pointer_cast < SizeTextStyleModifier > ( currentMods [ TextStyleModifier : : ModifierType : : SIZE ] ) - > get_size ( ) ;
newTextColor = std : : static_pointer_cast < ColorTextStyleModifier > ( currentMods [ TextStyleModifier : : ModifierType : : COLOR ] ) - > get_color ( ) ;
2025-11-24 17:45:21 +03:00
newHighlightColor = std : : static_pointer_cast < HighlightColorTextStyleModifier > ( currentMods [ TextStyleModifier : : ModifierType : : HIGHLIGHT_COLOR ] ) - > get_color ( ) ;
2025-11-10 16:49:02 +03:00
newIsBold = std : : static_pointer_cast < WeightTextStyleModifier > ( currentMods [ TextStyleModifier : : ModifierType : : WEIGHT ] ) - > get_weight ( ) = = SkFontStyle : : Weight : : kBold_Weight ;
newIsItalic = std : : static_pointer_cast < SlantTextStyleModifier > ( currentMods [ TextStyleModifier : : ModifierType : : SLANT ] ) - > get_slant ( ) = = SkFontStyle : : Slant : : kItalic_Slant ;
newIsUnderlined = std : : static_pointer_cast < DecorationTextStyleModifier > ( currentMods [ TextStyleModifier : : ModifierType : : DECORATION ] ) - > get_decoration_value ( ) & skia : : textlayout : : TextDecoration : : kUnderline ;
newIsLinethrough = std : : static_pointer_cast < DecorationTextStyleModifier > ( currentMods [ TextStyleModifier : : ModifierType : : DECORATION ] ) - > get_decoration_value ( ) & skia : : textlayout : : TextDecoration : : kLineThrough ;
newIsOverline = std : : static_pointer_cast < DecorationTextStyleModifier > ( currentMods [ TextStyleModifier : : ModifierType : : DECORATION ] ) - > get_decoration_value ( ) & skia : : textlayout : : TextDecoration : : kOverline ;
currentPStyle = a - > textBox - > get_paragraph_style_data_at ( start . fParagraphIndex ) ;
2025-11-05 14:55:22 +03:00
}
2025-08-02 20:10:33 +03:00
void TextBoxEditTool : : commit_edit_updates ( const std : : shared_ptr < DrawComponent > & comp , std : : any & prevData ) {
std : : shared_ptr < DrawTextBox > a = std : : static_pointer_cast < DrawTextBox > ( comp ) ;
a - > d . editing = false ;
2025-10-25 17:31:55 +03:00
auto pData = std : : any_cast < TextBoxEditToolAllData > ( prevData ) ;
TextBoxEditToolAllData cData = get_all_data ( a ) ;
2025-11-10 14:45:51 +03:00
TextData richText = a - > textBox - > get_rich_text_data ( ) ;
2025-08-02 20:10:33 +03:00
drawP . world . undo . push ( UndoManager : : UndoRedoPair {
2025-10-25 17:31:55 +03:00
[ & drawP = drawP , a , pData ] ( ) {
a - > d = pData . textboxData ;
a - > textBox - > set_rich_text_data ( pData . richText ) ;
2025-08-02 20:10:33 +03:00
a - > d . editing = false ;
2025-10-01 08:59:44 +03:00
a - > client_send_update ( drawP , true ) ;
2025-08-02 20:10:33 +03:00
a - > commit_update ( drawP ) ;
return true ;
} ,
2025-10-25 17:31:55 +03:00
[ & drawP = drawP , a , cData ] ( ) {
a - > d = cData . textboxData ;
a - > textBox - > set_rich_text_data ( cData . richText ) ;
2025-08-02 20:10:33 +03:00
a - > d . editing = false ;
2025-10-01 08:59:44 +03:00
a - > client_send_update ( drawP , true ) ;
2025-08-02 20:10:33 +03:00
a - > commit_update ( drawP ) ;
return true ;
}
} ) ;
}
2025-10-25 17:31:55 +03:00
TextBoxEditTool : : TextBoxEditToolAllData TextBoxEditTool : : get_all_data ( const std : : shared_ptr < DrawTextBox > & a ) {
return {
. textboxData = a - > d ,
. richText = a - > textBox - > get_rich_text_data ( )
} ;
}
2025-08-02 20:10:33 +03:00
void TextBoxEditTool : : edit_start ( EditTool & editTool , const std : : shared_ptr < DrawComponent > & comp , std : : any & prevData ) {
std : : shared_ptr < DrawTextBox > a = std : : static_pointer_cast < DrawTextBox > ( comp ) ;
2025-10-20 17:30:36 +03:00
auto & cur = a - > cursor ;
2025-08-02 20:10:33 +03:00
auto & textbox = a - > textBox ;
2025-11-10 14:45:51 +03:00
cur = std : : make_shared < TextBox : : Cursor > ( ) ;
2025-08-02 20:10:33 +03:00
Vector2f textSelectPos = a - > get_mouse_pos ( drawP ) ;
2025-10-20 17:30:36 +03:00
textbox - > process_mouse_left_button ( * cur , textSelectPos , true , false , false ) ;
2025-11-04 10:58:26 +03:00
prevData = get_all_data ( a ) ;
2025-08-02 20:10:33 +03:00
a - > d . editing = true ;
2025-11-05 12:29:31 +03:00
a - > textBox - > inputChangedTextBox = true ;
a - > commit_update ( drawP ) ;
2025-10-01 08:59:44 +03:00
a - > client_send_update ( drawP , false ) ;
2025-11-05 12:29:31 +03:00
2025-11-10 16:49:02 +03:00
set_styles_at_selection ( a ) ;
2025-11-05 12:29:31 +03:00
2025-08-02 20:10:33 +03:00
editTool . add_point_handle ( { & a - > d . p1 , nullptr , & a - > d . p2 } ) ;
editTool . add_point_handle ( { & a - > d . p2 , & a - > d . p1 , nullptr } ) ;
}
bool TextBoxEditTool : : edit_update ( const std : : shared_ptr < DrawComponent > & comp ) {
std : : shared_ptr < DrawTextBox > a = std : : static_pointer_cast < DrawTextBox > ( comp ) ;
SCollision : : ColliderCollection < float > mousePointCollection ;
mousePointCollection . circle . emplace_back ( drawP . world . main . input . mouse . pos , 1.0f ) ;
mousePointCollection . recalculate_bounds ( ) ;
2025-11-12 10:44:17 +03:00
a - > init_text_box ( drawP ) ;
2025-08-02 20:10:33 +03:00
InputManager & input = drawP . world . main . input ;
2025-10-20 17:30:36 +03:00
bool collidesWithBox = a - > collides_with_cam_coords ( drawP . world . drawData . cam . c , mousePointCollection ) ;
2025-08-02 20:10:33 +03:00
2025-11-09 16:24:40 +03:00
input . text . set_rich_text_box_input ( a - > textBox , a - > cursor , currentMods ) ;
2025-10-20 17:30:36 +03:00
a - > textBox - > process_mouse_left_button ( * a - > cursor , a - > get_mouse_pos ( drawP ) , drawP . controls . leftClick & & collidesWithBox , drawP . controls . leftClickHeld , input . key ( InputManager : : KEY_GENERIC_LSHIFT ) . held ) ;
2025-08-02 20:10:33 +03:00
return true ;
}