diff --git a/lazproj/coedit.lpi b/lazproj/coedit.lpi index efd69c2c..b85c391c 100644 --- a/lazproj/coedit.lpi +++ b/lazproj/coedit.lpi @@ -137,7 +137,7 @@ - + @@ -365,6 +365,10 @@ + + + + diff --git a/lazproj/coedit.lpr b/lazproj/coedit.lpr index 3a5d7c55..700f4047 100644 --- a/lazproj/coedit.lpr +++ b/lazproj/coedit.lpr @@ -10,7 +10,7 @@ uses ce_observer, ce_libman, ce_tools, ce_dcd, ce_main, ce_writableComponent, ce_symstring, ce_staticmacro, ce_inspectors, ce_editoroptions, ce_dockoptions, ce_shortcutseditor, ce_mru, ce_processes, ce_dubproject, ce_dialogs, -ce_dubprojeditor, ce_gdb; +ce_dubprojeditor, ce_gdb, ce_controls; {$R *.res} diff --git a/src/ce_controls.pas b/src/ce_controls.pas new file mode 100644 index 00000000..7674e229 --- /dev/null +++ b/src/ce_controls.pas @@ -0,0 +1,338 @@ +unit ce_controls; + +{$I ce_defines.inc} + +interface + +uses + Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ComCtrls, + ExtCtrls, buttons; + +type + TCEPageControlButton = (pbClose, pbMoveLeft, pbMoveRight, pbAdd); + TCEPageControlButtons = set of TCEPageControlButton; + +const + CEPageControlDefaultButtons = [pbClose, pbMoveLeft, pbMoveRight, pbAdd]; + +type + + TCEPage = class(TCustomControl) + protected + procedure RealSetText(const Value: TCaption); override; + end; + + TCEPageControl = class(TWinControl) + private + fHeader: TWinControl; + fTabs: TTabControl; + fCloseBtn: TSpeedButton; + fMoveLeftBtn: TSpeedButton; + fMoveRightBtn: TSpeedButton; + fAddBtn: TSpeedButton; + fContent: TPanel; + fPages: TFPList; + fPageIndex: integer; + fButtons: TCEPageControlButtons; + fOnChanged: TNotifyEvent; + + procedure btnCloseClick(sender: TObject); + procedure btnMoveLeftClick(sender: TObject); + procedure btnMoveRightClick(sender: TObject); + procedure btnAddClick(sender: TObject); + + procedure tabsChanged(sender: TObject); + procedure hidePage(index: integer); + procedure showPage(index: integer); + procedure setPageIndex(index: integer); + procedure setButtons(value: TCEPageControlButtons); + procedure setCurrentPage(value: TCEPage); + function getCurrentPage: TCEPage; + function getPageCount: integer; + function getPage(index: integer): TCEPage; + + procedure changedNotify; + + public + constructor Create(aowner: TComponent); override; + destructor Destroy; override; + + function addPage: TCEPage; + procedure deletePage(index: integer); + function getPageIndex(page: TCEPage): integer; + procedure movePageRight; + procedure movePageLeft; + + property currentPage: TCEPage read getCurrentPage write setCurrentPage; + property pageIndex: integer read fPageIndex write setPageIndex; + property pageCount: integer read getPageCount; + property pages[index: integer]: TCEPage read getPage; default; + + property buttons: TCEPageControlButtons read fButtons write setButtons; + property closeButton: TSpeedButton read fCloseBtn; + property moveLeftButton: TSpeedButton read fMoveLeftBtn; + property moveRightButton: TSpeedButton read fMoveRightBtn; + property addButton: TSpeedButton read fAddBtn; + + property onChanged: TNotifyEvent read fOnChanged write fOnChanged; + end; + +implementation + + +procedure TCEPage.RealSetText(const Value: TCaption); +var + i: integer; + ctrl: TCEPageControl; +begin + inherited; + ctrl := TCEPageControl(Owner); + i := ctrl.getPageIndex(self); + if i <> -1 then ctrl.fTabs.Tabs.Strings[i] := caption; +end; + +constructor TCEPageControl.Create(aowner: TComponent); +begin + inherited; + + fHeader := TWinControl.Create(self); + fHeader.Parent:= self; + fHeader.Align := alTop; + fHeader.Height:= 32; + + fTabs := TTabControl.Create(self); + fTabs.Parent:= fHeader; + fTabs.Align := alClient; + fTabs.Options:=[]; + fTabs.OnChange:=@tabsChanged; + + fMoveLeftBtn:= TSpeedButton.Create(self); + fMoveLeftBtn.Parent := fHeader; + fMoveLeftBtn.Align:= alRight; + fMoveLeftBtn.Width:= 28; + fMoveLeftBtn.BorderSpacing.Around:= 2; + fMoveLeftBtn.ShowCaption:=false; + fMoveLeftBtn.OnClick:=@btnMoveLeftClick; + fMoveLeftBtn.Hint:='move page to the left'; + + fMoveRightBtn:= TSpeedButton.Create(self); + fMoveRightBtn.Parent := fHeader; + fMoveRightBtn.Align:= alRight; + fMoveRightBtn.Width:= 28; + fMoveRightBtn.BorderSpacing.Around:= 2; + fMoveRightBtn.ShowCaption:=false; + fMoveRightBtn.OnClick:=@btnMoveRightClick; + fMoveRightBtn.Hint:='move page to the right'; + + fAddBtn:= TSpeedButton.Create(self); + fAddBtn.Parent := fHeader; + fAddBtn.Align:= alRight; + fAddBtn.Width:= 28; + fAddBtn.BorderSpacing.Around:= 2; + fAddBtn.ShowCaption:=false; + fAddBtn.OnClick:=@btnAddClick; + + fCloseBtn := TSpeedButton.Create(self); + fCloseBtn.Parent := fHeader; + fCloseBtn.Align:= alRight; + fCloseBtn.Width:= 28; + fCloseBtn.BorderSpacing.Around:= 2; + fCloseBtn.ShowCaption:=false; + fCloseBtn.OnClick:=@btnCloseClick; + fCloseBtn.Hint:='close page'; + + fContent := TPanel.Create(self); + fContent.Parent := self; + fContent.Align := alClient; + fContent.BevelInner:= bvNone; + fContent.BevelOuter:= bvNone; + fContent.BorderStyle:=bsNone; + fContent.BorderSpacing.Around:=2; + + fPages := TFPList.Create; + fPageIndex := -1; + + fButtons:= CEPageControlDefaultButtons; +end; + +destructor TCEPageControl.Destroy; +begin + while fPages.Count > 0 do + deletePage(fPages.Count-1); + fPages.Free; + inherited; +end; + +procedure TCEPageControl.changedNotify; +begin + if assigned(fOnChanged) then + fOnChanged(self); +end; + +procedure TCEPageControl.tabsChanged(sender: TObject); +begin + setPageIndex(fTabs.TabIndex); +end; + +procedure TCEPageControl.hidePage(index: integer); +var + pge: TCEPage; + ctl: TControl; +begin + if (index < 0) or (index > fPages.Count-1) then + exit; + + pge := TCEPage(fPages.Items[index]); + pge.Visible:=false; + for ctl in pge.GetEnumeratorControls do + ctl.Visible:=false; +end; + +procedure TCEPageControl.showPage(index: integer); +var + pge: TCEPage; + ctl: TControl; +begin + if (index < 0) or (index > fPages.Count-1) then + exit; + + pge := TCEPage(fPages.Items[index]); + pge.Visible:=true; + pge.Repaint; + for ctl in pge.GetEnumeratorControls do + ctl.Visible:=true; +end; + +procedure TCEPageControl.setPageIndex(index: integer); +begin + if (index > fPages.Count-1) then + index := fPages.Count-1; + if (index < 0) then + exit; + + hidePage(fPageIndex); + fPageIndex := index; + showPage(fPageIndex); + fTabs.TabIndex:= fPageIndex; + + changedNotify; +end; + +function TCEPageControl.addPage: TCEPage; +var + pge: TCEPage; +begin + pge := TCEPage.Create(self); + pge.Parent := fContent; + pge.Align:= alClient; + + fPages.Add(pge); + fTabs.Tabs.Add(format('', [fPages.Count])); + setPageIndex(fTabs.Tabs.Count-1); + + result := pge; +end; + +procedure TCEPageControl.deletePage(index: integer); +begin + if (index > fPages.Count-1) or (index < 0) then + exit; + + TCEPage(fPages.Items[index]).Free; + fPages.Delete(index); + fTabs.Tabs.Delete(index); + + if fPageIndex >= fPages.Count then + fPageIndex -= 1; + if fPages.Count = 0 then exit; + + showPage(fPageIndex); + changedNotify; +end; + +function TCEPageControl.getPageIndex(page: TCEPage): integer; +begin + exit(fPages.IndexOf(page)); +end; + +function TCEPageControl.getCurrentPage: TCEPage; +begin + if (fPageIndex < 0) or (fPageIndex > fPages.Count-1) then + exit(nil) + else + exit(TCEPage(fPages.Items[fPageIndex])); +end; + +procedure TCEPageControl.setCurrentPage(value: TCEPage); +begin + setPageIndex(getPageIndex(value)); +end; + +function TCEPageControl.getPageCount: integer; +begin + exit(fPages.Count); +end; + +function TCEPageControl.getPage(index: integer): TCEPage; +begin + exit(TCEPage(fPages.Items[index])); +end; + +procedure TCEPageControl.movePageRight; +begin + if fPageIndex = fPages.Count-1 then + exit; + + fPages.Exchange(fPageIndex, fPageIndex + 1); + fTabs.Tabs.Exchange(fPageIndex, fPageIndex + 1); + setPageIndex(fPageIndex+1); +end; + +procedure TCEPageControl.movePageLeft; +begin + if fPageIndex <= 0 then + exit; + + fPages.Exchange(fPageIndex, fPageIndex - 1); + fTabs.Tabs.Exchange(fPageIndex, fPageIndex - 1); + setPageIndex(fPageIndex-1); +end; + + + +procedure TCEPageControl.btnCloseClick(sender: TObject); +begin + deletePage(fPageIndex); +end; + +procedure TCEPageControl.btnMoveLeftClick(sender: TObject); +begin + movePageLeft; +end; + +procedure TCEPageControl.btnMoveRightClick(sender: TObject); +begin + movePageRight; +end; + +procedure TCEPageControl.btnAddClick(sender: TObject); +begin + addPage; +end; + +procedure TCEPageControl.setButtons(value: TCEPageControlButtons); +begin + fButtons:= value; + fHeader.DisableAlign; + + fCloseBtn.Visible:= pbClose in fButtons; + fMoveLeftBtn.Visible:= pbMoveLeft in fButtons; + fCloseBtn.Visible:= pbMoveRight in fButtons; + fAddBtn.Visible:= pbAdd in fButtons; + + fHeader.EnableAlign; + fHeader.ReAlign; +end; + +end. + diff --git a/src/ce_editor.lfm b/src/ce_editor.lfm index 2d98ace8..80303710 100644 --- a/src/ce_editor.lfm +++ b/src/ce_editor.lfm @@ -14,28 +14,14 @@ inherited CEEditorWidget: TCEEditorWidget inherited Content: TPanel Height = 406 Width = 465 - BevelOuter = bvRaised ClientHeight = 406 ClientWidth = 465 - object PageControl: TExtendedNotebook[0] - Left = 3 - Height = 380 - Top = 3 - Width = 459 - Align = alClient - BorderSpacing.Around = 2 - TabOrder = 0 - OnChange = PageControlChange - OnChanging = PageControlChanging - Options = [nboShowCloseButtons, nboShowAddTabButton] - TabDragMode = dmAutomatic - TabDragAcceptMode = dmAutomatic - end - object editorStatus: TStatusBar[1] - Left = 3 + object editorStatus: TStatusBar[0] + Left = 2 Height = 18 - Top = 385 - Width = 459 + Top = 386 + Width = 461 + AutoSize = False BorderSpacing.Around = 2 Panels = < item diff --git a/src/ce_editor.pas b/src/ce_editor.pas index eecc849c..03519c78 100644 --- a/src/ce_editor.pas +++ b/src/ce_editor.pas @@ -9,18 +9,10 @@ uses Graphics, SynEditKeyCmds, ComCtrls, SynEditHighlighter, ExtCtrls, Menus, SynMacroRecorder, SynPluginSyncroEdit, SynEdit, SynHighlighterMulti, ce_dialogs, ce_widget, ce_interfaces, ce_synmemo, ce_dlang, ce_common, ce_dcd, ce_observer, - ce_sharedres; + ce_sharedres, ce_controls; type - // this descendant propagates the Visible property to the children. - // this fix the bug described in commit c1a0ed2799390d788b1d1e435eb8dc1ed3369ce7 - TCEEditorPage = class(TTabSheet) - protected - procedure SetVisible(Value: Boolean); override; - end; - - //TODO-crefact: moves the macro recorded to TCESynMemo, + add visual feedback + declare shortcuts ecXXXX { TCEEditorWidget } @@ -36,7 +28,6 @@ type mnuedRedo: TMenuItem; MenuItem7: TMenuItem; mnuedJum2Decl: TMenuItem; - PageControl: TExtendedNotebook; macRecorder: TSynMacroRecorder; editorStatus: TStatusBar; mnuEditor: TPopupMenu; @@ -55,15 +46,14 @@ type procedure updateDelayed; override; procedure updateImperative; override; private + pageControl: TCEPageControl; fKeyChanged: boolean; fDoc: TCESynMemo; fTokList: TLexTokenList; fErrList: TLexErrorList; fModStart: boolean; fLastCommand: TSynEditorCommand; - {$IFDEF LINUX} procedure pageCloseBtnClick(Sender: TObject); - {$ENDIF} procedure lexFindToken(const aToken: PLexToken; out doStop: boolean); procedure memoKeyPress(Sender: TObject; var Key: char); procedure memoKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); @@ -95,25 +85,19 @@ type implementation {$R *.lfm} -procedure TCEEditorPage.SetVisible(Value: Boolean); -var - i: integer; -begin - inherited; - for i := 0 to ControlCount-1 do - Controls[i].Visible:= Value; -end; - {$REGION Standard Comp/Obj------------------------------------------------------} constructor TCEEditorWidget.create(aOwner: TComponent); begin inherited; // + pageControl := TCEPageControl.Create(self); + pageControl.Parent := Content; + pageControl.align := alClient; + pageControl.onChanged:= @PageControlChange; + pageControl.closeButton.OnClick:=@pageCloseBtnClick; + fTokList := TLexTokenList.Create; fErrList := TLexErrorList.Create; - {$IFDEF LINUX} - PageControl.OnCloseTabClicked := @pageCloseBtnClick; - {$ENDIF} // AssignPng(mnuedCopy.Bitmap, 'copy'); AssignPng(mnuedCut.Bitmap, 'cut'); @@ -133,9 +117,9 @@ var begin EntitiesConnector.removeObserver(self); for i := PageControl.PageCount-1 downto 0 do - if PageControl.Page[i].ControlCount > 0 then - if (PageControl.Page[i].Controls[0] is TCESynMemo) then - PageControl.Page[i].Controls[0].Free; + if PageControl.Pages[i].ControlCount > 0 then + if (PageControl.Pages[i].Controls[0] is TCESynMemo) then + PageControl.Pages[i].Controls[0].Free; fTokList.Free; fErrList.Free; inherited; @@ -150,13 +134,12 @@ end; {$REGION ICEMultiDocObserver ---------------------------------------------------} procedure TCEEditorWidget.docNew(aDoc: TCESynMemo); var - sheet: TCEEditorPage; + pge: TCEPage; begin - sheet := TCEEditorPage.Create(self); - sheet.PageControl := PageControl; + pge := pageControl.addPage; // aDoc.Align := alClient; - aDoc.Parent := sheet; + aDoc.Parent := pge; // aDoc.OnKeyDown := @memoKeyDown; aDoc.OnKeyUp := @memoKeyUp; @@ -167,24 +150,20 @@ begin aDoc.OnCommandProcessed:= @memoCmdProcessed; // fDoc := aDoc; - pageControl.ActivePage := sheet; focusedEditorChanged; beginDelayedUpdate; updateImperative; end; procedure TCEEditorWidget.docClosing(aDoc: TCESynMemo); -var - sheet: TWinControl; begin if aDoc = nil then exit; - sheet := aDoc.Parent; aDoc.Parent := nil; if aDoc = fDoc then fDoc := nil; - if sheet <> nil then sheet.Free; updateImperative; + pageControl.deletePage(pageControl.pageIndex); end; procedure TCEEditorWidget.docFocused(aDoc: TCESynMemo); @@ -240,7 +219,7 @@ var begin doc := findDocument(aFilename); if doc <> nil then begin - PageControl.ActivePage := TTabSheet(doc.Parent); + PageControl.currentPage := TCEPage(doc.Parent); exit; end; doc := TCESynMemo.Create(nil); @@ -261,13 +240,10 @@ end; {$ENDREGION} {$REGION PageControl/Editor things ---------------------------------------------} -{$IFDEF LINUX} procedure TCEEditorWidget.pageCloseBtnClick(Sender: TObject); begin - PageControl.PageIndex := TTabSheet(sender).PageIndex; closeDocument(PageControl.PageIndex); end; -{$ENDIF} procedure TCEEditorWidget.focusedEditorChanged; begin @@ -276,7 +252,7 @@ begin // macRecorder.Editor:= fDoc; fDoc.PopupMenu := mnuEditor; - if (pageControl.ActivePage.Caption = '') then + if (pageControl.currentPage.Caption = '') then begin fKeyChanged := true; beginDelayedUpdate; @@ -389,8 +365,8 @@ begin editorStatus.Panels[0].Text := format('%d : %d | %d', [fDoc.CaretY, fDoc.CaretX, fDoc.SelEnd - fDoc.SelStart]); editorStatus.Panels[1].Text := modstr[fDoc.modified]; editorStatus.Panels[2].Text := fDoc.fileName; - if Visible and (pageControl.ActivePage <> nil) and ((pageControl.ActivePage.Caption = '') or - (pageControl.ActivePage.Caption = '')) then + if Visible and (pageControl.currentPage <> nil) and ((pageControl.currentPage.Caption = '') or + (pageControl.currentPage.Caption = '')) then begin if fDoc.isDSource then begin @@ -400,7 +376,7 @@ begin fErrList.Clear; end; if md = '' then md := extractFileName(fDoc.fileName); - pageControl.ActivePage.Caption := md; + pageControl.currentPage.Caption := md; end; end; end; @@ -437,7 +413,7 @@ begin fErrList.Clear; end; if md = '' then md := extractFileName(fDoc.fileName); - pageControl.ActivePage.Caption := md; + pageControl.currentPage.Caption := md; // note: not true anymore vecause cesyms use send the doc in stdin // when a widget saves a temp file & syncro mode is on: