--- a/hedgewars/uChat.pas Sat Feb 28 22:20:53 2015 +0100
+++ b/hedgewars/uChat.pas Sun Mar 01 04:15:11 2015 +0100
@@ -28,7 +28,7 @@
procedure CleanupInput;
procedure AddChatString(s: shortstring);
procedure DrawChat;
-procedure KeyPressChat(Key, Sym: Longword);
+procedure KeyPressChat(Key, Sym: Longword; Modifier: Word);
procedure SendHogSpeech(s: shortstring);
implementation
@@ -64,7 +64,7 @@
ChatHidden: boolean;
InputLinePrefix: shortstring;
// cursor
- cursorPos, cursorX: LongInt;
+ cursorPos, cursorX, selectedPos, selectionDx: LongInt;
LastKeyPressTick: LongWord;
const
@@ -94,11 +94,19 @@
const Padding = 2;
ClHeight = 2 * Padding + 16; // font height
+procedure ResetSelection();
+begin
+ selectedPos:= -1;
+end;
+
procedure UpdateCursorCoords();
var font: THWFont;
str : shortstring;
- coff: LongInt;
+ coff, soff: LongInt;
begin
+ if cursorPos = selectedPos then
+ ResetSelection();
+
// calculate cursor offset
str:= InputLinePrefix + InputStr.s;
@@ -109,12 +117,25 @@
// get render size of text
TTF_SizeUTF8(Fontz[font].Handle, Str2PChar(str), @coff, nil);
+ cursorX:= 7 - cScreenWidth div 2 + coff;
- cursorX:= 7 - cScreenWidth div 2 + coff;
+ // calculate selection width on screen
+ if selectedPos >= 0 then
+ begin
+ if selectedPos > cursorPos then
+ str:= InputLinePrefix + InputStr.s;
+ SetLength(str, Length(InputLinePrefix) + selectedPos);
+ TTF_SizeUTF8(Fontz[font].Handle, Str2PChar(str), @soff, nil);
+ selectionDx:= soff - coff;
+ end
+ else
+ selectionDx:= 0;
end;
+
procedure ResetCursor();
begin
+ ResetSelection();
cursorPos:= 0;
UpdateCursorCoords();
end;
@@ -226,6 +247,7 @@
procedure DrawChat;
var i, t, left, top, cnt: LongInt;
+ selRect: TSDL_Rect;
begin
ChatReady:= true; // maybe move to somewhere else?
@@ -240,9 +262,29 @@
if (GameState = gsChat) and (InputStr.Tex <> nil) then
begin
DrawTexture(left, top, InputStr.Tex);
- // draw cursor
- if ((RealTicks - LastKeyPressTick) and 512) < 256 then
- DrawLineOnScreen(cursorX, top + 2, cursorX, top + ClHeight - 2, 2.0, $00, $FF, $FF, $FF);
+ if selectedPos < 0 then
+ begin
+ // draw cursor
+ if ((RealTicks - LastKeyPressTick) and 512) < 256 then
+ DrawLineOnScreen(cursorX, top + 2, cursorX, top + ClHeight - 2, 2.0, $00, $FF, $FF, $FF);
+ end
+ else // draw selection
+ begin
+ selRect.y:= top + 2;
+ selRect.h:= clHeight - 4;
+ if selectionDx < 0 then
+ begin
+ selRect.x:= cursorX + selectionDx;
+ selRect.w:= -selectionDx;
+ end
+ else
+ begin
+ selRect.x:= cursorX;
+ selRect.w:= selectionDx;
+ end;
+
+ DrawRect(selRect, $FF, $FF, $FF, $40, true);
+ end;
end;
@@ -452,7 +494,7 @@
ResetKbd;
end;
-procedure DelBytesFromInputStr(endIdx: integer; count: byte);
+procedure DelBytesFromInputStrBack(endIdx: integer; count: byte);
var i, startIdx: integer;
begin
// nothing to do if count is 0
@@ -494,44 +536,77 @@
DelCharFromInputStr:= btw;
- DelBytesFromInputStr(idx, btw);
+ DelBytesFromInputStrBack(idx, btw);
end;
+// unchecked
procedure DoCursorStepForward();
begin
- if cursorPos < Length(InputStr.s) then
+ // go to end of next utf8-char
+ repeat
+ inc(cursorPos);
+ until InputStrL[cursorPos] <> InputStrLNoPred;
+end;
+
+procedure DeleteSelected();
+begin
+ if (selectedPos >= 0) and (cursorPos <> selectedPos) then
begin
- // go to end of next utf8-char
- repeat
- inc(cursorPos);
- until InputStrL[cursorPos] <> InputStrLNoPred;
+ DelBytesFromInputStrBack(max(cursorPos, selectedPos), abs(selectedPos-cursorPos));
+ cursorPos:= min(cursorPos, selectedPos);
+ ResetSelection();
end;
end;
-procedure KeyPressChat(Key, Sym: Longword);
+procedure HandleSelection(enabled: boolean);
+begin
+if enabled then
+ begin
+ if selectedPos < 0 then
+ selectedPos:= cursorPos;
+ end
+else
+ ResetSelection();
+end;
+
+procedure KeyPressChat(Key, Sym: Longword; Modifier: Word);
const firstByteMark: array[0..3] of byte = (0, $C0, $E0, $F0);
var i, btw, index: integer;
utf8: shortstring;
- action: boolean;
+ action, selMode, ctrl: boolean;
begin
LastKeyPressTick:= RealTicks;
action:= true;
+
+ selMode:= (modifier and (KMOD_LSHIFT or KMOD_RSHIFT)) <> 0;
+ ctrl:= (modifier and (KMOD_LCTRL or KMOD_RCTRL)) <> 0;
+
case Sym of
SDLK_BACKSPACE:
begin
- // remove char before cursor (note: cursorPos is 0-based, char idx isn't)
- dec(cursorPos, DelCharFromInputStr(cursorPos));
+ if selectedPos < 0 then
+ begin
+ // remove char before cursor (note: cursorPos is 0-based, char idx isn't)
+ dec(cursorPos, DelCharFromInputStr(cursorPos));
+ end
+ else
+ DeleteSelected();
UpdateCursorCoords();
end;
SDLK_DELETE:
begin
- // remove char after cursor
- if cursorPos < Length(InputStr.s) then
+ if selectedPos < 0 then
begin
- DoCursorStepForward();
- dec(cursorPos, DelCharFromInputStr(cursorPos));
- UpdateCursorCoords();
- end;
+ // remove char after cursor
+ if cursorPos < Length(InputStr.s) then
+ begin
+ DoCursorStepForward();
+ dec(cursorPos, DelCharFromInputStr(cursorPos));
+ end;
+ end
+ else
+ DeleteSelected();
+ UpdateCursorCoords();
end;
SDLK_ESCAPE:
begin
@@ -569,14 +644,15 @@
SetLine(InputStr, LocalStrs[index], true);
InputStrL:= LocalStrsL[index];
end;
- // TODO rebuild/restore InputStrL!!
cursorPos:= Length(InputStr.s);
+ ResetSelection();
UpdateCursorCoords();
end;
SDLK_HOME:
begin
if cursorPos > 0 then
begin
+ HandleSelection(selMode);
cursorPos:= 0;
UpdateCursorCoords();
end;
@@ -586,7 +662,7 @@
i:= Length(InputStr.s);
if cursorPos < i then
begin
- // TODO uft-8
+ HandleSelection(selMode);
cursorPos:= i;
UpdateCursorCoords();
end;
@@ -595,25 +671,62 @@
begin
if cursorPos > 0 then
begin
- // go to end of previous utf8-char
- cursorPos:= InputStrL[cursorPos];
+ if selMode or (selectedPos < 0) then
+ begin
+ HandleSelection(selMode);
+ // go to end of previous utf8-char
+ cursorPos:= InputStrL[cursorPos];
+ end
+ else // if we're leaving selection mode, jump to its left end
+ begin
+ cursorPos:= min(cursorPos, selectedPos);
+ ResetSelection();
+ end;
UpdateCursorCoords();
end;
end;
SDLK_RIGHT:
begin
- DoCursorStepForward();
- UpdateCursorCoords();
+ if cursorPos < Length(InputStr.s) then
+ begin
+ if selMode or (selectedPos < 0) then
+ begin
+ HandleSelection(selMode);
+ DoCursorStepForward();
+ end
+ else // if we're leaving selection mode, jump to its right end
+ begin
+ cursorPos:= max(cursorPos, selectedPos);
+ ResetSelection();
+ end;
+ UpdateCursorCoords();
+ end;
end;
SDLK_PAGEUP, SDLK_PAGEDOWN:
begin
// ignore me!!!
end;
+ SDLK_a:
+ begin
+ // select all
+ if ctrl then
+ begin
+ ResetSelection();
+ cursorPos:= Length(InputStr.s);
+ HandleSelection(true);
+ cursorPos:= 0;
+ UpdateCursorCoords();
+ end
+ else
+ action:= false;
+ end;
else
action:= false;
end;
if not action and (Key <> 0) then
begin
+ DeleteSelected();
+
if (Key < $80) then
btw:= 1
else if (Key < $800) then