@@ -12,7 +12,10 @@ interface
1212
1313uses
1414 Classes, SysUtils, SynEdit, SynEditKeyCmds, SynEditHighlighter, laz.VirtualTrees,
15- Graphics, SynCompletion, Types;
15+ Graphics, SynCompletion, Types
16+ { $IFDEF HEIDI_LINUX_QT}
17+ , Forms, LMessages
18+ { $ENDIF} ;
1619
1720type
1821
@@ -30,6 +33,10 @@ THeidiVirtualStringTree = class(TLazVirtualStringTree)
3033 function BlendQtColor (BaseColor, AccentColor: TColor; AccentPercent: Byte): TColor;
3134 procedure DrawQtSolidLine (Canvas: TCanvas; Left, Top, Right, Bottom: Integer);
3235 protected
36+ procedure CMHintShow (var Message: TCMHintShow); message CM_HINTSHOW;
37+ procedure CMHintShowPause (var Message: TCMHintShowPause); message CM_HINTSHOWPAUSE;
38+ function QtHintMaxWidth : Integer;
39+ function WrapQtHintLongTokens (const S: String; MaxWidth: Integer): String;
3340 procedure DoBeforeCellPaint (Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
3441 CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); override;
3542 procedure DoAfterCellPaint (Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
@@ -208,7 +215,134 @@ implementation
208215
209216{ $IFDEF HEIDI_LINUX_QT}
210217uses
211- Math;
218+ Math, LazUTF8;
219+ const
220+ QtHintInitialPauseMs = 250 ;
221+ QtHintKeepAliveMs = 24 * 60 * 60 * 1000 ;
222+
223+ function THeidiVirtualStringTree.QtHintMaxWidth : Integer;
224+ var
225+ Monitor: TMonitor;
226+ WorkWidth, PreferredWidth, MinimumWidth, ScreenCap: Integer;
227+ begin
228+ PreferredWidth := Canvas.TextWidth(StringOfChar(' 0' , 96 )) + 24 ;
229+ MinimumWidth := Canvas.TextWidth(StringOfChar(' 0' , 48 )) + 24 ;
230+ Monitor := Screen.MonitorFromWindow(Handle);
231+ if Assigned(Monitor) then
232+ WorkWidth := Monitor.WorkareaRect.Right - Monitor.WorkareaRect.Left
233+ else
234+ WorkWidth := Screen.Width;
235+
236+ Result := PreferredWidth;
237+ if WorkWidth > 0 then begin
238+ ScreenCap := (WorkWidth * 2 ) div 3 ;
239+ if ScreenCap < MinimumWidth then
240+ Result := ScreenCap
241+ else
242+ Result := Min(Result, ScreenCap);
243+ end ;
244+ Result := Max(240 , Result);
245+ end ;
246+
247+ function THeidiVirtualStringTree.WrapQtHintLongTokens (const S: String; MaxWidth: Integer): String;
248+ const
249+ BreakChars = ' .,;:/\_-+=)]}>' ;
250+
251+ function WrapToken (Token: String): String;
252+ var
253+ CharCount, LowPos, HighPos, MidPos, FitPos, BreakPos, I: Integer;
254+ Prefix, C: String;
255+ begin
256+ Result := ' ' ;
257+ while (Token <> ' ' ) and (Canvas.TextWidth(Token) > MaxWidth) do begin
258+ CharCount := UTF8Length(Token);
259+ if CharCount <= 1 then
260+ Break;
261+
262+ LowPos := 1 ;
263+ HighPos := CharCount;
264+ FitPos := 1 ;
265+ while LowPos <= HighPos do begin
266+ MidPos := (LowPos + HighPos) div 2 ;
267+ Prefix := UTF8Copy(Token, 1 , MidPos);
268+ if Canvas.TextWidth(Prefix) <= MaxWidth then begin
269+ FitPos := MidPos;
270+ LowPos := MidPos + 1 ;
271+ end
272+ else
273+ HighPos := MidPos - 1 ;
274+ end ;
275+
276+ BreakPos := FitPos;
277+ for I := FitPos downto Max(1 , (FitPos * 3 ) div 4 ) do begin
278+ C := UTF8Copy(Token, I, 1 );
279+ if Pos(C, BreakChars) > 0 then begin
280+ BreakPos := I;
281+ Break;
282+ end ;
283+ end ;
284+
285+ Result := Result + UTF8Copy(Token, 1 , BreakPos) + LineEnding;
286+ Token := UTF8Copy(Token, BreakPos + 1 , CharCount - BreakPos);
287+ end ;
288+ Result := Result + Token;
289+ end ;
290+
291+ var
292+ I, TokenStart: Integer;
293+ Token: String;
294+ begin
295+ if (S = ' ' ) or (MaxWidth <= 0 ) then begin
296+ Result := S;
297+ Exit;
298+ end ;
299+
300+ Result := ' ' ;
301+ TokenStart := 1 ;
302+ I := 1 ;
303+ while I <= Length(S) do begin
304+ if S[I] in [#9 , #10 , #13 , ' ' ] then begin
305+ if I > TokenStart then begin
306+ Token := Copy(S, TokenStart, I - TokenStart);
307+ Result := Result + WrapToken(Token);
308+ end ;
309+ Result := Result + S[I];
310+ Inc(I);
311+ TokenStart := I;
312+ end
313+ else
314+ Inc(I);
315+ end ;
316+ if TokenStart <= Length(S) then begin
317+ Token := Copy(S, TokenStart, Length(S) - TokenStart + 1 );
318+ Result := Result + WrapToken(Token);
319+ end ;
320+ end ;
321+
322+ procedure THeidiVirtualStringTree.CMHintShowPause (var Message: TCMHintShowPause);
323+ begin
324+ if Assigned(Message.Pause) and (Message.WasActive = 0 ) and
325+ (Message.Pause^ > QtHintInitialPauseMs) then
326+ Message.Pause^ := QtHintInitialPauseMs;
327+ Message.Result := 0 ;
328+ end ;
329+
330+ procedure THeidiVirtualStringTree.CMHintShow (var Message: TCMHintShow);
331+ var
332+ MaxWidth: Integer;
333+ begin
334+ LastHintRect := Rect(0 , 0 , 0 , 0 );
335+ inherited ;
336+
337+ if (Message.Result <> 0 ) or not Assigned(Message.HintInfo) then
338+ Exit;
339+
340+ MaxWidth := QtHintMaxWidth;
341+ Message.HintInfo^.HintMaxWidth := MaxWidth;
342+ Message.HintInfo^.HideTimeout := QtHintKeepAliveMs;
343+ Message.HintInfo^.ReshowTimeout := 0 ;
344+ Message.HintInfo^.HintStr := WrapQtHintLongTokens(Message.HintInfo^.HintStr, Max(1 , MaxWidth - 16 ));
345+ end ;
212346
213347function THeidiVirtualStringTree.BlendQtColor (BaseColor, AccentColor: TColor;
214348 AccentPercent: Byte): TColor;
0 commit comments