@@ -1228,11 +1228,13 @@ func get_previous_character(double_previous := false) -> DialogicCharacter:
1228
1228
## ##############################################################################
1229
1229
1230
1230
var search_results := {}
1231
- func _search_timeline (search_text :String ) -> bool :
1232
- # for event in search_results:
1233
- # if is_instance_valid(search_results[event]):
1234
- # search_results[event].set_search_text("")
1235
- #
1231
+ func _search_timeline (search_text :String , match_case := false , whole_words := false ) -> bool :
1232
+ var flags := 0
1233
+ if match_case :
1234
+ flags = flags | TextEdit .SEARCH_MATCH_CASE
1235
+ if whole_words :
1236
+ flags = flags | TextEdit .SEARCH_WHOLE_WORDS
1237
+
1236
1238
search_results .clear ()
1237
1239
1238
1240
# This checks all text events for whether they contain the text.
@@ -1245,13 +1247,15 @@ func _search_timeline(search_text:String) -> bool:
1245
1247
1246
1248
text_field .deselect ()
1247
1249
text_field .set_search_text (search_text )
1250
+ text_field .set_search_flags (flags )
1248
1251
1249
- if text_field .search (search_text , 0 , 0 , 0 ).x != - 1 :
1252
+ if text_field .search (search_text , flags , 0 , 0 ).x != - 1 :
1250
1253
search_results [block ] = text_field
1251
1254
1252
1255
text_field .queue_redraw ()
1253
1256
1254
1257
set_meta ("current_search" , search_text )
1258
+ set_meta ("current_search_flags" , flags )
1255
1259
1256
1260
search_navigate (false )
1257
1261
@@ -1267,10 +1271,24 @@ func _search_navigate_up() -> void:
1267
1271
1268
1272
1269
1273
func search_navigate (navigate_up := false ) -> void :
1274
+ var next_pos := get_next_search_position (navigate_up )
1275
+ if next_pos :
1276
+ var event : Node = next_pos [0 ]
1277
+ var field : TextEdit = next_pos [1 ]
1278
+ var result : Vector2i = next_pos [2 ]
1279
+ if not event in selected_items :
1280
+ select_item (next_pos [0 ], false )
1281
+ % TimelineArea .ensure_control_visible (event )
1282
+ event ._on_ToggleBodyVisibility_toggled (true )
1283
+ field .call_deferred ("select" , result .y , result .x , result .y , result .x + len (get_meta ("current_search" )))
1284
+
1285
+
1286
+ func get_next_search_position (navigate_up := false , include_current := false ) -> Array :
1270
1287
var search_text : String = get_meta ("current_search" , "" )
1288
+ var search_flags : int = get_meta ("current_search_flags" , 0 )
1271
1289
1272
1290
if search_results .is_empty () or % Timeline .get_child_count () == 0 :
1273
- return
1291
+ return []
1274
1292
1275
1293
# We start the search on the selected item,
1276
1294
# so these checks make sure something sensible is selected
@@ -1294,16 +1312,19 @@ func search_navigate(navigate_up := false) -> void:
1294
1312
1295
1313
var event : Node = selected_items [0 ]
1296
1314
var counter := 0
1315
+ var first := true
1297
1316
while true :
1298
1317
counter += 1
1299
1318
var field : TextEdit = search_results [event ]
1300
1319
field .queue_redraw ()
1301
1320
1302
1321
# First locates the next result in this field
1303
- var result := search_text_field (field , search_text , navigate_up )
1322
+ var result := search_text_field (field , search_text , search_flags , navigate_up , first and include_current )
1304
1323
var current_line := field .get_selection_from_line () if field .has_selection () else - 1
1305
1324
var current_column := field .get_selection_from_column () if field .has_selection () else - 1
1306
1325
1326
+ first = false
1327
+
1307
1328
# Determines if the found result is valid or navigation should continue into the next event
1308
1329
var next_is_in_this_event := false
1309
1330
if result .y == - 1 :
@@ -1313,17 +1334,14 @@ func search_navigate(navigate_up := false) -> void:
1313
1334
current_line = field .get_line_count ()- 1
1314
1335
current_column = field .get_line (current_line ).length ()
1315
1336
next_is_in_this_event = result .x < current_column or result .y < current_line
1337
+ elif include_current :
1338
+ next_is_in_this_event = true
1316
1339
else :
1317
1340
next_is_in_this_event = result .x > current_column or result .y > current_line
1318
1341
1319
- # If the next result was found, select it and break out of the loop
1342
+ # If the next result was found return it
1320
1343
if next_is_in_this_event :
1321
- if not event in selected_items :
1322
- select_item (event , false )
1323
- % TimelineArea .ensure_control_visible (event )
1324
- event ._on_ToggleBodyVisibility_toggled (true )
1325
- field .call_deferred ("select" , result .y , result .x , result .y , result .x + len (search_text ))
1326
- break
1344
+ return [event , field , result ]
1327
1345
1328
1346
# Otherwise deselct this field and continue in the next/previous
1329
1347
field .deselect ()
@@ -1333,9 +1351,10 @@ func search_navigate(navigate_up := false) -> void:
1333
1351
if counter > 5 :
1334
1352
print ("[Dialogic] Search failed." )
1335
1353
break
1354
+ return []
1336
1355
1337
1356
1338
- func search_text_field (field :TextEdit , search_text := "" , navigate_up := false ) -> Vector2i :
1357
+ func search_text_field (field :TextEdit , search_text := "" , flags : = 0 , navigate_up : = false , include_current := false ) -> Vector2i :
1339
1358
var search_from_line : int = 0
1340
1359
var search_from_column : int = 0
1341
1360
if field .has_selection ():
@@ -1347,6 +1366,9 @@ func search_text_field(field:TextEdit, search_text := "", navigate_up:= false) -
1347
1366
if search_from_line == - 1 :
1348
1367
return Vector2i (- 1 , - 1 )
1349
1368
search_from_column = field .get_line (search_from_line ).length ()- 1
1369
+ elif include_current :
1370
+ search_from_line = field .get_selection_from_line ()
1371
+ search_from_column = field .get_selection_from_column ()
1350
1372
else :
1351
1373
search_from_line = field .get_selection_to_line ()
1352
1374
search_from_column = field .get_selection_to_column ()
@@ -1355,7 +1377,62 @@ func search_text_field(field:TextEdit, search_text := "", navigate_up:= false) -
1355
1377
search_from_line = field .get_line_count ()- 1
1356
1378
search_from_column = field .get_line (search_from_line ).length ()- 1
1357
1379
1358
- var search := field .search (search_text , 4 if navigate_up else 0 , search_from_line , search_from_column )
1380
+ if navigate_up :
1381
+ flags = flags | TextEdit .SEARCH_BACKWARDS
1382
+
1383
+ var search := field .search (search_text , flags , search_from_line , search_from_column )
1359
1384
return search
1360
1385
1386
+
1387
+ func replace (replace_text :String ) -> void :
1388
+ var next_pos := get_next_search_position (false , true )
1389
+ var event : Node = next_pos [0 ]
1390
+ var field : TextEdit = next_pos [1 ]
1391
+ var result : Vector2i = next_pos [2 ]
1392
+
1393
+ if field .has_selection ():
1394
+ field .set_caret_column (field .get_selection_from_column ())
1395
+ field .set_caret_line (field .get_selection_from_line ())
1396
+
1397
+ field .begin_complex_operation ()
1398
+ field .insert_text ("@@" , result .y , result .x )
1399
+ if get_meta ("current_search_flags" ) & TextEdit .SEARCH_MATCH_CASE :
1400
+ field .text = field .text .replace ("@@" + get_meta ("current_search" ), replace_text )
1401
+ else :
1402
+ field .text = field .text .replacen ("@@" + get_meta ("current_search" ), replace_text )
1403
+ field .end_complex_operation ()
1404
+
1405
+ timeline_editor .replace_in_timeline ()
1406
+
1407
+
1408
+ func replace_all (replace_text :String ) -> void :
1409
+ var next_pos := get_next_search_position ()
1410
+ if not next_pos :
1411
+ return
1412
+ var event : Node = next_pos [0 ]
1413
+ var field : TextEdit = next_pos [1 ]
1414
+ var result : Vector2i = next_pos [2 ]
1415
+ field .begin_complex_operation ()
1416
+ while next_pos :
1417
+ event = next_pos [0 ]
1418
+ if field != next_pos [1 ]:
1419
+ field .end_complex_operation ()
1420
+ field = next_pos [1 ]
1421
+ field .begin_complex_operation ()
1422
+ result = next_pos [2 ]
1423
+
1424
+ if field .has_selection ():
1425
+ field .set_caret_column (field .get_selection_from_column ())
1426
+ field .set_caret_line (field .get_selection_from_line ())
1427
+
1428
+ field .insert_text ("@@" , result .y , result .x )
1429
+ if get_meta ("current_search_flags" ) & TextEdit .SEARCH_MATCH_CASE :
1430
+ field .text = field .text .replace ("@@" + get_meta ("current_search" ), replace_text )
1431
+ else :
1432
+ field .text = field .text .replacen ("@@" + get_meta ("current_search" ), replace_text )
1433
+
1434
+ next_pos = get_next_search_position ()
1435
+ field .end_complex_operation ()
1436
+ timeline_editor .replace_in_timeline ()
1437
+
1361
1438
#endregion
0 commit comments