mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-09-01 23:00:27 +02:00
lcl:
- add more UTF8 string functions (Delete, Insert, LoweCase, UpperCase) - revert gtk SelStart, SelLength changes - they are and will return position in Characters - fix combobox completion code git-svn-id: trunk@16478 -
This commit is contained in:
parent
5f4857e470
commit
8ae1d62bbe
@ -483,7 +483,7 @@ end;
|
||||
|
||||
procedure TCustomComboBox.KeyUp(var Key: Word; Shift: TShiftState);
|
||||
var
|
||||
iSelStart: Integer; // byte position
|
||||
iSelStart: Integer; // char position
|
||||
sCompleteText, sPrefixText, sResultText: string;
|
||||
begin
|
||||
inherited KeyUp(Key, Shift);
|
||||
@ -510,10 +510,10 @@ begin
|
||||
iSelStart := SelStart;//Capture original cursor position
|
||||
//DebugLn(['TCustomComboBox.UTF8KeyPress SelStart=',SelStart,' Text=',Text]);
|
||||
//End of line completion
|
||||
if ((iSelStart < Length(Text))
|
||||
and (cbactEndOfLineComplete in FAutoCompleteText)) then
|
||||
if ((iSelStart < UTF8Length(Text)) and
|
||||
(cbactEndOfLineComplete in FAutoCompleteText)) then
|
||||
Exit;
|
||||
sPrefixText := LeftStr(Text, iSelStart);
|
||||
sPrefixText := UTF8Copy(Text, 1, iSelStart);
|
||||
sCompleteText := GetCompleteText(Text, iSelStart,
|
||||
(cbactSearchCaseSensitive in FAutoCompleteText),
|
||||
(cbactSearchAscending in FAutoCompleteText), Items);
|
||||
@ -524,12 +524,12 @@ begin
|
||||
if ((cbactEndOfLineComplete in FAutoCompleteText) and
|
||||
(cbactRetainPrefixCase in FAutoCompleteText)) then
|
||||
begin//Retain Prefix Character cases
|
||||
Delete(sResultText, 1, iSelStart);
|
||||
Insert(sPrefixText, sResultText, 1);
|
||||
UTF8Delete(sResultText, 1, iSelStart);
|
||||
UTF8Insert(sPrefixText, sResultText, 1);
|
||||
end;
|
||||
Text := sResultText;
|
||||
SelStart := iSelStart;
|
||||
SelLength := Length(Text);
|
||||
SelLength := UTF8Length(Text);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
@ -539,8 +539,8 @@ procedure TCustomComboBox.KeyPress(var Key: char);
|
||||
begin
|
||||
//Convert character cases if FCharCase is not ecNormalCase
|
||||
case FCharCase of
|
||||
ecLowerCase: Key := lowerCase(Key);
|
||||
ecUpperCase: Key := upCase(Key);
|
||||
ecLowerCase: Key := lowerCase(Key);
|
||||
ecUpperCase: Key := upCase(Key);
|
||||
end;
|
||||
inherited KeyPress(Key);
|
||||
end;
|
||||
@ -549,8 +549,8 @@ procedure TCustomComboBox.UTF8KeyPress(var UTF8Key: TUTF8Char);
|
||||
begin
|
||||
//Convert character cases if FCharCase is not ecNormalCase
|
||||
case FCharCase of
|
||||
ecLowerCase: UTF8Key := AnsiLowerCase(UTF8Key);
|
||||
ecUpperCase: UTF8Key := AnsiUpperCase(UTF8Key);
|
||||
ecLowerCase: UTF8Key := AnsiLowerCase(UTF8Key);
|
||||
ecUpperCase: UTF8Key := AnsiUpperCase(UTF8Key);
|
||||
end;
|
||||
inherited UTF8KeyPress(UTF8Key);
|
||||
end;
|
||||
|
@ -1224,14 +1224,10 @@ begin
|
||||
// if the combo is an editable ...
|
||||
Entry := GetComboBoxEntry(WidgetInfo^.CoreWidget);
|
||||
if Entry<>nil then begin
|
||||
// Note: gtk begins at 0, LCL at 1
|
||||
if gtk_editable_get_selection_bounds(PGtkEditable(Entry), @AStart, @AEnd) = gtk_true then
|
||||
Result := Min(AStart,AEnd)
|
||||
if gtk_editable_get_selection_bounds(PGtkEditable(Entry), @AStart, @AEnd) = False then
|
||||
Result := gtk_editable_get_position(PGtkEditable(Entry))
|
||||
else
|
||||
Result := gtk_editable_get_position(PGtkEditable(Entry));
|
||||
//DebugLn(['TGtk2WSCustomComboBox.GetSelStart CharStart=',Result]);
|
||||
Result:=UTF8CharToByteIndex(gtk_entry_get_text(Entry),High(integer),Result+1)-1;
|
||||
//DebugLn(['TGtk2WSCustomComboBox.GetSelStart ',dbgsName(ACustomComboBox),' AText=',gtk_entry_get_text(Entry),' Result=',Result]);
|
||||
Result := Min(AStart, AEnd);
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -1241,7 +1237,6 @@ var
|
||||
WidgetInfo: PWidgetInfo;
|
||||
Entry: PGtkEntry;
|
||||
AStart, AEnd: gint;
|
||||
AText: Pgchar;
|
||||
begin
|
||||
Result := 0;
|
||||
WidgetInfo := GetWidgetInfo(Pointer(ACustomComboBox.Handle));
|
||||
@ -1249,16 +1244,9 @@ begin
|
||||
// if the combo is an editable ...
|
||||
Entry := GetComboBoxEntry(WidgetInfo^.CoreWidget);
|
||||
if Entry<>nil then begin
|
||||
if gtk_editable_get_selection_bounds(PGtkEditable(Entry), @AStart, @AEnd) = gtk_true then
|
||||
begin
|
||||
MakeMinMax(AStart,AEnd);
|
||||
AText:=gtk_editable_get_chars(PGtkEditable(Entry),AStart,AEnd);
|
||||
Result:=UTF8Length(AText,(AEnd-AStart)*4);
|
||||
g_free(AText);
|
||||
end
|
||||
else
|
||||
Result := 0;
|
||||
DebugLn(['TGtk2WSCustomComboBox.GetSelLength ',dbgsName(ACustomComboBox),' AText=',gtk_entry_get_text(Entry),' Result=',Result]);
|
||||
if gtk_editable_get_selection_bounds(PGtkEditable(Entry), @AStart, @AEnd) = False then
|
||||
Exit(gtk_editable_get_position(PGtkEditable(Entry)));
|
||||
Result := ABS(AStart - AEnd);
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -1325,16 +1313,13 @@ class procedure TGtk2WSCustomComboBox.SetSelStart(
|
||||
var
|
||||
WidgetInfo: PWidgetInfo;
|
||||
Entry: PGtkEntry;
|
||||
AText: Pgchar;
|
||||
begin
|
||||
WidgetInfo := GetWidgetInfo(Pointer(ACustomComboBox.Handle));
|
||||
|
||||
Entry := GetComboBoxEntry(WidgetInfo^.CoreWidget);
|
||||
if Entry<>nil then begin
|
||||
//gtk_entry_select_region(Entry, NewStart, NewStart);
|
||||
AText:=gtk_entry_get_text(Entry);
|
||||
//DebugLn(['TGtk2WSCustomComboBox.SetSelStart ',dbgsName(ACustomComboBox),' AText=',AText,' NewStart=',NewStart,' UTF8Start=',UTF8Length(AText,NewStart-1)]);
|
||||
gtk_editable_set_position(PGtkEditable(Entry), UTF8Length(AText,NewStart));
|
||||
gtk_editable_set_position(PGtkEditable(Entry), NewStart);
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -1343,27 +1328,14 @@ class procedure TGtk2WSCustomComboBox.SetSelLength(
|
||||
var
|
||||
WidgetInfo: PWidgetInfo;
|
||||
Entry: PGtkEntry;
|
||||
AStart, AEnd: gint;// starts at 0
|
||||
ByteStart: LongInt;// starts at 0
|
||||
AText: Pgchar;
|
||||
NewCharLength: LongInt;
|
||||
Start: Integer;
|
||||
begin
|
||||
WidgetInfo := GetWidgetInfo(Pointer(ACustomComboBox.Handle));
|
||||
|
||||
Entry := GetComboBoxEntry(WidgetInfo^.CoreWidget);
|
||||
if Entry<>nil then begin
|
||||
if gtk_editable_get_selection_bounds(PGtkEditable(Entry), @AStart, @AEnd) = gtk_true then
|
||||
MakeMinMax(AStart,AEnd)
|
||||
else
|
||||
AStart := gtk_editable_get_position(PGtkEditable(Entry));
|
||||
AText:=gtk_entry_get_text(Entry);
|
||||
NewCharLength:=NewLength;
|
||||
if (NewCharLength>0) and (AText<>nil) then begin
|
||||
ByteStart:=UTF8CharToByteIndex(AText,High(integer),AStart+1)-1;
|
||||
NewCharLength:=UTF8Length(@AText[ByteStart],NewLength);
|
||||
end;
|
||||
//DebugLn(['TGtk2WSCustomComboBox.SetSelLength ',dbgsName(ACustomComboBox),' AText=',AText,' CharStart=',AStart,' ByteStart=',ByteStart,' NewLength=',NewLength,' NewCharLength=',NewCharLength]);
|
||||
gtk_editable_select_region(PGtkEditable(Entry), AStart, AStart + NewCharLength);
|
||||
Start := GetSelStart(ACustomComboBox);
|
||||
gtk_editable_select_region(PGtkEditable(Entry), Start, Start + NewLength);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
@ -302,6 +302,10 @@ function UTF8CharacterStrictLength(P: PChar): integer;
|
||||
function UTF8CStringToUTF8String(SourceStart: PChar; SourceLen: SizeInt) : string;
|
||||
function UTF8Pos(const SearchForText, SearchInText: string): integer;
|
||||
function UTF8Copy(const s: string; StartCharIndex, CharCount: integer): string;
|
||||
procedure UTF8Delete(var s: String; StartCharIndex, CharCount: integer);
|
||||
procedure UTF8Insert(const source: String; var s: string; StartCharIndex: integer);
|
||||
function UTF8LowerCase(const s: String): String;
|
||||
function UTF8UpperCase(const s: String): String;
|
||||
function FindInvalidUTF8Character(p: PChar; Count: integer;
|
||||
StopOnNonASCII: Boolean = false): integer;
|
||||
procedure AssignUTF8ListToAnsi(UTF8List, AnsiList: TStrings);
|
||||
@ -533,11 +537,13 @@ function GetCompleteText(sText: string; iSelStart: Integer;
|
||||
|
||||
function IsSamePrefix(sCompareText, sPrefix: string; iStart: Integer;
|
||||
var ResultText: string): Boolean;
|
||||
var sTempText: string;
|
||||
var
|
||||
sTempText: string;
|
||||
begin
|
||||
Result := False;
|
||||
sTempText := LeftStr(sCompareText, iStart);
|
||||
if not bCaseSensitive then sTempText := UpperCase(sTempText);
|
||||
sTempText := UTF8Copy(sCompareText, 1, iStart);
|
||||
if not bCaseSensitive then
|
||||
sTempText := UTF8UpperCase(sTempText);
|
||||
if (sTempText = sPrefix) then
|
||||
begin
|
||||
ResultText := sCompareText;
|
||||
@ -545,25 +551,28 @@ function GetCompleteText(sText: string; iSelStart: Integer;
|
||||
end;
|
||||
end;
|
||||
|
||||
var i: Integer;
|
||||
sPrefixText: string;
|
||||
var
|
||||
i: Integer;
|
||||
sPrefixText: string;
|
||||
begin
|
||||
//DebugLn(['GetCompleteText sText=',sText,' iSelStart=',iSelStart,' bCaseSensitive=',bCaseSensitive,' bSearchAscending=',bSearchAscending,' slTextList.Count=',slTextList.Count]);
|
||||
Result := sText;//Default to return original text if no identical text are found
|
||||
if (sText = '') then Exit;//Everything is compatible with nothing, Exit.
|
||||
if (iSelStart = 0) then Exit;//Cursor at beginning
|
||||
if (slTextList.Count = 0) then Exit;//No text list to search for idtenticals, Exit.
|
||||
sPrefixText := LeftStr(sText, iSelStart);//Get text from beginning to cursor position.
|
||||
sPrefixText := UTF8Copy(sText, 1, iSelStart);//Get text from beginning to cursor position.
|
||||
if not bCaseSensitive then
|
||||
sPrefixText := UpperCase(sPrefixText);
|
||||
sPrefixText := UTF8UpperCase(sPrefixText);
|
||||
if bSearchAscending then
|
||||
begin
|
||||
for i:=0 to slTextList.Count-1 do
|
||||
if IsSamePrefix(slTextList[i], sPrefixText, iSelStart, Result) then Break;
|
||||
for i := 0 to slTextList.Count - 1 do
|
||||
if IsSamePrefix(slTextList[i], sPrefixText, iSelStart, Result) then
|
||||
break;
|
||||
end else
|
||||
begin
|
||||
for i:=slTextList.Count-1 downto 0 do
|
||||
if IsSamePrefix(slTextList[i], sPrefixText, iSelStart, Result) then Break;
|
||||
for i := slTextList.Count - 1 downto 0 do
|
||||
if IsSamePrefix(slTextList[i], sPrefixText, iSelStart, Result) then
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -2684,6 +2693,43 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure UTF8Delete(var s: String; StartCharIndex, CharCount: integer);
|
||||
var
|
||||
StartBytePos: PChar;
|
||||
EndBytePos: PChar;
|
||||
MaxBytes: PtrInt;
|
||||
begin
|
||||
StartBytePos:=UTF8CharStart(PChar(s),length(s),StartCharIndex-1);
|
||||
if StartBytePos <> nil then
|
||||
begin
|
||||
MaxBytes:=PtrInt(PChar(s)+length(s)-StartBytePos);
|
||||
EndBytePos:=UTF8CharStart(StartBytePos,MaxBytes,CharCount);
|
||||
if EndBytePos=nil then
|
||||
Delete(s,StartBytePos-PChar(s)+1,MaxBytes)
|
||||
else
|
||||
Delete(s,StartBytePos-PChar(s)+1,EndBytePos-StartBytePos);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure UTF8Insert(const source: String; var s: string; StartCharIndex: integer);
|
||||
var
|
||||
StartBytePos: PChar;
|
||||
begin
|
||||
StartBytePos:=UTF8CharStart(PChar(s),length(s),StartCharIndex-1);
|
||||
if StartBytePos <> nil then
|
||||
Insert(source, s, StartBytePos-PChar(s)+1);
|
||||
end;
|
||||
|
||||
function UTF8LowerCase(const s: String): String;
|
||||
begin
|
||||
Result := UTF8Encode(WideLowerCase(UTF8Decode(s)));
|
||||
end;
|
||||
|
||||
function UTF8UpperCase(const s: String): String;
|
||||
begin
|
||||
Result := UTF8Encode(WideUpperCase(UTF8Decode(s)));
|
||||
end;
|
||||
|
||||
function FindInvalidUTF8Character(p: PChar; Count: integer;
|
||||
StopOnNonASCII: Boolean): integer;
|
||||
// return -1 if ok
|
||||
|
Loading…
Reference in New Issue
Block a user