IDE: Make source editor use the new HintManager class.

git-svn-id: trunk@45828 -
This commit is contained in:
juha 2014-07-11 16:31:23 +00:00
parent 39ed58f021
commit a4ee0ab208
3 changed files with 171 additions and 114 deletions

View File

@ -17,7 +17,7 @@ unit IDEHelpIntf;
interface
uses
Classes, SysUtils, LCLProc, Forms, Controls, HelpIntfs, LazHelpIntf,
Classes, SysUtils, types, LCLProc, Forms, Controls, HelpIntfs, LazHelpIntf,
TextTools;
type
@ -145,22 +145,33 @@ type
{ THintWindowManager }
THintWindowManager = class
private
FHintWindowClass: THintWindowClass;
FHintWindow: THintWindow;
FHtmlHelpProvider: TAbstractIDEHTMLProvider;
FBaseURL: string;
FFlags: TIDEHTMLControlFlags;
private
FOrigMousePos: TPoint;
// These will be passed to HintWindow.
FWindowName: string;
FHideInterval: Integer;
function HtmlHelpProvider: TAbstractIDEHTMLProvider;
procedure SetHideInterval(AValue: Integer);
procedure SetWindowName(AValue: string);
protected
FHintWindow: THintWindow;
public
constructor Create; overload;
constructor Create(AHintWindowClass: THintWindowClass); overload;
destructor Destroy; override;
function HintWindow: THintWindow;
function HintIsVisible: boolean;
function ShowHint(ScreenPos: TPoint; TheHint: string): boolean;
procedure HideHint;
public
property BaseURL: string read FBaseURL write FBaseURL;
property Flags: TIDEHTMLControlFlags read FFlags write FFlags;
property HideInterval: Integer read FHideInterval write SetHideInterval;
property WindowName: string read FWindowName write SetWindowName;
end;
var
@ -240,6 +251,7 @@ begin
inherited Create;
FHintWindowClass := THintWindow;
FFlags := [ihcWithClipboardMenu];
FHideInterval := 3000;
end;
constructor THintWindowManager.Create(AHintWindowClass: THintWindowClass);
@ -254,6 +266,23 @@ begin
inherited Destroy;
end;
function THintWindowManager.HintWindow: THintWindow;
begin
if FHintWindow = nil then
begin
FHintWindow := FHintWindowClass.Create(Nil);
if FWindowName <> '' then
FHintWindow.Name := FWindowName;
FHintWindow.HideInterval := FHideInterval;
end;
Result := FHintWindow;
end;
function THintWindowManager.HintIsVisible: boolean;
begin
Result := Assigned(FHintWindow) and FHintWindow.Visible;
end;
function THintWindowManager.HtmlHelpProvider: TAbstractIDEHTMLProvider;
var
HelpControl: TControl;
@ -261,8 +290,8 @@ begin
if FHtmlHelpProvider = nil then
begin
//Include(FFlags, ihcScrollable); // Debug (memo control does not work)
HelpControl := CreateIDEHTMLControl(FHintWindow, FHtmlHelpProvider, FFlags);
HelpControl.Parent := FHintWindow;
HelpControl := CreateIDEHTMLControl(HintWindow, FHtmlHelpProvider, FFlags);
HelpControl.Parent := HintWindow;
HelpControl.Align := alClient;
end;
Result := FHtmlHelpProvider;
@ -273,12 +302,10 @@ var
ms: TMemoryStream;
NewWidth, NewHeight: integer;
begin
Result:=true;
if TheHint = '' then exit;
if TheHint = '' then Exit(False);
FOrigMousePos := Mouse.CursorPos;
if FHintWindow <> nil then
FHintWindow.Visible := false; // ???
if FHintWindow = nil then
FHintWindow := FHintWindowClass.Create(Nil);
if CompareText(copy(TheHint,1,6),'<HTML>')=0 then // Text is HTML
begin
HtmlHelpProvider.BaseURL:=FBaseURL;
@ -296,17 +323,18 @@ begin
NewWidth := 500;
if NewHeight <= 0 then
NewHeight := 200;
FHintWindow.HintRect := Rect(0, 0, NewWidth, NewHeight);
FHintWindow.OffsetHintRect(ScreenPos);
HintWindow.HintRect := Rect(0, 0, NewWidth, NewHeight);
HintWindow.OffsetHintRect(ScreenPos);
//DebugLn('--- ShowHint with HTML formatting ---');
FHintWindow.ActivateHint;
HintWindow.ActivateHint;
end
else begin // Plain text
FHintWindow.CalcHintRect(Screen.Width, TheHint, nil);
FHintWindow.OffsetHintRect(ScreenPos);
HintWindow.CalcHintRect(Screen.Width, TheHint, nil);
HintWindow.OffsetHintRect(ScreenPos);
//DebugLn('--- ShowHint plain text ---');
FHintWindow.ActivateHint(TheHint);
HintWindow.ActivateHint(TheHint);
end;
Result:=True;
end;
procedure THintWindowManager.HideHint;
@ -315,5 +343,23 @@ begin
FHintWindow.Visible := False;
end;
// Setters
procedure THintWindowManager.SetHideInterval(AValue: Integer);
begin
if FHideInterval = AValue then Exit;
FHideInterval := AValue;
if Assigned(FHintWindow) then
FHintWindow.HideInterval := FHideInterval;
end;
procedure THintWindowManager.SetWindowName(AValue: string);
begin
if FWindowName = AValue then Exit;
FWindowName := AValue;
if Assigned(FHintWindow) then
FHintWindow.Name := FWindowName;
end;
end.

View File

@ -245,6 +245,15 @@ type
property RTLHelpDBPath: THelpBaseURLObject read FRTLHelpDBPath;
end;
{ TIDEHintWindowManager }
TIDEHintWindowManager = class(THintWindowManager)
public
function HintIsComplex: boolean;
function SenderIsHintControl(Sender: TObject): Boolean;
function PtIsOnHint(Pt: TPoint): boolean;
end;
{ THelpSelectorDialog }
THelpSelectorDialog = class(TForm)
@ -1761,5 +1770,51 @@ begin
Result:=ConvertCodePosToPascalHelpContext(@CodePos);
end;
{ TIDEHintWindowManager }
function TIDEHintWindowManager.HintIsComplex: boolean;
begin
if FHintWindow = Nil then Exit(False);
Assert(FHintWindow.ControlCount > 0,
'HintIsComplex: ControlCount = ' + IntToStr(FHintWindow.ControlCount));
Result := FHintWindow.Visible and not (FHintWindow.Controls[0] is TSimpleHTMLControl);
end;
function TIDEHintWindowManager.PtIsOnHint(Pt: TPoint): boolean;
begin
Result := PtInRect(FHintWindow.BoundsRect, Pt);
end;
function TIDEHintWindowManager.SenderIsHintControl(Sender: TObject): Boolean;
// ToDo: simplify. FHintWindow only has one child control.
function IsHintControl(Control: TWinControl): Boolean;
var
I: Integer;
begin
if not Control.Visible then
Exit(False);
Result := Control = Sender;
if Result then
Exit;
for I := 0 to Control.ControlCount - 1 do
begin
Result := Control.Controls[I] = Sender;
if Result then
Exit;
if (Control.Controls[I] is TWinControl) then
begin
Result := IsHintControl(TWinControl(Control.Controls[I]));
if Result then
Exit;
end;
end;
end;
begin
Result := Assigned(Sender) and Assigned(FHintWindow) and IsHintControl(FHintWindow);
end;
end.

View File

@ -717,7 +717,7 @@ type
States: TSourceNotebookStates;
// HintWindow stuff
// ToDo: HintWindow should be common to all SourceNotebooks. Only one hint is shown at a time.
FHintWindow: THintWindow;
FHintManager: TIDEHintWindowManager;
FMouseHintTimer: TIdleTimer;
FMouseHideHintTimer: TTimer;
FHintMousePos: TPoint;
@ -5773,7 +5773,7 @@ begin
FManager := TSourceEditorManager(AOwner);
FUpdateLock := 0;
FFocusLock := 0;
Visible:=false;
Visible := false;
FIsClosing := False;
FWindowID := AWindowID;
if AWindowID > 0 then
@ -5786,14 +5786,14 @@ begin
else
FBaseCaption := locWndSrcEditor;
Caption := FBaseCaption;
KeyPreview:=true;
KeyPreview := true;
FProcessingCommand := false;
FSourceEditorList := TFPList.Create;
FHistoryList := TFPList.Create;
FSrcEditsSortedForFilenames := TAvgLvlTree.Create(@CompareSrcEditIntfWithFilename);
OnDropFiles:=@SourceNotebookDropFiles;
OnDropFiles := @SourceNotebookDropFiles;
AllowDropFiles:=true;
// popup menu
@ -5802,7 +5802,7 @@ begin
// HintTimer
FMouseHintTimer := TIdleTimer.Create(Self);
with FMouseHintTimer do begin
Name:=Self.Name+'_MouseHintTimer';
Name := Self.Name+'_MouseHintTimer';
Interval := EditorOpts.AutoDelayInMSec;
Enabled := False;
AutoEnabled := False;
@ -5812,21 +5812,16 @@ begin
// Track mouse movements outside the IDE, if hint is visible
FMouseHideHintTimer := TTimer.Create(Self);
with FMouseHideHintTimer do begin
Name:=Self.Name+'_MouseHintHideTimer';
Name := Self.Name+'_MouseHintHideTimer';
Interval := 500;
Enabled := False;
OnTimer := @HideHintTimer;
OnTimer := @HideHintTimer;
end;
// HintWindow
FHintWindow := THintWindow.Create(Self);
with FHintWindow do begin
Name:=Self.Name+'_HintWindow';
Visible := False;
Caption := '';
HideInterval := 4000;
AutoHide := False;
end;
FHintManager := TIDEHintWindowManager.Create;
FHintManager.WindowName := Self.Name+'_HintWindow';
FHintManager.HideInterval := 4000;
FUpdateTabAndPageTimer := TTimer.Create(Self);
FUpdateTabAndPageTimer.Interval := 500;
@ -5862,7 +5857,7 @@ begin
Application.RemoveOnMinimizeHandler(@OnApplicationDeactivate);
FreeThenNil(FMouseHintTimer);
FreeThenNil(FMouseHideHintTimer);
FreeThenNil(FHintWindow);
FreeThenNil(FHintManager);
FreeAndNil(FNotebook);
inherited Destroy;
@ -6717,9 +6712,9 @@ Begin
SenderDeleted:=(Sender as TControl).Parent=nil;
if SenderDeleted then exit;
UpdateStatusBar;
if (FHintWindow <> nil) and FHintWindow.Visible then
if FHintManager.HintIsVisible then
HideHint;
if assigned(Manager) then
if Assigned(Manager) then
Manager.DoEditorStatusChanged(FindSourceEditorWithEditorComponent(TSynEdit(Sender)));
End;
@ -7347,22 +7342,12 @@ end;
procedure TSourceNotebook.ActivateHint(const ScreenPos: TPoint;
const BaseURL, TheHint: string);
var
HintWinRect: TRect;
AHint: String;
begin
if csDestroying in ComponentState then exit;
if FHintWindow<>nil then
FHintWindow.Visible:=false;
if FHintWindow=nil then
FHintWindow:=THintWindow.Create(Self);
AHint:=TheHint;
FHintMousePos := Mouse.CursorPos;
if LazarusHelp.CreateHint(FHintWindow,ScreenPos,BaseURL,AHint,HintWinRect) then
begin
FHintWindow.ActivateHint(HintWinRect,aHint);
FHintManager.BaseURL := BaseURL;
if FHintManager.ShowHint(ScreenPos,TheHint) then
FMouseHideHintTimer.Enabled := True;
end;
end;
procedure TSourceNotebook.HideHint;
@ -7377,11 +7362,7 @@ begin
FMouseHideHintTimer.Enabled := False;
if AutoStartCompletionBoxTimer<>nil then
AutoStartCompletionBoxTimer.Enabled:=false;
if FHintWindow<>nil then begin
FHintWindow.Visible:=false;
Assert(FHintWindow.ControlCount <= 1,
'TSourceNotebook.HideHint: FHintWindow.ControlCount = '+IntToStr(FHintWindow.ControlCount));
end;
FHintManager.HideHint;
end;
procedure TSourceNotebook.MaybeHideHint;
@ -7390,42 +7371,44 @@ const
var
Cur: TPoint;
OkX, OkY: Boolean;
hw: THintWindow;
begin
FMouseHideHintTimer.Enabled := False;
if (FHintWindow <> nil) and (FHintWindow.Visible) then begin
if FHintManager.HintIsVisible then begin
hw := FHintManager.HintWindow;
Cur := Mouse.CursorPos; // Desktop coordinates
OkX := ( (FHintMousePos.x <= FHintWindow.Left) and
(Cur.x > FHintMousePos.x) and (Cur.x <= FHintWindow.Left + FHintWindow.Width)
OkX := ( (FHintMousePos.x <= hw.Left) and
(Cur.x > FHintMousePos.x) and (Cur.x <= hw.Left + hw.Width)
) or
( (FHintMousePos.x >= FHintWindow.Left + FHintWindow.Width) and
(Cur.x < FHintMousePos.x) and (Cur.x >= FHintWindow.Left)
( (FHintMousePos.x >= hw.Left + hw.Width) and
(Cur.x < FHintMousePos.x) and (Cur.x >= hw.Left)
) or
( (Cur.x >= FHintWindow.Left) and (Cur.x <= FHintWindow.Left + FHintWindow.Width) );
OkY := ( (FHintMousePos.y <= FHintWindow.Top) and
(Cur.y > FHintMousePos.y) and (Cur.y <= FHintWindow.Top + FHintWindow.Height)
( (Cur.x >= hw.Left) and (Cur.x <= hw.Left + hw.Width) );
OkY := ( (FHintMousePos.y <= hw.Top) and
(Cur.y > FHintMousePos.y) and (Cur.y <= hw.Top + hw.Height)
) or
( (FHintMousePos.y >= FHintWindow.Top + FHintWindow.Height) and
(Cur.y < FHintMousePos.y) and (Cur.y >= FHintWindow.Top)
( (FHintMousePos.y >= hw.Top + hw.Height) and
(Cur.y < FHintMousePos.y) and (Cur.y >= hw.Top)
) or
( (Cur.y >= FHintWindow.Top) and (Cur.y <= FHintWindow.Top + FHintWindow.Height) );
( (Cur.y >= hw.Top) and (Cur.y <= hw.Top + hw.Height) );
if OkX then FHintMousePos.x := Cur.x;
if OkY then FHintMousePos.y := Cur.y;
OkX := OkX or
( (FHintMousePos.x <= FHintWindow.Left + MaxJitter) and
(Cur.x > FHintMousePos.x - MaxJitter) and (Cur.x <= FHintWindow.Left + FHintWindow.Width + MaxJitter)
( (FHintMousePos.x <= hw.Left + MaxJitter) and
(Cur.x > FHintMousePos.x - MaxJitter) and (Cur.x <= hw.Left + hw.Width + MaxJitter)
) or
( (FHintMousePos.x >= FHintWindow.Left + FHintWindow.Width - MaxJitter) and
(Cur.x < FHintMousePos.x + MaxJitter) and (Cur.x >= FHintWindow.Left - MaxJitter)
( (FHintMousePos.x >= hw.Left + hw.Width - MaxJitter) and
(Cur.x < FHintMousePos.x + MaxJitter) and (Cur.x >= hw.Left - MaxJitter)
);
OkY := OkY or
( (FHintMousePos.y <= FHintWindow.Top + MaxJitter) and
(Cur.y > FHintMousePos.y - MaxJitter) and (Cur.y <= FHintWindow.Top + FHintWindow.Height + MaxJitter)
( (FHintMousePos.y <= hw.Top + MaxJitter) and
(Cur.y > FHintMousePos.y - MaxJitter) and (Cur.y <= hw.Top + hw.Height + MaxJitter)
) or
( (FHintMousePos.y >= FHintWindow.Top + FHintWindow.Height - MaxJitter) and
(Cur.y < FHintMousePos.y + MaxJitter) and (Cur.y >= FHintWindow.Top - MaxJitter)
( (FHintMousePos.y >= hw.Top + hw.Height - MaxJitter) and
(Cur.y < FHintMousePos.y + MaxJitter) and (Cur.y >= hw.Top - MaxJitter)
);
if (OkX and OkY) then begin
@ -8132,7 +8115,7 @@ Begin
try
Exclude(States, snNotebookPageChangedNeeded);
SrcEdit:=GetActiveSE;
if (FHintWindow <> nil) and FHintWindow.Visible then
if FHintManager.HintIsVisible then
HideHint;
if (CodeContextFrm<>nil) then
CodeContextFrm.Hide;
@ -8473,18 +8456,17 @@ end;
procedure TSourceNotebook.HideHintTimer(Sender: TObject);
begin
if (FHintWindow = nil) or (not FHintWindow.Visible) then begin
if FHintManager.HintIsVisible then begin
if ComparePoints(FHintMousePos, Mouse.CursorPos) <> 0 then begin
// TODO: introduce property, to indicate if hint is interactive
if FHintManager.HintIsComplex then
MaybeHideHint
else
HideHint;
end;
end
else
FMouseHideHintTimer.Enabled := false;
exit;
end;
if ComparePoints(FHintMousePos, Mouse.CursorPos) <> 0 then begin
// TODO: introduce property, to indicate if hint is interactive
if (FHintWindow.ControlCount > 0) and not(FHintWindow.Controls[0] is TSimpleHTMLControl) then
MaybeHideHint
else
HideHint;
end;
end;
{------------------------------------------------------------------------------
@ -8492,37 +8474,12 @@ end;
Msg: Cardinal);
------------------------------------------------------------------------------}
procedure TSourceNotebook.OnApplicationUserInput(Sender: TObject; Msg: Cardinal);
function IsHintControl(Control: TWinControl): Boolean;
var
I: Integer;
begin
if not(Assigned(Control) and Control.Visible) then
Exit(False);
Result := Control = Sender;
if Result then
Exit;
for I := 0 to Control.ControlCount - 1 do
begin
Result := Control.Controls[I] = Sender;
if Result then
Exit;
if (Control.Controls[I] is TWinControl) then
begin
Result := IsHintControl(TWinControl(Control.Controls[I]));
if Result then
Exit;
end;
end;
end;
begin
if (FHintWindow <> nil) and FHintWindow.Visible and
// TODO: introduce property, to indicate if hint is interactive
(FHintWindow.ControlCount > 0) and not(FHintWindow.Controls[0] is TSimpleHTMLControl)
then begin
if PtInRect(FHintWindow.BoundsRect, Mouse.CursorPos) then begin // ignore any action over Hint
if FHintWindow.Active then
if FHintManager.HintIsComplex then
begin
// TODO: introduce property, to indicate if hint is interactive
if FHintManager.PtIsOnHint(Mouse.CursorPos) then begin // ignore any action over Hint
if FHintManager.HintWindow.Active then
exit;
if (Msg = WM_MOUSEMOVE) {$IFDEF WINDOWS} or (Msg = WM_NCMOUSEMOVE)or
((Msg >= WM_MOUSEFIRST) and (Msg <= WM_MOUSELAST)) {$ENDIF}
@ -8537,7 +8494,7 @@ begin
//debugln('TSourceNotebook.OnApplicationUserInput');
// don't hide hint if Sender is a hint window or child control
if not Assigned(Sender) or not IsHintControl(FHintWindow) then
if not FHintManager.SenderIsHintControl(Sender) then
HideHint;
end;
@ -10584,8 +10541,7 @@ begin
ShowLineNumbers:=MenuItem.Checked;
for i:=0 to SourceEditorCount-1 do
SourceEditors[i].EditorComponent.Gutter.LineNumberPart.Visible
:= ShowLineNumbers;
SourceEditors[i].EditorComponent.Gutter.LineNumberPart.Visible := ShowLineNumbers;
EditorOpts.ShowLineNumbers := ShowLineNumbers;
EditorOpts.Save;
end;