diff --git a/README.md b/README.md index d19ff10..98c8f43 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,23 @@ This unofficial project is a migration of [D Forms Library (DFL)](http://wiki.dprogramming.com/Dfl/HomePage "D Forms Library (DFL)") that is managed on SVN. DFL is a Win32 windowing library for the D language. +## Recent major features +- **Module "dfl.chart" is now comming.** + - **TableRenderer (with example)** + - ~LineGraphRenderer~ + - ~TimeChartRenderer~ +- **Add simple clock "Dclock" as an example of DFL application.** +- Module "dfl.printing" is now comming. + - PrintDialog + - PrintSetupDialog + - PrintPreviewDialog +- DUB is available for DFL. +- Remove dflexe. +- Remove GTK-based DFL. +- Remove some bundled libraries such as user32_dfl.lib etc... (From now on, use dmd-bundled libraries such as the MinGW platform library and so on.) + +## Screen shots + ![screen shot](./examples/buttons/image/screenshot.png "screen shot") ![screen shot](./examples/tabcontrol/image/screenshot.png "screen shot") ![screen shot](./examples/listview/image/screenshot.png "screen shot") @@ -22,16 +39,7 @@ DFL is a Win32 windowing library for the D language. ![screen shot](./examples/toolbar/image/screenshot.png "screen shot") ![screen shot](./examples/richtextbox/image/screenshot.png "screen shot") ![screen shot](./examples/dclock/image/screenshot.png "screen shot") - -## Recent major features -- **Module "dfl.printing" is now comming.** - - **PrintDialog** - - **PrintSetupDialog** - - **PrintPreviewDialog** -- DUB is available for DFL. -- Remove dflexe. -- Remove GTK-based DFL. -- Remove some bundled libraries such as user32_dfl.lib etc... (From now on, use dmd-bundled libraries such as the MinGW platform library and so on.) +![screen shot](./examples/tablerenderer/image/screenshot.png "screen shot") ## Build and Install (dfl.lib and dfl_debug.lib) ### 1. Set environment variables diff --git a/examples/tablerenderer/.gitignore b/examples/tablerenderer/.gitignore new file mode 100644 index 0000000..60a5f2a --- /dev/null +++ b/examples/tablerenderer/.gitignore @@ -0,0 +1,16 @@ +.dub +docs.json +__dummy.html +docs/ +/hello_dfl +hello_dfl.so +hello_dfl.dylib +hello_dfl.dll +hello_dfl.a +hello_dfl.lib +hello_dfl-test-* +*.exe +*.pdb +*.o +*.obj +*.lst diff --git a/examples/tablerenderer/.vscode/launch.json b/examples/tablerenderer/.vscode/launch.json new file mode 100644 index 0000000..4443f19 --- /dev/null +++ b/examples/tablerenderer/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "C++ Launch (Windows) tablerenderer", + "type": "cppvsdbg", + "request": "launch", + "cwd": "${workspaceRoot}", + "program": "./bin/tablerenderer.exe", + "console": "internalConsole" + } + ] +} \ No newline at end of file diff --git a/examples/tablerenderer/.vscode/tasks.json b/examples/tablerenderer/.vscode/tasks.json new file mode 100644 index 0000000..0bc5912 --- /dev/null +++ b/examples/tablerenderer/.vscode/tasks.json @@ -0,0 +1,20 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "type": "dub", + "run": false, + "cwd": ".", + "compiler": "$current", + "archType": "$current", + "buildType": "$current", + "configuration": "$current", + "problemMatcher": [ + "$dmd" + ], + "group": "build", + "label": "dub: Build tablerenderer_sample", + "detail": "dub build --compiler=dmd.EXE -a=x86_64 -b=debug -c=application" + } + ] +} \ No newline at end of file diff --git a/examples/tablerenderer/README.md b/examples/tablerenderer/README.md new file mode 100644 index 0000000..b1a86ca --- /dev/null +++ b/examples/tablerenderer/README.md @@ -0,0 +1,2 @@ +# Screen Shot +![screen shot](./image/screenshot.png "screen shot") diff --git a/examples/tablerenderer/dub.json b/examples/tablerenderer/dub.json new file mode 100644 index 0000000..40f975c --- /dev/null +++ b/examples/tablerenderer/dub.json @@ -0,0 +1,16 @@ +{ + "authors": ["haru-s"], + "copyright": "Copyright (C) 2024 haru-s", + "description": "DFL sample code.", + "name": "tablerenderer", + "targetType": "executable", + "targetPath": "bin", + "dependencies": { + "dfl": { + "path": "../../../dfl" + } + }, + "lflags-windows-x86_omf-dmd": ["/exet:nt/su:windows:6.0"], + "lflags-windows-x86_mscoff-dmd": ["/SUBSYSTEM:WINDOWS", "/ENTRY:mainCRTStartup"], + "lflags-windows-x86_64-dmd": ["/SUBSYSTEM:WINDOWS", "/ENTRY:mainCRTStartup"] +} \ No newline at end of file diff --git a/examples/tablerenderer/image/screenshot.png b/examples/tablerenderer/image/screenshot.png new file mode 100644 index 0000000..e1bdb7a Binary files /dev/null and b/examples/tablerenderer/image/screenshot.png differ diff --git a/examples/tablerenderer/shell.bat b/examples/tablerenderer/shell.bat new file mode 100644 index 0000000..49ab56b --- /dev/null +++ b/examples/tablerenderer/shell.bat @@ -0,0 +1,3 @@ +set dmd_path=c:\d\dmd2\windows +set dmc_path=c:\dmc\dm +cmd diff --git a/examples/tablerenderer/source/tablerenderer_sample.d b/examples/tablerenderer/source/tablerenderer_sample.d new file mode 100644 index 0000000..fd9fe0e --- /dev/null +++ b/examples/tablerenderer/source/tablerenderer_sample.d @@ -0,0 +1,67 @@ +import dfl; + +version(Have_dfl) // For DUB. +{ +} +else +{ + pragma(lib, "dfl.lib"); +} + +class MainForm : Form +{ + alias CustomTableRenderer = TableRenderer!(string, string, string); + CustomTableRenderer _table; + + public this() + { + this.text = "TableRenderer example"; + this.size = Size(450, 450); + string csv = + "ID,Name,Value\n" ~ + "1,Kyoto,100\n" ~ + "2,Osaka,50\n" ~ + "3,Tokyo,20\n" ~ + "4,Aomori,10\n"; + _table = new CustomTableRenderer(csv); + _table.height = 40; + _table.width[0] = 50; + _table.width[1] = 80; + _table.width[2] = 150; + _table.paddingX = 10; + _table.paddingY = 12; + _table.margin = Point(20, 20); + _table.hasHeader = true; // true : 1st line is header. + _table.showHeader = true; + _table.firstRecord = 0; + _table.lastRecord = 3; + _table.textColor = Color.black; + _table.backColor = Color.white; + _table.lineColor = Color.lightGray; + _table.headerLine = true; + _table.topSideLine = true; + _table.leftSideLine = true; + _table.bottomSideLine = true; + _table.rightSideLine = true; + _table.verticalLine = true; + _table.horizontalLine = true; + _table.headerFont = new Font("MS Gothic", 16f, FontStyle.BOLD); + _table.recordFont = new Font("MS Gothic", 12f, FontStyle.REGULAR); + } + + protected override void onPaint(PaintEventArgs e) + { + if (_table) + _table.draw(e.graphics); + } +} + +static this() +{ + Application.enableVisualStyles(); +} + +void main() +{ + Application.run(new MainForm()); +} diff --git a/examples/tablerenderer/tablerenderer.code-workspace b/examples/tablerenderer/tablerenderer.code-workspace new file mode 100644 index 0000000..7e696bc --- /dev/null +++ b/examples/tablerenderer/tablerenderer.code-workspace @@ -0,0 +1,12 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": { + "d.projectImportPaths": [ + "..\\..\\..\\dfl\\source" + ] + } +} \ No newline at end of file diff --git a/makecoff.bat b/makecoff.bat index 8d74716..06f445a 100644 --- a/makecoff.bat +++ b/makecoff.bat @@ -67,9 +67,9 @@ set VCCOMMON="%VCINSTALLDIR%\bin" @set PATH=%VCCOMMON%;%PATH% -set dfl_files=package.d all.d base.d application.d internal/dlib.d internal/clib.d internal/utf.d internal/com.d control.d clippingform.d form.d registry.d drawing.d menu.d notifyicon.d commondialog.d filedialog.d folderdialog.d panel.d textboxbase.d textbox.d richtextbox.d picturebox.d listbox.d groupbox.d splitter.d usercontrol.d button.d label.d collections.d internal/winapi.d internal/wincom.d event.d socket.d timer.d environment.d messagebox.d tooltip.d combobox.d treeview.d tabcontrol.d colordialog.d listview.d data.d clipboard.d fontdialog.d progressbar.d resources.d statusbar.d imagelist.d toolbar.d trackbar.d sharedcontrol.d printing.d %_stdcwindowsd% +set dfl_files=package.d all.d base.d application.d internal/dlib.d internal/clib.d internal/utf.d internal/com.d control.d clippingform.d form.d registry.d drawing.d menu.d notifyicon.d commondialog.d filedialog.d folderdialog.d panel.d textboxbase.d textbox.d richtextbox.d picturebox.d listbox.d groupbox.d splitter.d usercontrol.d button.d label.d collections.d internal/winapi.d internal/wincom.d event.d socket.d timer.d environment.d messagebox.d tooltip.d combobox.d treeview.d tabcontrol.d colordialog.d listview.d data.d clipboard.d fontdialog.d progressbar.d resources.d statusbar.d imagelist.d toolbar.d trackbar.d sharedcontrol.d printing.d chart.d %_stdcwindowsd% -set dfl_objs=package.obj all.obj base.obj application.obj dlib.obj clib.obj utf.obj com.obj control.obj clippingform.obj form.obj registry.obj drawing.obj menu.obj notifyicon.obj commondialog.obj filedialog.obj folderdialog.obj panel.obj textboxbase.obj textbox.obj richtextbox.obj picturebox.obj listbox.obj groupbox.obj splitter.obj usercontrol.obj button.obj label.obj collections.obj winapi.obj wincom.obj event.obj socket.obj timer.obj environment.obj messagebox.obj tooltip.obj combobox.obj treeview.obj tabcontrol.obj colordialog.obj listview.obj data.obj clipboard.obj fontdialog.obj progressbar.obj resources.obj statusbar.obj imagelist.obj toolbar.obj trackbar.obj sharedcontrol.obj printing.obj %_stdcwindowsobj% +set dfl_objs=package.obj all.obj base.obj application.obj dlib.obj clib.obj utf.obj com.obj control.obj clippingform.obj form.obj registry.obj drawing.obj menu.obj notifyicon.obj commondialog.obj filedialog.obj folderdialog.obj panel.obj textboxbase.obj textbox.obj richtextbox.obj picturebox.obj listbox.obj groupbox.obj splitter.obj usercontrol.obj button.obj label.obj collections.obj winapi.obj wincom.obj event.obj socket.obj timer.obj environment.obj messagebox.obj tooltip.obj combobox.obj treeview.obj tabcontrol.obj colordialog.obj listview.obj data.obj clipboard.obj fontdialog.obj progressbar.obj resources.obj statusbar.obj imagelist.obj toolbar.obj trackbar.obj sharedcontrol.obj printing.obj chart.obj %_stdcwindowsobj% @rem Also update link pragmas for build. if "%MODEL%" == "64" ( diff --git a/makelib.bat b/makelib.bat index 77e0525..40a6459 100644 --- a/makelib.bat +++ b/makelib.bat @@ -59,9 +59,9 @@ set _stdcwindowsd=internal/_stdcwindows.d set _stdcwindowsobj=_stdcwindows.obj :dfl_not_tango_files -set dfl_files=package.d all.d base.d application.d internal/dlib.d internal/clib.d internal/utf.d internal/com.d control.d clippingform.d form.d registry.d drawing.d menu.d notifyicon.d commondialog.d filedialog.d folderdialog.d panel.d textboxbase.d textbox.d richtextbox.d picturebox.d listbox.d groupbox.d splitter.d usercontrol.d button.d label.d collections.d internal/winapi.d internal/wincom.d event.d socket.d timer.d environment.d messagebox.d tooltip.d combobox.d treeview.d tabcontrol.d colordialog.d listview.d data.d clipboard.d fontdialog.d progressbar.d resources.d statusbar.d imagelist.d toolbar.d trackbar.d sharedcontrol.d printing.d %_stdcwindowsd% +set dfl_files=package.d all.d base.d application.d internal/dlib.d internal/clib.d internal/utf.d internal/com.d control.d clippingform.d form.d registry.d drawing.d menu.d notifyicon.d commondialog.d filedialog.d folderdialog.d panel.d textboxbase.d textbox.d richtextbox.d picturebox.d listbox.d groupbox.d splitter.d usercontrol.d button.d label.d collections.d internal/winapi.d internal/wincom.d event.d socket.d timer.d environment.d messagebox.d tooltip.d combobox.d treeview.d tabcontrol.d colordialog.d listview.d data.d clipboard.d fontdialog.d progressbar.d resources.d statusbar.d imagelist.d toolbar.d trackbar.d sharedcontrol.d printing.d chart.d %_stdcwindowsd% -set dfl_objs=package.obj all.obj base.obj application.obj dlib.obj clib.obj utf.obj com.obj control.obj clippingform.obj form.obj registry.obj drawing.obj menu.obj notifyicon.obj commondialog.obj filedialog.obj folderdialog.obj panel.obj textboxbase.obj textbox.obj richtextbox.obj picturebox.obj listbox.obj groupbox.obj splitter.obj usercontrol.obj button.obj label.obj collections.obj winapi.obj wincom.obj event.obj socket.obj timer.obj environment.obj messagebox.obj tooltip.obj combobox.obj treeview.obj tabcontrol.obj colordialog.obj listview.obj data.obj clipboard.obj fontdialog.obj progressbar.obj resources.obj statusbar.obj imagelist.obj toolbar.obj trackbar.obj sharedcontrol.obj printing.obj %_stdcwindowsobj% +set dfl_objs=package.obj all.obj base.obj application.obj dlib.obj clib.obj utf.obj com.obj control.obj clippingform.obj form.obj registry.obj drawing.obj menu.obj notifyicon.obj commondialog.obj filedialog.obj folderdialog.obj panel.obj textboxbase.obj textbox.obj richtextbox.obj picturebox.obj listbox.obj groupbox.obj splitter.obj usercontrol.obj button.obj label.obj collections.obj winapi.obj wincom.obj event.obj socket.obj timer.obj environment.obj messagebox.obj tooltip.obj combobox.obj treeview.obj tabcontrol.obj colordialog.obj listview.obj data.obj clipboard.obj fontdialog.obj progressbar.obj resources.obj statusbar.obj imagelist.obj toolbar.obj trackbar.obj sharedcontrol.obj printing.obj chart.obj %_stdcwindowsobj% @rem Also update link pragmas for build. set dfl_libs_dfl=%dmd_path%\lib\user32.lib %dmd_path%\lib\shell32.lib %dmd_path%\lib\oleaut32.lib %dmd_path%\lib\undead.lib diff --git a/source/dfl/chart.d b/source/dfl/chart.d new file mode 100644 index 0000000..d2e846a --- /dev/null +++ b/source/dfl/chart.d @@ -0,0 +1,332 @@ +// chart.d +// +// Written by haru-s/Rayerd in 2024. + +/// +module dfl.chart; + +private import dfl.base; +private import dfl.drawing; + +private import std.csv; +private import std.typecons; +private import std.conv; +private import std.algorithm; + +/// +class TableRenderer(T...) +{ + enum DEFAULT_HEIGHT = 25; /// + enum DEFAULT_WIDTH = 100; /// + enum DEFAULT_PADDING_X = 5; /// + enum DEFAULT_PADDING_Y = 5; /// + + /// + this(string csv) + { + _csv = csv; + _columns = T.length; + height = DEFAULT_HEIGHT; + for (int i; i < columns; i++) + _width ~= DEFAULT_WIDTH; + _headerFont = new Font("MS Gothic", 12f, FontStyle.BOLD); + _recordFont = new Font("MS Gothic", 12f, FontStyle.REGULAR); + _paddingX = DEFAULT_PADDING_X; + _paddingY = DEFAULT_PADDING_Y; + _textColor = Color.black; + _backColor = Color.white; + _lineColor = Color.black; + } + + /// Draw records from first record to last record. + void draw(Graphics g) + { + // Draw background. + g.fillRectangle(new SolidBrush(_backColor), bounds); + // Draw top side line. + if (_topSideLine) + g.drawLine(new Pen(_lineColor), Point(margin.x, margin.y), Point(bounds.right, margin.y)); + // Draw header line. + if (_showHeader && _hasHeader && _headerLine) + g.drawLine(new Pen(_lineColor), Point(margin.x, margin.y + height), Point(bounds.right, margin.y + height)); + // Draw header and records. + int row; // -row- is line number in CSV. + int viewLine; // -viewLine- is line number on display. + foreach (record; csvReader!(Tuple!T)(_csv)) + { + // Draw header. + if (row == 0) + { + if (_showHeader) + { + int y = margin.y + viewLine * height + _paddingY; + foreach (int col, value; record) + { + int x = margin.x + sum(_width[0..col]) + _paddingX; + g.drawText(to!string(value), _headerFont, _textColor, Rect(x, y, bounds.right, bounds.bottom)); + } + row++; + viewLine++; + continue; + } + else + { + row++; + // Do not increment -viewLine- here. + continue; + } + } + // Draw record. + if (firstRecord + (_hasHeader?1:0) <= row && row <= lastRecord + (_hasHeader?1:0)) + { + int y = margin.y + viewLine * height + _paddingY; + foreach (int col, value; record) + { + int x = margin.x + sum(_width[0..col]) + _paddingX; + g.drawText(to!string(value), _recordFont, _textColor, Rect(x, y, bounds.right, bounds.bottom)); + } + // Draw horizontal line. + if (_horizontalLine && viewLine < lastRecord - firstRecord + (_showHeader?1:0)) + { + int y2 = margin.y + height * (viewLine + 1); + g.drawLine(new Pen(_lineColor), Point(margin.x, y2), Point(bounds.right, y2)); + } + row++; + viewLine++; + } + else + { + row++; + // Do not increment -viewLine- here. + } + } + // Draw left side line. + if (_leftSideLine) + g.drawLine(new Pen(_lineColor), Point(margin.x, margin.y), Point(margin.x, margin.y + height * viewLine)); + // Draw right side line. + if (_rightSideLine) + g.drawLine(new Pen(_lineColor), Point(bounds.right, margin.y), Point(bounds.right, margin.y + height * viewLine)); + // Draw vertical line. + if (_verticalLine) + { + for (int i; i < _columns - 1; i++) + { + int w = sum(_width[0..i+1]); + g.drawLine(new Pen(_lineColor), Point(margin.x + w, margin.y), Point(margin.x + w, margin.y + height * viewLine)); + } + } + // Draw bottom side line. + if (_bottomSideLine) + g.drawLine(new Pen(_lineColor), Point(margin.x, margin.y + height * viewLine), Point(bounds.right, margin.y + height * viewLine)); + } + + /// + void hasHeader(bool byes) + { + _hasHeader = byes; + } + + /// + void showHeader(bool byes) + { + if (!_hasHeader) + throw new DflException("DFL: showHeader is failure because do not have header."); + _showHeader = byes; + } + + /// + void headerLine(bool byes) + { + _headerLine = byes; + } + + /// + void topSideLine(bool byes) + { + _topSideLine = byes; + } + + /// + void leftSideLine(bool byes) + { + _leftSideLine = byes; + } + + /// + void bottomSideLine(bool byes) + { + _bottomSideLine = byes; + } + + /// + void rightSideLine(bool byes) + { + _rightSideLine = byes; + } + + /// + void verticalLine(bool byes) + { + _verticalLine = byes; + } + + /// + void horizontalLine(bool byes) + { + _horizontalLine = byes; + } + + /// + Rect bounds() const + { + int rows = (_showHeader?1:0) + lastRecord - firstRecord + 1; + return Rect(_margin.x, _margin.y, sum(_width), height * rows); + } + + /// Left and Top margins. + void margin(Point pt) + { + _margin.x = pt.x; + _margin.y = pt.y; + } + /// ditto + Point margin() const + { + return _margin; + } + + /// + void paddingX(int px) + { + _paddingX = px; + } + + /// + void paddingY(int py) + { + _paddingY = py; + } + + /// + void firstRecord(int r) + { + _firstRecord = r; + } + /// + int firstRecord() const + { + return _firstRecord; + } + + /// + void lastRecord(int r) + { + _lastRecord = r; + } + /// + int lastRecord() const + { + return _lastRecord; + } + + /// + int columns() const + { + return _columns; + } + + /// + void height(int h) + { + _height = h; + } + /// ditto + int height() const + { + return _height; + } + + /// + struct WidthObject // Internal struct. + { + /// + this(ref int[] w) + { + _arr = w; + } + + /// + void opIndexAssign(int value, size_t i) + { + _arr[i] = value; + } + + /// + int opIndex(size_t i) + { + return _arr[i]; + } + + private: + int[] _arr; + } + + /// + WidthObject width() + { + return WidthObject(_width); + } + + /// + void textColor(Color c) + { + _textColor = c; + } + + /// + void backColor(Color c) + { + _backColor = c; + } + + /// + void lineColor(Color c) + { + _lineColor = c; + } + + void headerFont(Font f) + { + _headerFont = f; + } + + void recordFont(Font f) + { + _recordFont = f; + } + +private: + string _csv; + Point _margin; + int _paddingX; + int _paddingY; + int _columns; + int _height; + int[] _width; + int _firstRecord; + int _lastRecord; + Color _textColor; + Color _backColor; + Color _lineColor; + bool _hasHeader; + bool _showHeader; + bool _headerLine; + bool _topSideLine; + bool _leftSideLine; + bool _bottomSideLine; + bool _rightSideLine; + bool _verticalLine; + bool _horizontalLine; + Font _headerFont; + Font _recordFont; +} diff --git a/source/dfl/package.d b/source/dfl/package.d index c21e5d7..a80aa58 100644 --- a/source/dfl/package.d +++ b/source/dfl/package.d @@ -15,4 +15,4 @@ public import dfl.base, dfl.menu, dfl.control, dfl.usercontrol, dfl.combobox, dfl.treeview, dfl.picturebox, dfl.tabcontrol, dfl.listview, dfl.statusbar, dfl.progressbar, dfl.resources, dfl.imagelist, dfl.toolbar, dfl.trackbar, dfl.sharedcontrol, - dfl.printing; + dfl.printing, dfl.chart;