diff --git a/icons/other/splitter.png b/icons/other/splitter.png new file mode 100644 index 00000000..1aacb081 Binary files /dev/null and b/icons/other/splitter.png differ diff --git a/lazproj/test/pagecontrol/pagecontrol.lpi b/lazproj/test/pagecontrol/pagecontrol.lpi index d6cbb4dc..b20c9d17 100644 --- a/lazproj/test/pagecontrol/pagecontrol.lpi +++ b/lazproj/test/pagecontrol/pagecontrol.lpi @@ -55,6 +55,21 @@ + + + + + + + + + + + + + + + diff --git a/lazproj/test/pagecontrol/pagecontroltester.pas b/lazproj/test/pagecontrol/pagecontroltester.pas index 0f1c50c3..82ac37ca 100644 --- a/lazproj/test/pagecontrol/pagecontroltester.pas +++ b/lazproj/test/pagecontrol/pagecontroltester.pas @@ -36,6 +36,7 @@ begin AssignPng(fPageControl.addButton.Glyph, 'document_add'); AssignPng(fPageControl.moveLeftButton.Glyph, 'document_back'); AssignPng(fPageControl.moveRightButton.Glyph, 'document_next'); + AssignPng(fPageControl.splitButton.Glyph, 'splitter'); end; procedure TForm1.pageControlChanged(sender: TObject); diff --git a/src/ce_controls.pas b/src/ce_controls.pas index 573f022e..90b08bc9 100644 --- a/src/ce_controls.pas +++ b/src/ce_controls.pas @@ -8,11 +8,11 @@ uses Classes, SysUtils, Forms, Controls, ComCtrls, ExtCtrls, buttons; type - TCEPageControlButton = (pbClose, pbMoveLeft, pbMoveRight, pbAdd); + TCEPageControlButton = (pbClose, pbMoveLeft, pbMoveRight, pbAdd, pbSplit); TCEPageControlButtons = set of TCEPageControlButton; const - CEPageControlDefaultButtons = [pbClose, pbMoveLeft, pbMoveRight, pbAdd]; + CEPageControlDefaultButtons = [pbClose, pbMoveLeft, pbMoveRight, pbAdd, pbSplit]; type @@ -30,8 +30,9 @@ type * Minimalist page-control dedicated to Coedit * * - get rid of the framed aspect of the default LCL one - * - no published props, since CE has to be compilable w/o extra IDE comps + * - no published props, no need for design time support * - add/close/move left and right speed buttons + * - a particular tab can be set to reside on a split view *) TCEPageControl = class(TWinControl) private @@ -41,17 +42,22 @@ type fMoveLeftBtn: TSpeedButton; fMoveRightBtn: TSpeedButton; fAddBtn: TSpeedButton; + fSplitBtn: TSpeedButton; fContent: TPanel; fPages: TFPList; fPageIndex: integer; + fSplittedPageIndex: integer; fButtons: TCEPageControlButtons; fOnChanged: TNotifyEvent; fOnChanging: TTabChangingEvent; + fSplitter: TSplitter; + fOldSplitPos: integer; procedure btnCloseClick(sender: TObject); procedure btnMoveLeftClick(sender: TObject); procedure btnMoveRightClick(sender: TObject); procedure btnAddClick(sender: TObject); + procedure btnSplitClick(sender: TObject); procedure tabsChanging(Sender: TObject; var AllowChange: Boolean); procedure tabsChanged(sender: TObject); @@ -87,6 +93,7 @@ type property moveLeftButton: TSpeedButton read fMoveLeftBtn; property moveRightButton: TSpeedButton read fMoveRightBtn; property addButton: TSpeedButton read fAddBtn; + property splitButton: TSpeedButton read fSplitBtn; property onChanged: TNotifyEvent read fOnChanged write fOnChanged; property onChanging: TTabChangingEvent read fOnChanging write fOnChanging; @@ -126,6 +133,8 @@ begin fHeader.Align := alTop; fHeader.Height:= 32; + fSplittedPageIndex:=-1; + fTabs := TTabControl.Create(self); fTabs.Parent:= fHeader; fTabs.Align := alClient; @@ -169,6 +178,15 @@ begin fCloseBtn.OnClick:=@btnCloseClick; fCloseBtn.Hint:='close current page'; + fSplitBtn := TSpeedButton.Create(self); + fSplitBtn.Parent := fHeader; + fSplitBtn.Align:= alRight; + fSplitBtn.Width:= 28; + fSplitBtn.BorderSpacing.Around:= 2; + fSplitBtn.ShowCaption:=false; + fSplitBtn.OnClick:=@btnSplitClick; + fSplitBtn.Hint:= 'pin or un-pin the page to the right'; + fContent := TPanel.Create(self); fContent.Parent := self; fContent.Align := alClient; @@ -177,6 +195,12 @@ begin fContent.BorderStyle:=bsNone; fContent.BorderSpacing.Top:=3; + fSplitter := TSplitter.Create(self); + fSplitter.Parent := fContent; + fSplitter.Visible:= false; + fSplitter.Align := alLeft; + fSplitter.Width := 6; + fPages := TFPList.Create; fPageIndex := -1; @@ -201,7 +225,8 @@ end; procedure TCEPageControl.tabsChanged(sender: TObject); begin - setPageIndex(fTabs.TabIndex); + if fTabs.TabIndex < fPages.Count then + setPageIndex(fTabs.TabIndex); end; procedure TCEPageControl.tabsChanging(Sender: TObject; var AllowChange: Boolean); @@ -229,6 +254,8 @@ begin exit; pge := TCEPage(fPages.Items[index]); + if (fSplittedPageIndex = -1) or (index = fSplittedPageIndex) then + pge.Align:=alClient; pge.Visible:=true; pge.Repaint; for ctl in pge.GetEnumeratorControls do @@ -236,15 +263,42 @@ begin end; procedure TCEPageControl.setPageIndex(index: integer); +var + leftp, rightp: TCEPage; begin + if (fPageIndex <> fSplittedPageIndex) then + fOldSplitPos := fSplitter.Left; if (index > fPages.Count-1) then index := fPages.Count-1; if (index < 0) then exit; - hidePage(fPageIndex); - fPageIndex := index; - showPage(fPageIndex); + if (fSplittedPageIndex = -1) or (index = fSplittedPageIndex) then + begin + hidePage(fPageIndex); + fPageIndex := index; + showPage(fPageIndex); + fSplitter.Visible:= false; + end + else if (fSplittedPageIndex <> -1) then + begin + hidePage(fPageIndex); + fPageIndex := index; + + fSplitter.Visible:= true; + + leftp := getPage(fPageIndex); + leftp.Align := alLeft; + if fOldSplitPos = 0 then + leftp.Width:= (fContent.Width - fSplitter.Width) div 2 + else + leftp.Width:= fOldSplitPos; + showPage(fPageIndex); + + rightp := getPage(fSplittedPageIndex); + rightp.Align := alClient; + showPage(fSplittedPageIndex); + end; if fTabs.TabIndex <> fPageIndex then fTabs.TabIndex:= fPageIndex; @@ -272,12 +326,18 @@ begin if (index > fPages.Count-1) or (index < 0) then exit; + if index = fSplittedPageIndex then + fSplittedPageIndex := -1 + else if index < fSplittedPageIndex then + fSplittedPageIndex -= 1; + TCEPage(fPages.Items[index]).Free; + if fPageIndex >= fPages.Count then + fPageIndex -= 1; + fPages.Delete(index); fTabs.Tabs.Delete(index); - if fPageIndex >= fPages.Count then - fPageIndex -= 1; updateButtonsState; if fPages.Count = 0 then exit; @@ -320,6 +380,8 @@ begin fPages.Exchange(fPageIndex, fPageIndex + 1); fTabs.Tabs.Exchange(fPageIndex, fPageIndex + 1); + if fPageIndex = fSplittedPageIndex then + fSplittedPageIndex += 1; setPageIndex(fPageIndex+1); end; @@ -330,6 +392,8 @@ begin fPages.Exchange(fPageIndex, fPageIndex - 1); fTabs.Tabs.Exchange(fPageIndex, fPageIndex - 1); + if fPageIndex = fSplittedPageIndex then + fSplittedPageIndex -= 1; setPageIndex(fPageIndex-1); end; @@ -353,6 +417,19 @@ begin addPage; end; +procedure TCEPageControl.btnSplitClick(sender: TObject); +begin + if fPageIndex = fSplittedPageIndex then + fSplittedPageIndex := -1 + else + begin + if (fSplittedPageIndex <> -1) then + hidePage(fSplittedPageIndex); + fSplittedPageIndex:= fPageIndex; + end; + setPageIndex(fPageIndex); +end; + procedure TCEPageControl.setButtons(value: TCEPageControlButtons); begin if fButtons = value then @@ -370,6 +447,7 @@ begin fMoveLeftBtn.Visible:= pbMoveLeft in fButtons; fCloseBtn.Visible:= pbMoveRight in fButtons; fAddBtn.Visible:= pbAdd in fButtons; + fSplitBtn.Visible:= pbSplit in fButtons; fHeader.EnableAlign; fCloseBtn.Enabled := fPageIndex <> -1; fMoveLeftBtn.Enabled := fPageIndex > 0; diff --git a/src/ce_editor.pas b/src/ce_editor.pas index 6afac642..3d74408f 100644 --- a/src/ce_editor.pas +++ b/src/ce_editor.pas @@ -77,6 +77,7 @@ type function findDocument(aFilename: string): TCESynMemo; procedure openDocument(aFilename: string); function closeDocument(index: Integer): boolean; + function closeDocument(doc: TCESynMemo): boolean; public constructor create(aOwner: TComponent); override; destructor destroy; override; @@ -102,6 +103,7 @@ begin AssignPng(pageControl.moveRightButton, 'go_next'); AssignPng(pageControl.addButton, 'document_add'); AssignPng(pageControl.closeButton, 'document_delete'); + AssignPng(pageControl.splitButton, 'splitter'); fTokList := TLexTokenList.Create; fErrList := TLexErrorList.Create; @@ -245,6 +247,16 @@ begin doc.Free; result := true; end; + +function TCEEditorWidget.closeDocument(doc: TCESynMemo): boolean; +var + page: TCEPage = nil; +begin + page := TCEPage(doc.Parent); + if not assigned(page) then + exit(false); + exit(closeDocument(page.index)); +end; {$ENDREGION} {$REGION PageControl/Editor things ---------------------------------------------} diff --git a/src/ce_icons.inc b/src/ce_icons.inc index 2f651bb5..6022543c 100644 --- a/src/ce_icons.inc +++ b/src/ce_icons.inc @@ -1879,6 +1879,22 @@ LazarusResources.Add('script_bricks','PNG',[ +#208#201#143'>'#252#244#1#12#220#156#248'7'#240'qB'#160'$'#2#254#184#240'?' +#248'.'#192#0#5#181#10'l'#246#0'3S'#0#0#0#0'IEND'#174'B`'#130 ]); +LazarusResources.Add('splitter','PNG',[ + #137'PNG'#13#10#26#10#0#0#0#13'IHDR'#0#0#0#16#0#0#0#16#8#4#0#0#0#181#250'7' + +#234#0#0#0#4'gAMA'#0#0#177#143#11#252'a'#5#0#0#0' cHRM'#0#0'z&'#0#0#128#132#0 + +#0#250#0#0#0#128#232#0#0'u0'#0#0#234'`'#0#0':'#152#0#0#23'p'#156#186'Q<'#0#0 + +#0#2'bKGD'#0#255#135#143#204#191#0#0#0#158'IDAT('#207#133#145'A'#10#194'0'#16 + +'E_'#146#174#4'!'#189#137#160#135#240#2#30'F'#196#149'G'#17#234#29#188#131 + +#224'M*'#212#173#254'.'#146#198'&'#218':'#217#204#252#188#201#12'?F'#132'0'#0 + +'\Z'#239#159#143']'#13#16'n,Y'#188#253#150#133#31'+'#5' Z'#196#12#0'U'#28'6' + +#9#216'B*'#0'C5'#13#236#5#138'/'#28#244#5#28#163#228#176#128'Iu'#2'N'#155'a' + +#136#0#165#26#197#3#172#225','#233#170#144#7'}'#188#209'mh'#249#228'?'#140 + +#226#159'Q'#204#251'`'#1'W8'#155#27#213'5Ku'#153#146#127'7+'#28'/'#238'iYz' + +#241#246'-'#217#139'7'#147#144#0#0#0'%tEXtdate:create'#0'2014-03-13T04:26:36' + +'+02:00'#249'}l'#149#0#0#0'%tEXtdate:modify'#0'2013-01-08T13:07:58+02:00'#133 + +#178'Km'#0#0#0#25'tEXtSoftware'#0'Adobe ImageReadyq'#201'e<'#0#0#0#0'IEND' + +#174'B`'#130 +]); LazarusResources.Add('application','PNG',[ #137'PNG'#13#10#26#10#0#0#0#13'IHDR'#0#0#0#16#0#0#0#16#8#6#0#0#0#31#243#255'a' +#0#0#0#25'tEXtSoftware'#0'Adobe ImageReadyq'#201'e<'#0#0#1#175'IDATx'#218#156 diff --git a/src/ce_interfaces.pas b/src/ce_interfaces.pas index e5ac445c..fdd48bed 100644 --- a/src/ce_interfaces.pas +++ b/src/ce_interfaces.pas @@ -289,14 +289,16 @@ type ICEMultiDocHandler = interface(ICESingleService) // returns the count of opened document function documentCount: Integer; - // returns the index-th document + // returns the nth document function getDocument(index: Integer): TCESynMemo; // returns true if the document matching aFielanme is already opened. function findDocument(aFilename: string): TCESynMemo; // open or set the focus on the document matching aFilename procedure openDocument(aFilename: string); - // close the index-th document + // close the nth document function closeDocument(index: Integer): boolean; + // close a particular document + function closeDocument(doc: TCESynMemo): boolean; // conveniance property property document[index: integer]: TCESynMemo read getDocument; end; diff --git a/src/ce_main.lfm b/src/ce_main.lfm index 7faea280..2065616f 100644 --- a/src/ce_main.lfm +++ b/src/ce_main.lfm @@ -1,7 +1,7 @@ object CEMainForm: TCEMainForm - Left = 480 + Left = 485 Height = 49 - Top = 238 + Top = 239 Width = 745 AllowDropFiles = True Caption = 'Coedit' diff --git a/src/ce_main.pas b/src/ce_main.pas index 45d41540..d2fa54bc 100644 --- a/src/ce_main.pas +++ b/src/ce_main.pas @@ -1575,7 +1575,7 @@ begin if fDoc = nil then exit; if (fDoc.modified or(fDoc.fileName = fDoc.tempFilename)) and (dlgFileChangeClose(fDoc.fileName) = mrCancel) then exit; - fDoc.Free; + getMultiDocHandler.closeDocument(fDoc); end; procedure TCEMainForm.actFileSaveAllExecute(Sender: TObject); diff --git a/src/ce_synmemo.pas b/src/ce_synmemo.pas index d16d043f..2dcdb22a 100644 --- a/src/ce_synmemo.pas +++ b/src/ce_synmemo.pas @@ -8,7 +8,7 @@ uses Classes, SysUtils, controls,lcltype, Forms, graphics, ExtCtrls, crc, SynEdit, SynPluginSyncroEdit, SynCompletion, SynEditKeyCmds, LazSynEditText, SynHighlighterLFM, SynEditHighlighter, SynEditMouseCmds, SynEditFoldedView, - SynEditMarks, SynEditMarkup, SynEditTypes, + SynEditMarks, SynEditMarkup, SynEditTypes, Messages, LMessages, ce_common, ce_observer, ce_writableComponent, ce_d2syn, ce_txtsyn, ce_dialogs, ce_sharedres; @@ -103,6 +103,7 @@ type fIsDSource: boolean; fIsTxtFile: boolean; fIsConfig: boolean; + fFocusForInput: boolean; fIdentifier: string; fTempFileName: string; fMultiDocSubject: TCECustomSubject; @@ -154,6 +155,8 @@ type procedure removeBreakPoint(line: integer); function findBreakPoint(line: integer): boolean; protected + procedure DoEnter; override; + procedure DoExit; override; procedure DoOnProcessCommand(var Command: TSynEditorCommand; var AChar: TUTF8Char; Data: pointer); override; procedure MouseLeave; override; @@ -556,6 +559,25 @@ begin subjDocFocused(TCEMultiDocSubject(fMultiDocSubject), self); end; +procedure TCESynMemo.DoEnter; +begin + inherited; + checkFileDate; + if not fFocusForInput then + subjDocFocused(TCEMultiDocSubject(fMultiDocSubject), self); + fFocusForInput := true; +end; + +procedure TCESynMemo.DoExit; +begin + inherited; + fFocusForInput := false; + fDDocWin.Hide; + fCallTipWin.Hide; + if fCompletion.IsActive then + fCompletion.Deactivate; +end; + procedure TCESynMemo.SetVisible(Value: Boolean); begin inherited; @@ -569,7 +591,7 @@ begin else begin fDDocWin.Hide; fCallTipWin.Hide; - if fCompletion.IsActive then + if fCompletion.IsActive then fCompletion.Deactivate; end; end; @@ -1091,6 +1113,7 @@ end; procedure TCESynMemo.MouseLeave; begin + inherited; fDDocWin.Hide; fCallTipWin.Hide; end;