diff --git a/components/synedit/synedit.pp b/components/synedit/synedit.pp index a1d07242bc..3a2655f1d9 100644 --- a/components/synedit/synedit.pp +++ b/components/synedit/synedit.pp @@ -77,6 +77,7 @@ uses SynEditMarkup, SynEditMarkupHighAll, SynEditMarkupBracket, SynEditMarkupCtrlMouseLink, SynEditMarkupSpecialLine, SynEditMarkupSelection, SynEditTextBase, SynEditTextTrimmer, SynEditFoldedView, + SynGutter, {$ENDIF} SynEditMiscClasses, SynEditTextBuffer, SynEditHighlighter, SynTextDrawer; @@ -117,10 +118,6 @@ const // maximum scroll range MAX_SCROLL = 32767; -// Max number of book/gutter marks returned from GetEditMarksForLine - that -// really should be enough. - maxMarks = 16; - SYNEDIT_CLIPBOARD_FORMAT = 'SynEdit Control Block Type'; {$IFNDEF SYN_LAZARUS} @@ -270,64 +267,13 @@ type TCustomSynEdit = class; - TSynEditMark = class - protected - fLine, fColumn, fImage: Integer; - fEdit: TCustomSynEdit; - fVisible: boolean; - fInternalImage: boolean; - fBookmarkNum: integer; - function GetEdit: TCustomSynEdit; virtual; - procedure SetColumn(const Value: Integer); virtual; - procedure SetImage(const Value: Integer); virtual; - procedure SetLine(const Value: Integer); virtual; - procedure SetVisible(const Value: boolean); {$IFDEF SYN_LAZARUS}virtual;{$ENDIF} //MWE: Laz needs to know when a line gets visible, so the editor color can be updated - procedure SetInternalImage(const Value: boolean); - function GetIsBookmark: boolean; - public - constructor Create(AOwner: TCustomSynEdit); - property Line: integer read fLine write SetLine; - property Column: integer read fColumn write SetColumn; - property ImageIndex: integer read fImage write SetImage; - property BookmarkNumber: integer read fBookmarkNum write fBookmarkNum; - property Visible: boolean read fVisible write SetVisible; - property InternalImage: boolean read fInternalImage write SetInternalImage; - property IsBookmark: boolean read GetIsBookmark; - end; + { Make them visible for Units that use TSynEdit } + TSynEditMark = SynGutter.TSynEditMark; + TPlaceMarkEvent = SynGutter.TPlaceMarkEvent; + TSynEditMarks = SynGutter.TSynEditMarks; + TSynEditMarkList = SynGutter.TSynEditMarkList; + TGutterClickEvent = SynGutter.TGutterClickEvent; - TPlaceMarkEvent = procedure(Sender: TObject; var Mark: TSynEditMark) - of object; - - TSynEditMarks = array[1..maxMarks] of TSynEditMark; - - { A list of mark objects. Each object cause a litle picture to be drawn in the - gutter. } - TSynEditMarkList = class(TList) - protected - fEdit: TCustomSynEdit; - fOnChange: TNotifyEvent; - procedure DoChange; - function Get(Index: Integer): TSynEditMark; - procedure Put(Index: Integer; Item: TSynEditMark); - public - constructor Create(AOwner: TCustomSynEdit); - destructor Destroy; override; - function Add(Item: TSynEditMark): Integer; - procedure ClearLine(line: integer); - procedure Delete(Index: Integer); - function First: TSynEditMark; - procedure GetMarksForLine(line: integer; var Marks: TSynEditMarks); - procedure Insert(Index: Integer; Item: TSynEditMark); - function Last: TSynEditMark; - procedure Place(Mark: TSynEditMark); - function Remove(Item: TSynEditMark): Integer; - public - property Items[Index: Integer]: TSynEditMark read Get write Put; default; - property OnChange: TNotifyEvent read FOnChange write FOnChange; - end; - - TGutterClickEvent = procedure(Sender: TObject; X, Y, Line: integer; - mark: TSynEditMark) of object; TSynEditPlugin = class(TObject) private @@ -359,7 +305,7 @@ type { TCustomSynEdit } - TCustomSynEdit = class(TCustomControl) + TCustomSynEdit = class(TSynEditBase) private procedure WMDropFiles(var Msg: TMessage); message WM_DROPFILES; procedure WMEraseBkgnd(var Msg: TMessage); message WM_ERASEBKGND; @@ -481,7 +427,6 @@ type fOnClearMark: TPlaceMarkEvent; // djlp 2000-08-29 fOnCommandProcessed: TProcessCommandEvent; fOnDropFiles: TDropFilesEvent; - fOnGutterClick: TGutterClickEvent; fOnPaint: TPaintEvent; fOnPlaceMark: TPlaceMarkEvent; fOnProcessCommand: TProcessCommandEvent; @@ -521,9 +466,11 @@ type function GetIncrementColor : TSynSelectedColor; function GetLineHighlightColor: TSynSelectedColor; function GetLineNumberColor: TSynSelectedColor; + function GetOnGutterClick : TGutterClickEvent; function GetSelectedColor : TSynSelectedColor; function GetBracketMatchColor : TSynSelectedColor; function GetMouseLinkColor : TSynSelectedColor; + procedure SetOnGutterClick(const AValue : TGutterClickEvent); procedure SetRealLines(const AValue : TStrings); procedure SetSelectedColor(const AValue : TSynSelectedColor); procedure SetSpecialLineColors(const AValue : TSpecialLineColorsEvent); @@ -698,7 +645,6 @@ type var AChar: {$IFDEF SYN_LAZARUS}TUTF8Char{$ELSE}Char{$ENDIF}; Data: pointer); virtual; procedure Paint; override; - procedure PaintGutter(AClip: TRect; FirstLine, LastLine: integer); virtual; procedure PaintTextLines(AClip: TRect; FirstLine, LastLine, FirstCol, LastCol: integer); virtual; {$IFDEF SYN_LAZARUS} @@ -721,7 +667,6 @@ type procedure UndoItem; //sbs 2000-11-19 protected fGutterWidth: Integer; - fInternalImage: TSynInternalImage; {$IFDEF EnableDoubleBuf} BufferBitmap: TBitmap; // the double buffer {$ENDIF} @@ -731,7 +676,6 @@ type AChar: {$IFDEF SYN_LAZARUS}TUTF8Char{$ELSE}Char{$ENDIF}; Data: pointer); virtual; // no method DoOnDropFiles, intercept the WM_DROPFILES instead - procedure DoOnGutterClick(X, Y: integer); virtual; procedure DoOnPaint; virtual; procedure DoOnPlaceMark(var Mark: TSynEditMark); virtual; procedure DoOnProcessCommand(var Command: TSynEditorCommand; @@ -1001,7 +945,7 @@ type read fOnCommandProcessed write fOnCommandProcessed; property OnDropFiles: TDropFilesEvent read fOnDropFiles write fOnDropFiles; property OnGutterClick: TGutterClickEvent - read fOnGutterClick write fOnGutterClick; + read GetOnGutterClick write SetOnGutterClick; property OnPaint: TPaintEvent read fOnPaint write fOnPaint; property OnPlaceBookmark: TPlaceMarkEvent read FOnPlaceMark write FOnPlaceMark; @@ -1509,11 +1453,12 @@ begin fSelectedColor := TSynSelectedColor.Create; fSelectedColor.OnChange := {$IFDEF FPC}@{$ENDIF}SelectedColorsChanged; {$ENDIF} + fTextDrawer := TheTextDrawer.Create([fsBold], fFontDummy); fBookMarkOpt := TSynBookMarkOpt.Create(Self); fBookMarkOpt.OnChange := {$IFDEF FPC}@{$ENDIF}BookMarkOptionsChanged; // fRightEdge has to be set before FontChanged is called for the first time fRightEdge := 80; - fGutter := TSynGutter.Create; + fGutter := TSynGutter.Create(self, fTextView, fBookMarkOpt, fTextDrawer); fGutter.OnChange := {$IFDEF FPC}@{$ENDIF}GutterChanged; fGutterWidth := fGutter.Width; fTextOffset := fGutterWidth + 2; @@ -1558,7 +1503,6 @@ begin fFontDummy.CharSet := DEFAULT_CHARSET; {$ENDIF} {$ENDIF} - fTextDrawer := TheTextDrawer.Create([fsBold], fFontDummy); Font.Assign(fFontDummy); Font.OnChange := {$IFDEF FPC}@{$ENDIF}FontChanged; FontChanged(nil); @@ -1714,7 +1658,6 @@ begin fRedoList.Free; fGutter.Free; fTextDrawer.Free; - fInternalImage.Free; fFontDummy.Free; Lines.Free; {$ELSE} @@ -1730,7 +1673,6 @@ begin FreeAndNil(fRedoList); FreeAndNil(fGutter); FreeAndNil(fTextDrawer); - FreeAndNil(fInternalImage); FreeAndNil(fFontDummy); FreeAndNil(fTextView); FreeAndNil(fTrimLines); @@ -1813,6 +1755,11 @@ begin Result := fGutter.MarkupInfoLineNumber; end; +function TCustomSynEdit.GetOnGutterClick : TGutterClickEvent; +begin + Result := fGutter.OnGutterClick; +end; + function TCustomSynEdit.GetSelectedColor : TSynSelectedColor; begin result := fMarkupSelection.MarkupInfoSeletion; @@ -1845,6 +1792,11 @@ begin Result := fMarkupCtrlMouse.MarkupInfo; end; +procedure TCustomSynEdit.SetOnGutterClick(const AValue : TGutterClickEvent); +begin + fGutter.OnGutterClick := AValue; +end; + procedure TCustomSynEdit.SetRealLines(const AValue : TStrings); begin if HandleAllocated then @@ -2570,7 +2522,7 @@ begin {$IFDEF SYN_LAZARUS} if (X < fGutterWidth) and (Button=mbLeft) then begin Include(fStateFlags, sfPossibleGutterClick); - DoOnGutterClick(X, Y); + fGutter.DoOnGutterClick(X, Y); end; LCLIntf.SetFocus(Handle); UpdateCaret; @@ -2798,7 +2750,7 @@ begin {$IFDEF SYN_LAZARUS}and (Button = mbLeft){$ENDIF} then begin {$IFNDEF SYN_LAZARUS} - DoOnGutterClick(X, Y); + fGutter.DoOnGutterClick(X, Y); {$ENDIF} end else if fStateFlags * [sfDblClicked, @@ -2812,6 +2764,7 @@ begin {$ELSE}CaretXY{$ENDIF}); Exclude(fStateFlags, sfWaitForDragging); end; + if (Button=mbLeft) and (fStateFlags * [sfWaitForDragging] = []) then begin @@ -2839,62 +2792,6 @@ begin //DebugLn('TCustomSynEdit.MouseUp END Mouse=',X,',',Y,' Caret=',CaretX,',',CaretY,', BlockBegin=',BlockBegin.X,',',BlockBegin.Y,' BlockEnd=',BlockEnd.X,',',BlockEnd.Y); end; -procedure TCustomSynEdit.DoOnGutterClick(X, Y: integer); -var - i : integer; - offs : integer; - line : integer; - allmrk: TSynEditMarks; - mark : TSynEditMark; -begin - {$IFDEF SYN_LAZARUS} - line := PixelsToRowColumn(Point(X, Y)).Y; - //debugln('TCustomSynEdit.DoOnGutterClick A ',dbgs(line)); - if line <= Lines.Count then begin - mark := nil; - if Gutter.ShowCodeFolding and (X fGutterWidth) then begin @@ -3001,343 +2898,6 @@ begin end; {$ENDIF} -procedure TCustomSynEdit.PaintGutter(AClip: TRect; FirstLine, LastLine: integer); -var - i, iLine: integer; - rcLine: TRect; - bHasOtherMarks: boolean; - aGutterOffs: PIntArray; - s: string; - dc: HDC; - rcCodeFold: TRect; - tmp: TSynEditCodeFoldType; - CodeFoldOffset: Integer; - ShowDot: boolean; - - procedure DrawMark(iMark: integer); - {$IFDEF SYN_LAZARUS} - var - iLine: integer; - itop : Longint; - CurMark: TSynEditMark; - begin - iTop := 0; - CurMark:=Marks[iMark]; - if (CurMark.Line<1) or (CurMark.Line>Lines.Count) then exit; - if fTextView.FoldedAtTextIndex[CurMark.Line-1] then exit; - iLine := fTextView.TextIndexToScreenLine(CurMark.Line-1); - - if Assigned(fBookMarkOpt.BookmarkImages) and not CurMark.InternalImage - then begin - if (CurMark.ImageIndex <= fBookMarkOpt.BookmarkImages.Count) then begin - if CurMark.IsBookmark = BookMarkOptions.DrawBookmarksFirst then - aGutterOffs^[iLine] := CodeFoldOffset - else if aGutterOffs^[iLine] = 0 then - aGutterOffs^[iLine] := fBookMarkOpt.BookmarkImages.Width + CodeFoldOffset; - if fTextHeight > fBookMarkOpt.BookmarkImages.Height then - iTop := (fTextHeight - fBookMarkOpt.BookmarkImages.Height) div 2; - with fBookMarkOpt do - BookmarkImages.Draw(Canvas, LeftMargin + aGutterOffs^[iLine], - iTop + iLine * fTextHeight, CurMark.ImageIndex,true); - - Inc(aGutterOffs^[iLine], fBookMarkOpt.BookmarkImages.Width); - end; - end else - begin - if CurMark.ImageIndex in [0..9] then begin - if not Assigned(fInternalImage) then begin - fInternalImage := TSynInternalImage.Create('SynEditInternalImages',10); - end; - if (aGutterOffs^[iLine]=0) and Gutter.ShowCodeFolding then - aGutterOffs^[iLine]:=Gutter.CodeFoldingWidth; - fInternalImage.DrawMark(Canvas, CurMark.ImageIndex, - fBookMarkOpt.LeftMargin + aGutterOffs^[iLine], iLine * fTextHeight, - fTextHeight); - Inc(aGutterOffs^[iLine], fBookMarkOpt.Xoffset); - end; - end; - end; - {$ELSE below: not SYN_LAZARUS} - var - iLine: integer; - itop : Longint; - begin - iTop := 0; - if Assigned(fBookMarkOpt.BookmarkImages) and not Marks[i].InternalImage - then begin - if Marks[iMark].ImageIndex <= fBookMarkOpt.BookmarkImages.Count then begin - iLine := Marks[iMark].Line - TopLine; -// if Marks[iMark].IsBookmark then - if Marks[iMark].IsBookmark = BookMarkOptions.DrawBookmarksFirst then //mh 2000-10-12 - aGutterOffs^[iLine] := 0 - else if aGutterOffs^[iLine] = 0 then - aGutterOffs^[iLine] := fBookMarkOpt.XOffset; - If fTextHeight > fBookMarkOpt.BookmarkImages.Height then - iTop := (fTextHeight - fBookMarkOpt.BookmarkImages.Height) div 2; - with fBookMarkOpt do - if not TSynEditStringList(fLines).Folded[iLine] then - BookmarkImages.Draw(Canvas, LeftMargin + aGutterOffs^[iLine], iTop + iLine * fTextHeight, Marks[iMark].ImageIndex,true); - - Inc(aGutterOffs^[iLine], fBookMarkOpt.XOffset); - end; - end else - begin - if Marks[iMark].ImageIndex in [0..9] then begin - iLine := Marks[iMark].Line - TopLine; - if not Assigned(fInternalImage) then begin - fInternalImage := TSynInternalImage.Create('SynEditInternalImages', - 10); - end; - fInternalImage.DrawMark(Canvas, Marks[iMark].ImageIndex, fBookMarkOpt.LeftMargin + aGutterOffs^[iLine], iLine * fTextHeight, fTextHeight); - Inc(aGutterOffs^[iLine], fBookMarkOpt.XOffset); - end; - end; - end; - {$ENDIF} - - procedure DrawNodeBox(rcCodeFold: TRect; Collapsed: boolean); - const cNodeOffset = 3; - var - rcNode: TRect; - ptCenter : TPoint; - iSquare: integer; - begin - //center of the draw area - ptCenter.X := (rcCodeFold.Left + rcCodeFold.Right) div 2; - ptCenter.Y := (rcCodeFold.Top + rcCodeFold.Bottom) div 2; - - //make node rect square - iSquare := Max(0, rcCodeFold.Bottom - rcCodeFold.Top - 14) div 2; - - //area of drawbox - rcNode.Right := rcCodeFold.Right - cNodeOffset + 1; - rcNode.Left := rcCodeFold.Left + cNodeOffset; - rcNode.Top := rcCodeFold.Top + cNodeOffset + iSquare; - rcNode.Bottom := rcCodeFold.Bottom - cNodeOffset - iSquare + 1; - - Canvas.Brush.Color:=clWhite; - Canvas.Rectangle(rcNode); - - //draw bottom handle to paragraph line - Canvas.MoveTo((rcNode.Left + rcNode.Right) div 2, rcNode.Bottom); - Canvas.LineTo((rcNode.Left + rcNode.Right) div 2, rcCodeFold.Bottom); - - //draw unfolded sign in node box - Canvas.MoveTo(ptCenter.X - 2, ptCenter.Y); - Canvas.LineTo(ptCenter.X + 3, ptCenter.Y); - - //draw folded sign - if Collapsed then - begin - Canvas.MoveTo(ptCenter.X, ptCenter.Y - 2); - Canvas.LineTo(ptCenter.X, ptCenter.Y + 3); - end; - end; - - procedure DrawParagraphContinue(rcCodeFold: TRect); - var - iCenter : integer; - begin - //center of the draw area - iCenter := (rcCodeFold.Left + rcCodeFold.Right) div 2; - - Canvas.MoveTo(iCenter, rcCodeFold.Top); - Canvas.LineTo(iCenter, rcCodeFold.Bottom); - end; - - procedure DrawParagraphEnd(rcCodeFold: TRect); - var - ptCenter : TPoint; - begin - //center of the draw area - ptCenter.X := (rcCodeFold.Left + rcCodeFold.Right) div 2; - ptCenter.Y := (rcCodeFold.Top + rcCodeFold.Bottom) div 2; - - Canvas.MoveTo(ptCenter.X, rcCodeFold.Top); - Canvas.LineTo(ptCenter.X, ptCenter.Y); - Canvas.LineTo(rcCodeFold.Right, ptCenter.Y); - end; - -begin - {$IFNDEF SYN_LAZARUS} - if (FirstLine = 1) and (LastLine = 0) then - LastLine := 1; - {$ENDIF} - // Changed to use fTextDrawer.BeginDrawing and fTextDrawer.EndDrawing only - // when absolutely necessary. Note: Never change brush / pen / font of the - // canvas inside of this block (only through methods of fTextDrawer)! - Canvas.Brush.Color := Gutter.Color; - // If we have to draw the line numbers then we don't want to erase - // the background first. Do it line by line with TextRect instead - // and fill only the area after the last visible line. - dc := Canvas.Handle; - {$IFDEF SYN_LAZARUS} - LCLIntf.SetBkColor(dc,Canvas.Brush.Color); - if Gutter.ShowCodeFolding then - CodeFoldOffset:=Gutter.CodeFoldingWidth - else - CodeFoldOffset:=0; - {$ENDIF} - if fGutter.ShowLineNumbers then - begin - fTextDrawer.BeginDrawing(dc); - try - if FGutter.MarkupInfoLineNumber.Background <> clNone then - fTextDrawer.SetBackColor(FGutter.MarkupInfoLineNumber.Background) - else - fTextDrawer.SetBackColor(FGutter.Color); - if FGutter.MarkupInfoLineNumber.Foreground <> clNone then - fTextDrawer.SetForeColor(FGutter.MarkupInfoLineNumber.Foreground) - else - fTextDrawer.SetForeColor(Self.Font.Color); - fTextDrawer.Style := FGutter.MarkupInfoLineNumber.Style; - // prepare the rect initially - rcLine := AClip; - rcLine.Right := fGutterWidth - 2; - //rcLine.Right := Max(rcLine.Right, fGutterWidth - 2); - {$IFDEF SYN_LAZARUS} - rcLine.Bottom := FirstLine * fTextHeight; - rcLine.Left := CodeFoldOffset + fGutter.LeftOffset; - for i := FirstLine to LastLine do - begin - iLine := fTextView.DisplayNumber[i]; - // next line rect - rcLine.Top := rcLine.Bottom; - // Must show a dot instead of line number if - // line number is not the first, the last, the current line - // or a multiple of Gutter.ShowOnlyLineNumbersMultiplesOf - ShowDot := ((iLine mod fGutter.ShowOnlyLineNumbersMultiplesOf) <> 0) - and (iLine <> CaretY) and (iLine <> 1) and (iLine <> Lines.Count); - // Get the formatted line number or dot - s := fGutter.FormatLineNumber(iLine, ShowDot); - Inc(rcLine.Bottom, fTextHeight); - // erase the background and draw the line number string in one go - fTextDrawer.ExtTextOut(rcLine.Left, rcLine.Top, ETO_OPAQUE, rcLine, - PChar(Pointer(S)),Length(S)); - end; - {$ELSE} - rcLine.Bottom := (FirstLine - TopLine) * fTextHeight; - for iLine := FirstLine to LastLine do begin - // next line rect - rcLine.Top := rcLine.Bottom; - s := fGutter.FormatLineNumber(iLine, false); - Inc(rcLine.Bottom, fTextHeight); - // erase the background and draw the line number string in one go - Windows.ExtTextOut(DC, fGutter.LeftOffset, rcLine.Top, ETO_OPAQUE, - @rcLine, PChar(s), Length(s), nil); - end; - {$ENDIF} - // now erase the remaining area if any - if AClip.Bottom > rcLine.Bottom then - begin - rcLine.Top := rcLine.Bottom; - rcLine.Bottom := AClip.Bottom; - with rcLine do - fTextDrawer.ExtTextOut(Left, Top, ETO_OPAQUE, rcLine, nil, 0); - end; - // restore original style - fTextDrawer.SetBackColor(fGutter.Color); - fTextDrawer.SetForeColor(Self.Font.Color); - if AClip.Left < rcLine.Left then - begin - rcLine.Right := rcLine.Left; - rcLine.Left := AClip.Left; - rcLine.Top := AClip.Top; - rcLine.Bottom := AClip.Bottom; - with rcLine do - fTextDrawer.ExtTextOut(Left, Top, ETO_OPAQUE, rcLine, nil, 0); - end; - finally - fTextDrawer.EndDrawing; - end; - end else - InternalFillRect(dc, AClip); - - //draw the code folding marks - if fGutter.ShowCodeFolding then - begin - with Canvas do - begin - Pen.Color := clDkGray; - Pen.Width := 1; - - rcLine.Bottom := FirstLine * fTextHeight; - for iLine := FirstLine to LastLine do - begin - // next line rect - rcLine.Top := rcLine.Bottom; - Inc(rcLine.Bottom, fTextHeight); - - rcCodeFold.Left := 0; - rcCodeFold.Right := 14; - rcCodeFold.Top := rcLine.Top; - rcCodeFold.Bottom := rcLine.Bottom; - -//DebugLn(['** GUTTER at ',iLine,' scrline=',fTextView.TextIndexToScreenLine(iLine-1),' type ', SynEditCodeFoldTypeNames[fTextView.FoldType[fTextView.TextIndexToScreenLine(iLine-1)]]]); - tmp := fTextView.FoldType[iLine]; - - case tmp of - cfCollapsed: DrawNodeBox(rcCodeFold, True); - cfExpanded: DrawNodeBox(rcCodeFold, False); - cfContinue: DrawParagraphContinue(rcCodeFold); - cfEnd: DrawParagraphEnd(rcCodeFold); - end; - end; - end; - end; - - // the gutter separator if visible - if AClip.Right >= fGutterWidth - 2 then - with Canvas do begin - Pen.Color := {$IFDEF SYN_LAZARUS}clWhite{$ELSE}clBtnHighlight{$ENDIF}; - Pen.Width := 1; - with AClip do begin - MoveTo(fGutterWidth - 2, Top); - LineTo(fGutterWidth - 2, Bottom); - Pen.Color := {$IFDEF SYN_LAZARUS}clDkGray{$ELSE}clBtnShadow{$ENDIF}; - MoveTo(fGutterWidth - 1, Top); - LineTo(fGutterWidth - 1, Bottom); - end; - end; - // now the gutter marks - if BookMarkOptions.GlyphsVisible and (Marks.Count > 0) - and (LastLine >= FirstLine) - then begin - aGutterOffs := AllocMem((LastLine+1{$IFNDEF SYN_LAZARUS}-TopLine{$ENDIF}) * SizeOf(integer)); - try - // Instead of making a two pass loop we look while drawing the bookmarks - // whether there is any other mark to be drawn - bHasOtherMarks := FALSE; - for i := 0 to Marks.Count - 1 do with Marks[i] do - {$IFDEF SYN_LAZARUS} - if Visible and (Line >= fTextView.TextIndex[FirstLine]+1) and (Line <= fTextView.TextIndex[LastLine]+1) then - {$ELSE} - if Visible and (Line >= FirstLine) and (Line <= LastLine) then - {$ENDIF} - begin - if IsBookmark <> BookMarkOptions.DrawBookmarksFirst then //mh 2000-10-12 - bHasOtherMarks := TRUE - else - DrawMark(i); - end; - if bHasOtherMarks then - for i := 0 to Marks.Count - 1 do with Marks[i] do - begin - if Visible and (IsBookmark <> BookMarkOptions.DrawBookmarksFirst) //mh 2000-10-12 - {$IFDEF SYN_LAZARUS} - and (Line >= fTextView.TextIndex[FirstLine]+1) and (Line <= fTextView.TextIndex[LastLine]+1) - {$ELSE} - and (Line >= FirstLine) and (Line <= LastLine) - {$ENDIF} - then - DrawMark(i); - end; - finally - FreeMem(aGutterOffs); - end; - end; -end; - procedure TCustomSynEdit.PaintTextLines(AClip: TRect; FirstLine, LastLine, FirstCol, LastCol: integer); {$IFDEF SYN_LAZARUS} @@ -11471,174 +11031,6 @@ begin end; {$ENDIF} -{ TSynEditMark } - -function TSynEditMark.GetEdit: TCustomSynEdit; -begin - if FEdit <> nil then try - if FEdit.Marks.IndexOf(self) = -1 then - FEdit := nil; - except - FEdit := nil; - end; - Result := FEdit; -end; - -function TSynEditMark.GetIsBookmark: boolean; -begin - Result := (fBookmarkNum >= 0); -end; - -procedure TSynEditMark.SetColumn(const Value: Integer); -begin - FColumn := Value; -end; - -procedure TSynEditMark.SetImage(const Value: Integer); -begin - FImage := Value; - if fVisible and Assigned(fEdit) then - fEdit.InvalidateGutterLines(fLine, fLine); -end; - -procedure TSynEditMark.SetInternalImage(const Value: boolean); -begin - fInternalImage := Value; - if fVisible and Assigned(fEdit) then - fEdit.InvalidateGutterLines(fLine, fLine); -end; - -procedure TSynEditMark.SetLine(const Value: Integer); -begin - if fVisible and Assigned(fEdit) then begin - if fLine > 0 then - fEdit.InvalidateGutterLines(fLine, fLine); - fLine := Value; - fEdit.InvalidateGutterLines(fLine, fLine); - end else - fLine := Value; -end; - -procedure TSynEditMark.SetVisible(const Value: boolean); -begin - if fVisible <> Value then begin - fVisible := Value; - if Assigned(fEdit) then - fEdit.InvalidateGutterLines(fLine, fLine); - end; -end; - -constructor TSynEditMark.Create(AOwner: TCustomSynEdit); -begin - inherited Create; - fBookmarkNum := -1; - fEdit := AOwner; -end; - -{ TSynEditMarkList } - -function TSynEditMarkList.Add(Item: TSynEditMark): Integer; -begin - Result := inherited Add(Item); - DoChange; -end; - -procedure TSynEditMarkList.ClearLine(Line: integer); -var - i: integer; -begin - for i := Count - 1 downto 0 do - if not Items[i].IsBookmark and (Items[i].Line = Line) then Delete(i); -end; - -constructor TSynEditMarkList.Create(AOwner: TCustomSynEdit); -begin - inherited Create; - fEdit := AOwner; -end; - -destructor TSynEditMarkList.Destroy; -var - i: integer; -begin - for i := 0 to Pred(Count) do - Get(i).Free; - inherited Destroy; -end; - -procedure TSynEditMarkList.Delete(Index: Integer); -begin - inherited Delete(Index); - DoChange; -end; - -procedure TSynEditMarkList.DoChange; -begin - if Assigned(FOnChange) then - FOnChange(Self); -end; - -function TSynEditMarkList.First: TSynEditMark; -begin - result := TSynEditMark(inherited First); -end; - -function TSynEditMarkList.Get(Index: Integer): TSynEditMark; -begin - result := TSynEditMark(inherited Get(Index)); -end; - -//Returns up to maxMarks book/gutter marks for a chosen line. - -procedure TSynEditMarkList.GetMarksForLine(line: integer; - var marks: TSynEditMarks); -var - cnt: integer; - i: integer; -begin - FillChar(marks, SizeOf(marks), 0); - cnt := 0; - for i := 0 to Count - 1 do begin - if Items[i].Line = line then begin - Inc(cnt); - marks[cnt] := Items[i]; - if cnt = maxMarks then break; - end; - end; -end; - -procedure TSynEditMarkList.Insert(Index: Integer; Item: TSynEditMark); -begin - inherited Insert(Index, Item); - DoChange; -end; - -function TSynEditMarkList.Last: TSynEditMark; -begin - result := TSynEditMark(inherited Last); -end; - -procedure TSynEditMarkList.Place(mark: TSynEditMark); -begin - if assigned(fEdit) then - if assigned(fEdit.OnPlaceBookmark) then fEdit.OnPlaceBookmark(fEdit, mark); - if assigned(mark) then - Add(mark); - DoChange; -end; - -procedure TSynEditMarkList.Put(Index: Integer; Item: TSynEditMark); -begin - inherited Put(Index, Item); - DoChange; -end; - -function TSynEditMarkList.Remove(Item: TSynEditMark): Integer; -begin - Result := inherited Remove(Item); - DoChange; -end; - { TSynEditPlugin } constructor TSynEditPlugin.Create(AOwner: TCustomSynEdit); diff --git a/components/synedit/syneditmiscclasses.pp b/components/synedit/syneditmiscclasses.pp index 78bc46f999..8231b5c73e 100644 --- a/components/synedit/syneditmiscclasses.pp +++ b/components/synedit/syneditmiscclasses.pp @@ -51,6 +51,10 @@ uses type + // Empty - For type checking on function-arguments + // in places where TCustomSynEdit can not be used due to circular unit refs + TSynEditBase = class(TCustomControl); + { TSynSelectedColor } TSynSelectedColor = class(TPersistent) @@ -87,86 +91,6 @@ type property OnChange: TNotifyEvent read fOnChange write fOnChange; end; - { TSynGutter } - - TSynGutter = class(TPersistent) - private - {$IFDEF SYN_LAZARUS} - FCodeFoldingWidth: integer; - fShowCodeFolding: boolean; - FShowOnlyLineNumbersMultiplesOf: integer; - FMarkupInfoLineNumber: TSynSelectedColor; - {$ENDIF} - fColor: TColor; - fWidth: integer; - fShowLineNumbers: boolean; - fDigitCount: integer; - fLeadingZeros: boolean; - fZeroStart: boolean; - fLeftOffset: integer; - fRightOffset: integer; - fOnChange: TNotifyEvent; - fCursor: TCursor; - fVisible: boolean; - fAutoSize: boolean; - fAutoSizeDigitCount: integer; - procedure SetAutoSize(const Value: boolean); - {$IFDEF SYN_LAZARUS} - procedure SetCodeFoldingWidth(const AValue: integer); - procedure SetShowCodeFolding(const Value: boolean); - procedure SetShowOnlyLineNumbersMultiplesOf(const AValue: integer); - {$ENDIF} - procedure SetColor(const Value: TColor); - procedure SetDigitCount(Value: integer); - procedure SetLeadingZeros(const Value: boolean); - procedure SetLeftOffset(Value: integer); - procedure SetRightOffset(Value: integer); - procedure SetShowLineNumbers(const Value: boolean); - procedure SetVisible(Value: boolean); - procedure SetWidth(Value: integer); - procedure SetZeroStart(const Value: boolean); - procedure DoChange(Sender: TObject); - public - constructor Create; - destructor Destroy; override; - procedure Assign(Source: TPersistent); override; - procedure AutoSizeDigitCount(LinesCount: integer); - function FormatLineNumber(Line: integer; IsDot: boolean): string; - function RealGutterWidth(CharWidth: integer): integer; - {$IFDEF SYN_LAZARUS} - property OnChange: TNotifyEvent read fOnChange write fOnChange; - {$ENDIF} - published - property AutoSize: boolean read fAutoSize write SetAutoSize default FALSE; - property Color: TColor read fColor write SetColor default clBtnFace; - property Cursor: TCursor read fCursor write fCursor default crDefault; - property DigitCount: integer read fDigitCount write SetDigitCount - default 4; - property LeadingZeros: boolean read fLeadingZeros write SetLeadingZeros - default FALSE; - property LeftOffset: integer read fLeftOffset write SetLeftOffset - default 16; - property RightOffset: integer read fRightOffset write SetRightOffset - default 2; - property ShowLineNumbers: boolean read fShowLineNumbers - write SetShowLineNumbers default FALSE; - property Visible: boolean read fVisible write SetVisible default TRUE; - property Width: integer read fWidth write SetWidth default 30; - property ZeroStart: boolean read fZeroStart write SetZeroStart default FALSE; - {$IFNDEF SYN_LAZARUS} - property OnChange: TNotifyEvent read fOnChange write fOnChange; - {$ENDIF} - {$IFDEF SYN_LAZARUS} - property ShowCodeFolding: boolean read fShowCodeFolding - write SetShowCodeFolding default FALSE; - property CodeFoldingWidth: integer read FCodeFoldingWidth write SetCodeFoldingWidth - default 14; - property ShowOnlyLineNumbersMultiplesOf: integer read FShowOnlyLineNumbersMultiplesOf - write SetShowOnlyLineNumbersMultiplesOf default 1; - property MarkupInfoLineNumber: TSynSelectedColor read FMarkupInfoLineNumber; - {$ENDIF} - end; - { TSynBookMarkOpt } TSynBookMarkOpt = class(TPersistent) @@ -373,246 +297,6 @@ begin end; end; -{ TSynGutter } - -constructor TSynGutter.Create; -begin - inherited Create; - fColor := clBtnFace; - fVisible := TRUE; - fWidth := 30; - fLeftOffset := 16; - fDigitCount := 4; - fAutoSizeDigitCount := fDigitCount; - fRightOffset := 2; - fShowOnlyLineNumbersMultiplesOf := 1; - fCodeFoldingWidth := 14; - FMarkupInfoLineNumber := TSynSelectedColor.Create; - FMarkupInfoLineNumber.Background := clNone; - FMarkupInfoLineNumber.Foreground := clNone; - FMarkupInfoLineNumber.OnChange := @DoChange; -end; - -destructor TSynGutter.Destroy; -begin - FMarkupInfoLineNumber.Free; - inherited Destroy; -end; - -procedure TSynGutter.Assign(Source: TPersistent); -var - Src: TSynGutter; -begin - if Assigned(Source) and (Source is TSynGutter) then - begin - Src := TSynGutter(Source); - fColor := Src.fColor; - fVisible := Src.fVisible; - fWidth := Src.fWidth; - fShowLineNumbers := Src.fShowLineNumbers; - fLeadingZeros := Src.fLeadingZeros; - fZeroStart := Src.fZeroStart; - fLeftOffset := Src.fLeftOffset; - fDigitCount := Src.fDigitCount; - fRightOffset := Src.fRightOffset; - fAutoSize := Src.fAutoSize; - fAutoSizeDigitCount := Src.fAutoSizeDigitCount; - {$IFDEF SYN_LAZARUS} - FCodeFoldingWidth := Src.FCodeFoldingWidth; - fShowCodeFolding := Src.fShowCodeFolding; - FShowOnlyLineNumbersMultiplesOf := Src.FShowOnlyLineNumbersMultiplesOf; - FMarkupInfoLineNumber.Assign(Src.MarkupInfoLineNumber); - {$ENDIF} - DoChange(Self); - end else - inherited; -end; - -procedure TSynGutter.AutoSizeDigitCount(LinesCount: integer); -var - nDigits: integer; -begin - if fVisible and fAutoSize and fShowLineNumbers then - begin - if fZeroStart then Dec(LinesCount); - nDigits := Max(Length(IntToStr(LinesCount)), fDigitCount); - if fAutoSizeDigitCount <> nDigits then - begin - fAutoSizeDigitCount := nDigits; - DoChange(Self); - end; - end else - fAutoSizeDigitCount := fDigitCount; -end; - -function TSynGutter.FormatLineNumber(Line: integer; IsDot: boolean): string; -var - i: integer; -begin - Result := ''; - // if a dot must be showed - if IsDot then - if Line mod 5 = 0 then // every 5 lines show '-' instead of '.' - Result := StringOfChar(' ', fAutoSizeDigitCount-1) + '-' - else - Result := StringOfChar(' ', fAutoSizeDigitCount-1) + '.' - // else format the line number - else begin - if fZeroStart then Dec(Line); - Str(Line : fAutoSizeDigitCount, Result); - if fLeadingZeros then - for i := 1 to fAutoSizeDigitCount - 1 do begin - if (Result[i] <> ' ') then break; - Result[i] := '0'; - end; - end; -end; - -function TSynGutter.RealGutterWidth(CharWidth: integer): integer; -begin - if not fVisible then - begin - Result := 0; - Exit; - end; - - if fShowLineNumbers then - Result := fLeftOffset + fRightOffset + fAutoSizeDigitCount * CharWidth + 2 - else - Result := fWidth; - - if fShowCodeFolding then - Result := Result + CodeFoldingWidth; -end; - -procedure TSynGutter.SetAutoSize(const Value: boolean); -begin - if fAutoSize <> Value then - begin - fAutoSize := Value; - DoChange(Self); - end; -end; - -{$IFDEF SYN_LAZARUS} -procedure TSynGutter.SetCodeFoldingWidth(const AValue: integer); -begin - if FCodeFoldingWidth=AValue then exit; - FCodeFoldingWidth:=AValue; - DoChange(Self); -end; -{$ENDIF} - -procedure TSynGutter.SetColor(const Value: TColor); -begin - if fColor <> Value then - begin - fColor := Value; - DoChange(Self); - end; -end; - -procedure TSynGutter.SetDigitCount(Value: integer); -begin - Value := MinMax(Value, 2, 12); - if fDigitCount <> Value then - begin - fDigitCount := Value; - fAutoSizeDigitCount := fDigitCount; - DoChange(Self); - end; -end; - -procedure TSynGutter.SetLeadingZeros(const Value: boolean); -begin - if fLeadingZeros <> Value then - begin - fLeadingZeros := Value; - DoChange(Self); - end; -end; - -procedure TSynGutter.SetLeftOffset(Value: integer); -begin - Value := Max(0, Value); - if fLeftOffset <> Value then - begin - fLeftOffset := Value; - DoChange(Self); - end; -end; - -procedure TSynGutter.SetRightOffset(Value: integer); -begin - Value := Max(0, Value); - if fRightOffset <> Value then - begin - fRightOffset := Value; - DoChange(Self); - end; -end; - -procedure TSynGutter.SetShowOnlyLineNumbersMultiplesOf(const AValue: integer); -begin - if FShowOnlyLineNumbersMultiplesOf <> AValue then - begin - FShowOnlyLineNumbersMultiplesOf := AValue; - DoChange(Self); - end; -end; - -procedure TSynGutter.SetShowLineNumbers(const Value: boolean); -begin - if fShowLineNumbers <> Value then - begin - fShowLineNumbers := Value; - DoChange(Self); - end; -end; - -procedure TSynGutter.SetShowCodeFolding(const Value: boolean); -begin - if fShowCodeFolding <> Value then - begin - fShowCodeFolding := Value; - DoChange(Self); - end; -end; - -procedure TSynGutter.SetVisible(Value: boolean); -begin - if fVisible <> Value then - begin - fVisible := Value; - DoChange(Self); - end; -end; - -procedure TSynGutter.SetWidth(Value: integer); -begin - Value := Max(0, Value); - if fWidth <> Value then - begin - fWidth := Value; - DoChange(Self); - end; -end; - -procedure TSynGutter.SetZeroStart(const Value: boolean); -begin - if fZeroStart <> Value then - begin - fZeroStart := Value; - DoChange(Self); - end; -end; - -procedure TSynGutter.DoChange(Sender: TObject); -begin - if Assigned(fOnChange) then - fOnChange(Self); -end; - { TSynBookMarkOpt } constructor TSynBookMarkOpt.Create(AOwner: TComponent); diff --git a/components/synedit/syngutter.pp b/components/synedit/syngutter.pp index a978189213..a8b4cf28ad 100644 --- a/components/synedit/syngutter.pp +++ b/components/synedit/syngutter.pp @@ -211,6 +211,9 @@ implementation uses SynEdit, SynGutterLineNumber, SynGutterCodeFolding, SynGutterMarks; +type // This is until InvalidateGutterLines, can be moved to an accessible place + SynEditAccess = Class(TCustomSynEdit); + { TSynEditMark } function TSynEditMark.GetEdit: TSynEditBase; @@ -238,23 +241,23 @@ procedure TSynEditMark.SetImage(const Value: Integer); begin FImage := Value; if fVisible and Assigned(fEdit) then - TCustomSynEdit(FEdit).InvalidateGutterLines(fLine, fLine); + SynEditAccess(Pointer(FEdit)).InvalidateGutterLines(fLine, fLine); end; procedure TSynEditMark.SetInternalImage(const Value: boolean); begin fInternalImage := Value; if fVisible and Assigned(fEdit) then - TCustomSynEdit(FEdit).InvalidateGutterLines(fLine, fLine); + SynEditAccess(Pointer(FEdit)).InvalidateGutterLines(fLine, fLine); end; procedure TSynEditMark.SetLine(const Value: Integer); begin if fVisible and Assigned(fEdit) then begin if fLine > 0 then - TCustomSynEdit(FEdit).InvalidateGutterLines(fLine, fLine); + SynEditAccess(Pointer(FEdit)).InvalidateGutterLines(fLine, fLine); fLine := Value; - TCustomSynEdit(FEdit).InvalidateGutterLines(fLine, fLine); + SynEditAccess(Pointer(FEdit)).InvalidateGutterLines(fLine, fLine); end else fLine := Value; end; @@ -264,7 +267,7 @@ begin if fVisible <> Value then begin fVisible := Value; if Assigned(fEdit) then - TCustomSynEdit(FEdit).InvalidateGutterLines(fLine, fLine); + SynEditAccess(Pointer(FEdit)).InvalidateGutterLines(fLine, fLine); end; end;