@@ -92,13 +92,8 @@ proc runeAtCursor*(self: TextBox): Rune =
92
92
return Rune(0)
93
93
result = self.layout.runes[self.clamped(Left, 0, inclusive=false ) ]
94
94
95
- proc findLine* (self: TextBox, down: bool , select: bool = false ): int =
96
- # # Finds the index of the line in self.layout.lines that contains the
97
- # # relevant cursor/selection point.
98
- # # - `down`: Indicates the direction of intended cursor movement (true for down, false for up).
99
- # # Used when `select` is false to determine which end of selection to check.
100
- # # - `select`: True if the selection is currently being grown (e.g., Shift + Arrow).
101
- # # Defaults to false.
95
+ proc findLine* (self: TextBox): int =
96
+ # # Returns the line the cursor is on.
102
97
103
98
result = - 1 # Default to -1 if no line is found
104
99
@@ -108,16 +103,7 @@ proc findLine*(self: TextBox, down: bool, select: bool = false): int =
108
103
if self.layout.lines.len == 0 :
109
104
return - 1
110
105
111
- var charPosToFind: int
112
- if select:
113
- charPosToFind = self.cursorPos
114
- else :
115
- if down:
116
- charPosToFind = self.selectionRange.b
117
- else :
118
- charPosToFind = self.selectionRange.a
119
-
120
- let clampedCharPos = clamp(charPosToFind, 0 , self.runes().len())
106
+ let clampedCharPos = clamp(self.cursorPos, 0 , self.runes().len())
121
107
122
108
for idx, lineSlice in self.layout.lines:
123
109
# Standard case: character position is within the rune indices of the line.
@@ -216,13 +202,14 @@ proc updateSelection*(self: var TextBox) =
216
202
rect.h = (rhs.y + rhs.h) - lhs.y
217
203
self.selectionRects.add rect.descaled()
218
204
219
- proc growSelection* (self: var TextBox) =
205
+ proc growSelection(self: var TextBox) =
220
206
self.selectionRange.a = min(self.cursorPos, self.anchor)
221
207
self.selectionRange.b = max(self.cursorPos, self.anchor)
222
208
if not self.selectionExists: self.selectionExists = true
223
209
self.updateSelection()
224
210
225
211
proc clearSelection* (self: var TextBox) =
212
+ # # Clears any existing selection.
226
213
self.anchor = self.cursorPos
227
214
self.selectionRange.a = self.cursorPos
228
215
self.selectionRange.b = self.cursorPos
@@ -248,20 +235,20 @@ proc updateCursor*(self: var TextBox) =
248
235
self.cursorRect = cursor.descaled()
249
236
250
237
proc placeCursor* (self: var TextBox, pos: int , select = false ) =
251
- # Places the keyboard cursor at the specified position.
252
- # Clears the selection and brings the anchor along unless
253
- # clearSelection is set to false.
238
+ # Places the keyboard cursor at the specified position (`pos`).
239
+ #
240
+ # If `select` is false (default), then the selection is cleared
241
+ # and the archor is moved with the cursor. Otherwise, a selection
242
+ # will be created.
254
243
self.cursorPos = clamp(pos, 0 , self.runes().len())
255
244
self.updateCursor()
256
245
if select: self.growSelection()
257
246
else : self.clearSelection()
258
247
259
- proc shiftCursorDown* (self: var TextBox, select = false ): int =
260
- # # Move cursor or selection down one line.
261
- # # - `select`: If true, extends the selection downwards.
262
- # # If false, moves the cursor and clears any existing selection.
248
+ proc shiftCursorDown(self: var TextBox): int =
249
+ # # Returns the target position for a downward movement of the cursor.
263
250
264
- let presentLineIdx = self.findLine(down = true , select = select )
251
+ let presentLineIdx = self.findLine()
265
252
266
253
# If findLine returns -1 (e.g., empty layout), do nothing.
267
254
if presentLineIdx == - 1 :
@@ -282,20 +269,17 @@ proc shiftCursorDown*(self: var TextBox, select = false): int =
282
269
let nextLineSlice = self.layout.lines[nextLineIdx]
283
270
284
271
# Calculate the horizontal offset (difference in rune indices)
285
- # from the start of the current line to the cursor's Right edge.
286
- let horizontalOffset = self.clamped(Right) - currentLineStartIdx
272
+ let horizontalOffset = self.cursorPos - currentLineStartIdx
287
273
288
274
# Calculate the target rune index on the next line.
289
275
# Add the horizontal offset to the start of the next line.
290
276
# Ensure the target index doesn't go beyond the end index of the next line.
291
277
return min(nextLineSlice.a + horizontalOffset, nextLineSlice.b)
292
278
293
- proc shiftCursorUp* (self: var TextBox, select = false ): int =
294
- # # Move cursor or selection up one line.
295
- # # - `select`: If true, extends the selection upwards.
296
- # # If false, moves the cursor and clears any existing selection.
279
+ proc shiftCursorUp(self: var TextBox): int =
280
+ # # Returns the target position for a upward movement of the cursor.
297
281
298
- let presentLineIdx = self.findLine(down = false , select = select )
282
+ let presentLineIdx = self.findLine()
299
283
if presentLineIdx == - 1 :
300
284
return
301
285
@@ -305,26 +289,27 @@ proc shiftCursorUp*(self: var TextBox, select = false): int =
305
289
else :
306
290
let previousLineIdx = clamp(presentLineIdx - 1 , 0 , self.layout.lines.high)
307
291
let previousLineSlice = self.layout.lines[previousLineIdx]
308
- let horizontalOffset = self.clamped(Left) - currentLineStartIdx
292
+ let horizontalOffset = self.cursorPos - currentLineStartIdx
309
293
return min(previousLineSlice.a + horizontalOffset, previousLineSlice.b)
310
294
311
295
proc shiftCursor* (self: var TextBox,
312
- orientation: Orient,
313
- select = false ) =
314
- # Shifts the keyboard cursor based on an orientation.
315
- # Options include: Right, Left, Up, Down,
316
- # Beginning, TheEnd, PreviousWord, NextWord.
317
- # Clears the selection and brings the anchor along unless
318
- # select is set to true.
296
+ orientation: Orient,
297
+ select = false ) =
298
+ # # Shifts the keyboard cursor based on an `orientation`.
299
+ # #
300
+ # # Orientations include: Right, Left, Up, Down,
301
+ # # Beginning, TheEnd, PreviousWord, NextWord.
302
+ # # If `select` is true, the selection is extended.
303
+ # # Otherwise, any existing selection is cleared.
319
304
let pos: int = case orientation
320
305
of Right: self.cursorPos + 1
321
306
of Left: self.cursorPos - 1
322
307
of NextWord: self.findNextWord()
323
308
of PreviousWord: self.findPrevWord()
324
309
of Beginning: 0
325
310
of TheEnd: self.runes().len()
326
- of Up: self.shiftCursorUp(select )
327
- of Down: self.shiftCursorDown(select )
311
+ of Up: self.shiftCursorUp()
312
+ of Down: self.shiftCursorDown()
328
313
self.cursorPos = clamp(pos, 0 , self.runes().len())
329
314
self.updateCursor()
330
315
if select: self.growSelection()
@@ -386,28 +371,50 @@ proc delete*(self: var TextBox, orientation: Orient) =
386
371
self.placeCursor(idx)
387
372
else : discard
388
373
389
- proc insert* (self: var TextBox, rune: Rune) =
390
-
374
+ proc insert* (self: var TextBox,
375
+ rune: Rune,
376
+ overWrite = false ,
377
+ rangeLimit = 0 ) =
378
+ # # Inserts a rune at the current cursor position.
379
+ # #
380
+ # # overWrite: If set to true, then replace the rune in front of cursorPos.
381
+ # # rangeLimit: If set to a number larger than 0,
382
+ # # then this function will not insert a rune once there are that many runes.
391
383
if self.selectionExists:
392
384
self.deleteSelected()
393
385
394
- if Overwrite in self.opts:
386
+ # 1. no overWrite, no rangeLimit
387
+ if not overWrite and rangeLimit == 0 :
388
+ self.runes.insert(rune, self.cursorPos)
389
+ # 2. no overWrite, yes rangeLimit
390
+ elif not overWrite and rangeLimit > 0 :
391
+ if rangeLimit > self.runes.len:
392
+ self.runes.insert(rune, self.cursorPos)
393
+ # 3. yes overWrite, no rangeLimit
394
+ elif overWrite and rangeLimit == 0 :
395
395
if self.cursorPos < self.runes.len():
396
396
self.runes[self.cursorPos] = rune
397
397
else :
398
398
self.runes.insert(rune, self.cursorPos)
399
- else :
400
- self.runes.insert(rune, self.cursorPos)
399
+ # 4. yes overWrite, yes rangeLimit
400
+ elif overWrite and rangeLimit > 0 :
401
+ if self.cursorPos <= rangeLimit - 1 :
402
+ if self.cursorPos < self.runes.len():
403
+ self.runes[self.cursorPos] = rune
404
+ else :
405
+ self.runes.insert(rune, self.cursorPos)
401
406
402
407
self.updateLayout()
403
408
self.shiftCursor(Right)
404
409
405
- proc insert* (self: var TextBox, runes: seq [Rune]) =
410
+ proc insert* (self: var TextBox,
411
+ runes: seq [Rune],
412
+ overWrite = false ) =
406
413
407
- if self.hasSelection() :
414
+ if self.selectionExists :
408
415
self.deleteSelected()
409
416
410
- if Overwrite in self.opts :
417
+ if overWrite :
411
418
for i in 0 ..< runes.len():
412
419
if self.cursorPos < self.runes.len():
413
420
self.runes[self.cursorPos] = runes[i]
0 commit comments