summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorGraeme Geldenhuys <graeme@mastermaths.co.za>2013-02-21 15:33:08 +0000
committerGraeme Geldenhuys <graeme@mastermaths.co.za>2013-02-21 15:33:08 +0000
commita2a47250423e3b22bdcf1a52f2e214b71102579c (patch)
treed25b0246eda04a73a58f7e1657bd3bc47ab302a3 /examples
parenta35615c726e05796feb2ff5ae63dbd3958d4135a (diff)
downloadfpGUI-a2a47250423e3b22bdcf1a52f2e214b71102579c.tar.xz
nanoedit - a mini notepad like text editor
I have been using this for some time now. I required a mini editor on non-Windows platforms, so created this project to solve that. This is also a testbed project for my "elastic tabstops" implementation.
Diffstat (limited to 'examples')
-rw-r--r--examples/apps/nanoedit/README.txt10
-rw-r--r--examples/apps/nanoedit/elastictabstops.pas219
-rw-r--r--examples/apps/nanoedit/extrafpc.cfg6
-rw-r--r--examples/apps/nanoedit/frm_find.pas196
-rw-r--r--examples/apps/nanoedit/install/nanoedit.desktop9
-rw-r--r--examples/apps/nanoedit/install/nanoedit.xpm47
-rw-r--r--examples/apps/nanoedit/mainfrm.pas267
-rw-r--r--examples/apps/nanoedit/nanoedit.lpi82
-rw-r--r--examples/apps/nanoedit/nanoedit.lpr27
-rw-r--r--examples/apps/nanoedit/testfiles/file1.pas109
-rw-r--r--examples/apps/nanoedit/testfiles/file2.pas19
11 files changed, 991 insertions, 0 deletions
diff --git a/examples/apps/nanoedit/README.txt b/examples/apps/nanoedit/README.txt
new file mode 100644
index 00000000..50b5bbab
--- /dev/null
+++ b/examples/apps/nanoedit/README.txt
@@ -0,0 +1,10 @@
+Title: nanoedit
+Author: Graeme Geldenhuys <graemeg@gmail.com>
+Description:
+------------
+I often need a Notepad like (very basic) editor on non-Windows platforms,
+for some of my other projects. I created nanoedit for that reason. I'm
+also using nanoedit as a testing platform for the fpg_textedit unit
+(part of the Maximus IDE example project), and for my experimental
+"elastic tabstops" [http://nickgravgaard.com/elastictabstops/]
+implementation.
diff --git a/examples/apps/nanoedit/elastictabstops.pas b/examples/apps/nanoedit/elastictabstops.pas
new file mode 100644
index 00000000..53861ad8
--- /dev/null
+++ b/examples/apps/nanoedit/elastictabstops.pas
@@ -0,0 +1,219 @@
+unit elastictabstops;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ Classes, SysUtils, fpg_memo;
+
+type
+
+ TMutableInteger = class(TObject)
+ public
+ Value: integer;
+ end;
+
+
+ TETLine = class(TObject)
+ public
+ StartPos: integer;
+ EndPos: integer;
+ NumTabs: integer;
+ constructor Create;
+ end;
+
+
+ TETTabstop = class(TObject)
+ public
+ TextWidthPix: integer;
+ WidestWidthPix: TMutableInteger;
+ StartPos: integer;
+ EndPos: integer;
+ EndsInTab: boolean;
+ constructor Create;
+ end;
+
+
+
+ TElasticTabstopsDocFilter = class(TObject)
+ private
+ FMemo: TfpgMemo;
+ FTabMultiples: integer;
+ FTabMinimum: integer;
+ FTabPadding: integer;
+ FMaxTabstops: integer;
+ protected
+ property Memo: TfpgMemo read FMemo;
+ function CalcTabWidth(TextWidthInTab: integer): integer;
+ public
+ constructor Create(AMemo: TfpgMemo);
+ procedure StretchTabstops;
+ property MaxTabstops: integer read FMaxTabstops write FMaxTabstops;
+ end;
+
+
+implementation
+
+{ TETLine }
+
+constructor TETLine.Create;
+begin
+ StartPos := 0;
+ EndPos := 0;
+ NumTabs := 0;
+end;
+
+{ TETTabstop }
+
+constructor TETTabstop.Create;
+begin
+ TextWidthPix := 0;
+// WidestWidthPix := 0;
+ StartPos := 0;
+ EndPos := 0;
+ EndsInTab := False;
+end;
+
+
+{ TElasticTabstopsDocFilter }
+
+function TElasticTabstopsDocFilter.CalcTabWidth(TextWidthInTab: integer): integer;
+var
+ w: integer;
+begin
+ w := ((TextWidthInTab div FTabMultiples) + 1) * FTabMultiples;
+ if w < FTabMinimum then
+ w := FTabMinimum;
+ Inc(w, FTabPadding);
+ Result := w;
+end;
+
+constructor TElasticTabstopsDocFilter.Create(AMemo: TfpgMemo);
+begin
+ FMemo := AMemo;
+ // tabstops are at least 32 pixels plus 8 pixels of padding
+ FTabMultiples := 1; // must be greater than 0
+ FTabMinimum := 32;
+ FTabPadding := 8;
+
+ FMaxTabstops := 32; // tabs per line
+end;
+
+procedure TElasticTabstopsDocFilter.StretchTabstops;
+var
+ linecount: integer;
+ lines: array of TETLine;
+ grid: array of array of TETTabstop;
+ l: integer;
+ t: integer;
+ c: integer;
+ lineStart: integer;
+ lineEnd: integer;
+ lineText: string;
+ tabs_on_line: integer;
+ textWidthInTab: integer;
+ theWidestWidthPix: TMutableInteger;
+ maxWidth: integer;
+ accTabStop: integer;
+begin
+ linecount := FMemo.Lines.Count;
+ SetLength(lines, linecount);
+ SetLength(grid, linecount, FMaxTabstops);
+
+ // initialise array
+ for l := 0 to linecount - 1 do // for each line
+ begin
+ lines[l] := TETLine.Create;
+ for t := 0 to MaxTabstops - 1 do // for each column
+ grid[l, t] := TETTabstop.Create;
+ end;
+
+ // get width of text in cells
+ for l := 0 to linecount - 1 do // for each line
+ begin
+ {$Note What must these be??? }
+ lineStart := 0;
+ lineEnd := 0;
+ lines[l].StartPos := lineStart;
+ lines[l].EndPos := lineEnd;
+
+ lineText := FMemo.Lines[l];
+ tabs_on_line := 0;
+ textWidthInTab := 0;
+
+ for c := 1 to Length(lineText) do // for each char in current line
+ begin
+ if c = Length(lineText) then
+ begin
+ grid[l, tabs_on_line].EndsInTab := False;
+ grid[l, tabs_on_line].EndPos := lineStart + c;
+ textWidthInTab := 0;
+ end
+ else if lineText[c] = #9 then
+ begin
+ grid[l, tabs_on_line].EndsInTab := True;
+ grid[l, tabs_on_line].EndPos := lineStart + c;
+ grid[l, tabs_on_line].TextWidthPix := CalcTabWidth(textWidthInTab);
+ Inc(tabs_on_line, 1);
+ grid[l, tabs_on_line].StartPos := lineStart + c + 1;
+ Inc(lines[l].NumTabs, 1);
+ textWidthInTab := 0;
+ end
+ else
+ Inc(textWidthInTab, FMemo.Canvas.Font.TextWidth(lineText[c]));
+ end; { for c }
+ end; { for l }
+
+ // find columns blocks and stretch to fit the widest cell
+ for t := 0 to MaxTabstops - 1 do // for each column
+ begin
+ // All tabstops in column block point to same number. You change one, and
+ // they all change
+ theWidestWidthPix := TMutableInteger.Create; // reference
+ theWidestWidthPix.Value := 0;
+ maxWidth := 0;
+ for l := 0 to linecount - 1 do // for each line
+ begin
+ if grid[l, t].EndsInTab then
+ begin
+ grid[l, t].WidestWidthPix := theWidestWidthPix; // copy reference
+ if grid[l, t].TextWidthPix < maxWidth then
+ grid[l, t].TextWidthPix := maxWidth
+ else
+ begin
+ maxWidth := grid[l, t].TextWidthPix;
+ theWidestWidthPix.Value := maxWidth;
+ end;
+ end
+ else // end column block
+ begin
+ theWidestWidthPix := TMutableInteger.Create; // new reference
+ theWidestWidthPix.Value := 0;
+ maxWidth := 0;
+ end; { if/else }
+ end; { for l }
+ end;
+
+ // apply tabstop sizes to the text
+ for l := 0 to linecount - 1 do // for each line
+ begin
+ // accumulate tabstop widths
+ accTabStop := 0;
+ for t := 0 to lines[l].NumTabs - 1 do
+ begin
+ Inc(accTabStop, grid[l, t].WidestWidthPix.Value);
+ grid[l, t].TextWidthPix := accTabStop;
+ end;
+
+ // SetBlocksTabStops(grid[l], lines[l].NumTabs);
+// Delete();
+
+// FMemo.Lines[l];
+// FMemo.Invalidate;
+ end;
+
+end;
+
+end.
+
diff --git a/examples/apps/nanoedit/extrafpc.cfg b/examples/apps/nanoedit/extrafpc.cfg
new file mode 100644
index 00000000..034a7b9d
--- /dev/null
+++ b/examples/apps/nanoedit/extrafpc.cfg
@@ -0,0 +1,6 @@
+-FUunits
+-Fu../../lib/$fpctarget
+-Fu../ide/src/
+-Xs
+-XX
+-CX
diff --git a/examples/apps/nanoedit/frm_find.pas b/examples/apps/nanoedit/frm_find.pas
new file mode 100644
index 00000000..96bfe6fa
--- /dev/null
+++ b/examples/apps/nanoedit/frm_find.pas
@@ -0,0 +1,196 @@
+unit frm_find;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ SysUtils, Classes, fpg_base, fpg_main, fpg_form, fpg_label,
+ fpg_edit, fpg_button, fpg_checkbox, fpg_panel, fpg_radiobutton,
+ fpg_textedit;
+
+type
+
+ TFindForm = class(TfpgForm)
+ private
+ {@VFD_HEAD_BEGIN: FindForm}
+ Label1: TfpgLabel;
+ FindEdit: TfpgEdit;
+ btnFind: TfpgButton;
+ btnCancel: TfpgButton;
+ GroupBox1: TfpgGroupBox;
+ chkWholeWord: TfpgCheckBox;
+ chkCaseSensitive: TfpgCheckBox;
+ rbForward: TfpgRadioButton;
+ rbBackward: TfpgRadioButton;
+ {@VFD_HEAD_END: FindForm}
+ procedure btnFindClicked(Sender: TObject);
+ function GetTextToFind: TfpgString;
+ function GetIsForward: boolean;
+ function GetFindOptions: TfpgFindOptions;
+ public
+ procedure AfterCreate; override;
+ function Execute: boolean;
+ property TextToFind: TfpgString read GetTextToFind;
+ property IsForward: boolean read GetIsForward;
+ property FindOptions: TfpgFindOptions read GetFindOptions;
+ end;
+
+{@VFD_NEWFORM_DECL}
+
+implementation
+
+{@VFD_NEWFORM_IMPL}
+
+procedure TFindForm.btnFindClicked(Sender: TObject);
+begin
+ ModalResult := mrOK;
+end;
+
+function TFindForm.GetTextToFind: TfpgString;
+begin
+ Result := FindEdit.Text;
+end;
+
+function TFindForm.GetIsForward: boolean;
+begin
+ Result := rbForward.Checked;
+end;
+
+function TFindForm.GetFindOptions: TfpgFindOptions;
+begin
+ Result := [foEntireScope];
+ if chkWholeWord.Checked then
+ Result := Result + [foWholeWords];
+ if chkCaseSensitive.Checked then
+ Result := Result + [foMatchCase];
+end;
+
+procedure TFindForm.AfterCreate;
+begin
+ {%region 'Auto-generated GUI code' -fold}
+ {@VFD_BODY_BEGIN: FindForm}
+ Name := 'FindForm';
+ SetPosition(292, 173, 429, 110);
+ WindowTitle := 'Find';
+ Hint := '';
+
+ Label1 := TfpgLabel.Create(self);
+ with Label1 do
+ begin
+ Name := 'Label1';
+ SetPosition(4, 4, 280, 16);
+ FontDesc := '#Label1';
+ Hint := '';
+ Text := 'Text to find:';
+ end;
+
+ FindEdit := TfpgEdit.Create(self);
+ with FindEdit do
+ begin
+ Name := 'FindEdit';
+ SetPosition(4, 20, 332, 24);
+ Anchors := [anLeft,anRight,anTop];
+ ExtraHint := '';
+ FontDesc := '#Edit1';
+ Hint := '';
+ TabOrder := 2;
+ Text := '';
+ end;
+
+ btnFind := TfpgButton.Create(self);
+ with btnFind do
+ begin
+ Name := 'btnFind';
+ SetPosition(345, 8, 80, 24);
+ Anchors := [anRight,anTop];
+ Text := 'Find';
+ FontDesc := '#Label1';
+ Hint := '';
+ ImageName := '';
+ TabOrder := 3;
+ OnClick := @btnFindClicked;
+ end;
+
+ btnCancel := TfpgButton.Create(self);
+ with btnCancel do
+ begin
+ Name := 'btnCancel';
+ SetPosition(345, 36, 80, 24);
+ Anchors := [anRight,anTop];
+ Text := 'Cancel';
+ FontDesc := '#Label1';
+ Hint := '';
+ ImageName := '';
+ ModalResult := mrCancel;
+ TabOrder := 4;
+ end;
+
+ GroupBox1 := TfpgGroupBox.Create(self);
+ with GroupBox1 do
+ begin
+ Name := 'GroupBox1';
+ SetPosition(160, 56, 176, 44);
+ FontDesc := '#Label1';
+ Hint := '';
+ Text := 'Direction';
+ end;
+
+ chkWholeWord := TfpgCheckBox.Create(self);
+ with chkWholeWord do
+ begin
+ Name := 'chkWholeWord';
+ SetPosition(4, 52, 148, 20);
+ FontDesc := '#Label1';
+ Hint := '';
+ TabOrder := 6;
+ Text := 'Whole words only';
+ end;
+
+ chkCaseSensitive := TfpgCheckBox.Create(self);
+ with chkCaseSensitive do
+ begin
+ Name := 'chkCaseSensitive';
+ SetPosition(4, 72, 148, 20);
+ FontDesc := '#Label1';
+ Hint := '';
+ TabOrder := 7;
+ Text := 'Case sensitive';
+ end;
+
+ rbForward := TfpgRadioButton.Create(GroupBox1);
+ with rbForward do
+ begin
+ Name := 'rbForward';
+ SetPosition(8, 20, 76, 20);
+ Checked := True;
+ FontDesc := '#Label1';
+ GroupIndex := 0;
+ Hint := '';
+ TabOrder := 1;
+ Text := 'Forword';
+ end;
+
+ rbBackward := TfpgRadioButton.Create(GroupBox1);
+ with rbBackward do
+ begin
+ Name := 'rbBackward';
+ SetPosition(88, 20, 84, 20);
+ FontDesc := '#Label1';
+ GroupIndex := 0;
+ Hint := '';
+ TabOrder := 2;
+ Text := 'Backward';
+ end;
+
+ {@VFD_BODY_END: FindForm}
+ {%endregion}
+end;
+
+function TFindForm.Execute: boolean;
+begin
+ Result := ShowModal <> mrCancel;
+end;
+
+
+end.
diff --git a/examples/apps/nanoedit/install/nanoedit.desktop b/examples/apps/nanoedit/install/nanoedit.desktop
new file mode 100644
index 00000000..0670af6e
--- /dev/null
+++ b/examples/apps/nanoedit/install/nanoedit.desktop
@@ -0,0 +1,9 @@
+[Desktop Entry]
+Encoding=UTF-8
+Version=1.0
+Type=Application
+Exec='/path/to/nanoedit/nanoedit' %f
+Name=NanoEdit
+Icon=/path/to/fpgui/examples/apps/nanoedit/install/nanoedit.xpm
+Comment=fpGUI's own mini text editor
+NoDisplay=true
diff --git a/examples/apps/nanoedit/install/nanoedit.xpm b/examples/apps/nanoedit/install/nanoedit.xpm
new file mode 100644
index 00000000..cf439e29
--- /dev/null
+++ b/examples/apps/nanoedit/install/nanoedit.xpm
@@ -0,0 +1,47 @@
+/* XPM */
+static char *editpad[] = {
+"32 32 11 1",
+"0 c None",
+"1 c #000000",
+"2 c #FFFFFF",
+"3 c #00DF00",
+"4 c #6BFF6B",
+"5 c #00DF4A",
+"6 c #009600",
+"7 c #848284",
+"8 c #C6C3C6",
+"9 c #000084",
+"a c #0000FF",
+"00000000000110110110110110110000",
+"00000000011211211211211211211100",
+"00000000133144144144144144153610",
+"00000000134444444444444444433171",
+"00000001344444444444444444436171",
+"00000001344444444444444444331871",
+"00000013444411111111114444361871",
+"00000013444444444444444443318871",
+"00000134444111111111144443619971",
+"00000134444444444444444433188871",
+"00001344444444444444444436188871",
+"00001344444444444444444331999971",
+"00013444444444444444444361882871",
+"00013444444444444444443318882871",
+"0013444444444444444444361999a971",
+"00134444444444444444433188822871",
+"01344444444444444444436188822871",
+"013444444444444444443319999aa971",
+"13444444444444444444361888222871",
+"13333333333333333333318888222871",
+"16666666666666666666619999aaa971",
+"01111111111111111111188882222871",
+"00000000018888888888888822222871",
+"000000000199999999999999aaaaa971",
+"00000000018888888888888222222871",
+"00000000018888888888888222222871",
+"0000000001999999999999aaaaaaa971",
+"00000000018888888888822222222871",
+"00000000012222222222222222228871",
+"00000000001888888888888888888771",
+"00000000000177777777777777777710",
+"00000000000011111111111111111100"
+};
diff --git a/examples/apps/nanoedit/mainfrm.pas b/examples/apps/nanoedit/mainfrm.pas
new file mode 100644
index 00000000..bcacf714
--- /dev/null
+++ b/examples/apps/nanoedit/mainfrm.pas
@@ -0,0 +1,267 @@
+unit mainfrm;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ SysUtils, Classes, fpg_base, fpg_main,
+ fpg_form, fpg_button, fpg_menu, fpg_textedit;
+
+type
+
+ TMainForm = class(TfpgForm)
+ private
+ {@VFD_HEAD_BEGIN: MainFrom}
+ menu: TfpgMenuBar;
+ mnuFile: TfpgPopupMenu;
+ mnuSearch: TfpgPopupMenu;
+ memEditor: TfpgTextEdit;
+ btnGO: TfpgButton;
+ {@VFD_HEAD_END: MainFrom}
+ FTextToFind: TfpgString;
+ FFindOptions: TfpgFindOptions;
+ FIsForward: boolean;
+ procedure FormShow(Sender: TObject);
+ procedure miOpenClick(Sender: TObject);
+ procedure miSaveClick(Sender: TObject);
+ procedure miSaveAsClick(Sender: TObject);
+ procedure miGoToLineClick(Sender: TObject);
+ procedure miFindClick(Sender: TObject);
+ procedure miFindNextClick(Sender: TObject);
+ procedure miQuitClick(Sender: TObject);
+ procedure btnGOClick(Sender: TObject);
+ procedure memEditorChanged(Sender: TObject);
+ public
+ procedure AfterCreate; override;
+ end;
+
+{@VFD_NEWFORM_DECL}
+
+implementation
+
+uses
+ elastictabstops,
+ fpg_dialogs,
+ frm_find;
+
+{@VFD_NEWFORM_IMPL}
+
+procedure TMainForm.FormShow(Sender: TObject);
+var
+ s: string;
+begin
+ if ParamCount > 0 then
+ begin
+ ShowMessage(ParamStr(1));
+ s := ParamStr(1);
+ if Pos('file://', s) > 0 then
+ s := StringReplace(s, 'file://', '', []);
+ memEditor.LoadFromFile(s);
+ end;
+end;
+
+procedure TMainForm.miOpenClick(Sender: TObject);
+var
+ dlg: TfpgFileDialog;
+begin
+ dlg := TfpgFileDialog.Create(nil);
+ try
+ if dlg.RunOpenFile then
+ begin
+ memEditor.Lines.LoadFromFile(dlg.FileName);
+ end;
+ finally
+ dlg.Free;
+ end;
+end;
+
+procedure TMainForm.miSaveClick(Sender: TObject);
+var
+ dlg: TfpgFileDialog;
+begin
+ dlg := TfpgFileDialog.Create(nil);
+ try
+ if dlg.RunSaveFile then
+ begin
+ memEditor.Lines.SaveToFile(dlg.FileName);
+ end;
+ finally
+ dlg.Free;
+ end;
+end;
+
+procedure TMainForm.miSaveAsClick(Sender: TObject);
+var
+ dlg: TfpgFileDialog;
+begin
+ dlg := TfpgFileDialog.Create(nil);
+ try
+ if dlg.RunSaveFile then
+ begin
+ memEditor.Lines.SaveToFile(dlg.FileName);
+ end;
+ finally
+ dlg.Free;
+ end;
+end;
+
+procedure TMainForm.miGoToLineClick(Sender: TObject);
+var
+ sValue: string;
+ i: integer;
+begin
+ if fpgInputQuery('Go to line', 'Go to line number?', sValue) then
+ begin
+ try
+ i := StrToInt(sValue);
+ memEditor.GotoLine(i);
+ except
+ on E: Exception do
+ ShowMessage('Invalid line number.' + LineEnding + E.Message);
+ end;
+ end;
+end;
+
+procedure TMainForm.miFindClick(Sender: TObject);
+var
+ dlg: TFindForm;
+begin
+ FTextToFind := '';
+ dlg := TFindForm.Create(nil);
+ try
+ if dlg.Execute then
+ begin
+ FTextToFind := dlg.TextToFind;
+ FFindOptions := dlg.FindOptions;
+ FIsForward := dlg.IsForward;
+ miFindNextClick(nil);
+ end;
+ finally
+ dlg.Free;
+ end;
+end;
+
+procedure TMainForm.miFindNextClick(Sender: TObject);
+begin
+ if FTextToFind <> '' then
+ memEditor.FindText(FTextToFind, FFindOptions, FIsForward);
+end;
+
+procedure TMainForm.miQuitClick(Sender: TObject);
+begin
+ Close;
+end;
+
+procedure TMainForm.btnGOClick(Sender: TObject);
+var
+ ftr: TElasticTabstopsDocFilter;
+begin
+{
+ ftr := TElasticTabstopsDocFilter.Create(memEditor);
+ try
+ try
+ ftr.StretchTabstops;
+ finally
+ ftr.Free;
+ end;
+ except
+ on E: exception do
+ ShowMessage(e.Message);
+ end;
+}
+end;
+
+procedure TMainForm.memEditorChanged(Sender: TObject);
+var
+ ftr: TElasticTabstopsDocFilter;
+begin
+{
+ ftr := TElasticTabstopsDocFilter.Create(memEditor);
+ try
+ try
+ ftr.StretchTabstops;
+ finally
+ ftr.Free;
+ end;
+ except
+ on E: exception do
+ ShowMessage(e.Message);
+ end;
+}
+end;
+
+procedure TMainForm.AfterCreate;
+begin
+ {@VFD_BODY_BEGIN: MainFrom}
+ Name := 'MainFrom';
+ SetPosition(298, 169, 717, 410);
+ WindowTitle := 'fpGUI nanoedit';
+ Hint := '';
+ WindowPosition := wpScreenCenter;
+ OnShow := @FormShow;
+
+ menu := TfpgMenuBar.Create(self);
+ with menu do
+ begin
+ Name := 'menu';
+ SetPosition(0, 0, 717, 24);
+ Anchors := [anLeft,anRight,anTop];
+ end;
+
+ mnuFile := TfpgPopupMenu.Create(self);
+ with mnuFile do
+ begin
+ Name := 'mnuFile';
+ SetPosition(320, 4, 120, 20);
+ AddMenuItem('Open...', 'Ctrl+O', @miOpenClick);
+ AddMenuItem('Save', 'Ctrl+S', @miSaveClick);
+ AddMenuItem('Save as...', 'Ctrl+Shift+S', @miSaveAsClick);
+ AddMenuItem('-', '', nil);
+ AddMenuItem('Quit', 'Ctrl+Q', @miQuitClick);
+ end;
+
+ mnuSearch := TfpgPopupMenu.Create(self);
+ with mnuSearch do
+ begin
+ Name := 'mnuSearch';
+ SetPosition(320, 25, 120, 20);
+ AddMenuItem('Find...', 'Ctrl+F', @miFindClick);
+ AddMenuItem('Find next', 'F3', @miFindNextClick);
+ AddMenuItem('Replace', 'Ctrl+R', nil).Enabled := False;
+ AddMenuitem('-', '', nil);
+ AddMenuItem('Go to line...', 'Ctrl+G', @miGoToLineClick);
+ end;
+
+ memEditor := TfpgTextEdit.Create(self);
+ with memEditor do
+ begin
+ Name := 'memEditor';
+ SetPosition(0, 52, 717, 358);
+ Anchors := [anLeft,anRight,anTop,anBottom];
+ FontDesc := '#edit2';
+ GutterVisible := True;
+ RightEdge := True;
+ end;
+
+ btnGO := TfpgButton.Create(self);
+ with btnGO do
+ begin
+ Name := 'btnGO';
+ SetPosition(260, 26, 75, 24);
+ Text := 'GO';
+ FontDesc := '#Label1';
+ Hint := '';
+ ImageName := '';
+ TabOrder := 4;
+ OnClick := @btnGOClick;
+ end;
+
+ {@VFD_BODY_END: MainFrom}
+
+ menu.AddMenuItem('&File', nil).SubMenu := mnuFile;
+ menu.AddMenuItem('&Search', nil).SubMenu := mnuSearch;
+end;
+
+
+end.
diff --git a/examples/apps/nanoedit/nanoedit.lpi b/examples/apps/nanoedit/nanoedit.lpi
new file mode 100644
index 00000000..3eb499a8
--- /dev/null
+++ b/examples/apps/nanoedit/nanoedit.lpi
@@ -0,0 +1,82 @@
+<?xml version="1.0"?>
+<CONFIG>
+ <ProjectOptions>
+ <Version Value="9"/>
+ <General>
+ <Flags>
+ <LRSInOutputDirectory Value="False"/>
+ <SaveJumpHistory Value="False"/>
+ <SaveFoldState Value="False"/>
+ </Flags>
+ <SessionStorage Value="InProjectDir"/>
+ <MainUnit Value="0"/>
+ </General>
+ <VersionInfo>
+ <Language Value=""/>
+ <CharSet Value=""/>
+ <StringTable ProductVersion=""/>
+ </VersionInfo>
+ <BuildModes Count="1">
+ <Item1 Name="default" Default="True"/>
+ </BuildModes>
+ <PublishOptions>
+ <Version Value="2"/>
+ <IgnoreBinaries Value="False"/>
+ <IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
+ <ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/>
+ </PublishOptions>
+ <RunParams>
+ <local>
+ <FormatVersion Value="1"/>
+ <LaunchingApplication PathPlusParams="/usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/>
+ </local>
+ </RunParams>
+ <RequiredPackages Count="1">
+ <Item1>
+ <PackageName Value="fpgui_toolkit"/>
+ </Item1>
+ </RequiredPackages>
+ <Units Count="5">
+ <Unit0>
+ <Filename Value="nanoedit.lpr"/>
+ <IsPartOfProject Value="True"/>
+ <UnitName Value="nanoedit"/>
+ </Unit0>
+ <Unit1>
+ <Filename Value="mainfrm.pas"/>
+ <IsPartOfProject Value="True"/>
+ <UnitName Value="mainfrm"/>
+ </Unit1>
+ <Unit2>
+ <Filename Value="elastictabstops.pas"/>
+ <IsPartOfProject Value="True"/>
+ <UnitName Value="elastictabstops"/>
+ </Unit2>
+ <Unit3>
+ <Filename Value="frm_find.pas"/>
+ <IsPartOfProject Value="True"/>
+ <UnitName Value="frm_find"/>
+ </Unit3>
+ <Unit4>
+ <Filename Value="../ide/src/fpg_textedit.pas"/>
+ <IsPartOfProject Value="True"/>
+ <UnitName Value="fpg_textedit"/>
+ </Unit4>
+ </Units>
+ </ProjectOptions>
+ <CompilerOptions>
+ <Version Value="11"/>
+ <SearchPaths>
+ <OtherUnitFiles Value="../ide/src"/>
+ </SearchPaths>
+ <Parsing>
+ <SyntaxOptions>
+ <UseAnsiStrings Value="False"/>
+ </SyntaxOptions>
+ </Parsing>
+ <Other>
+ <CustomOptions Value="-FUunits"/>
+ <CompilerPath Value="$(CompPath)"/>
+ </Other>
+ </CompilerOptions>
+</CONFIG>
diff --git a/examples/apps/nanoedit/nanoedit.lpr b/examples/apps/nanoedit/nanoedit.lpr
new file mode 100644
index 00000000..659ed7d5
--- /dev/null
+++ b/examples/apps/nanoedit/nanoedit.lpr
@@ -0,0 +1,27 @@
+program nanoedit;
+
+{$mode objfpc}{$H+}
+{$ifdef mswindows} {$apptype gui} {$endif}
+
+uses
+ Classes, fpg_main, mainfrm;
+
+
+procedure MainProc;
+var
+ frm: TMainForm;
+begin
+ fpgApplication.Initialize;
+ frm := TMainForm.Create(nil);
+ try
+ frm.Show;
+ fpgApplication.Run;
+ finally
+ frm.Free;
+ end;
+end;
+
+begin
+ MainProc;
+end.
+
diff --git a/examples/apps/nanoedit/testfiles/file1.pas b/examples/apps/nanoedit/testfiles/file1.pas
new file mode 100644
index 00000000..717c65d1
--- /dev/null
+++ b/examples/apps/nanoedit/testfiles/file1.pas
@@ -0,0 +1,109 @@
+unit file1;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ SysUtils, Classes, gfxbase, fpgfx, gui_edit,
+ gfx_widget, gui_form, gui_label, gui_button,
+ gui_listbox, gui_memo, gui_combobox, gui_grid,
+ gui_dialogs, gui_checkbox, gui_tree, gui_trackbar,
+ gui_progressbar, gui_radiobutton, gui_tab, gui_menu;
+
+type
+
+ TMainForm = class(TfpgForm)
+ private
+ procedure miOpenClick(Sender: TObject);
+ procedure miSaveClick(Sender: TObject);
+ procedure miQuitClick(Sender: TObject);
+ public
+ {@VFD_HEAD_BEGIN: MainFrom}
+ menu: TfpgMenuBar;
+ mnuFile: TfpgPopupMenu;
+ memEditor: TfpgMemo;
+ {@VFD_HEAD_END: MainFrom}
+
+ procedure AfterCreate; override;
+ end;
+
+{@VFD_NEWFORM_DECL}
+
+implementation
+
+{@VFD_NEWFORM_IMPL}
+
+procedure TMainForm.miOpenClick(Sender: TObject);
+var
+ dlg: TfpgFileDialog;
+begin
+ dlg := TfpgFileDialog.Create(nil);
+ try
+ if dlg.RunOpenFile then
+ begin
+ memEditor.Lines.LoadFromFile(dlg.FileName);
+ end;
+ finally
+ dlg.Free;
+ end;
+end;
+
+procedure TMainForm.miSaveClick(Sender: TObject);
+var
+ dlg: TfpgFileDialog;
+begin
+ dlg := TfpgFileDialog.Create(nil);
+ try
+ if dlg.RunSaveFile then
+ begin
+ memEditor.Lines.SaveToFile(dlg.FileName);
+ end;
+ finally
+ dlg.Free;
+ end;
+end;
+
+procedure TMainForm.miQuitClick(Sender: TObject);
+begin
+ Close;
+end;
+
+procedure TMainForm.AfterCreate;
+begin
+ {@VFD_BODY_BEGIN: MainFrom}
+ SetPosition(327, 283, 500, 348);
+ WindowPosition := wpScreenCenter;
+ WindowTitle := 'fpGUI nanoedit';
+
+ menu := TfpgMenuBar.Create(self);
+ with menu do
+ begin
+ SetPosition(0, 0, 500, 24);
+ Anchors := [anTop, anLeft, anRight];
+ end;
+
+ mnuFile := TfpgPopupMenu.Create(self);
+ with mnuFile do
+ begin
+ SetPosition(320, 4, 120, 20);
+ AddMenuItem('Open...', '', @miOpenClick);
+ AddMenuItem('Save...', '', @miSaveClick);
+ AddMenuItem('Quit', '', @miQuitClick);
+ end;
+
+ memEditor := TfpgMemo.Create(self);
+ with memEditor do
+ begin
+ SetPosition(0, 24, 500, 324);
+ Anchors := [anLeft,anRight,anTop,anBottom];
+ FontDesc := '#Edit1';
+ end;
+
+ {@VFD_BODY_END: MainFrom}
+
+ menu.AddMenuItem('&File', nil).SubMenu := mnuFile;
+end;
+
+
+end.
diff --git a/examples/apps/nanoedit/testfiles/file2.pas b/examples/apps/nanoedit/testfiles/file2.pas
new file mode 100644
index 00000000..86144432
--- /dev/null
+++ b/examples/apps/nanoedit/testfiles/file2.pas
@@ -0,0 +1,19 @@
+{ **************************************
+ * oeu oe uoe uoeu *
+ * oeu oe uoe uoeu *
+ * oeu oe uoe uoeu *
+ ************************************** }
+procedure TMainForm.miOpenClick(Sender: TObject);
+var
+ dlg: TfpgFileDialog;
+begin
+ dlg := TfpgFileDialog.Create(nil);
+ try
+ if dlg.RunOpenFile then
+ begin
+ memEditor.Lines.LoadFromFile(dlg.FileName);
+ end;
+ finally
+ dlg.Free;
+ end;
+end;