├── Images ├── dco_build.png ├── dflpart.png └── dub_build.png ├── README.md ├── cmd.bat ├── dco └── source │ ├── dco.d │ ├── dco.ini │ └── dco.visualdproj ├── dfl2.sln ├── dfl2.suo ├── dflexe ├── dub.json └── source │ ├── dfl_exe.suo │ ├── dfl_exe.visualdproj │ └── dflexe.d ├── dubbuild.bat ├── example ├── app.d └── dflTEST.visualdproj ├── package.json └── source ├── dfl.visualdproj └── dfl ├── all.d ├── application.d ├── base.d ├── button.d ├── clipboard.d ├── clippingform.d ├── collections.d ├── colordialog.d ├── combobox.d ├── commondialog.d ├── control.d ├── data.d ├── drawing.d ├── environment.d ├── event.d ├── filedialog.d ├── folderdialog.d ├── fontdialog.d ├── form.d ├── groupbox.d ├── imagelist.d ├── internal ├── clib.d ├── com.d ├── d1.d ├── d2.d ├── dlib.d ├── utf.d ├── winapi.d └── wincom.d ├── label.d ├── listbox.d ├── listview.d ├── menu.d ├── messagebox.d ├── notifyicon.d ├── package.d ├── panel.d ├── picturebox.d ├── progressbar.d ├── registry.d ├── resources.d ├── richtextbox.d ├── socket.d ├── splitter.d ├── statusbar.d ├── tabcontrol.d ├── textbox.d ├── timer.d ├── toolbar.d ├── tooltip.d ├── treeview.d └── usercontrol.d /Images/dco_build.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrankLIKE/dfl2/fd652fb32da5307b3b3dedf2ce0d7ae3761dd8a1/Images/dco_build.png -------------------------------------------------------------------------------- /Images/dflpart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrankLIKE/dfl2/fd652fb32da5307b3b3dedf2ce0d7ae3761dd8a1/Images/dflpart.png -------------------------------------------------------------------------------- /Images/dub_build.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrankLIKE/dfl2/fd652fb32da5307b3b3dedf2ce0d7ae3761dd8a1/Images/dub_build.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | dfl2 2 | ==== 3 | dfl2 is a GUI library for windows,which is based on D2 ,now D2.067b1. 4 | 5 | linker libs: 6 | --- 7 | user32.lib ole32.lib oleAut32.lib gdi32.lib Comctl32.lib Comdlg32.lib advapi32.lib uuid.lib ws2_32.lib. 8 | 9 | How to start: 10 | -- 11 | git clone https://github.com/FrankLIKE/dfl2 12 | 13 | or 14 | 15 | dub fetch dfl2 --local 16 | 17 | The latest features: 18 | --- 19 | 1、dfl can be build by dco,and can get the 64 bit version. 20 | 21 | 2、dfl can be used in Visual Studio .net (here VS 2010), whose intellisense will help you very well(to look at the Screenshot),now it can debug in VD 0.3.39. 22 | 23 | 3、dfl can be used in DUB: 24 | 25 | base work 26 | -- 27 | You should copy the 'dfl2\source\dfl' folder to your 'dmd2\window\import'(if not exists,create it),and add importpath to sc.ini (after 'DFLAGS=', add "-I%@P%\..\..\windows\import"). 28 | 29 | How to get the libs or exe files: 30 | --- 31 | 1、 Double click the 'build.bat',to get them in the folder,if your x64 can work,you can get the 64 bit version 'dfl64.lib'.(some things will be auto work) 32 | 33 | or 34 | 35 | 2、run the dubbuild.bat in the path, to get them in 'debug' folder. 36 | or 37 | dub fetch dfl2,and run the dubbuild.bat in the path(C:\Users\[yourUserName]\AppData\Roaming\dub\packages\dfl2-1.0.7) 38 | 39 | or 40 | 41 | 3、Open the dfl.sln, and run the projects to get them in 'debug' folder and 'release' folder(Now,auto copy to the '$(DMDInstallDir)windows\lib' OR 'bin' folder ). 42 | 43 | note: If you want to get the release version ,use dcobuild.bat. or vs2010 please. 44 | --- 45 | 46 | New thing : dco.exe 47 | --- 48 | 'dco.exe' can create the batch processing info : 49 | 50 | How to use the 'dco': 51 | --- 52 | dco ↓ 53 | 54 | or 55 | 56 | dco app.d 57 | 58 | or 59 | 60 | dco app.d -gui 61 | 62 | more info : dco -h 63 | 64 | more examples: git clone https://github.com/FrankLIKE/dfl-examples-d2 65 | -- 66 | 67 | Screenshot: 68 | --- 69 | in dco: 70 | 71 | ![dfl2 In dco](https://raw.githubusercontent.com/FrankLIKE/dfl2/master/Images/dco_build.png) 72 | 73 | in DUB: 74 | 75 | ![dfl2 In DUB](https://raw.githubusercontent.com/FrankLIKE/dfl2/master/Images/dub_build.png) 76 | 77 | in VS2010 78 | 79 | ![dfl's intellisense in VS2010](https://raw.githubusercontent.com/FrankLIKE/dfl2/master/Images/dflpart.png) 80 | 81 | -------------------------------------------------------------------------------- /cmd.bat: -------------------------------------------------------------------------------- 1 | cmd.exe -------------------------------------------------------------------------------- /dco/source/dco.ini: -------------------------------------------------------------------------------- 1 | DC=dmd 2 | DCStandardEnvBin=dmd2\windows\bin 3 | SpecialLib=dfl 4 | importPath= -I..\\source 5 | ;lflags= 6 | ;dflags= 7 | ;libs= -------------------------------------------------------------------------------- /dco/source/dco.visualdproj: -------------------------------------------------------------------------------- 1 | 2 | {D76B995D-0F23-43F0-95CA-617EB9E8ED95} 3 | 4 | 0 5 | 0 6 | 0 7 | 0 8 | 0 9 | 0 10 | 0 11 | 0 12 | 0 13 | 0 14 | 0 15 | 0 16 | 1 17 | 0 18 | 0 19 | 0 20 | 0 21 | 0 22 | 0 23 | 0 24 | 0 25 | 0 26 | 0 27 | 1 28 | 0 29 | 0 30 | 0 31 | 0 32 | 0 33 | 0 34 | 0 35 | 0 36 | 0 37 | 0 38 | 0 39 | 1 40 | 0 41 | 1 42 | 0 43 | 0 44 | 0 45 | 0 46 | 2.043 47 | 0 48 | 0 49 | 0 50 | 0 51 | 0 52 | $(DMDInstallDir)windows\bin\dmd.exe 53 | 54 | 55 | $(ConfigurationName) 56 | $(OutDir) 57 | 58 | 59 | 0 60 | 61 | 62 | 63 | 64 | 0 65 | 66 | 67 | 1 68 | $(IntDir)\$(TargetName).json 69 | 0 70 | 71 | 0 72 | 73 | 0 74 | 0 75 | 0 76 | 77 | 78 | 79 | 0 80 | 81 | 1 82 | $(VisualDInstallDir)cv2pdb\cv2pdb.exe 83 | 0 84 | 0 85 | 0 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | $(OutDir)\$(ProjectName)_debug.exe 94 | 1 95 | 2 96 | 97 | 98 | copy $(OutDir)\$(ProjectName)_debug.exe $(DMDInstallDir)windows\bin 99 | *.obj;*.cmd;*.build;*.json;*.dep 100 | 101 | 102 | 0 103 | 0 104 | 0 105 | 0 106 | 0 107 | 0 108 | 0 109 | 0 110 | 0 111 | 0 112 | 0 113 | 0 114 | 0 115 | 0 116 | 0 117 | 0 118 | 0 119 | 0 120 | 0 121 | 0 122 | 0 123 | 0 124 | 0 125 | 1 126 | 0 127 | 0 128 | 0 129 | 0 130 | 0 131 | 0 132 | 0 133 | 0 134 | 0 135 | 1 136 | 0 137 | 1 138 | 0 139 | 1 140 | 0 141 | 0 142 | 0 143 | 0 144 | 2 145 | 0 146 | 0 147 | 0 148 | 0 149 | 0 150 | $(DMDInstallDir)windows\bin\dmd.exe 151 | 152 | 153 | $(ConfigurationName) 154 | $(OutDir) 155 | 156 | 157 | 0 158 | 159 | 160 | 161 | 162 | 0 163 | 164 | 165 | 1 166 | $(IntDir)\$(TargetName).json 167 | 0 168 | 169 | 0 170 | 171 | 0 172 | 0 173 | 0 174 | 175 | 176 | 177 | 0 178 | 179 | 1 180 | $(VisualDInstallDir)cv2pdb\cv2pdb.exe 181 | 0 182 | 0 183 | 0 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | $(OutDir)\$(ProjectName).exe 192 | 1 193 | 1 194 | 195 | 196 | copy $(OutDir)\$(ProjectName).exe $(DMDInstallDir)windows\bin 197 | *.obj;*.cmd;*.build;*.json;*.dep 198 | 199 | 200 | 201 | 202 | 203 | -------------------------------------------------------------------------------- /dfl2.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{002A2DE9-8BB6-484D-9802-7E4AD4084715}") = "dfl", "source\dfl.visualdproj", "{13A743BF-14CA-4000-B66D-13E47B6E1823}" 5 | EndProject 6 | Project("{002A2DE9-8BB6-484D-9802-7E4AD4084715}") = "dflTEST", "example\dflTEST.visualdproj", "{2480FA5C-5D6A-497C-B208-BF90DF379377}" 7 | ProjectSection(ProjectDependencies) = postProject 8 | {13A743BF-14CA-4000-B66D-13E47B6E1823} = {13A743BF-14CA-4000-B66D-13E47B6E1823} 9 | EndProjectSection 10 | EndProject 11 | Project("{002A2DE9-8BB6-484D-9802-7E4AD4084715}") = "dflexe", "othersource\dflexe\source\dfl_exe.visualdproj", "{A3C7FC9E-D964-4783-AC46-0690042350E6}" 12 | ProjectSection(ProjectDependencies) = postProject 13 | {13A743BF-14CA-4000-B66D-13E47B6E1823} = {13A743BF-14CA-4000-B66D-13E47B6E1823} 14 | EndProjectSection 15 | EndProject 16 | Project("{002A2DE9-8BB6-484D-9802-7E4AD4084715}") = "dco", "dco\source\dco.visualdproj", "{D76B995D-0F23-43F0-95CA-617EB9E8ED95}" 17 | EndProject 18 | Global 19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 20 | Debug|Win32 = Debug|Win32 21 | Debug|x64 = Debug|x64 22 | Release|Win32 = Release|Win32 23 | Release|x64 = Release|x64 24 | EndGlobalSection 25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 26 | {13A743BF-14CA-4000-B66D-13E47B6E1823}.Debug|Win32.ActiveCfg = Debug|Win32 27 | {13A743BF-14CA-4000-B66D-13E47B6E1823}.Debug|Win32.Build.0 = Debug|Win32 28 | {13A743BF-14CA-4000-B66D-13E47B6E1823}.Debug|x64.ActiveCfg = Debug|x64 29 | {13A743BF-14CA-4000-B66D-13E47B6E1823}.Debug|x64.Build.0 = Debug|x64 30 | {13A743BF-14CA-4000-B66D-13E47B6E1823}.Release|Win32.ActiveCfg = Release|Win32 31 | {13A743BF-14CA-4000-B66D-13E47B6E1823}.Release|Win32.Build.0 = Release|Win32 32 | {13A743BF-14CA-4000-B66D-13E47B6E1823}.Release|x64.ActiveCfg = Release|x64 33 | {13A743BF-14CA-4000-B66D-13E47B6E1823}.Release|x64.Build.0 = Release|x64 34 | {2480FA5C-5D6A-497C-B208-BF90DF379377}.Debug|Win32.ActiveCfg = Debug|Win32 35 | {2480FA5C-5D6A-497C-B208-BF90DF379377}.Debug|Win32.Build.0 = Debug|Win32 36 | {2480FA5C-5D6A-497C-B208-BF90DF379377}.Debug|x64.ActiveCfg = Debug|x64 37 | {2480FA5C-5D6A-497C-B208-BF90DF379377}.Debug|x64.Build.0 = Debug|x64 38 | {2480FA5C-5D6A-497C-B208-BF90DF379377}.Release|Win32.ActiveCfg = Release|Win32 39 | {2480FA5C-5D6A-497C-B208-BF90DF379377}.Release|Win32.Build.0 = Release|Win32 40 | {2480FA5C-5D6A-497C-B208-BF90DF379377}.Release|x64.ActiveCfg = Release|x64 41 | {2480FA5C-5D6A-497C-B208-BF90DF379377}.Release|x64.Build.0 = Release|x64 42 | {A3C7FC9E-D964-4783-AC46-0690042350E6}.Debug|Win32.ActiveCfg = Debug|Win32 43 | {A3C7FC9E-D964-4783-AC46-0690042350E6}.Debug|Win32.Build.0 = Debug|Win32 44 | {A3C7FC9E-D964-4783-AC46-0690042350E6}.Debug|x64.ActiveCfg = Debug|Win32 45 | {A3C7FC9E-D964-4783-AC46-0690042350E6}.Release|Win32.ActiveCfg = Release|Win32 46 | {A3C7FC9E-D964-4783-AC46-0690042350E6}.Release|Win32.Build.0 = Release|Win32 47 | {A3C7FC9E-D964-4783-AC46-0690042350E6}.Release|x64.ActiveCfg = Release|Win32 48 | {D76B995D-0F23-43F0-95CA-617EB9E8ED95}.Debug|Win32.ActiveCfg = Debug|Win32 49 | {D76B995D-0F23-43F0-95CA-617EB9E8ED95}.Debug|Win32.Build.0 = Debug|Win32 50 | {D76B995D-0F23-43F0-95CA-617EB9E8ED95}.Debug|x64.ActiveCfg = Debug|Win32 51 | {D76B995D-0F23-43F0-95CA-617EB9E8ED95}.Release|Win32.ActiveCfg = Release|Win32 52 | {D76B995D-0F23-43F0-95CA-617EB9E8ED95}.Release|Win32.Build.0 = Release|Win32 53 | {D76B995D-0F23-43F0-95CA-617EB9E8ED95}.Release|x64.ActiveCfg = Release|Win32 54 | EndGlobalSection 55 | GlobalSection(SolutionProperties) = preSolution 56 | HideSolutionNode = FALSE 57 | EndGlobalSection 58 | EndGlobal 59 | -------------------------------------------------------------------------------- /dfl2.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrankLIKE/dfl2/fd652fb32da5307b3b3dedf2ce0d7ae3761dd8a1/dfl2.suo -------------------------------------------------------------------------------- /dflexe/dub.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "name": "dflexe", 4 | "description": "dflexe is a build tool for dfl2, it can be built by DUB and Visual Studio .NET(such as VS 2010).", 5 | "homepage": "https://github.com/FrankLIKE/dfl2", 6 | "targetName": "dflexe", 7 | "mainSourceFile": "source/dflexe.d", 8 | "targetPath": "../debug", 9 | "targetType": "executable", 10 | "importPaths": ["../source"], 11 | "libs": [ 12 | "../debug/dfl_debug", 13 | "ole32", 14 | "oleAut32", 15 | "gdi32", 16 | "comctl32", 17 | "comdlg32", 18 | "advapi32", 19 | "uuid", 20 | "ws2_32" 21 | ], 22 | "lflags": ["/su:console:4"] 23 | } -------------------------------------------------------------------------------- /dflexe/source/dfl_exe.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrankLIKE/dfl2/fd652fb32da5307b3b3dedf2ce0d7ae3761dd8a1/dflexe/source/dfl_exe.suo -------------------------------------------------------------------------------- /dflexe/source/dfl_exe.visualdproj: -------------------------------------------------------------------------------- 1 | 2 | {A3C7FC9E-D964-4783-AC46-0690042350E6} 3 | 4 | 0 5 | 0 6 | 0 7 | 0 8 | 0 9 | 0 10 | 0 11 | 0 12 | 0 13 | 0 14 | 0 15 | 0 16 | 2 17 | 0 18 | 0 19 | 0 20 | 0 21 | 0 22 | 0 23 | 0 24 | 0 25 | 0 26 | 0 27 | 1 28 | 0 29 | 0 30 | 0 31 | 0 32 | 0 33 | 0 34 | 0 35 | 0 36 | 0 37 | 0 38 | 0 39 | 1 40 | 0 41 | 1 42 | 0 43 | 0 44 | 0 45 | 0 46 | 2.043 47 | 0 48 | 0 49 | 0 50 | 0 51 | 0 52 | $(DMDInstallDir)windows\bin\dmd.exe 53 | .. 54 | .. 55 | $(ConfigurationName) 56 | $(OutDir) 57 | 58 | 59 | 0 60 | 61 | 62 | 63 | 64 | 0 65 | 66 | 67 | 1 68 | $(IntDir)\$(TargetName).json 69 | 0 70 | 71 | 0 72 | 73 | 0 74 | 0 75 | 0 76 | 77 | 78 | 79 | 0 80 | 81 | 1 82 | $(VisualDInstallDir)cv2pdb\cv2pdb.exe 83 | 0 84 | 0 85 | 0 86 | 87 | 88 | 89 | ..\..\..\source\Debug\dfl_debug.lib ole32.lib oleAut32.lib gdi32.lib Comctl32.lib Comdlg32.lib advapi32.lib uuid.lib ws2_32.lib 90 | ..\..\..\source\Debug 91 | 92 | 93 | $(OutDir)\$(ProjectName)_debug.exe 94 | 1 95 | 2 96 | 97 | 98 | copy $(OutDir)\$(ProjectName)_debug.exe $(DMDInstallDir)windows\bin 99 | *.obj;*.cmd;*.build;*.json;*.dep 100 | 101 | 102 | 0 103 | 0 104 | 0 105 | 0 106 | 0 107 | 0 108 | 0 109 | 0 110 | 0 111 | 0 112 | 0 113 | 0 114 | 0 115 | 0 116 | 0 117 | 0 118 | 0 119 | 0 120 | 0 121 | 0 122 | 0 123 | 0 124 | 0 125 | 1 126 | 0 127 | 0 128 | 0 129 | 0 130 | 0 131 | 0 132 | 0 133 | 0 134 | 0 135 | 1 136 | 0 137 | 1 138 | 0 139 | 1 140 | 0 141 | 0 142 | 0 143 | 0 144 | 2.043 145 | 0 146 | 0 147 | 0 148 | 0 149 | 0 150 | $(DMDInstallDir)windows\bin\dmd.exe 151 | .. 152 | .. 153 | $(ConfigurationName) 154 | $(OutDir) 155 | 156 | 157 | 0 158 | 159 | 160 | 161 | 162 | 0 163 | 164 | 165 | 1 166 | $(IntDir)\$(TargetName).json 167 | 0 168 | 169 | 0 170 | 171 | 0 172 | 0 173 | 0 174 | 175 | 176 | 177 | 0 178 | 179 | 0 180 | $(VisualDInstallDir)cv2pdb\cv2pdb.exe 181 | 0 182 | 0 183 | 0 184 | 185 | 186 | 187 | ..\..\..\source\release\dfl.lib ole32.lib oleAut32.lib gdi32.lib Comctl32.lib Comdlg32.lib advapi32.lib uuid.lib ws2_32.lib 188 | ..\..\..\source\release 189 | 190 | 191 | $(OutDir)\$(ProjectName).exe 192 | 1 193 | 1 194 | 195 | 196 | copy $(OutDir)\$(ProjectName).exe $(DMDInstallDir)windows\bin 197 | *.obj;*.cmd;*.build;*.json;*.dep 198 | 199 | 200 | 201 | 202 | 203 | -------------------------------------------------------------------------------- /dflexe/source/dflexe.d: -------------------------------------------------------------------------------- 1 | module dflexe; 2 | ///come from the old 'dflexe.d' 3 | import std.stdio; 4 | import std.path; 5 | import std.stream; 6 | import dfl.application; 7 | import std.conv; 8 | import std.string; 9 | private import dfl.internal.winapi, dfl.internal.utf;//dfl.all, 10 | 11 | alias dfl.internal.winapi.ShellExecuteA ShellExecuteA; 12 | alias dfl.environment.Environment Environment; 13 | 14 | 15 | private extern(Windows) 16 | { 17 | DWORD GetLogicalDriveStringsA(DWORD nBufferLength,LPSTR lpBuffer); 18 | UINT GetDriveTypeA(LPCTSTR lpRootPathName); 19 | DWORD GetShortPathNameA(LPCSTR lpszLongPath, LPSTR lpszShortPath, DWORD cchBuffer); 20 | 21 | 22 | enum: UINT 23 | { 24 | DRIVE_FIXED = 3, 25 | } 26 | alias DWORD function(LPCWSTR lpszLongPath, LPWSTR lpszShortPath, DWORD cchBuffer) GetShortPathNameWProc; 27 | } 28 | 29 | 30 | enum Flags: DWORD 31 | { 32 | NONE = 0, 33 | 34 | INSTALLED = 1, // Everything is setup. 35 | } 36 | 37 | 38 | string importdir,startpath, basepath; 39 | string dmdpath, dmdpath_windows = "\0"; 40 | string strDebug="-debug"; 41 | string strWindow="SUBSYSTEM:WINDOWS"; 42 | string strDFLlib="dfl_debug.lib"; 43 | string strDFile=""; 44 | void main(string[] args) 45 | { 46 | startpath = getshortpath(Application.startupPath); 47 | if(args.length <2 || (args.length == 2 && (args[1]=="-h" || args[1]=="-help"))) 48 | { 49 | ShowUsage(); 50 | return; 51 | } 52 | 53 | buildExe(args); 54 | } 55 | 56 | void buildExe(string[] args) 57 | { 58 | string batfilepath = std.path.buildPath(startpath, "exe.bat"); 59 | 60 | scope batf = new BufferedFile(batfilepath, FileMode.OutNew); 61 | string c; 62 | int i; 63 | foreach(arg;args) 64 | { 65 | c = toLower(arg); 66 | i = c.indexOf('-'); 67 | if(i != -1) 68 | { 69 | c=c[i+1 .. c.length]; 70 | } 71 | switch(c) 72 | { 73 | case "debug": 74 | strDFLlib = "dfl_debug.lib"; 75 | break; 76 | case "release": 77 | strDFLlib = "dfl.lib"; 78 | strDebug ="-"~c.idup; 79 | break; 80 | case "gui","windows","winexe": 81 | strWindow ="SUBSYSTEM:WINDOWS"; 82 | break; 83 | case "console","con","exe": 84 | strWindow ="su:console:4"; 85 | break; 86 | default: 87 | if(c.indexOf(".d") !=-1) 88 | { 89 | strDFile ~=" "; 90 | strDFile~=arg; 91 | } 92 | break; 93 | } 94 | } 95 | 96 | if(strDFile == "") 97 | { 98 | writeln("Please input *.d file"); 99 | return; 100 | } 101 | string strwinLib = " ole32.lib oleAut32.lib gdi32.lib Comctl32.lib Comdlg32.lib advapi32.lib uuid.lib ws2_32.lib"; 102 | string buildstr ="dmd -de -w -property -X -I$(DMDInstallDir)windows\\import "~strDFLlib~strwinLib~" -L/"~strWindow~" "~strDFile~" "~strDebug~"\r\n";// 103 | batf.writeString(buildstr); 104 | batf.writeString("\r\n"); 105 | batf.close(); 106 | 107 | std.process.spawnShell(batfilepath.dup()); 108 | 109 | //std.file.remove(batfilepath); 110 | 111 | } 112 | 113 | string getshortpath(string fn) 114 | { 115 | if(dfl.internal.utf.useUnicode) 116 | { 117 | version(STATIC_UNICODE) 118 | { 119 | alias GetShortPathNameW proc; 120 | } 121 | else 122 | { 123 | const string NAME = "GetShortPathNameW"; 124 | static GetShortPathNameWProc proc = null; 125 | 126 | if(!proc) 127 | { 128 | proc = cast(GetShortPathNameWProc)GetProcAddress(GetModuleHandleA("kernel32.dll"), NAME.ptr); 129 | if(!proc) 130 | throw new Exception("GetShortPathNameW not found"); 131 | } 132 | } 133 | 134 | DWORD len; 135 | wchar[MAX_PATH] s; 136 | len = proc(dfl.internal.utf.toUnicodez(fn), s.ptr, s.length); 137 | return to!string(s[0..len]); 138 | } 139 | else 140 | { 141 | DWORD len; 142 | char[MAX_PATH] s; 143 | len = GetShortPathNameA(dfl.internal.utf.toAnsiz(fn), s.ptr, s.length); 144 | return to!string(s[0..len]); 145 | } 146 | } 147 | 148 | void ShowUsage() 149 | { 150 | writeln("\ndflexe written by FrankLIKE,and study by Christopher E. Miller\n"); 151 | writeln("Usage:\n" 152 | " dflexe [] \n\n" 153 | ~" for example: dflexe app.d \n\n"); 154 | writeln("Switches:\n" 155 | " -release Build files's Release version(Default version is 'debug').\n"~ 156 | " -con output to Console(Default 'windows').\n"); 157 | 158 | } 159 | 160 | -------------------------------------------------------------------------------- /dubbuild.bat: -------------------------------------------------------------------------------- 1 | @cls 2 | 3 | @echo will get the dfl_debug debug version..... 4 | 5 | dub --force 6 | 7 | cd dco 8 | dub --force 9 | cd.. 10 | cd dflexe 11 | dub --force 12 | cd.. 13 | @pause 14 | -------------------------------------------------------------------------------- /example/app.d: -------------------------------------------------------------------------------- 1 | // Written by Christopher E. Miller 2 | // This code is public domain. 3 | 4 | // To compile: 5 | // vs2010 6 | 7 | 8 | private import std.string, std.conv; 9 | 10 | private import dfl.all, dfl.internal.utf; 11 | 12 | 13 | class MainForm: Form 14 | { 15 | uint docnum = 0; 16 | 17 | this() 18 | { 19 | text = "DFL MDI"; 20 | startPosition = FormStartPosition.WINDOWS_DEFAULT_BOUNDS; 21 | 22 | MenuItem mi; 23 | menu = new MainMenu; 24 | 25 | with(mi = new MenuItem) 26 | { 27 | text = "New"; 28 | 29 | click ~= &menubar_click; 30 | } 31 | menu.menuItems.add(mi); 32 | 33 | isMdiContainer = true; 34 | 35 | addChild(); 36 | } 37 | 38 | 39 | private void mdiChildHiClick(Object sender, EventArgs ea) 40 | { 41 | Button btn; 42 | btn = cast(Button)sender; 43 | assert(btn); 44 | 45 | Form f; 46 | f = cast(Form)btn.parent; 47 | assert(f); 48 | 49 | f.close(); 50 | } 51 | 52 | 53 | final void addChild() 54 | { 55 | Form f; 56 | with(f = new Form) 57 | { 58 | text = "MDI child #" ~ std.conv.to!string(++docnum) ~ "/" ~ std.conv.to!string(this.mdiChildren().length + 1); 59 | mdiParent = this; 60 | 61 | with(new Button) 62 | { 63 | text = "&Hi"; 64 | location = Point(42, 42); 65 | parent = f; 66 | click ~= &mdiChildHiClick; 67 | } 68 | 69 | show(); 70 | } 71 | } 72 | 73 | 74 | private void menubar_click(Object sender, EventArgs ea) 75 | { 76 | addChild(); 77 | } 78 | } 79 | 80 | 81 | int main() 82 | { 83 | int result = 0; 84 | 85 | try 86 | { 87 | // Application initialization code here. 88 | 89 | Application.run(new MainForm()); 90 | } 91 | catch(DflThrowable o) 92 | { 93 | msgBox(o.toString(), "Fatal Error", MsgBoxButtons.OK, MsgBoxIcon.ERROR); 94 | 95 | result = 1; 96 | } 97 | 98 | return result; 99 | } 100 | 101 | -------------------------------------------------------------------------------- /example/dflTEST.visualdproj: -------------------------------------------------------------------------------- 1 | 2 | {2480FA5C-5D6A-497C-B208-BF90DF379377} 3 | 4 | 0 5 | 0 6 | 0 7 | 2 8 | 0 9 | 0 10 | 0 11 | 0 12 | 0 13 | 0 14 | 0 15 | 0 16 | 2 17 | 0 18 | 0 19 | 0 20 | 0 21 | 0 22 | 0 23 | 0 24 | 0 25 | 0 26 | 0 27 | 1 28 | 0 29 | 0 30 | 0 31 | 0 32 | 0 33 | 0 34 | 0 35 | 0 36 | 0 37 | 0 38 | 0 39 | 1 40 | 0 41 | 1 42 | 0 43 | 0 44 | 0 45 | 0 46 | 2 47 | 0 48 | 0 49 | 0 50 | 0 51 | 0 52 | $(DMDInstallDir)windows\bin\dmd.exe 53 | ..\source 54 | ..\source 55 | $(ConfigurationName) 56 | $(OutDir) 57 | 58 | 59 | 0 60 | 61 | 62 | 63 | 64 | 0 65 | 66 | 67 | 1 68 | $(IntDir)\$(TargetName).json 69 | 0 70 | 71 | 0 72 | 73 | 0 74 | 0 75 | 0 76 | 77 | 78 | 79 | 0 80 | 81 | 1 82 | $(VisualDInstallDir)cv2pdb\cv2pdb.exe 83 | 0 84 | 0 85 | 0 86 | 87 | 88 | 89 | ..\source\Debug\dfl_debug.lib ole32.lib oleAut32.lib gdi32.lib Comctl32.lib Comdlg32.lib advapi32.lib uuid.lib ws2_32.lib 90 | ..\source\Debug 91 | 92 | 93 | $(OutDir)\$(ProjectName).exe 94 | 1 95 | 2 96 | 97 | 98 | 99 | *.obj;*.cmd;*.build;*.json;*.dep 100 | 101 | 102 | 0 103 | 0 104 | 0 105 | 2 106 | 0 107 | 0 108 | 0 109 | 0 110 | 0 111 | 0 112 | 0 113 | 0 114 | 0 115 | 0 116 | 0 117 | 0 118 | 0 119 | 0 120 | 0 121 | 0 122 | 0 123 | 0 124 | 0 125 | 0 126 | 0 127 | 0 128 | 0 129 | 0 130 | 0 131 | 0 132 | 0 133 | 0 134 | 0 135 | 1 136 | 0 137 | 0 138 | 0 139 | 0 140 | 0 141 | 0 142 | 0 143 | 0 144 | 2 145 | 0 146 | 0 147 | 0 148 | 0 149 | 0 150 | $(DMDInstallDir)windows\bin\dmd.exe 151 | ..\source 152 | ..\source 153 | $(ConfigurationName) 154 | $(OutDir) 155 | 156 | 157 | 0 158 | 159 | 160 | 161 | 162 | 0 163 | 164 | 165 | 1 166 | $(IntDir)\$(TargetName).json 167 | 0 168 | 169 | 0 170 | 171 | 0 172 | 0 173 | 0 174 | 175 | 176 | 177 | 0 178 | 179 | 0 180 | $(VisualDInstallDir)cv2pdb\cv2pdb.exe 181 | 0 182 | 0 183 | 0 184 | 185 | 186 | 187 | ..\source\release\dfl.lib ole32.lib oleAut32.lib gdi32.lib Comctl32.lib Comdlg32.lib advapi32.lib uuid.lib ws2_32.lib 188 | ..\source\release 189 | 190 | 191 | $(OutDir)\$(ProjectName).exe 192 | 1 193 | 1 194 | 195 | 196 | 197 | *.obj;*.cmd;*.build;*.json;*.dep 198 | 199 | 200 | 0 201 | 0 202 | 0 203 | 2 204 | 0 205 | 0 206 | 0 207 | 0 208 | 0 209 | 0 210 | 0 211 | 0 212 | 0 213 | 0 214 | 0 215 | 1 216 | 0 217 | 0 218 | 0 219 | 0 220 | 0 221 | 0 222 | 0 223 | 1 224 | 0 225 | 0 226 | 0 227 | 0 228 | 0 229 | 0 230 | 0 231 | 0 232 | 0 233 | 0 234 | 0 235 | 1 236 | 0 237 | 1 238 | 0 239 | 0 240 | 0 241 | 0 242 | 2 243 | 0 244 | 0 245 | 0 246 | 0 247 | 0 248 | $(DMDInstallDir)windows\bin\dmd.exe 249 | ..\dfl 250 | .. 251 | $(ConfigurationName) 252 | $(OutDir) 253 | 254 | 255 | 0 256 | 257 | 258 | 259 | 260 | 0 261 | 262 | 263 | 1 264 | $(IntDir)\$(TargetName).json 265 | 0 266 | 267 | 0 268 | 269 | 0 270 | 0 271 | 0 272 | 273 | 274 | 275 | 0 276 | 277 | 1 278 | $(VisualDInstallDir)cv2pdb\cv2pdb.exe 279 | 0 280 | 0 281 | 0 282 | 283 | 284 | 285 | ..\dfl\Debug\dfl.lib ole32.lib oleAut32.lib gdi32.lib Comctl32.lib Comdlg32.lib 286 | ..\dfl\Debug 287 | 288 | 289 | $(OutDir)\$(ProjectName).exe 290 | 1 291 | 2 292 | 293 | 294 | 295 | *.obj;*.cmd;*.build;*.json;*.dep 296 | 297 | 298 | 0 299 | 0 300 | 0 301 | 2 302 | 0 303 | 0 304 | 0 305 | 0 306 | 0 307 | 0 308 | 0 309 | 0 310 | 0 311 | 0 312 | 0 313 | 1 314 | 0 315 | 0 316 | 0 317 | 0 318 | 0 319 | 0 320 | 0 321 | 0 322 | 0 323 | 0 324 | 0 325 | 0 326 | 0 327 | 0 328 | 0 329 | 0 330 | 0 331 | 1 332 | 0 333 | 0 334 | 0 335 | 0 336 | 0 337 | 0 338 | 0 339 | 0 340 | 2 341 | 0 342 | 0 343 | 0 344 | 0 345 | 0 346 | $(DMDInstallDir)windows\bin\dmd.exe 347 | 348 | 349 | $(ConfigurationName) 350 | $(OutDir) 351 | 352 | 353 | 0 354 | 355 | 356 | 357 | 358 | 0 359 | 360 | 361 | 1 362 | $(IntDir)\$(TargetName).json 363 | 0 364 | 365 | 0 366 | 367 | 0 368 | 0 369 | 0 370 | 371 | 372 | 373 | 0 374 | 375 | 0 376 | $(VisualDInstallDir)cv2pdb\cv2pdb.exe 377 | 0 378 | 0 379 | 0 380 | 381 | 382 | 383 | dfl.lib ole32.lib oleAut32.lib gdi32.lib Comctl32.lib Comdlg32.lib 384 | 385 | 386 | 387 | $(OutDir)\$(ProjectName).exe 388 | 1 389 | 1 390 | 391 | 392 | 393 | *.obj;*.cmd;*.build;*.json;*.dep 394 | 395 | 396 | 397 | 398 | 399 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dfl2", 3 | "description": "dfl2 is a GUI library for Windows,now it can be built by dco, DUB or Visual Studio .NET(such as VS 2010).", 4 | "license": "LGPL-3.0", 5 | "authors": [ 6 | "Christopher E. Miller","FrankLIKE" 7 | ], 8 | "homepage": "https://github.com/FrankLIKE/dfl2", 9 | "importPaths": ["source/"], 10 | "targetType": "library", 11 | "targetName": "dfl_debug", 12 | "targetPath": "debug", 13 | "libs": [ "user32", "ole32", "oleAut32", "gdi32", "Comctl32", "Comdlg32", "advapi32", "uuid", "ws2_32" ] 14 | } 15 | -------------------------------------------------------------------------------- /source/dfl/all.d: -------------------------------------------------------------------------------- 1 | // Written by Christopher E. Miller 2 | // See the included license.txt for copyright and license details. 3 | 4 | 5 | /// Imports all of DFL's public interface. 6 | module dfl.all; 7 | 8 | 9 | public import dfl; 10 | 11 | -------------------------------------------------------------------------------- /source/dfl/clipboard.d: -------------------------------------------------------------------------------- 1 | // Written by Christopher E. Miller 2 | // See the included license.txt for copyright and license details. 3 | 4 | 5 | /// Interfacing with the system clipboard for copy and paste operations. 6 | module dfl.clipboard; 7 | 8 | private import dfl.base, dfl.internal.winapi, dfl.data, dfl.internal.wincom, 9 | dfl.internal.dlib; 10 | 11 | 12 | /// 13 | class Clipboard // docmain 14 | { 15 | private this() {} 16 | 17 | 18 | static: 19 | 20 | /// 21 | dfl.data.IDataObject getDataObject() 22 | { 23 | dfl.internal.wincom.IDataObject comdobj; 24 | if(S_OK != OleGetClipboard(&comdobj)) 25 | throw new DflException("Unable to obtain clipboard data object"); 26 | if(comdobj is comd) 27 | return dd; 28 | //delete dd; 29 | comd = comdobj; 30 | return dd = new ComToDdataObject(comdobj); 31 | } 32 | 33 | /// ditto 34 | void setDataObject(Data obj, bool persist = false) 35 | { 36 | comd = null; 37 | /+ 38 | Object ddd; 39 | ddd = cast(Object)dd; 40 | delete ddd; 41 | +/ 42 | dd = null; 43 | objref = null; 44 | 45 | if(obj.info) 46 | { 47 | if(cast(TypeInfo_Class)obj.info) 48 | { 49 | Object foo; 50 | foo = obj.getObject(); 51 | 52 | /+ 53 | if(cast(Bitmap)foo) 54 | { 55 | // ... 56 | } 57 | else +/ if(cast(dfl.data.IDataObject)foo) 58 | { 59 | dd = cast(dfl.data.IDataObject)foo; 60 | objref = foo; 61 | } 62 | else 63 | { 64 | // Can't set any old class object. 65 | throw new DflException("Unknown data object"); 66 | } 67 | } 68 | else if(obj.info == typeid(dfl.data.IDataObject)) 69 | { 70 | dd = obj.getValue!(dfl.data.IDataObject)(); 71 | objref = cast(Object)dd; 72 | } 73 | else if(cast(TypeInfo_Interface)obj.info) 74 | { 75 | // Can't set any old interface. 76 | throw new DflException("Unknown data object"); 77 | } 78 | else 79 | { 80 | DataObject foo = new DataObject; 81 | dd = foo; 82 | objref = foo; 83 | dd.setData(obj); 84 | } 85 | 86 | assert(!(dd is null)); 87 | comd = new DtoComDataObject(dd); 88 | if(S_OK != OleSetClipboard(comd)) 89 | { 90 | comd = null; 91 | //delete dd; 92 | dd = null; 93 | goto err_set; 94 | } 95 | 96 | if(persist) 97 | OleFlushClipboard(); 98 | } 99 | else 100 | { 101 | dd = null; 102 | if(S_OK != OleSetClipboard(null)) 103 | goto err_set; 104 | } 105 | 106 | return; 107 | err_set: 108 | throw new DflException("Unable to set clipboard data"); 109 | } 110 | 111 | /// ditto 112 | void setDataObject(dfl.data.IDataObject obj, bool persist = false) 113 | { 114 | setDataObject(Data(obj), persist); 115 | } 116 | 117 | 118 | /// 119 | void setString(Dstring str, bool persist = false) 120 | { 121 | setDataObject(Data(str), persist); 122 | } 123 | 124 | /// ditto 125 | Dstring getString() 126 | { 127 | dfl.data.IDataObject ido; 128 | ido = getDataObject(); 129 | if(ido.getDataPresent(DataFormats.utf8)) 130 | return ido.getData(DataFormats.utf8).getString(); 131 | return null; // ? 132 | } 133 | 134 | 135 | /// 136 | // ANSI text. 137 | void setText(ubyte[] ansiText, bool persist = false) 138 | { 139 | setDataObject(Data(ansiText), persist); 140 | } 141 | 142 | /// ditto 143 | ubyte[] getText() 144 | { 145 | dfl.data.IDataObject ido; 146 | ido = getDataObject(); 147 | if(ido.getDataPresent(DataFormats.text)) 148 | return ido.getData(DataFormats.text).getText(); 149 | return null; // ? 150 | } 151 | 152 | 153 | private: 154 | dfl.internal.wincom.IDataObject comd; 155 | dfl.data.IDataObject dd; 156 | Object objref; // Prevent dd from being garbage collected! 157 | 158 | 159 | /+ 160 | static ~this() 161 | { 162 | Object ddd; 163 | ddd = cast(Object)dd; 164 | delete ddd; 165 | } 166 | +/ 167 | } 168 | 169 | -------------------------------------------------------------------------------- /source/dfl/clippingform.d: -------------------------------------------------------------------------------- 1 | module dfl.clippingform; 2 | 3 | private import dfl.all, dfl.internal.winapi; 4 | private import core.memory; 5 | 6 | private extern (Windows) 7 | { 8 | struct RGNDATAHEADER 9 | { 10 | DWORD64 dwSize; 11 | DWORD64 iType; 12 | DWORD64 nCount; 13 | DWORD64 nRgnSize;//DWORD64 14 | RECT rcBound; 15 | } 16 | 17 | struct RGNDATA 18 | { 19 | RGNDATAHEADER rdh; 20 | ubyte[1] Buffer; 21 | } 22 | 23 | struct XFORM 24 | { 25 | FLOAT eM11; 26 | FLOAT eM12; 27 | FLOAT eM21; 28 | FLOAT eM22; 29 | FLOAT eDx; 30 | FLOAT eDy; 31 | } 32 | 33 | enum {RDH_RECTANGLES = 1} 34 | enum {BI_RGB = 0} 35 | enum {DIB_RGB_COLORS = 0} 36 | 37 | HRGN ExtCreateRegion(void*, DWORD64, RGNDATA*); 38 | int GetDIBits(HDC, HBITMAP, UINT, UINT, PVOID, LPBITMAPINFO, UINT); 39 | } 40 | 41 | 42 | /// 43 | struct RegionRects 44 | { 45 | private: 46 | RGNDATA* _rgn = null; 47 | INT _capacity = 0; 48 | INT _width = 0; 49 | INT _height = 0; 50 | public: 51 | 52 | 53 | const @property 54 | size_t width() 55 | { 56 | return _width; 57 | } 58 | 59 | 60 | /// 61 | const @property 62 | size_t height() 63 | { 64 | return _height; 65 | } 66 | 67 | 68 | /// 69 | void clear() 70 | { 71 | if (_rgn) 72 | { 73 | GC.free(_rgn); 74 | } 75 | _rgn = null; 76 | _capacity = 0; 77 | _width = 0; 78 | _height = 0; 79 | } 80 | 81 | 82 | /// 83 | void add(RECT rc) 84 | { 85 | if (_capacity == 0) 86 | { 87 | _capacity = 1024; 88 | _rgn = cast(RGNDATA*) GC.malloc( 89 | RGNDATAHEADER.sizeof + RECT.sizeof * _capacity); 90 | _rgn.rdh.nCount = 0; 91 | } 92 | else if (_rgn.rdh.nCount == _capacity) 93 | { 94 | _capacity *= 2; 95 | _rgn = cast(RGNDATA*) GC.realloc(cast(void*)_rgn, 96 | RGNDATAHEADER.sizeof + RECT.sizeof * _capacity); 97 | } 98 | (cast(RECT*)_rgn.Buffer.ptr)[cast(uint)(_rgn.rdh.nCount++)] = rc; 99 | } 100 | 101 | 102 | /// ditto 103 | void add(int l, int t, int r, int b) 104 | { 105 | add(RECT(l, t, r, b)); 106 | } 107 | 108 | 109 | /// ditto 110 | void opCatAssign(RECT rc) 111 | { 112 | add(rc); 113 | } 114 | 115 | 116 | /// 117 | @property 118 | Region region() 119 | { 120 | if (_rgn is null) return null; 121 | with (_rgn.rdh) 122 | { 123 | dwSize = RGNDATAHEADER.sizeof; 124 | iType = RDH_RECTANGLES; 125 | nRgnSize = RGNDATAHEADER.sizeof + RECT.sizeof*nCount; 126 | rcBound = RECT(0,0,_width,_height); 127 | } 128 | if (auto hRgn = ExtCreateRegion(null, _rgn.rdh.nRgnSize, _rgn)) 129 | { 130 | return new Region(hRgn); 131 | } 132 | throw new Exception("Failed to make a region data."); 133 | } 134 | 135 | 136 | private Region createClippingRegionFromHDC(HBITMAP hBitmap) 137 | { 138 | HDC hDC = CreateCompatibleDC(null); 139 | auto h = _height; 140 | auto w = _width; 141 | if (!hDC) throw new Exception("Failed to get device context data."); 142 | BITMAPINFOHEADER bi; 143 | with(bi) 144 | { 145 | biSize = BITMAPINFOHEADER.sizeof; 146 | biWidth = w; 147 | biHeight = h; 148 | biPlanes = 1; 149 | biBitCount = 32; 150 | biCompression = BI_RGB; 151 | } 152 | auto pxs = new COLORREF[w]; 153 | COLORREF tr; 154 | for (int y = 1; y < h; ++y) 155 | { 156 | GetDIBits(hDC, hBitmap, h-y, 1, pxs.ptr, cast(BITMAPINFO*)&bi, DIB_RGB_COLORS); 157 | if (y == 1) tr = pxs[0]; 158 | for (int x = 0; x < w; x++) 159 | { 160 | if (pxs[x] == tr) continue; 161 | int sx = x; 162 | while (x < w) 163 | { 164 | if (pxs[x++] == tr) break; 165 | } 166 | add(sx, y-1, x-1, y); 167 | } 168 | } 169 | return region; 170 | } 171 | 172 | 173 | /// 174 | Region create(MemoryGraphics g) 175 | { 176 | clear(); 177 | _width = g.width; 178 | _height = g.height; 179 | return createClippingRegionFromHDC(cast(HBITMAP)g.hbitmap); 180 | } 181 | 182 | 183 | /// ditto 184 | Region create(Image img) 185 | { 186 | clear(); 187 | _width = img.width; 188 | _height = img.height; 189 | if (auto bmp = cast(Bitmap)img) 190 | { 191 | return createClippingRegionFromHDC(cast(HBITMAP)bmp.handle); 192 | } 193 | auto g = new MemoryGraphics(img.width, img.height); 194 | img.draw(g, Point(0,0)); 195 | return create(g); 196 | } 197 | } 198 | 199 | 200 | /// 201 | class ClippingForm: Form 202 | { 203 | private: 204 | Image m_Image; 205 | RegionRects m_RegionRects; 206 | protected: 207 | override void createParams(ref CreateParams cp) 208 | { 209 | super.createParams(cp); 210 | cp.style = WS_EX_TOPMOST | WS_EX_TOOLWINDOW; 211 | } 212 | public: 213 | 214 | 215 | /// 216 | @property Image clipping() 217 | { 218 | return m_Image; 219 | } 220 | 221 | 222 | /// ditto 223 | @property void clipping(Image img) 224 | { 225 | m_Image = img; 226 | } 227 | 228 | 229 | /// 230 | override void onHandleCreated(EventArgs ea) 231 | { 232 | if (m_Image) 233 | { 234 | region = m_RegionRects.create(m_Image); 235 | } 236 | super.onHandleCreated(ea); 237 | } 238 | 239 | 240 | /// 241 | override void onPaint(PaintEventArgs pea) 242 | { 243 | if (m_Image) 244 | { 245 | m_Image.draw(pea.graphics, Point(0,0)); 246 | } 247 | else 248 | { 249 | super.onPaint(pea); 250 | } 251 | } 252 | } 253 | -------------------------------------------------------------------------------- /source/dfl/collections.d: -------------------------------------------------------------------------------- 1 | // Written by Christopher E. Miller 2 | // See the included license.txt for copyright and license details. 3 | 4 | 5 | // Not actually part of forms, but is handy. 6 | 7 | /// 8 | module dfl.collections; 9 | 10 | private import dfl.internal.dlib; 11 | 12 | private import dfl.base; 13 | 14 | 15 | void _blankListCallback(TValue)(size_t idx, TValue val) // package 16 | { 17 | } 18 | 19 | 20 | // Mixin. 21 | // Item*Callback called before modifications. 22 | // For clear(), index is size_t.max and value is null. If CLEAR_EACH, also called back for each value. 23 | template ListWrapArray(TValue, alias Array, 24 | /+ // DMD 1.005: basic type expected, not function 25 | alias ItemAddingCallback = function(size_t idx, TValue val){}, 26 | alias ItemAddedCallback = function(size_t idx, TValue val){}, 27 | alias ItemRemovingCallback = function(size_t idx, TValue val){}, 28 | alias ItemRemovedCallback = function(size_t idx, TValue val){}, 29 | +/ 30 | alias ItemAddingCallback, 31 | alias ItemAddedCallback, 32 | alias ItemRemovingCallback, 33 | alias ItemRemovedCallback, 34 | bool OVERLOAD_STRING = false, 35 | bool OVERLOAD_OBJECT = false, 36 | bool COW = true, 37 | bool CLEAR_EACH = false) // package 38 | { 39 | mixin OpApplyWrapArray!(TValue, Array); // Note: this overrides COW. 40 | 41 | 42 | static if(OVERLOAD_OBJECT) 43 | { 44 | static assert(!is(TValue == Object)); 45 | } 46 | 47 | static if(OVERLOAD_STRING) 48 | { 49 | static assert(!is(TValue == Dstring)); 50 | 51 | static if(is(TValue == Object)) 52 | alias StringObject TValueString; 53 | else 54 | alias TValue TValueString; 55 | } 56 | 57 | 58 | /// 59 | void opIndexAssign(TValue value, int index) 60 | { 61 | TValue oldval = Array[index]; 62 | ItemRemovingCallback(index, oldval); // Removing. 63 | static if(COW) 64 | { 65 | Array = Array.dup; 66 | } 67 | else 68 | { 69 | //Array[index] = TValue.init; 70 | } 71 | ItemRemovedCallback(index, oldval); // Removed. 72 | 73 | ItemAddingCallback(index, value); // Adding. 74 | Array[index] = value; 75 | ItemAddedCallback(index, value); // Added. 76 | } 77 | 78 | static if(OVERLOAD_OBJECT) 79 | { 80 | /// ditto 81 | void opIndexAssign(Object value, int index) 82 | { 83 | TValue tval; 84 | tval = cast(TValue)value; 85 | if(tval) 86 | return opIndexAssign(tval, index); 87 | else 88 | return opIndexAssign(new TValue(value), index); // ? 89 | } 90 | } 91 | 92 | static if(OVERLOAD_STRING) 93 | { 94 | /// ditto 95 | void opIndexAssign(Dstring value, int index) 96 | { 97 | return opIndexAssign(new TValueString(value), index); 98 | } 99 | } 100 | 101 | 102 | /// 103 | @property TValue opIndex(int index) // getter 104 | { 105 | return Array[index]; 106 | } 107 | 108 | 109 | /// 110 | void add(TValue value) 111 | { 112 | _insert(cast(int)Array.length, value); 113 | } 114 | 115 | static if(OVERLOAD_OBJECT) 116 | { 117 | /// ditto 118 | void add(Object value) 119 | { 120 | _insert(cast(int)Array.length, value); 121 | } 122 | } 123 | 124 | static if(OVERLOAD_STRING) 125 | { 126 | /// ditto 127 | void add(Dstring value) 128 | { 129 | _insert(cast(int)Array.length, new TValueString(value)); 130 | } 131 | } 132 | 133 | 134 | /// 135 | void clear() 136 | { 137 | ItemRemovingCallback(int.max, null); // Removing ALL. 138 | 139 | int iw; 140 | iw = cast(int)Array.length; 141 | if(iw) 142 | { 143 | static if(CLEAR_EACH) 144 | { 145 | try 146 | { 147 | // Remove in reverse order so the indices don't keep shifting. 148 | TValue oldval; 149 | for(--iw;; iw--) 150 | { 151 | oldval = Array[iw]; 152 | static if(CLEAR_EACH) 153 | { 154 | ItemRemovingCallback(iw, oldval); // Removing. 155 | } 156 | /+static if(COW) 157 | { 158 | } 159 | else 160 | { 161 | //Array[iw] = TValue.init; 162 | }+/ 163 | debug 164 | { 165 | Array = Array[0 .. iw]; // 'Temporarily' removes it for ItemRemovedCallback. 166 | } 167 | static if(CLEAR_EACH) 168 | { 169 | ItemRemovedCallback(iw, oldval); // Removed. 170 | } 171 | if(!iw) 172 | break; 173 | } 174 | } 175 | finally 176 | { 177 | Array = Array[0 .. iw]; 178 | static if(COW) 179 | { 180 | if(!iw) 181 | Array = null; 182 | } 183 | } 184 | } 185 | else 186 | { 187 | Array = Array[0 .. 0]; 188 | static if(COW) 189 | { 190 | Array = null; 191 | } 192 | } 193 | } 194 | 195 | ItemRemovedCallback(int.max, null); // Removed ALL. 196 | } 197 | 198 | 199 | /// 200 | bool contains(TValue value) 201 | { 202 | return -1 != findIsIndex!(TValue)(Array, value); 203 | } 204 | 205 | static if(OVERLOAD_OBJECT) 206 | { 207 | /// ditto 208 | bool contains(Object value) 209 | { 210 | return -1 != indexOf(value); 211 | } 212 | } 213 | 214 | static if(OVERLOAD_STRING) 215 | { 216 | /// ditto 217 | bool contains(Dstring value) 218 | { 219 | return -1 != indexOf(value); 220 | } 221 | } 222 | 223 | 224 | /// 225 | int indexOf(TValue value) 226 | { 227 | return findIsIndex!(TValue)(Array, value); 228 | } 229 | 230 | static if(OVERLOAD_OBJECT) 231 | { 232 | /// ditto 233 | int indexOf(Object value) 234 | { 235 | TValue tval; 236 | tval = cast(TValue)value; 237 | if(tval) 238 | { 239 | return indexOf(tval); 240 | } 241 | else 242 | { 243 | foreach(size_t idx, TValue onval; Array) 244 | { 245 | if(onval == value) // TValue must have opEquals. 246 | return idx; 247 | } 248 | return -1; 249 | } 250 | } 251 | } 252 | 253 | static if(OVERLOAD_STRING) 254 | { 255 | /// ditto 256 | int indexOf(Dstring value) 257 | { 258 | foreach(uint idx, TValue onval; Array) 259 | { 260 | static if(is(TValue == TValueString)) 261 | { 262 | if(onval == value) // TValue must have opEquals. 263 | return idx; 264 | } 265 | else 266 | { 267 | if(getObjectString(onval) == value) 268 | return idx; 269 | } 270 | } 271 | return -1; 272 | } 273 | } 274 | 275 | 276 | private final void _insert(int index, TValue value) 277 | { 278 | if(index > Array.length) 279 | index = cast(int)Array.length; 280 | ItemAddingCallback(index, value); // Adding. 281 | static if(COW) 282 | { 283 | if(index >= Array.length) 284 | { 285 | if(Array.length) // Workaround old bug ? 286 | { 287 | Array = Array[0 .. index] ~ (&value)[0 .. 1]; 288 | } 289 | else 290 | { 291 | Array = (&value)[0 .. 1].dup; 292 | } 293 | goto insert_done; 294 | } 295 | } 296 | else 297 | { 298 | if(index >= Array.length) 299 | { 300 | Array ~= value; 301 | goto insert_done; 302 | } 303 | } 304 | Array = Array[0 .. index] ~ (&value)[0 .. 1] ~ Array[index .. Array.length]; 305 | insert_done: 306 | ItemAddedCallback(index, value); // Added. 307 | } 308 | 309 | static if(OVERLOAD_OBJECT) 310 | { 311 | private final void _insert(int index, Object value) 312 | { 313 | TValue tval; 314 | tval = cast(TValue)value; 315 | if(tval) 316 | return _insert(index, tval); 317 | else 318 | return _insert(index, new TValue(value)); // ? 319 | } 320 | } 321 | 322 | static if(OVERLOAD_STRING) 323 | { 324 | /// ditto 325 | private final void _insert(int index, Dstring value) 326 | { 327 | return _insert(index, new TValueString(value)); 328 | } 329 | } 330 | 331 | 332 | /// 333 | void insert(int index, TValue value) 334 | { 335 | _insert(index, value); 336 | } 337 | 338 | static if(OVERLOAD_OBJECT) 339 | { 340 | /// ditto 341 | void insert(int index, Object value) 342 | { 343 | _insert(index, value); 344 | } 345 | } 346 | 347 | static if(OVERLOAD_STRING) 348 | { 349 | /// ditto 350 | void insert(int index, Dstring value) 351 | { 352 | return _insert(index, value); 353 | } 354 | } 355 | 356 | 357 | /// 358 | void remove(TValue value) 359 | { 360 | int index; 361 | index = findIsIndex!(TValue)(Array, value); 362 | if(-1 != index) 363 | removeAt(index); 364 | } 365 | 366 | static if(OVERLOAD_OBJECT) 367 | { 368 | /// ditto 369 | void remove(Object value) 370 | { 371 | TValue tval; 372 | tval = cast(TValue)value; 373 | if(tval) 374 | { 375 | return remove(tval); 376 | } 377 | else 378 | { 379 | int i; 380 | i = indexOf(value); 381 | if(-1 != i) 382 | removeAt(i); 383 | } 384 | } 385 | } 386 | 387 | static if(OVERLOAD_STRING) 388 | { 389 | /// ditto 390 | void remove(Dstring value) 391 | { 392 | int i; 393 | i = indexOf(value); 394 | if(-1 != i) 395 | removeAt(i); 396 | } 397 | } 398 | 399 | 400 | /// 401 | void removeAt(int index) 402 | { 403 | TValue oldval = Array[index]; 404 | ItemRemovingCallback(index, oldval); // Removing. 405 | if(!index) 406 | Array = Array[1 .. Array.length]; 407 | else if(index == Array.length - 1) 408 | Array = Array[0 .. index]; 409 | else if(index > 0 && index < cast(int)Array.length) 410 | Array = Array[0 .. index] ~ Array[index + 1 .. Array.length]; 411 | ItemRemovedCallback(index, oldval); // Removed. 412 | } 413 | 414 | 415 | deprecated alias length count; 416 | 417 | /// 418 | @property size_t length() // getter 419 | { 420 | return Array.length; 421 | } 422 | 423 | 424 | deprecated alias dup clone; 425 | 426 | /// 427 | TValue[] dup() 428 | { 429 | return Array.dup; 430 | } 431 | 432 | 433 | /// 434 | void copyTo(TValue[] dest, int destIndex) 435 | { 436 | dest[destIndex .. destIndex + Array.length] = Array[]; 437 | } 438 | 439 | 440 | /// 441 | void addRange(TValue[] values) 442 | { 443 | foreach(TValue value; values) 444 | { 445 | add(value); 446 | } 447 | } 448 | 449 | static if(OVERLOAD_OBJECT) 450 | { 451 | /// ditto 452 | void addRange(Object[] values) 453 | { 454 | foreach(Object value; values) 455 | { 456 | add(value); 457 | } 458 | } 459 | } 460 | 461 | static if(OVERLOAD_STRING) 462 | { 463 | /// ditto 464 | void addRange(Dstring[] values) 465 | { 466 | foreach(Dstring value; values) 467 | { 468 | add(value); 469 | } 470 | } 471 | } 472 | } 473 | 474 | 475 | // Mixin. 476 | template OpApplyAddIndex(alias ApplyFunc, TValue, bool ADD_APPLY_FUNC = false) // package 477 | { 478 | /// 479 | int opApply(int delegate(ref size_t, ref TValue val) dg) 480 | { 481 | size_t idx = 0; 482 | return ApplyFunc( 483 | (ref TValue val) 484 | { 485 | int result; 486 | result = dg(idx, val); 487 | idx++; 488 | return result; 489 | }); 490 | } 491 | 492 | 493 | static if(ADD_APPLY_FUNC) 494 | { 495 | /// ditto 496 | int opApply(int delegate(ref TValue val) dg) 497 | { 498 | return ApplyFunc(dg); 499 | } 500 | } 501 | } 502 | 503 | 504 | // Mixin. 505 | template OpApplyWrapArray(TValue, alias Array) // package 506 | { 507 | /// 508 | int opApply(int delegate(ref TValue val) dg) 509 | { 510 | int result = 0; 511 | foreach(ref TValue val; Array) 512 | { 513 | result = dg(val); 514 | if(result) 515 | break; 516 | } 517 | return result; 518 | } 519 | 520 | /// ditto 521 | int opApply(int delegate(ref size_t, ref TValue val) dg) 522 | { 523 | int result = 0; 524 | foreach(size_t idx, ref TValue val; Array) 525 | { 526 | result = dg(idx, val); 527 | if(result) 528 | break; 529 | } 530 | return result; 531 | } 532 | } 533 | 534 | 535 | template removeIndex(T) // package 536 | { 537 | T[] removeIndex(T[] array, size_t index) 538 | { 539 | if(!index) 540 | array = array[1 .. array.length]; 541 | else if(index == array.length - 1) 542 | array = array[0 .. index]; 543 | else 544 | array = array[0 .. index] ~ array[index + 1 .. array.length]; 545 | return array; 546 | } 547 | } 548 | 549 | 550 | // Returns -1 if not found. 551 | template findIsIndex(T) // package 552 | { 553 | int findIsIndex(T[] array, T obj) 554 | { 555 | int idx; 556 | for(idx = 0; idx != array.length; idx++) 557 | { 558 | if(obj is array[idx]) 559 | return idx; 560 | } 561 | return -1; 562 | } 563 | } 564 | 565 | -------------------------------------------------------------------------------- /source/dfl/colordialog.d: -------------------------------------------------------------------------------- 1 | // Written by Christopher E. Miller 2 | // See the included license.txt for copyright and license details. 3 | 4 | 5 | /// 6 | module dfl.colordialog; 7 | 8 | private import dfl.commondialog, dfl.base, dfl.internal.winapi, dfl.internal.wincom; 9 | private import dfl.internal.utf, dfl.application, dfl.drawing, dfl.internal.dlib; 10 | 11 | 12 | /// 13 | class ColorDialog: CommonDialog // docmain 14 | { 15 | this() 16 | { 17 | Application.ppin(cast(void*)this); 18 | 19 | cc.lStructSize = cc.sizeof; 20 | cc.Flags = INIT_FLAGS; 21 | cc.rgbResult = Color.empty.toArgb(); 22 | cc.lCustData = cast(typeof(cc.lCustData))cast(void*)this; 23 | cc.lpfnHook = cast(typeof(cc.lpfnHook))&ccHookProc; 24 | _initcust(); 25 | } 26 | 27 | 28 | /// 29 | @property void allowFullOpen(bool byes) // setter 30 | { 31 | if(byes) 32 | cc.Flags &= ~CC_PREVENTFULLOPEN; 33 | else 34 | cc.Flags |= CC_PREVENTFULLOPEN; 35 | } 36 | 37 | /// ditto 38 | @property bool allowFullOpen() // getter 39 | { 40 | return (cc.Flags & CC_PREVENTFULLOPEN) != CC_PREVENTFULLOPEN; 41 | } 42 | 43 | 44 | /// 45 | @property void anyColor(bool byes) // setter 46 | { 47 | if(byes) 48 | cc.Flags |= CC_ANYCOLOR; 49 | else 50 | cc.Flags &= ~CC_ANYCOLOR; 51 | } 52 | 53 | /// ditto 54 | @property bool anyColor() // getter 55 | { 56 | return (cc.Flags & CC_ANYCOLOR) == CC_ANYCOLOR; 57 | } 58 | 59 | 60 | /// 61 | @property void solidColorOnly(bool byes) // setter 62 | { 63 | if(byes) 64 | cc.Flags |= CC_SOLIDCOLOR; 65 | else 66 | cc.Flags &= ~CC_SOLIDCOLOR; 67 | } 68 | 69 | /// ditto 70 | @property bool solidColorOnly() // getter 71 | { 72 | return (cc.Flags & CC_SOLIDCOLOR) == CC_SOLIDCOLOR; 73 | } 74 | 75 | 76 | /// 77 | final @property void color(Color c) // setter 78 | { 79 | cc.rgbResult = c.toRgb(); 80 | } 81 | 82 | /// ditto 83 | final @property Color color() // getter 84 | { 85 | return Color.fromRgb(cc.rgbResult); 86 | } 87 | 88 | 89 | /// 90 | final @property void customColors(COLORREF[] colors) // setter 91 | { 92 | if(colors.length >= _cust.length) 93 | _cust[] = colors[0 .. _cust.length]; 94 | else 95 | _cust[0 .. colors.length] = colors[]; 96 | } 97 | 98 | /// ditto 99 | final @property COLORREF[] customColors() // getter 100 | { 101 | return _cust; 102 | } 103 | 104 | 105 | /// 106 | @property void fullOpen(bool byes) // setter 107 | { 108 | if(byes) 109 | cc.Flags |= CC_FULLOPEN; 110 | else 111 | cc.Flags &= ~CC_FULLOPEN; 112 | } 113 | 114 | /// ditto 115 | @property bool fullOpen() // getter 116 | { 117 | return (cc.Flags & CC_FULLOPEN) == CC_FULLOPEN; 118 | } 119 | 120 | 121 | /// 122 | @property void showHelp(bool byes) // setter 123 | { 124 | if(byes) 125 | cc.Flags |= CC_SHOWHELP; 126 | else 127 | cc.Flags &= ~CC_SHOWHELP; 128 | } 129 | 130 | /// ditto 131 | @property bool showHelp() // getter 132 | { 133 | return (cc.Flags & CC_SHOWHELP) == CC_SHOWHELP; 134 | } 135 | 136 | 137 | /// 138 | override DialogResult showDialog() 139 | { 140 | return runDialog(GetActiveWindow()) ? 141 | DialogResult.OK : DialogResult.CANCEL; 142 | } 143 | 144 | /// ditto 145 | override DialogResult showDialog(IWindow owner) 146 | { 147 | return runDialog(owner ? owner.handle : GetActiveWindow()) ? 148 | DialogResult.OK : DialogResult.CANCEL; 149 | } 150 | 151 | 152 | /// 153 | override void reset() 154 | { 155 | cc.Flags = INIT_FLAGS; 156 | cc.rgbResult = Color.empty.toArgb(); 157 | _initcust(); 158 | } 159 | 160 | 161 | /// 162 | protected override bool runDialog(HWND owner) 163 | { 164 | if(!_runDialog(owner)) 165 | { 166 | if(!CommDlgExtendedError()) 167 | return false; 168 | _cantrun(); 169 | } 170 | return true; 171 | } 172 | 173 | 174 | private BOOL _runDialog(HWND owner) 175 | { 176 | if(cc.rgbResult == Color.empty.toArgb()) 177 | cc.Flags &= ~CC_RGBINIT; 178 | else 179 | cc.Flags |= CC_RGBINIT; 180 | cc.hwndOwner = owner; 181 | cc.lpCustColors = _cust.ptr; 182 | return ChooseColorA(&cc); 183 | } 184 | 185 | 186 | private: 187 | enum DWORD INIT_FLAGS = CC_ENABLEHOOK; 188 | 189 | CHOOSECOLORA cc; 190 | COLORREF[16] _cust; 191 | 192 | 193 | void _initcust() 194 | { 195 | COLORREF cdef; 196 | cdef = Color(0xFF, 0xFF, 0xFF).toRgb(); 197 | foreach(ref COLORREF cref; _cust) 198 | { 199 | cref = cdef; 200 | } 201 | } 202 | } 203 | 204 | 205 | private extern(Windows) UINT ccHookProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) 206 | { 207 | enum PROP_STR = "DFL_ColorDialog"; 208 | ColorDialog cd; 209 | UINT result = 0; 210 | 211 | try 212 | { 213 | if(msg == WM_INITDIALOG) 214 | { 215 | CHOOSECOLORA* cc; 216 | cc = cast(CHOOSECOLORA*)lparam; 217 | SetPropA(hwnd, PROP_STR.ptr, cast(HANDLE)cc.lCustData); 218 | cd = cast(ColorDialog)cast(void*)cc.lCustData; 219 | } 220 | else 221 | { 222 | cd = cast(ColorDialog)cast(void*)GetPropA(hwnd, PROP_STR.ptr); 223 | } 224 | 225 | if(cd) 226 | { 227 | result = cast(UINT)cd.hookProc(hwnd, msg, wparam, lparam); 228 | } 229 | } 230 | catch(DThrowable e) 231 | { 232 | Application.onThreadException(e); 233 | } 234 | 235 | return result; 236 | } 237 | 238 | -------------------------------------------------------------------------------- /source/dfl/commondialog.d: -------------------------------------------------------------------------------- 1 | // Written by Christopher E. Miller 2 | // See the included license.txt for copyright and license details. 3 | 4 | 5 | /// 6 | module dfl.commondialog; 7 | 8 | private import dfl.control, dfl.internal.winapi, dfl.base, dfl.drawing, 9 | dfl.event; 10 | private import dfl.application; 11 | 12 | public import dfl.filedialog, dfl.folderdialog, dfl.colordialog, dfl.fontdialog; 13 | 14 | 15 | /// 16 | abstract class CommonDialog // docmain 17 | { 18 | /// 19 | abstract void reset(); 20 | 21 | /// 22 | // Uses currently active window of the application as owner. 23 | abstract DialogResult showDialog(); 24 | 25 | /// ditto 26 | abstract DialogResult showDialog(IWindow owner); 27 | 28 | 29 | /// 30 | Event!(CommonDialog, HelpEventArgs) helpRequest; 31 | 32 | 33 | protected: 34 | 35 | /// 36 | // See the CDN_* Windows notification messages. 37 | LRESULT hookProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) 38 | { 39 | switch(msg) 40 | { 41 | case WM_NOTIFY: 42 | { 43 | NMHDR* nmhdr; 44 | nmhdr = cast(NMHDR*)lparam; 45 | switch(nmhdr.code) 46 | { 47 | case CDN_HELP: 48 | { 49 | Point pt; 50 | GetCursorPos(&pt.point); 51 | onHelpRequest(new HelpEventArgs(pt)); 52 | } 53 | break; 54 | 55 | default: 56 | } 57 | } 58 | break; 59 | 60 | default: 61 | } 62 | 63 | return 0; 64 | } 65 | 66 | 67 | // TODO: implement. 68 | //LRESULT ownerWndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) 69 | 70 | 71 | /// 72 | void onHelpRequest(HelpEventArgs ea) 73 | { 74 | helpRequest(this, ea); 75 | } 76 | 77 | 78 | /// 79 | abstract bool runDialog(HWND owner); 80 | 81 | 82 | package final void _cantrun() 83 | { 84 | throw new DflException("Error running dialog"); 85 | } 86 | } 87 | 88 | -------------------------------------------------------------------------------- /source/dfl/event.d: -------------------------------------------------------------------------------- 1 | // Not actually part of forms, but is needed. 2 | // This code is public domain. 3 | 4 | /// Event handling. 5 | module dfl.event; 6 | 7 | import dfl.internal.dlib; 8 | import std.functional; 9 | 10 | 11 | // Create an event handler; old style. 12 | deprecated template Event(TArgs : EventArgs = EventArgs) 13 | { 14 | alias Event!(Object, TArgs) Event; 15 | } 16 | 17 | 18 | /** Managing event handlers. 19 | Params: 20 | T1 = the sender type. 21 | T2 = the event arguments type. 22 | **/ 23 | template Event(T1, T2) // docmain 24 | { 25 | /// Managing event handlers. 26 | struct Event // docmain 27 | { 28 | alias void delegate(T1, T2) Handler; /// Event handler type. 29 | 30 | 31 | /// Add an event handler with the exact type. 32 | void addHandlerExact(Handler handler) 33 | in 34 | { 35 | assert(handler); 36 | } 37 | body 38 | { 39 | if(!_array.length) 40 | { 41 | _array = new Handler[2]; 42 | _array[1] = handler; 43 | unsetHot(); 44 | } 45 | else 46 | { 47 | if(!isHot()) 48 | { 49 | _array ~= handler; 50 | } 51 | else // Hot. 52 | { 53 | _array = _array ~ (&handler)[0 .. 1]; // Force duplicate. 54 | unsetHot(); 55 | } 56 | } 57 | } 58 | 59 | 60 | /// Add an event handler with parameter contravariance. 61 | void addHandler(TDG)(TDG handler) 62 | in 63 | { 64 | assert(handler); 65 | } 66 | body 67 | { 68 | mixin _validateHandler!(TDG); 69 | 70 | addHandlerExact(cast(Handler)toDelegate(handler)); 71 | } 72 | 73 | 74 | /// Shortcut for addHandler(). 75 | void opCatAssign(TDG)(TDG handler) 76 | { 77 | addHandler(toDelegate(handler)); 78 | } 79 | 80 | 81 | /// Remove the specified event handler with the exact Handler type. 82 | void removeHandlerExact(Handler handler) 83 | { 84 | if(!_array.length) 85 | return; 86 | 87 | size_t iw; 88 | for(iw = 1; iw != _array.length; iw++) 89 | { 90 | if(handler == _array[iw]) 91 | { 92 | if(iw == 1 && _array.length == 2) 93 | { 94 | _array = null; 95 | break; 96 | } 97 | 98 | if(iw == _array.length - 1) 99 | { 100 | _array[iw] = null; 101 | _array = _array[0 .. iw]; 102 | break; 103 | } 104 | 105 | if(!isHot()) 106 | { 107 | _array[iw] = _array[_array.length - 1]; 108 | _array[_array.length - 1] = null; 109 | _array = _array[0 .. _array.length - 1]; 110 | } 111 | else // Hot. 112 | { 113 | _array = _array[0 .. iw] ~ _array[iw + 1 .. _array.length]; // Force duplicate. 114 | unsetHot(); 115 | } 116 | break; 117 | } 118 | } 119 | } 120 | 121 | 122 | /// Remove the specified event handler with parameter contravariance. 123 | void removeHandler(TDG)(TDG handler) 124 | { 125 | mixin _validateHandler!(TDG); 126 | 127 | removeHandlerExact(cast(Handler)toDelegate(handler)); 128 | } 129 | 130 | 131 | /// Fire the event handlers. 132 | void opCall(T1 v1, T2 v2) 133 | { 134 | if(!_array.length) 135 | return; 136 | setHot(); 137 | 138 | Handler[] local; 139 | local = _array[1 .. _array.length]; 140 | foreach(Handler handler; local) 141 | { 142 | handler(v1, v2); 143 | } 144 | 145 | if(!_array.length) 146 | return; 147 | unsetHot(); 148 | } 149 | 150 | 151 | /// 152 | int opApply(int delegate(Handler) dg) 153 | { 154 | if(!_array.length) 155 | return 0; 156 | setHot(); 157 | 158 | int result = 0; 159 | 160 | Handler[] local; 161 | local = _array[1 .. _array.length]; 162 | foreach(Handler handler; local) 163 | { 164 | result = dg(handler); 165 | if(result) 166 | break; 167 | } 168 | 169 | if(_array.length) 170 | unsetHot(); 171 | 172 | return result; 173 | } 174 | 175 | 176 | /// 177 | @property bool hasHandlers() pure nothrow // getter 178 | { 179 | return _array.length > 1; 180 | } 181 | 182 | 183 | // Use opApply and hasHandlers instead. 184 | deprecated @property Handler[] handlers() pure nothrow // getter 185 | { 186 | if(!hasHandlers) 187 | return null; 188 | try 189 | { 190 | return _array[1 .. _array.length].dup; // Because _array can be modified. Function is deprecated anyway. 191 | } 192 | catch (DThrowable e) 193 | { 194 | return null; 195 | } 196 | } 197 | 198 | 199 | private: 200 | Handler[] _array; // Not what it seems. 201 | 202 | 203 | void setHot() 204 | { 205 | assert(_array.length); 206 | _array[0] = cast(Handler)&setHot; // Non-null, GC friendly. 207 | } 208 | 209 | 210 | void unsetHot() 211 | { 212 | assert(_array.length); 213 | _array[0] = null; 214 | } 215 | 216 | 217 | Handler isHot() 218 | { 219 | assert(_array.length); 220 | return _array[0]; 221 | } 222 | 223 | 224 | // Thanks to Tomasz "h3r3tic" Stachowiak for his assistance. 225 | template _validateHandler(TDG) 226 | { 227 | static assert(is(typeof(toDelegate(TDG.init))), "DFL: Event handler must be a callable"); 228 | 229 | alias ParameterTypeTuple!(TDG) TDGParams; 230 | static assert(TDGParams.length == 2, "DFL: Event handler needs exactly 2 parameters"); 231 | 232 | static if(is(TDGParams[0] : Object)) 233 | { 234 | static assert(is(T1: TDGParams[0]), "DFL: Event handler parameter 1 type mismatch"); 235 | } 236 | else 237 | { 238 | static assert(is(T1 == TDGParams[0]), "DFL: Event handler parameter 1 type mismatch"); 239 | } 240 | 241 | static if(is(TDGParams[1] : Object)) 242 | { 243 | static assert(is(T2 : TDGParams[1]), "DFL: Event handler parameter 2 type mismatch"); 244 | } 245 | else 246 | { 247 | static assert(is(T2 == TDGParams[1]), "DFL: Event handler parameter 2 type mismatch"); 248 | } 249 | } 250 | } 251 | } 252 | 253 | 254 | /// Base event arguments. 255 | class EventArgs // docmain 256 | { 257 | /+ 258 | private static byte[] buf; 259 | private import std.gc; // <-- ... 260 | 261 | 262 | new(uint sz) 263 | { 264 | void* result; 265 | 266 | // synchronized // Slows it down a lot. 267 | { 268 | if(sz > buf.length) 269 | buf = new byte[100 + sz]; 270 | 271 | result = buf[0 .. sz]; 272 | buf = buf[sz .. buf.length]; 273 | } 274 | 275 | // std.gc.addRange(result, result + sz); // So that it can contain pointers. 276 | return result; 277 | } 278 | +/ 279 | 280 | 281 | /+ 282 | delete(void* p) 283 | { 284 | std.gc.removeRange(p); 285 | } 286 | +/ 287 | 288 | 289 | //private static const EventArgs _e; 290 | private static EventArgs _e; 291 | 292 | 293 | static this() 294 | { 295 | _e = new EventArgs; 296 | } 297 | 298 | 299 | /// Property: get a reusable, _empty EventArgs. 300 | static @property EventArgs empty() nothrow // getter 301 | { 302 | return _e; 303 | } 304 | } 305 | 306 | 307 | // Simple event handler. 308 | alias Event!(Object, EventArgs) EventHandler; // deprecated 309 | 310 | 311 | /// 312 | class ThreadExceptionEventArgs: EventArgs 313 | { 314 | /// 315 | // The exception that occured. 316 | this(DThrowable theException) pure nothrow 317 | { 318 | except = theException; 319 | } 320 | 321 | 322 | /// 323 | final @property DThrowable exception() pure nothrow // getter 324 | { 325 | return except; 326 | } 327 | 328 | 329 | private: 330 | DThrowable except; 331 | } 332 | 333 | -------------------------------------------------------------------------------- /source/dfl/folderdialog.d: -------------------------------------------------------------------------------- 1 | // Written by Christopher E. Miller 2 | // See the included license.txt for copyright and license details. 3 | 4 | 5 | /// 6 | module dfl.folderdialog; 7 | 8 | private import dfl.internal.dlib, dfl.internal.clib; 9 | 10 | private import dfl.commondialog, dfl.base, dfl.internal.winapi, dfl.internal.wincom; 11 | private import dfl.internal.utf, dfl.application; 12 | 13 | 14 | private extern(Windows) nothrow 15 | { 16 | alias LPITEMIDLIST function(LPBROWSEINFOW lpbi) SHBrowseForFolderWProc; 17 | alias BOOL function(LPCITEMIDLIST pidl, LPWSTR pszPath) SHGetPathFromIDListWProc; 18 | } 19 | 20 | 21 | /// 22 | class FolderBrowserDialog: CommonDialog // docmain 23 | { 24 | this() 25 | { 26 | // Flag BIF_NEWDIALOGSTYLE requires OleInitialize(). 27 | //OleInitialize(null); 28 | 29 | Application.ppin(cast(void*)this); 30 | 31 | bi.ulFlags = INIT_FLAGS; 32 | bi.lParam = cast(typeof(bi.lParam))cast(void*)this; 33 | bi.lpfn = &fbdHookProc; 34 | } 35 | 36 | 37 | ~this() 38 | { 39 | //OleUninitialize(); 40 | } 41 | 42 | 43 | override DialogResult showDialog() 44 | { 45 | if(!runDialog(GetActiveWindow())) 46 | return DialogResult.CANCEL; 47 | return DialogResult.OK; 48 | } 49 | 50 | 51 | override DialogResult showDialog(IWindow owner) 52 | { 53 | if(!runDialog(owner ? owner.handle : GetActiveWindow())) 54 | return DialogResult.CANCEL; 55 | return DialogResult.OK; 56 | } 57 | 58 | 59 | override void reset() 60 | { 61 | bi.ulFlags = INIT_FLAGS; 62 | _desc = null; 63 | _selpath = null; 64 | } 65 | 66 | 67 | /// 68 | final @property void description(Dstring desc) // setter 69 | { 70 | // lpszTitle 71 | 72 | _desc = desc; 73 | } 74 | 75 | /// ditto 76 | final @property Dstring description() // getter 77 | { 78 | return _desc; 79 | } 80 | 81 | 82 | /// 83 | final @property void selectedPath(Dstring selpath) // setter 84 | { 85 | // pszDisplayName 86 | 87 | _selpath = selpath; 88 | } 89 | 90 | /// ditto 91 | final @property Dstring selectedPath() // getter 92 | { 93 | return _selpath; 94 | } 95 | 96 | 97 | // /// 98 | // Currently only works for shell32.dll version 6.0+. 99 | final @property void showNewFolderButton(bool byes) // setter 100 | { 101 | // BIF_NONEWFOLDERBUTTON exists with shell 6.0+. 102 | // Might need to enum child windows looking for window title 103 | // "&New Folder" and hide it, then shift "OK" and "Cancel" over. 104 | 105 | if(byes) 106 | bi.ulFlags &= ~BIF_NONEWFOLDERBUTTON; 107 | else 108 | bi.ulFlags |= BIF_NONEWFOLDERBUTTON; 109 | } 110 | 111 | // /// ditto 112 | final @property bool showNewFolderButton() // getter 113 | { 114 | return (bi.ulFlags & BIF_NONEWFOLDERBUTTON) == 0; 115 | } 116 | 117 | 118 | private void _errPathTooLong() 119 | { 120 | throw new DflException("Path name is too long"); 121 | } 122 | 123 | 124 | private void _errNoGetPath() 125 | { 126 | throw new DflException("Unable to obtain path"); 127 | } 128 | 129 | 130 | private void _errNoShMalloc() 131 | { 132 | throw new DflException("Unable to get shell memory allocator"); 133 | } 134 | 135 | 136 | protected override bool runDialog(HWND owner) 137 | { 138 | IMalloc shmalloc; 139 | 140 | bi.hwndOwner = owner; 141 | 142 | // Using size of wchar so that the buffer works for ansi and unicode. 143 | //void* pdescz = dfl.internal.clib.alloca(wchar.sizeof * MAX_PATH); 144 | //if(!pdescz) 145 | // throw new DflException("Out of memory"); // Stack overflow ? 146 | //wchar[MAX_PATH] pdescz = void; 147 | wchar[MAX_PATH] pdescz; // Initialize because SHBrowseForFolder() is modal. 148 | 149 | if(dfl.internal.utf.useUnicode) 150 | { 151 | enum BROWSE_NAME = "SHBrowseForFolderW"; 152 | enum PATH_NAME = "SHGetPathFromIDListW"; 153 | static SHBrowseForFolderWProc browseproc = null; 154 | static SHGetPathFromIDListWProc pathproc = null; 155 | 156 | if(!browseproc) 157 | { 158 | HMODULE hmod; 159 | hmod = GetModuleHandleA("shell32.dll"); 160 | 161 | browseproc = cast(SHBrowseForFolderWProc)GetProcAddress(hmod, BROWSE_NAME.ptr); 162 | if(!browseproc) 163 | throw new Exception("Unable to load procedure " ~ BROWSE_NAME); 164 | 165 | pathproc = cast(SHGetPathFromIDListWProc)GetProcAddress(hmod, PATH_NAME.ptr); 166 | if(!pathproc) 167 | throw new Exception("Unable to load procedure " ~ PATH_NAME); 168 | } 169 | 170 | biw.lpszTitle = dfl.internal.utf.toUnicodez(_desc); 171 | 172 | biw.pszDisplayName = cast(wchar*)pdescz; 173 | if(_desc.length) 174 | { 175 | Dwstring tmp; 176 | tmp = dfl.internal.utf.toUnicode(_desc); 177 | if(tmp.length >= MAX_PATH) 178 | _errPathTooLong(); 179 | biw.pszDisplayName[0 .. tmp.length] = tmp[]; 180 | biw.pszDisplayName[tmp.length] = 0; 181 | } 182 | else 183 | { 184 | biw.pszDisplayName[0] = 0; 185 | } 186 | 187 | // Show the dialog! 188 | LPITEMIDLIST result; 189 | result = browseproc(&biw); 190 | 191 | if(!result) 192 | { 193 | biw.lpszTitle = null; 194 | return false; 195 | } 196 | 197 | if(NOERROR != SHGetMalloc(&shmalloc)) 198 | _errNoShMalloc(); 199 | 200 | //wchar* wbuf = cast(wchar*)dfl.internal.clib.alloca(wchar.sizeof * MAX_PATH); 201 | wchar[MAX_PATH] wbuf = void; 202 | if(!pathproc(result, wbuf.ptr)) 203 | { 204 | shmalloc.Free(result); 205 | shmalloc.Release(); 206 | _errNoGetPath(); 207 | assert(0); 208 | } 209 | 210 | _selpath = dfl.internal.utf.fromUnicodez(wbuf.ptr); // Assumes fromUnicodez() copies. 211 | 212 | shmalloc.Free(result); 213 | shmalloc.Release(); 214 | 215 | biw.lpszTitle = null; 216 | } 217 | else 218 | { 219 | bia.lpszTitle = dfl.internal.utf.toAnsiz(_desc); 220 | 221 | bia.pszDisplayName = cast(char*)pdescz; 222 | if(_desc.length) 223 | { 224 | Dstring tmp; // ansi. 225 | tmp = dfl.internal.utf.toAnsi(_desc); 226 | if(tmp.length >= MAX_PATH) 227 | _errPathTooLong(); 228 | bia.pszDisplayName[0 .. tmp.length] = tmp[]; 229 | bia.pszDisplayName[tmp.length] = 0; 230 | } 231 | else 232 | { 233 | bia.pszDisplayName[0] = 0; 234 | } 235 | 236 | // Show the dialog! 237 | LPITEMIDLIST result; 238 | result = SHBrowseForFolderA(&bia); 239 | 240 | if(!result) 241 | { 242 | bia.lpszTitle = null; 243 | return false; 244 | } 245 | 246 | if(NOERROR != SHGetMalloc(&shmalloc)) 247 | _errNoShMalloc(); 248 | 249 | //char* abuf = cast(char*)dfl.internal.clib.alloca(char.sizeof * MAX_PATH); 250 | char[MAX_PATH] abuf = void; 251 | if(!SHGetPathFromIDListA(result, abuf.ptr)) 252 | { 253 | shmalloc.Free(result); 254 | shmalloc.Release(); 255 | _errNoGetPath(); 256 | assert(0); 257 | } 258 | 259 | _selpath = dfl.internal.utf.fromAnsiz(abuf.ptr); // Assumes fromAnsiz() copies. 260 | 261 | shmalloc.Free(result); 262 | shmalloc.Release(); 263 | 264 | bia.lpszTitle = null; 265 | } 266 | 267 | return true; 268 | } 269 | 270 | 271 | protected: 272 | 273 | /+ 274 | override LRESULT hookProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) 275 | { 276 | switch(msg) 277 | { 278 | case WM_NOTIFY: 279 | { 280 | NMHDR* nmhdr; 281 | nmhdr = cast(NMHDR*)lparam; 282 | switch(nmhdr.code) 283 | { 284 | /+ 285 | case CDN_FILEOK: 286 | break; 287 | +/ 288 | 289 | default: 290 | } 291 | } 292 | break; 293 | 294 | default: 295 | } 296 | 297 | return super.hookProc(hwnd, msg, wparam, lparam); 298 | } 299 | +/ 300 | 301 | 302 | private: 303 | 304 | union 305 | { 306 | BROWSEINFOW biw; 307 | BROWSEINFOA bia; 308 | alias biw bi; 309 | 310 | static assert(BROWSEINFOW.sizeof == BROWSEINFOA.sizeof); 311 | static assert(BROWSEINFOW.ulFlags.offsetof == BROWSEINFOA.ulFlags.offsetof); 312 | } 313 | 314 | Dstring _desc; 315 | Dstring _selpath; 316 | 317 | 318 | enum UINT INIT_FLAGS = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE; 319 | } 320 | 321 | 322 | private: 323 | 324 | private extern(Windows) int fbdHookProc(HWND hwnd, UINT msg, LPARAM lparam, LPARAM lpData) nothrow 325 | { 326 | FolderBrowserDialog fd; 327 | int result = 0; 328 | 329 | try 330 | { 331 | fd = cast(FolderBrowserDialog)cast(void*)lpData; 332 | if(fd) 333 | { 334 | Dstring s; 335 | switch(msg) 336 | { 337 | case BFFM_INITIALIZED: 338 | s = fd.selectedPath; 339 | if(s.length) 340 | { 341 | if(dfl.internal.utf.useUnicode) 342 | SendMessageA(hwnd, BFFM_SETSELECTIONW, TRUE, cast(LPARAM)dfl.internal.utf.toUnicodez(s)); 343 | else 344 | SendMessageA(hwnd, BFFM_SETSELECTIONA, TRUE, cast(LPARAM)dfl.internal.utf.toAnsiz(s)); 345 | } 346 | break; 347 | 348 | default: 349 | } 350 | } 351 | } 352 | catch(DThrowable e) 353 | { 354 | Application.onThreadException(e); 355 | } 356 | 357 | return result; 358 | } 359 | 360 | -------------------------------------------------------------------------------- /source/dfl/fontdialog.d: -------------------------------------------------------------------------------- 1 | // Written by Christopher E. Miller 2 | // See the included license.txt for copyright and license details. 3 | 4 | 5 | /// 6 | module dfl.fontdialog; 7 | 8 | private import dfl.base, dfl.commondialog, dfl.internal.winapi, dfl.application, 9 | dfl.control, dfl.drawing, dfl.event, dfl.internal.utf, 10 | dfl.internal.dlib; 11 | 12 | 13 | private extern(Windows) nothrow 14 | { 15 | alias BOOL function(LPCHOOSEFONTW lpcf) ChooseFontWProc; 16 | } 17 | 18 | 19 | /// 20 | class FontDialog: CommonDialog 21 | { 22 | this() 23 | { 24 | Application.ppin(cast(void*)this); 25 | 26 | cf.lStructSize = cf.sizeof; 27 | cf.Flags = INIT_FLAGS; 28 | cf.lpLogFont = cast(typeof(cf.lpLogFont))&lfw; 29 | cf.lCustData = cast(typeof(cf.lCustData))cast(void*)this; 30 | cf.lpfnHook = &fondHookProc; 31 | cf.rgbColors = 0; 32 | } 33 | 34 | 35 | override void reset() 36 | { 37 | _fon = null; 38 | cf.Flags = INIT_FLAGS; 39 | cf.rgbColors = 0; 40 | cf.nSizeMin = 0; 41 | cf.nSizeMax = 0; 42 | } 43 | 44 | 45 | /// 46 | final @property void allowSimulations(bool byes) // setter 47 | { 48 | if(byes) 49 | cf.Flags &= ~CF_NOSIMULATIONS; 50 | else 51 | cf.Flags |= CF_NOSIMULATIONS; 52 | } 53 | 54 | /// ditto 55 | final @property bool allowSimulations() // getter 56 | { 57 | if(cf.Flags & CF_NOSIMULATIONS) 58 | return false; 59 | return true; 60 | } 61 | 62 | 63 | /// 64 | final @property void allowVectorFonts(bool byes) // setter 65 | { 66 | if(byes) 67 | cf.Flags &= ~CF_NOVECTORFONTS; 68 | else 69 | cf.Flags |= CF_NOVECTORFONTS; 70 | } 71 | 72 | /// ditto 73 | final bool allowVectorFonts() // getter 74 | { 75 | if(cf.Flags & CF_NOVECTORFONTS) 76 | return false; 77 | return true; 78 | } 79 | 80 | 81 | /// 82 | final @property void allowVerticalFonts(bool byes) // setter 83 | { 84 | if(byes) 85 | cf.Flags &= ~CF_NOVERTFONTS; 86 | else 87 | cf.Flags |= CF_NOVERTFONTS; 88 | } 89 | 90 | /// ditto 91 | final @property bool allowVerticalFonts() // getter 92 | { 93 | if(cf.Flags & CF_NOVERTFONTS) 94 | return false; 95 | return true; 96 | } 97 | 98 | 99 | /// 100 | final @property void color(Color c) // setter 101 | { 102 | cf.rgbColors = c.toRgb(); 103 | } 104 | 105 | /// ditto 106 | final @property Color color() // getter 107 | { 108 | return Color.fromRgb(cf.rgbColors); 109 | } 110 | 111 | 112 | /// 113 | final @property void fixedPitchOnly(bool byes) // setter 114 | { 115 | if(byes) 116 | cf.Flags |= CF_FIXEDPITCHONLY; 117 | else 118 | cf.Flags &= ~CF_FIXEDPITCHONLY; 119 | } 120 | 121 | /// ditto 122 | final @property bool fixedPitchOnly() // getter 123 | { 124 | if(cf.Flags & CF_FIXEDPITCHONLY) 125 | return true; 126 | return false; 127 | } 128 | 129 | 130 | /// 131 | final @property void font(Font f) // setter 132 | { 133 | _fon = f; 134 | } 135 | 136 | /// ditto 137 | final @property Font font() // getter 138 | { 139 | if(!_fon) 140 | _fon = Control.defaultFont; // ? 141 | return _fon; 142 | } 143 | 144 | 145 | /// 146 | final @property void fontMustExist(bool byes) // setter 147 | { 148 | if(byes) 149 | cf.Flags |= CF_FORCEFONTEXIST; 150 | else 151 | cf.Flags &= ~CF_FORCEFONTEXIST; 152 | } 153 | 154 | /// ditto 155 | final @property bool fontMustExist() // getter 156 | { 157 | if(cf.Flags & CF_FORCEFONTEXIST) 158 | return true; 159 | return false; 160 | } 161 | 162 | 163 | /// 164 | final @property void maxSize(int max) // setter 165 | { 166 | if(max > 0) 167 | { 168 | if(max > cf.nSizeMin) 169 | cf.nSizeMax = max; 170 | cf.Flags |= CF_LIMITSIZE; 171 | } 172 | else 173 | { 174 | cf.Flags &= ~CF_LIMITSIZE; 175 | cf.nSizeMax = 0; 176 | cf.nSizeMin = 0; 177 | } 178 | } 179 | 180 | /// ditto 181 | final @property int maxSize() // getter 182 | { 183 | if(cf.Flags & CF_LIMITSIZE) 184 | return cf.nSizeMax; 185 | return 0; 186 | } 187 | 188 | 189 | /// 190 | final @property void minSize(int min) // setter 191 | { 192 | if(min > cf.nSizeMax) 193 | cf.nSizeMax = min; 194 | cf.nSizeMin = min; 195 | cf.Flags |= CF_LIMITSIZE; 196 | } 197 | 198 | /// ditto 199 | final @property int minSize() // getter 200 | { 201 | if(cf.Flags & CF_LIMITSIZE) 202 | return cf.nSizeMin; 203 | return 0; 204 | } 205 | 206 | 207 | /// 208 | final @property void scriptsOnly(bool byes) // setter 209 | { 210 | if(byes) 211 | cf.Flags |= CF_SCRIPTSONLY; 212 | else 213 | cf.Flags &= ~CF_SCRIPTSONLY; 214 | } 215 | 216 | /// ditto 217 | final @property bool scriptsOnly() // getter 218 | { 219 | if(cf.Flags & CF_SCRIPTSONLY) 220 | return true; 221 | return false; 222 | } 223 | 224 | 225 | /// 226 | final @property void showApply(bool byes) // setter 227 | { 228 | if(byes) 229 | cf.Flags |= CF_APPLY; 230 | else 231 | cf.Flags &= ~CF_APPLY; 232 | } 233 | 234 | /// ditto 235 | final @property bool showApply() // getter 236 | { 237 | if(cf.Flags & CF_APPLY) 238 | return true; 239 | return false; 240 | } 241 | 242 | 243 | /// 244 | final @property void showHelp(bool byes) // setter 245 | { 246 | if(byes) 247 | cf.Flags |= CF_SHOWHELP; 248 | else 249 | cf.Flags &= ~CF_SHOWHELP; 250 | } 251 | 252 | /// ditto 253 | final @property bool showHelp() // getter 254 | { 255 | if(cf.Flags & CF_SHOWHELP) 256 | return true; 257 | return false; 258 | } 259 | 260 | 261 | /// 262 | final @property void showEffects(bool byes) // setter 263 | { 264 | if(byes) 265 | cf.Flags |= CF_EFFECTS; 266 | else 267 | cf.Flags &= ~CF_EFFECTS; 268 | } 269 | 270 | /// ditto 271 | final @property bool showEffects() // getter 272 | { 273 | if(cf.Flags & CF_EFFECTS) 274 | return true; 275 | return false; 276 | } 277 | 278 | 279 | override DialogResult showDialog() 280 | { 281 | return runDialog(GetActiveWindow()) ? 282 | DialogResult.OK : DialogResult.CANCEL; 283 | } 284 | 285 | 286 | override DialogResult showDialog(IWindow owner) 287 | { 288 | return runDialog(owner ? owner.handle : GetActiveWindow()) ? 289 | DialogResult.OK : DialogResult.CANCEL; 290 | } 291 | 292 | 293 | /// 294 | EventHandler apply; 295 | 296 | 297 | protected override LRESULT hookProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) 298 | { 299 | switch(msg) 300 | { 301 | case WM_COMMAND: 302 | switch(LOWORD(wparam)) 303 | { 304 | case CF_APPLY: // ? 305 | _update(); 306 | onApply(EventArgs.empty); 307 | break; 308 | 309 | default: 310 | } 311 | break; 312 | 313 | default: 314 | } 315 | 316 | return super.hookProc(hwnd, msg, wparam, lparam); 317 | } 318 | 319 | 320 | protected override bool runDialog(HWND owner) 321 | { 322 | if(!_runDialog(owner)) 323 | { 324 | if(!CommDlgExtendedError()) 325 | return false; 326 | _cantrun(); 327 | } 328 | return true; 329 | } 330 | 331 | 332 | private BOOL _runDialog(HWND owner) 333 | { 334 | BOOL result = FALSE; 335 | 336 | cf.hwndOwner = owner; 337 | 338 | if(dfl.internal.utf.useUnicode) 339 | { 340 | font._info(&lfw); // -font- gets default font if not set. 341 | 342 | enum NAME = "ChooseFontW"; 343 | static ChooseFontWProc proc = null; 344 | 345 | if(!proc) 346 | { 347 | proc = cast(ChooseFontWProc)GetProcAddress(GetModuleHandleA("comdlg32.dll"), NAME.ptr); 348 | if(!proc) 349 | throw new Exception("Unable to load procedure " ~ NAME ~ "."); 350 | } 351 | 352 | result = proc(&cfw); 353 | } 354 | else 355 | { 356 | font._info(&lfa); // -font- gets default font if not set. 357 | 358 | result = ChooseFontA(&cfa); 359 | } 360 | 361 | if(result) 362 | { 363 | _update(); 364 | return result; 365 | } 366 | return FALSE; 367 | } 368 | 369 | 370 | private void _update() 371 | { 372 | LogFont lf; 373 | 374 | if(dfl.internal.utf.useUnicode) 375 | Font.LOGFONTWtoLogFont(lf, &lfw); 376 | else 377 | Font.LOGFONTAtoLogFont(lf, &lfa); 378 | 379 | _fon = new Font(Font._create(lf), true); 380 | } 381 | 382 | 383 | /// 384 | protected void onApply(EventArgs ea) 385 | { 386 | apply(this, ea); 387 | } 388 | 389 | 390 | private: 391 | 392 | union 393 | { 394 | CHOOSEFONTW cfw; 395 | CHOOSEFONTA cfa; 396 | alias cfw cf; 397 | 398 | static assert(CHOOSEFONTW.sizeof == CHOOSEFONTA.sizeof); 399 | static assert(CHOOSEFONTW.Flags.offsetof == CHOOSEFONTA.Flags.offsetof); 400 | static assert(CHOOSEFONTW.nSizeMax.offsetof == CHOOSEFONTA.nSizeMax.offsetof); 401 | } 402 | 403 | union 404 | { 405 | LOGFONTW lfw; 406 | LOGFONTA lfa; 407 | 408 | static assert(LOGFONTW.lfFaceName.offsetof == LOGFONTA.lfFaceName.offsetof); 409 | } 410 | 411 | Font _fon; 412 | 413 | 414 | enum UINT INIT_FLAGS = CF_EFFECTS | CF_ENABLEHOOK | CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS; 415 | } 416 | 417 | 418 | // WM_CHOOSEFONT_SETFLAGS to update flags after dialog creation ... ? 419 | 420 | 421 | private extern(Windows) UINT fondHookProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) nothrow 422 | { 423 | enum PROP_STR = "DFL_FontDialog"; 424 | FontDialog fd; 425 | LRESULT result = 0; 426 | 427 | try 428 | { 429 | if(msg == WM_INITDIALOG) 430 | { 431 | CHOOSEFONTA* cf; 432 | cf = cast(CHOOSEFONTA*)lparam; 433 | SetPropA(hwnd, PROP_STR.ptr, cast(HANDLE)cf.lCustData); 434 | fd = cast(FontDialog)cast(void*)cf.lCustData; 435 | } 436 | else 437 | { 438 | fd = cast(FontDialog)cast(void*)GetPropA(hwnd, PROP_STR.ptr); 439 | } 440 | 441 | if(fd) 442 | { 443 | result = fd.hookProc(hwnd, msg, wparam, lparam); 444 | } 445 | } 446 | catch(DThrowable e) 447 | { 448 | Application.onThreadException(e); 449 | } 450 | 451 | return cast(uint)result; 452 | } 453 | 454 | -------------------------------------------------------------------------------- /source/dfl/groupbox.d: -------------------------------------------------------------------------------- 1 | // Written by Christopher E. Miller 2 | // See the included license.txt for copyright and license details. 3 | 4 | 5 | /// 6 | module dfl.groupbox; 7 | 8 | private import dfl.control, dfl.base, dfl.button, dfl.drawing; 9 | private import dfl.internal.winapi, dfl.application, dfl.event; 10 | 11 | 12 | private extern(Windows) void _initButton(); 13 | 14 | 15 | version(NO_DRAG_DROP) 16 | version = DFL_NO_DRAG_DROP; 17 | 18 | 19 | /// 20 | class GroupBox: ControlSuperClass // docmain 21 | { 22 | override @property Rect displayRectangle() // getter 23 | { 24 | // Should only calculate this upon setting the text ? 25 | 26 | int xw = GetSystemMetrics(SM_CXFRAME); 27 | int yw = GetSystemMetrics(SM_CYFRAME); 28 | //const int _textHeight = 13; // Hack. 29 | return Rect(xw, yw + _textHeight, clientSize.width - xw * 2, clientSize.height - yw - _textHeight - yw); 30 | } 31 | 32 | 33 | override @property Size defaultSize() // getter 34 | { 35 | return Size(200, 100); 36 | } 37 | 38 | 39 | version(DFL_NO_DRAG_DROP) {} else 40 | { 41 | override @property void allowDrop(bool dyes) // setter 42 | { 43 | //if(dyes) 44 | // throw new DflException("Cannot drop on a group box"); 45 | assert(!dyes, "Cannot drop on a group box"); 46 | } 47 | 48 | alias Control.allowDrop allowDrop; // Overload. 49 | } 50 | 51 | 52 | this() 53 | { 54 | _initButton(); 55 | 56 | if(DEFTEXTHEIGHT_INIT == _defTextHeight) 57 | { 58 | //_recalcTextHeight(defaultFont); 59 | _recalcTextHeight(font); 60 | _defTextHeight = _textHeight; 61 | } 62 | _textHeight = _defTextHeight; 63 | 64 | wstyle |= BS_GROUPBOX /+ | WS_TABSTOP +/; // Should WS_TABSTOP be set? 65 | //wstyle |= BS_GROUPBOX | WS_TABSTOP; 66 | //wexstyle |= WS_EX_CONTROLPARENT; // ? 67 | wclassStyle = buttonClassStyle; 68 | ctrlStyle |= ControlStyles.CONTAINER_CONTROL; 69 | } 70 | 71 | 72 | protected override void onFontChanged(EventArgs ea) 73 | { 74 | _dispChanged(); 75 | 76 | super.onFontChanged(ea); 77 | } 78 | 79 | 80 | protected override void onHandleCreated(EventArgs ea) 81 | { 82 | super.onHandleCreated(ea); 83 | 84 | _dispChanged(); 85 | } 86 | 87 | 88 | protected override void createParams(ref CreateParams cp) 89 | { 90 | super.createParams(cp); 91 | 92 | cp.className = BUTTON_CLASSNAME; 93 | } 94 | 95 | 96 | protected override void wndProc(ref Message msg) 97 | { 98 | switch(msg.msg) 99 | { 100 | case WM_NCHITTEST: 101 | Control._defWndProc(msg); 102 | break; 103 | 104 | default: 105 | super.wndProc(msg); 106 | } 107 | } 108 | 109 | 110 | protected override void onPaintBackground(PaintEventArgs ea) 111 | { 112 | //Control.onPaintBackground(ea); // DMD 0.106: not accessible. 113 | 114 | RECT rect; 115 | ea.clipRectangle.getRect(&rect); 116 | FillRect(ea.graphics.handle, &rect, hbrBg); 117 | } 118 | 119 | 120 | protected override void prevWndProc(ref Message msg) 121 | { 122 | //msg.result = CallWindowProcA(buttonPrevWndProc, msg.hWnd, msg.msg, msg.wParam, msg.lParam); 123 | msg.result = dfl.internal.utf.callWindowProc(buttonPrevWndProc, msg.hWnd, msg.msg, msg.wParam, msg.lParam); 124 | 125 | // Work around a Windows issue... 126 | if(WM_PAINT == msg.msg) 127 | { 128 | auto hmuxt = GetModuleHandleA("uxtheme.dll"); 129 | if(hmuxt) 130 | { 131 | auto isAppThemed = cast(typeof(&IsAppThemed))GetProcAddress(hmuxt, "IsAppThemed"); 132 | if(isAppThemed && isAppThemed()) 133 | { 134 | auto txt = text; 135 | if(txt.length) 136 | { 137 | auto openThemeData = cast(typeof(&OpenThemeData))GetProcAddress(hmuxt, "OpenThemeData"); 138 | HTHEME htd; 139 | if(openThemeData 140 | && HTHEME.init != (htd = openThemeData(msg.hWnd, "Button"))) 141 | { 142 | HDC hdc = cast(HDC)msg.wParam; 143 | //PAINTSTRUCT ps; 144 | bool gotdc = false; 145 | if(!hdc) 146 | { 147 | //hdc = BeginPaint(msg.hWnd, &ps); 148 | gotdc = true; 149 | hdc = GetDC(msg.hWnd); 150 | } 151 | try 152 | { 153 | scope g = new Graphics(hdc, false); // Not owned. 154 | auto f = font; 155 | scope tfmt = new TextFormat(TextFormatFlags.SINGLE_LINE); 156 | 157 | Color c; 158 | COLORREF cr; 159 | auto getThemeColor = cast(typeof(&GetThemeColor))GetProcAddress(hmuxt, "GetThemeColor"); 160 | auto gtcState = enabled ? (1 /*PBS_NORMAL*/) : (2 /*GBS_DISABLED*/); 161 | if(getThemeColor 162 | && 0 == getThemeColor(htd, 4 /*BP_GROUPBOX*/, gtcState, 3803 /*TMT_TEXTCOLOR*/, &cr)) 163 | c = Color.fromRgb(cr); 164 | else 165 | c = enabled ? foreColor : SystemColors.grayText; // ? 166 | 167 | Size tsz = g.measureText(txt, f, tfmt); 168 | 169 | g.fillRectangle(backColor, 8, 0, 2 + tsz.width + 2, tsz.height + 2); 170 | g.drawText(txt, f, c, Rect(8 + 2, 0, tsz.width, tsz.height), tfmt); 171 | } 172 | finally 173 | { 174 | //if(ps.hdc) 175 | // EndPaint(msg.hWnd, &ps); 176 | if(gotdc) 177 | ReleaseDC(msg.hWnd, hdc); 178 | 179 | auto closeThemeData = cast(typeof(&CloseThemeData))GetProcAddress(hmuxt, "CloseThemeData"); 180 | assert(closeThemeData !is null); 181 | closeThemeData(htd); 182 | } 183 | } 184 | } 185 | } 186 | } 187 | } 188 | } 189 | 190 | 191 | private: 192 | 193 | enum int DEFTEXTHEIGHT_INIT = -1; 194 | static int _defTextHeight = DEFTEXTHEIGHT_INIT; 195 | int _textHeight = -1; 196 | 197 | 198 | void _recalcTextHeight(Font f) 199 | { 200 | _textHeight = cast(int)f.getSize(GraphicsUnit.PIXEL); 201 | } 202 | 203 | 204 | void _dispChanged() 205 | { 206 | int old = _textHeight; 207 | _recalcTextHeight(font); 208 | if(old != _textHeight) 209 | { 210 | //if(isHandleCreated) 211 | { 212 | // Display area changed... 213 | // ? 214 | suspendLayout(); 215 | resumeLayout(true); 216 | } 217 | } 218 | } 219 | } 220 | 221 | -------------------------------------------------------------------------------- /source/dfl/imagelist.d: -------------------------------------------------------------------------------- 1 | // Written by Christopher E. Miller 2 | // See the included license.txt for copyright and license details. 3 | 4 | 5 | /// 6 | module dfl.imagelist; 7 | 8 | import dfl.base, dfl.drawing, dfl.internal.winapi; 9 | import dfl.collections; 10 | 11 | 12 | version(DFL_NO_IMAGELIST) 13 | { 14 | } 15 | else 16 | { 17 | /// 18 | class ImageList // docmain 19 | { 20 | /// 21 | class ImageCollection 22 | { 23 | protected this() 24 | { 25 | } 26 | 27 | 28 | void insert(int index, Image img) 29 | { 30 | if(index >= _images.length) 31 | { 32 | add(img); 33 | } 34 | else 35 | { 36 | assert(0, "Must add images to the end of the image list"); 37 | } 38 | } 39 | 40 | 41 | final void addStrip(Image img) 42 | { 43 | HGDIOBJ hgo; 44 | if(1 != img._imgtype(&hgo)) 45 | { 46 | debug 47 | { 48 | assert(0, "Image list: addStrip needs bitmap"); 49 | } 50 | else 51 | { 52 | _unableimg(); 53 | } 54 | } 55 | 56 | auto sz = imageSize; 57 | if(img.height != sz.height 58 | || img.width % sz.width) 59 | { 60 | debug 61 | { 62 | assert(0, "Image list: invalid image size"); 63 | } 64 | else 65 | { 66 | _unableimg(); 67 | } 68 | } 69 | int num = img.width / sz.width; 70 | 71 | /+ 72 | if(1 == num) 73 | { 74 | add(img); 75 | return; 76 | } 77 | +/ 78 | 79 | auto _hdl = handle; // _addhbitmap needs the handle! Could avoid this in the future. 80 | _addhbitmap(hgo); 81 | 82 | int x = 0; 83 | for(; num; num--) 84 | { 85 | auto sp = new StripPart(); 86 | sp.origImg = img; 87 | sp.hbm = hgo; 88 | sp.partBounds = Rect(x, 0, sz.width, sz.height); 89 | 90 | _images ~= sp; 91 | 92 | x += sz.width; 93 | } 94 | } 95 | 96 | 97 | package: 98 | 99 | Image[] _images; 100 | 101 | 102 | static class StripPart: Image 103 | { 104 | override @property Size size() // getter 105 | { 106 | return partBounds.size; 107 | } 108 | 109 | 110 | override void draw(Graphics g, Point pt) 111 | { 112 | HDC memdc; 113 | memdc = CreateCompatibleDC(g.handle); 114 | try 115 | { 116 | HGDIOBJ hgo; 117 | hgo = SelectObject(memdc, hbm); 118 | BitBlt(g.handle, pt.x, pt.y, partBounds.width, partBounds.height, memdc, partBounds.x, partBounds.y, SRCCOPY); 119 | SelectObject(memdc, hgo); // Old bitmap. 120 | } 121 | finally 122 | { 123 | DeleteDC(memdc); 124 | } 125 | } 126 | 127 | 128 | override void drawStretched(Graphics g, Rect r) 129 | { 130 | HDC memdc; 131 | memdc = CreateCompatibleDC(g.handle); 132 | try 133 | { 134 | HGDIOBJ hgo; 135 | int lstretch; 136 | hgo = SelectObject(memdc, hbm); 137 | lstretch = SetStretchBltMode(g.handle, COLORONCOLOR); 138 | StretchBlt(g.handle, r.x, r.y, r.width, r.height, 139 | memdc, partBounds.x, partBounds.y, partBounds.width, partBounds.height, SRCCOPY); 140 | SetStretchBltMode(g.handle, lstretch); 141 | SelectObject(memdc, hgo); // Old bitmap. 142 | } 143 | finally 144 | { 145 | DeleteDC(memdc); 146 | } 147 | } 148 | 149 | 150 | Image origImg; // Hold this so the HBITMAP doesn't get collected. 151 | HBITMAP hbm; 152 | Rect partBounds; 153 | } 154 | 155 | 156 | void _adding(size_t idx, Image val) 157 | { 158 | assert(val !is null); 159 | 160 | switch(val._imgtype(null)) 161 | { 162 | case 1: 163 | case 2: 164 | break; 165 | default: 166 | debug 167 | { 168 | assert(0, "Image list: invalid image type"); 169 | } 170 | else 171 | { 172 | _unableimg(); 173 | } 174 | } 175 | 176 | if(val.size != imageSize) 177 | { 178 | debug 179 | { 180 | assert(0, "Image list: invalid image size"); 181 | } 182 | else 183 | { 184 | _unableimg(); 185 | } 186 | } 187 | } 188 | 189 | 190 | void _added(size_t idx, Image val) 191 | { 192 | if(isHandleCreated) 193 | { 194 | //if(idx >= _images.length) // Can't test for this here because -val- is already added to the array. 195 | _addimg(val); 196 | } 197 | } 198 | 199 | 200 | void _removed(size_t idx, Image val) 201 | { 202 | if(isHandleCreated) 203 | { 204 | if(size_t.max == idx) // Clear all. 205 | { 206 | imageListRemove(handle, -1); 207 | } 208 | else 209 | { 210 | imageListRemove(handle, cast(int)idx); 211 | } 212 | } 213 | } 214 | 215 | 216 | public: 217 | 218 | mixin ListWrapArray!(Image, _images, 219 | _adding, _added, 220 | _blankListCallback!(Image), _removed, 221 | false, false, false); 222 | } 223 | 224 | 225 | this() 226 | { 227 | InitCommonControls(); 228 | 229 | _cimages = new ImageCollection(); 230 | _transcolor = Color.transparent; 231 | } 232 | 233 | 234 | /// 235 | final @property void colorDepth(ColorDepth depth) // setter 236 | { 237 | assert(!isHandleCreated); 238 | 239 | this._depth = depth; 240 | } 241 | 242 | /// ditto 243 | final @property ColorDepth colorDepth() // getter 244 | { 245 | return _depth; 246 | } 247 | 248 | 249 | /// 250 | final @property void transparentColor(Color tc) // setter 251 | { 252 | assert(!isHandleCreated); 253 | 254 | _transcolor = tc; 255 | } 256 | 257 | /// ditto 258 | final @property Color transparentColor() // getter 259 | { 260 | return _transcolor; 261 | } 262 | 263 | 264 | /// 265 | final @property void imageSize(Size sz) // setter 266 | { 267 | assert(!isHandleCreated); 268 | 269 | assert(sz.width && sz.height); 270 | 271 | _w = sz.width; 272 | _h = sz.height; 273 | } 274 | 275 | /// ditto 276 | final @property Size imageSize() // getter 277 | { 278 | return Size(_w, _h); 279 | } 280 | 281 | 282 | /// 283 | final @property ImageCollection images() // getter 284 | { 285 | return _cimages; 286 | } 287 | 288 | 289 | /// 290 | final @property void tag(Object t) // setter 291 | { 292 | this._tag = t; 293 | } 294 | 295 | /// ditto 296 | final @property Object tag() // getter 297 | { 298 | return this._tag; 299 | } 300 | 301 | 302 | /+ // Actually, forget about these; just draw with the actual images. 303 | /// 304 | final void draw(Graphics g, Point pt, int index) 305 | { 306 | return draw(g, pt.x, pt.y, index); 307 | } 308 | 309 | /// ditto 310 | final void draw(Graphics g, int x, int y, int index) 311 | { 312 | imageListDraw(handle, index, g.handle, x, y, ILD_NORMAL); 313 | } 314 | 315 | /// ditto 316 | // stretch 317 | final void draw(Graphics g, int x, int y, int width, int height, int index) 318 | { 319 | // ImageList_DrawEx operates differently if the width or height is zero 320 | // so bail out if zero and pretend the zero size image was drawn. 321 | if(!width) 322 | return; 323 | if(!height) 324 | return; 325 | 326 | imageListDrawEx(handle, index, g.handle, x, y, width, height, 327 | CLR_NONE, CLR_NONE, ILD_NORMAL); // ? 328 | } 329 | +/ 330 | 331 | 332 | /// 333 | final @property bool isHandleCreated() // getter 334 | { 335 | return HIMAGELIST.init != _hil; 336 | } 337 | 338 | deprecated alias isHandleCreated handleCreated; 339 | 340 | 341 | /// 342 | final @property HIMAGELIST handle() // getter 343 | { 344 | if(!isHandleCreated) 345 | _createimagelist(); 346 | return _hil; 347 | } 348 | 349 | 350 | /// 351 | void dispose() 352 | { 353 | return dispose(true); 354 | } 355 | 356 | /// ditto 357 | void dispose(bool disposing) 358 | { 359 | if(isHandleCreated) 360 | imageListDestroy(_hil); 361 | _hil = HIMAGELIST.init; 362 | 363 | if(disposing) 364 | { 365 | //_cimages._images = null; // Not GC-safe in dtor. 366 | //_cimages = null; // Could cause bad things. 367 | } 368 | } 369 | 370 | 371 | ~this() 372 | { 373 | dispose(); 374 | } 375 | 376 | 377 | private: 378 | 379 | ColorDepth _depth = ColorDepth.DEPTH_8BIT; 380 | Color _transcolor; 381 | ImageCollection _cimages; 382 | HIMAGELIST _hil; 383 | int _w = 16, _h = 16; 384 | Object _tag; 385 | 386 | 387 | void _createimagelist() 388 | { 389 | if(isHandleCreated) 390 | { 391 | imageListDestroy(_hil); 392 | _hil = HIMAGELIST.init; 393 | } 394 | 395 | UINT flags = ILC_MASK; 396 | switch(_depth) 397 | { 398 | case ColorDepth.DEPTH_4BIT: flags |= ILC_COLOR4; break; 399 | default: case ColorDepth.DEPTH_8BIT: flags |= ILC_COLOR8; break; 400 | case ColorDepth.DEPTH_16BIT: flags |= ILC_COLOR16; break; 401 | case ColorDepth.DEPTH_24BIT: flags |= ILC_COLOR24; break; 402 | case ColorDepth.DEPTH_32BIT: flags |= ILC_COLOR32; break; 403 | } 404 | 405 | // Note: cGrow is not a limit, but how many images to preallocate each grow. 406 | _hil = imageListCreate(_w, _h, flags, cast(int)_cimages._images.length,cast(int) (4 + _cimages._images.length / 4)); 407 | if(!_hil) 408 | throw new DflException("Unable to create image list"); 409 | 410 | foreach(img; _cimages._images) 411 | { 412 | _addimg(img); 413 | } 414 | } 415 | 416 | 417 | void _unableimg() 418 | { 419 | throw new DflException("Unable to add image to image list"); 420 | } 421 | 422 | 423 | int _addimg(Image img) 424 | { 425 | assert(isHandleCreated); 426 | 427 | HGDIOBJ hgo; 428 | int result; 429 | switch(img._imgtype(&hgo)) 430 | { 431 | case 1: 432 | result = _addhbitmap(hgo); 433 | break; 434 | 435 | case 2: 436 | result = imageListAddIcon(_hil, cast(HICON)hgo); 437 | break; 438 | 439 | default: 440 | result = -1; 441 | } 442 | 443 | //if(-1 == result) 444 | // _unableimg(); 445 | return result; 446 | } 447 | 448 | int _addhbitmap(HBITMAP hbm) 449 | { 450 | assert(isHandleCreated); 451 | 452 | COLORREF cr; 453 | if(_transcolor == Color.empty 454 | || _transcolor == Color.transparent) 455 | { 456 | cr = CLR_NONE; // ? 457 | } 458 | else 459 | { 460 | cr = _transcolor.toRgb(); 461 | } 462 | return imageListAddMasked(_hil, cast(HBITMAP)hbm, cr); 463 | } 464 | } 465 | 466 | 467 | private extern(Windows) 468 | { 469 | // This was the only way I could figure out how to use the current actctx (Windows issue). 470 | 471 | HIMAGELIST imageListCreate( 472 | int cx, int cy, UINT flags, int cInitial, int cGrow) 473 | { 474 | alias typeof(&ImageList_Create) TProc; 475 | static TProc proc = null; 476 | if(!proc) 477 | proc = cast(typeof(proc))GetProcAddress(GetModuleHandleA("comctl32.dll"), "ImageList_Create"); 478 | return proc(cx, cy, flags, cInitial, cGrow); 479 | } 480 | 481 | int imageListAddIcon( 482 | HIMAGELIST himl, HICON hicon) 483 | { 484 | alias typeof(&ImageList_AddIcon) TProc; 485 | static TProc proc = null; 486 | if(!proc) 487 | proc = cast(typeof(proc))GetProcAddress(GetModuleHandleA("comctl32.dll"), "ImageList_AddIcon"); 488 | return proc(himl, hicon); 489 | } 490 | 491 | int imageListAddMasked( 492 | HIMAGELIST himl, HBITMAP hbmImage, COLORREF crMask) 493 | { 494 | alias typeof(&ImageList_AddMasked) TProc; 495 | static TProc proc = null; 496 | if(!proc) 497 | proc = cast(typeof(proc))GetProcAddress(GetModuleHandleA("comctl32.dll"), "ImageList_AddMasked"); 498 | return proc(himl, hbmImage, crMask); 499 | } 500 | 501 | BOOL imageListRemove( 502 | HIMAGELIST himl, int i) 503 | { 504 | alias typeof(&ImageList_Remove) TProc; 505 | static TProc proc = null; 506 | if(!proc) 507 | proc = cast(typeof(proc))GetProcAddress(GetModuleHandleA("comctl32.dll"), "ImageList_Remove"); 508 | return proc(himl, i); 509 | } 510 | 511 | BOOL imageListDestroy( 512 | HIMAGELIST himl) 513 | { 514 | alias typeof(&ImageList_Destroy) TProc; 515 | static TProc proc = null; 516 | if(!proc) 517 | proc = cast(typeof(proc))GetProcAddress(GetModuleHandleA("comctl32.dll"), "ImageList_Destroy"); 518 | return proc(himl); 519 | } 520 | } 521 | } 522 | 523 | -------------------------------------------------------------------------------- /source/dfl/internal/clib.d: -------------------------------------------------------------------------------- 1 | // Public domain. 2 | 3 | 4 | module dfl.internal.clib; 5 | 6 | 7 | public import core.stdc.stdlib, 8 | core.stdc.string, 9 | core.stdc.stdint, // Mostly the same as the C interface. 10 | core.stdc.stdio; 11 | 12 | alias core.stdc.stdio.printf cprintf; 13 | -------------------------------------------------------------------------------- /source/dfl/internal/com.d: -------------------------------------------------------------------------------- 1 | // Written by Christopher E. Miller 2 | // See the included license.txt for copyright and license details. 3 | 4 | 5 | module dfl.internal.com; 6 | 7 | private import dfl.internal.winapi, dfl.internal.wincom, dfl.internal.dlib; 8 | 9 | 10 | version(DFL_TANGO_SEEK_COMPAT) 11 | { 12 | } 13 | else 14 | { 15 | version = DFL_TANGO_NO_SEEK_COMPAT; 16 | } 17 | 18 | 19 | // Importing dfl.application here causes the compiler to crash. 20 | //import dfl.application; 21 | private extern(C) 22 | { 23 | size_t C_refCountInc(void* p); 24 | size_t C_refCountDec(void* p); 25 | } 26 | 27 | 28 | // Won't be killed by GC if not referenced in D and the refcount is > 0. 29 | class DflComObject: ComObject // package 30 | { 31 | extern(Windows): 32 | 33 | override ULONG AddRef() 34 | { 35 | //cprintf("AddRef `%.*s`\n", cast(int)toString().length, toString().ptr); 36 | return cast(ULONG)C_refCountInc(cast(void*)this); 37 | } 38 | 39 | override UINT Release() 40 | { 41 | //cprintf("Release `%.*s`\n", cast(int)toString().length, toString().ptr); 42 | return cast(ULONG)C_refCountDec(cast(void*)this); 43 | } 44 | } 45 | 46 | 47 | class DStreamToIStream: DflComObject, dfl.internal.wincom.IStream 48 | { 49 | this(DStream sourceDStream) 50 | { 51 | this.stm = sourceDStream; 52 | } 53 | 54 | 55 | extern(Windows): 56 | 57 | override HRESULT QueryInterface(IID* riid, void** ppv) 58 | { 59 | if(*riid == _IID_IStream) 60 | { 61 | *ppv = cast(void*)cast(dfl.internal.wincom.IStream)this; 62 | AddRef(); 63 | return S_OK; 64 | } 65 | else if(*riid == _IID_ISequentialStream) 66 | { 67 | *ppv = cast(void*)cast(dfl.internal.wincom.ISequentialStream)this; 68 | AddRef(); 69 | return S_OK; 70 | } 71 | else if(*riid == _IID_IUnknown) 72 | { 73 | *ppv = cast(void*)cast(IUnknown)this; 74 | AddRef(); 75 | return S_OK; 76 | } 77 | else 78 | { 79 | *ppv = null; 80 | return E_NOINTERFACE; 81 | } 82 | } 83 | 84 | 85 | HRESULT Read(void* pv, ULONG cb, ULONG* pcbRead) 86 | { 87 | ULONG read; 88 | HRESULT result = S_OK; 89 | 90 | try 91 | { 92 | read = cast(ULONG)stm.readBlock(pv, cb); 93 | } 94 | catch(DStreamException e) 95 | { 96 | result = S_FALSE; // ? 97 | } 98 | 99 | if(pcbRead) 100 | *pcbRead = read; 101 | //if(!read) 102 | // result = S_FALSE; 103 | return result; 104 | } 105 | 106 | 107 | HRESULT Write(void* pv, ULONG cb, ULONG* pcbWritten) 108 | { 109 | ULONG written; 110 | HRESULT result = S_OK; 111 | 112 | try 113 | { 114 | if(!stm.writeable) 115 | return E_NOTIMPL; 116 | written = cast(ULONG)stm.writeBlock(pv, cb); 117 | } 118 | catch(DStreamException e) 119 | { 120 | result = S_FALSE; // ? 121 | } 122 | 123 | if(pcbWritten) 124 | *pcbWritten = written; 125 | //if(!written) 126 | // result = S_FALSE; 127 | return result; 128 | } 129 | 130 | 131 | version(DFL_TANGO_NO_SEEK_COMPAT) 132 | { 133 | } 134 | else 135 | { 136 | long _fakepos = 0; 137 | } 138 | 139 | 140 | HRESULT Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition) 141 | { 142 | HRESULT result = S_OK; 143 | 144 | //cprintf("seek move=%u, origin=0x%x\n", cast(uint)dlibMove.QuadPart, dwOrigin); 145 | 146 | try 147 | { 148 | if(!stm.seekable) 149 | //return S_FALSE; // ? 150 | return E_NOTIMPL; // ? 151 | 152 | ulong pos; 153 | switch(dwOrigin) 154 | { 155 | case STREAM_SEEK_SET: 156 | pos = stm.seekSet(dlibMove.QuadPart); 157 | if(plibNewPosition) 158 | plibNewPosition.QuadPart = pos; 159 | break; 160 | 161 | case STREAM_SEEK_CUR: 162 | pos = stm.seekCur(dlibMove.QuadPart); 163 | if(plibNewPosition) 164 | plibNewPosition.QuadPart = pos; 165 | break; 166 | 167 | case STREAM_SEEK_END: 168 | pos = stm.seekEnd(dlibMove.QuadPart); 169 | if(plibNewPosition) 170 | plibNewPosition.QuadPart = pos; 171 | break; 172 | 173 | default: 174 | result = STG_E_INVALIDFUNCTION; 175 | } 176 | } 177 | catch(DStreamException e) 178 | { 179 | result = S_FALSE; // ? 180 | } 181 | 182 | return result; 183 | } 184 | 185 | 186 | HRESULT SetSize(ULARGE_INTEGER libNewSize) 187 | { 188 | return E_NOTIMPL; 189 | } 190 | 191 | 192 | HRESULT CopyTo(IStream pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten) 193 | { 194 | // TODO: implement. 195 | return E_NOTIMPL; 196 | } 197 | 198 | 199 | HRESULT Commit(DWORD grfCommitFlags) 200 | { 201 | // Ignore -grfCommitFlags- and just flush the stream.. 202 | //stm.flush(); 203 | stm.flush(); 204 | return S_OK; // ? 205 | } 206 | 207 | 208 | HRESULT Revert() 209 | { 210 | return E_NOTIMPL; // ? S_FALSE ? 211 | } 212 | 213 | 214 | HRESULT LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) 215 | { 216 | return E_NOTIMPL; 217 | } 218 | 219 | 220 | HRESULT UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) 221 | { 222 | return E_NOTIMPL; 223 | } 224 | 225 | 226 | HRESULT Stat(STATSTG* pstatstg, DWORD grfStatFlag) 227 | { 228 | return E_NOTIMPL; // ? 229 | } 230 | 231 | 232 | HRESULT Clone(IStream* ppstm) 233 | { 234 | // Cloned stream needs its own seek position. 235 | return E_NOTIMPL; // ? 236 | } 237 | 238 | 239 | extern(D): 240 | 241 | private: 242 | DStream stm; 243 | } 244 | 245 | class MemoryIStream: DflComObject, dfl.internal.wincom.IStream 246 | { 247 | this(void[] memory) 248 | { 249 | this.mem = memory; 250 | } 251 | 252 | 253 | extern(Windows): 254 | 255 | override HRESULT QueryInterface(IID* riid, void** ppv) 256 | { 257 | if(*riid == _IID_IStream) 258 | { 259 | *ppv = cast(void*)cast(dfl.internal.wincom.IStream)this; 260 | AddRef(); 261 | return S_OK; 262 | } 263 | else if(*riid == _IID_ISequentialStream) 264 | { 265 | *ppv = cast(void*)cast(dfl.internal.wincom.ISequentialStream)this; 266 | AddRef(); 267 | return S_OK; 268 | } 269 | else if(*riid == _IID_IUnknown) 270 | { 271 | *ppv = cast(void*)cast(IUnknown)this; 272 | AddRef(); 273 | return S_OK; 274 | } 275 | else 276 | { 277 | *ppv = null; 278 | return E_NOINTERFACE; 279 | } 280 | } 281 | 282 | 283 | HRESULT Read(void* pv, ULONG cb, ULONG* pcbRead) 284 | { 285 | // Shouldn't happen unless the mem changes, which doesn't happen yet. 286 | if(seekpos > mem.length) 287 | return S_FALSE; // ? 288 | 289 | size_t count = mem.length - seekpos; 290 | if(count > cb) 291 | count = cb; 292 | 293 | pv[0 .. count] = mem[seekpos .. seekpos + count]; 294 | seekpos += count; 295 | 296 | if(pcbRead) 297 | *pcbRead = cast(ULONG)count; 298 | return S_OK; 299 | } 300 | 301 | 302 | HRESULT Write(void* pv, ULONG cb, ULONG* pcbWritten) 303 | { 304 | //return STG_E_ACCESSDENIED; 305 | return E_NOTIMPL; 306 | } 307 | 308 | 309 | HRESULT Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition) 310 | { 311 | //cprintf("seek move=%u, origin=0x%x\n", cast(uint)dlibMove.QuadPart, dwOrigin); 312 | 313 | auto toPos = cast(long)dlibMove.QuadPart; 314 | switch(dwOrigin) 315 | { 316 | case STREAM_SEEK_SET: 317 | break; 318 | 319 | case STREAM_SEEK_CUR: 320 | toPos = cast(long)seekpos + toPos; 321 | break; 322 | 323 | case STREAM_SEEK_END: 324 | toPos = cast(long)mem.length - toPos; 325 | break; 326 | 327 | default: 328 | return STG_E_INVALIDFUNCTION; 329 | } 330 | 331 | if(withinbounds(toPos)) 332 | { 333 | seekpos = cast(size_t)toPos; 334 | if(plibNewPosition) 335 | plibNewPosition.QuadPart = seekpos; 336 | return S_OK; 337 | } 338 | else 339 | { 340 | return 0x80030005; //STG_E_ACCESSDENIED; // Seeking past end needs write access. 341 | } 342 | } 343 | 344 | 345 | HRESULT SetSize(ULARGE_INTEGER libNewSize) 346 | { 347 | return E_NOTIMPL; 348 | } 349 | 350 | 351 | HRESULT CopyTo(IStream pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten) 352 | { 353 | // TODO: implement. 354 | return E_NOTIMPL; 355 | } 356 | 357 | 358 | HRESULT Commit(DWORD grfCommitFlags) 359 | { 360 | return S_OK; // ? 361 | } 362 | 363 | 364 | HRESULT Revert() 365 | { 366 | return E_NOTIMPL; // ? S_FALSE ? 367 | } 368 | 369 | 370 | HRESULT LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) 371 | { 372 | return E_NOTIMPL; 373 | } 374 | 375 | 376 | HRESULT UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) 377 | { 378 | return E_NOTIMPL; 379 | } 380 | 381 | 382 | HRESULT Stat(STATSTG* pstatstg, DWORD grfStatFlag) 383 | { 384 | return E_NOTIMPL; // ? 385 | } 386 | 387 | 388 | HRESULT Clone(IStream* ppstm) 389 | { 390 | // Cloned stream needs its own seek position. 391 | return E_NOTIMPL; // ? 392 | } 393 | 394 | 395 | extern(D): 396 | 397 | private: 398 | void[] mem; 399 | size_t seekpos = 0; 400 | 401 | 402 | bool withinbounds(long pos) 403 | { 404 | if(pos < seekpos.min || pos > seekpos.max) 405 | return false; 406 | // Note: it IS within bounds if it's AT the end, it just can't read there. 407 | return cast(size_t)pos <= mem.length; 408 | } 409 | } 410 | 411 | -------------------------------------------------------------------------------- /source/dfl/internal/d1.d: -------------------------------------------------------------------------------- 1 | // Written by Christopher E. Miller 2 | // See the included license.txt for copyright and license details. 3 | 4 | 5 | module dfl.internal.d1; 6 | 7 | 8 | /// Gets the const type of a type, or the type itself if not supported. 9 | template ConstType(T) 10 | { 11 | alias T ConstType; 12 | } 13 | 14 | -------------------------------------------------------------------------------- /source/dfl/internal/d2.d: -------------------------------------------------------------------------------- 1 | // Written by Christopher E. Miller 2 | // See the included license.txt for copyright and license details. 3 | 4 | 5 | module dfl.internal.d2; 6 | 7 | 8 | /// Gets the const type of a type, or the type itself if not supported. 9 | template ConstType(T) 10 | { 11 | alias const(T) ConstType; 12 | } 13 | 14 | -------------------------------------------------------------------------------- /source/dfl/internal/dlib.d: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2007-2010 Christopher E. Miller 3 | 4 | This software is provided 'as-is', without any express or implied 5 | warranty. In no event will the authors be held liable for any damages 6 | arising from the use of this software. 7 | 8 | Permission is granted to anyone to use this software for any purpose, 9 | including commercial applications, and to alter it and redistribute it 10 | freely, subject to the following restrictions: 11 | 12 | 1. The origin of this software must not be misrepresented; you must not 13 | claim that you wrote the original software. If you use this software 14 | in a product, an acknowledgment in the product documentation would be 15 | appreciated but is not required. 16 | 2. Altered source versions must be plainly marked as such, and must not be 17 | misrepresented as being the original software. 18 | 3. This notice may not be removed or altered from any source distribution. 19 | */ 20 | 21 | 22 | module dfl.internal.dlib; 23 | 24 | 25 | alias typeof(""c[]) Dstring; 26 | alias typeof(""c.ptr) Dstringz; 27 | alias typeof(" "c[0]) Dchar; 28 | alias typeof(""w[]) Dwstring; 29 | alias typeof(""w.ptr) Dwstringz; 30 | alias typeof(" "w[0]) Dwchar; 31 | alias typeof(""d[]) Ddstring; 32 | alias typeof(""d.ptr) Ddstringz; 33 | alias typeof(" "d[0]) Ddchar; 34 | 35 | 36 | version(D_Version2) 37 | { 38 | version = DFL_D2; 39 | version = DFL_D2_AND_ABOVE; 40 | } 41 | else version(D_Version3) 42 | { 43 | version = DFL_D3; 44 | version = DFL_D3_AND_ABOVE; 45 | version = DFL_D2_AND_ABOVE; 46 | } 47 | else version(D_Version4) 48 | { 49 | version = DFL_D4; 50 | version = DFL_D4_AND_ABOVE; 51 | version = DFL_D3_AND_ABOVE; 52 | version = DFL_D2_AND_ABOVE; 53 | } 54 | else 55 | { 56 | version = DFL_D1; 57 | } 58 | //version = DFL_D1_AND_ABOVE; 59 | 60 | 61 | version(DFL_D1) 62 | { 63 | public import dfl.internal.d1; 64 | } 65 | else 66 | { 67 | public import dfl.internal.d2; 68 | } 69 | 70 | 71 | version(DFL_D1) 72 | { 73 | version(DFL_USE_CORE_MEMORY) 74 | { 75 | } 76 | else 77 | { 78 | version = DFL_NO_USE_CORE_MEMORY; 79 | version = _DFL_NO_USE_CORE_EXCEPTION_OUTOFMEMORY_EXCEPTION; 80 | } 81 | 82 | version(DFL_CONV_TO_TEMPLATE) 83 | { 84 | } 85 | else 86 | { 87 | version = DFL_NO_CONV_TO_TEMPLATE; 88 | } 89 | } 90 | 91 | 92 | version(DFL_D2_AND_ABOVE) 93 | { 94 | version(DFL_beforeDMD2020) 95 | { 96 | version = DFL_NO_USE_CORE_MEMORY; 97 | version = _DFL_NO_USE_CORE_EXCEPTION_OUTOFMEMORY_EXCEPTION; 98 | version = _DFL_NO_USE_CORE_EXCEPTION_OUTOFMEMORY_ERROR; 99 | 100 | version = DFL_beforeDMD2021; 101 | version = DFL_beforeDMD2029; 102 | } 103 | 104 | version(DFL_beforeDMD2021) 105 | { 106 | version = _DFL_NO_USE_CORE_EXCEPTION_OUTOFMEMORY_ERROR; 107 | 108 | version = DFL_beforeDMD2029; 109 | } 110 | 111 | version(DFL_beforeDMD2029) 112 | { 113 | version(DFL_CONV_TO_TEMPLATE) 114 | { 115 | } 116 | else 117 | { 118 | version = DFL_NO_CONV_TO_TEMPLATE; 119 | } 120 | } 121 | } 122 | 123 | 124 | version(DFL_NO_USE_CORE_MEMORY) 125 | { 126 | version = _DFL_NO_USE_CORE_EXCEPTION_OUTOFMEMORY_EXCEPTION; 127 | } 128 | 129 | 130 | public import std.traits; 131 | 132 | 133 | alias ReturnType!(Object.opEquals) Dequ; // Since D2 changes mid-stream. 134 | 135 | 136 | Dstring getObjectString(Object o) 137 | { 138 | return o.toString(); 139 | } 140 | 141 | 142 | version(DFL_NO_USE_CORE_MEMORY) 143 | { 144 | private import std.gc; // If you get "module gc cannot read file 'core\memory.d'" then use -version=DFL_NO_USE_CORE_MEMORY 145 | 146 | void gcPin(void* p) { } 147 | void gcUnpin(void* p) { } 148 | 149 | deprecated alias std.gc.genCollect gcGenCollect; 150 | 151 | alias std.gc.fullCollect gcFullCollect; 152 | } 153 | else 154 | { 155 | private import core.memory; // If you get "module gc cannot read file 'std\gc.d'" then use -version=DFL_USE_CORE_MEMORY 156 | 157 | void gcPin(void* p) { } 158 | void gcUnpin(void* p) { } 159 | 160 | deprecated void gcGenCollect() 161 | { 162 | core.memory.GC.collect(); 163 | } 164 | 165 | void gcFullCollect() nothrow 166 | { 167 | try 168 | { 169 | core.memory.GC.collect(); 170 | } 171 | catch (Throwable e) 172 | { 173 | } 174 | } 175 | } 176 | 177 | 178 | private import std.string; 179 | 180 | alias std.string.icmp stringICmp; 181 | 182 | version(DFL_NO_CONV_TO_TEMPLATE) 183 | { 184 | alias std.string.toString stringFromStringz; 185 | } 186 | else 187 | { 188 | version(DFL_DMD2029) 189 | { 190 | Dstring stringFromStringz(Dstringz sz) 191 | { 192 | return std.conv.to!(Dstring, Dstringz)(sz); // D 2.029 193 | } 194 | } 195 | else 196 | { 197 | Dstring stringFromStringz(Dstringz sz) 198 | { 199 | return std.conv.to!(Dstring)(sz); 200 | } 201 | } 202 | 203 | version(DFL_D2_AND_ABOVE) 204 | { 205 | Dstring stringFromStringz(char* sz) 206 | { 207 | return stringFromStringz(cast(Dstringz)sz); 208 | } 209 | } 210 | } 211 | 212 | alias std.string.split stringSplit; 213 | 214 | version(DFL_NO_CONV_TO_TEMPLATE) 215 | { 216 | alias std.string.toString intToString; 217 | } 218 | else 219 | { 220 | Dstring intToString(int i) 221 | { 222 | return to!(Dstring)(i); // D 2.029 223 | } 224 | } 225 | 226 | alias std.algorithm.find charFindInString; 227 | 228 | alias std.string.toStringz stringToStringz; 229 | 230 | Dstring uintToHexString(uint num) 231 | { 232 | return std.string.format("%X", num); 233 | } 234 | 235 | alias std.string.splitLines stringSplitLines; 236 | 237 | 238 | private import std.path; 239 | 240 | alias std.path.dirName pathGetDirName; 241 | 242 | version(D_Version2) 243 | alias std.ascii.newline nativeLineSeparatorString; 244 | else 245 | alias std.path.linesep nativeLineSeparatorString; 246 | 247 | alias std.path.buildPath pathJoin; 248 | 249 | alias std.path.pathSeparator nativePathSeparatorString; 250 | 251 | 252 | version(_DFL_NO_USE_CORE_EXCEPTION_OUTOFMEMORY_EXCEPTION) 253 | { 254 | private import std.outofmemory; 255 | 256 | alias std.outofmemory.OutOfMemoryException OomException; 257 | } 258 | else 259 | { 260 | private import core.exception; 261 | 262 | version(_DFL_NO_USE_CORE_EXCEPTION_OUTOFMEMORY_ERROR) 263 | { 264 | class OomException: core.exception.OutOfMemoryException 265 | { 266 | this() 267 | { 268 | super(null, 0); 269 | } 270 | } 271 | } 272 | else 273 | { 274 | class OomException: core.exception.OutOfMemoryError 275 | { 276 | this() 277 | { 278 | super(null, 0); 279 | } 280 | } 281 | } 282 | } 283 | 284 | 285 | private import std.utf; 286 | 287 | alias std.utf.decode utf8stringGetUtf32char; 288 | 289 | alias std.utf.toUTF8 utf16stringtoUtf8string; 290 | 291 | alias std.utf.toUTF16 utf8stringtoUtf16string; 292 | 293 | alias std.utf.toUTFz!(typeof(Dwstring.init.ptr)) utf8stringToUtf16stringz; 294 | 295 | alias std.utf.toUTF8 utf32stringtoUtf8string; 296 | 297 | alias std.utf.toUTF32 utf8stringtoUtf32string; 298 | 299 | 300 | private import std.uni; 301 | 302 | alias std.uni.toLower utf32charToLower; 303 | 304 | 305 | private import std.conv; 306 | 307 | version(DFL_NO_CONV_TO_TEMPLATE) 308 | { 309 | alias std.conv.toInt stringToInt; 310 | } 311 | else 312 | { 313 | version(DFL_DMD2029) 314 | { 315 | alias std.conv.to!(int, Dstring) stringToInt; // D 2.029 316 | } 317 | else 318 | { 319 | int stringToInt(Dstring s) 320 | { 321 | return std.conv.to!(int)(s); 322 | } 323 | } 324 | } 325 | 326 | 327 | private import std.ascii; 328 | 329 | alias std.ascii.isHexDigit charIsHexDigit; 330 | 331 | 332 | private import std.stream; 333 | 334 | alias std.stream.Stream DStream; 335 | 336 | alias std.stream.OutputStream DOutputStream; 337 | 338 | alias std.stream.StreamException DStreamException; 339 | 340 | 341 | alias Object DObject; 342 | version(DFL_D2_AND_ABOVE) 343 | { 344 | version(DFL_CanThrowObject) 345 | { 346 | alias Object DThrowable; 347 | } 348 | else 349 | { 350 | alias Throwable DThrowable; 351 | } 352 | } 353 | else 354 | { 355 | alias Object DThrowable; 356 | } 357 | 358 | 359 | char* unsafeToStringz(Dstring s) 360 | { 361 | // This is intentionally unsafe, hence the name. 362 | if(!s.ptr[s.length]) 363 | //return s.ptr; 364 | return cast(char*)s.ptr; // Needed in D2. 365 | //return stringToStringz(s); 366 | return cast(char*)stringToStringz(s); // Needed in D2. 367 | } 368 | 369 | -------------------------------------------------------------------------------- /source/dfl/label.d: -------------------------------------------------------------------------------- 1 | // Written by Christopher E. Miller 2 | // See the included license.txt for copyright and license details. 3 | 4 | 5 | /// 6 | module dfl.label; 7 | 8 | private import dfl.base, dfl.control, dfl.internal.winapi, dfl.application, 9 | dfl.event, dfl.drawing, dfl.internal.dlib; 10 | 11 | 12 | /// 13 | class Label: Control // docmain 14 | { 15 | this() 16 | { 17 | resizeRedraw = true; // Word wrap and center correctly. 18 | 19 | tfmt = new TextFormat(TextFormatFlags.WORD_BREAK | TextFormatFlags.LINE_LIMIT); 20 | } 21 | 22 | 23 | /// 24 | @property void borderStyle(BorderStyle bs) // setter 25 | { 26 | final switch(bs) 27 | { 28 | case BorderStyle.FIXED_3D: 29 | _style(_style() & ~WS_BORDER); 30 | _exStyle(_exStyle() | WS_EX_CLIENTEDGE); 31 | break; 32 | 33 | case BorderStyle.FIXED_SINGLE: 34 | _exStyle(_exStyle() & ~WS_EX_CLIENTEDGE); 35 | _style(_style() | WS_BORDER); 36 | break; 37 | 38 | case BorderStyle.NONE: 39 | _style(_style() & ~WS_BORDER); 40 | _exStyle(_exStyle() & ~WS_EX_CLIENTEDGE); 41 | break; 42 | } 43 | 44 | if(isHandleCreated) 45 | { 46 | redrawEntire(); 47 | } 48 | } 49 | 50 | /// ditto 51 | @property BorderStyle borderStyle() // getter 52 | { 53 | if(_exStyle() & WS_EX_CLIENTEDGE) 54 | return BorderStyle.FIXED_3D; 55 | else if(_style() & WS_BORDER) 56 | return BorderStyle.FIXED_SINGLE; 57 | return BorderStyle.NONE; 58 | } 59 | 60 | 61 | /// 62 | final @property void useMnemonic(bool byes) // setter 63 | { 64 | if(byes) 65 | { 66 | tfmt.formatFlags = tfmt.formatFlags & ~TextFormatFlags.NO_PREFIX; 67 | _style(_style() & ~SS_NOPREFIX); 68 | } 69 | else 70 | { 71 | tfmt.formatFlags = tfmt.formatFlags | TextFormatFlags.NO_PREFIX; 72 | _style(_style() | SS_NOPREFIX); 73 | } 74 | 75 | if(isHandleCreated) 76 | invalidate(); 77 | } 78 | 79 | /// ditto 80 | final @property bool useMnemonic() // getter 81 | { 82 | return (tfmt.formatFlags & TextFormatFlags.NO_PREFIX) == 0; 83 | } 84 | 85 | 86 | /// 87 | @property Size preferredSize() // getter 88 | { 89 | Size result; 90 | Graphics g; 91 | g = isHandleCreated ? createGraphics() : Graphics.getScreen(); 92 | result = g.measureText(text, font, tfmt); 93 | g.dispose(); 94 | return result; 95 | } 96 | 97 | 98 | private void doAutoSize(Dstring text) 99 | { 100 | //if(isHandleCreated) 101 | { 102 | clientSize = preferredSize; 103 | } 104 | } 105 | 106 | 107 | override @property void text(Dstring newText) // setter 108 | { 109 | super.text = newText; 110 | 111 | if(autosz) 112 | doAutoSize(newText); 113 | 114 | invalidate(false); 115 | } 116 | 117 | alias Control.text text; // Overload. 118 | 119 | 120 | /// 121 | @property void autoSize(bool byes) // setter 122 | { 123 | if(byes != autosz) 124 | { 125 | autosz = byes; 126 | 127 | if(byes) 128 | { 129 | doAutoSize(text); 130 | } 131 | } 132 | } 133 | 134 | /// ditto 135 | @property bool autoSize() // getter 136 | { 137 | return autosz; 138 | } 139 | 140 | 141 | /// 142 | @property void textAlign(ContentAlignment calign) // setter 143 | { 144 | final switch(calign) 145 | { 146 | case ContentAlignment.TOP_LEFT: 147 | tfmt.alignment = TextAlignment.TOP | TextAlignment.LEFT; 148 | break; 149 | 150 | case ContentAlignment.BOTTOM_CENTER: 151 | tfmt.alignment = TextAlignment.BOTTOM | TextAlignment.CENTER; 152 | break; 153 | 154 | case ContentAlignment.BOTTOM_LEFT: 155 | tfmt.alignment = TextAlignment.BOTTOM | TextAlignment.LEFT; 156 | break; 157 | 158 | case ContentAlignment.BOTTOM_RIGHT: 159 | tfmt.alignment = TextAlignment.BOTTOM | TextAlignment.RIGHT; 160 | break; 161 | 162 | case ContentAlignment.MIDDLE_CENTER: 163 | tfmt.alignment = TextAlignment.MIDDLE | TextAlignment.CENTER; 164 | break; 165 | 166 | case ContentAlignment.MIDDLE_LEFT: 167 | tfmt.alignment = TextAlignment.MIDDLE | TextAlignment.LEFT; 168 | break; 169 | 170 | case ContentAlignment.MIDDLE_RIGHT: 171 | tfmt.alignment = TextAlignment.MIDDLE | TextAlignment.RIGHT; 172 | break; 173 | 174 | case ContentAlignment.TOP_CENTER: 175 | tfmt.alignment = TextAlignment.TOP | TextAlignment.CENTER; 176 | break; 177 | 178 | case ContentAlignment.TOP_RIGHT: 179 | tfmt.alignment = TextAlignment.TOP | TextAlignment.RIGHT; 180 | break; 181 | } 182 | 183 | invalidate(); // ? 184 | } 185 | 186 | /// ditto 187 | @property ContentAlignment textAlign() // getter 188 | { 189 | TextAlignment ta; 190 | ta = tfmt.alignment; 191 | 192 | if(ta & TextAlignment.BOTTOM) 193 | { 194 | if(ta & TextAlignment.RIGHT) 195 | { 196 | return ContentAlignment.BOTTOM_RIGHT; 197 | } 198 | else if(ta & TextAlignment.CENTER) 199 | { 200 | return ContentAlignment.BOTTOM_CENTER; 201 | } 202 | else // Left. 203 | { 204 | return ContentAlignment.BOTTOM_LEFT; 205 | } 206 | } 207 | else if(ta & TextAlignment.MIDDLE) 208 | { 209 | if(ta & TextAlignment.RIGHT) 210 | { 211 | return ContentAlignment.MIDDLE_RIGHT; 212 | } 213 | else if(ta & TextAlignment.CENTER) 214 | { 215 | return ContentAlignment.MIDDLE_CENTER; 216 | } 217 | else // Left. 218 | { 219 | return ContentAlignment.MIDDLE_LEFT; 220 | } 221 | } 222 | else // Top. 223 | { 224 | if(ta & TextAlignment.RIGHT) 225 | { 226 | return ContentAlignment.TOP_RIGHT; 227 | } 228 | else if(ta & TextAlignment.CENTER) 229 | { 230 | return ContentAlignment.TOP_CENTER; 231 | } 232 | else // Left. 233 | { 234 | return ContentAlignment.TOP_LEFT; 235 | } 236 | } 237 | } 238 | 239 | 240 | protected override @property Size defaultSize() // getter 241 | { 242 | return Size(100, 23); 243 | } 244 | 245 | 246 | protected override void onPaint(PaintEventArgs ea) 247 | { 248 | int x, y, w, h; 249 | Dstring text; 250 | 251 | text = this.text; 252 | 253 | if(tfmt.alignment & TextAlignment.MIDDLE) 254 | { 255 | // Graphics.drawText() does not support middle alignment 256 | // if the text is multiline, so need to do extra work. 257 | Size sz; 258 | sz = ea.graphics.measureText(text, font, tfmt); 259 | x = 0; 260 | //if(sz.height >= this.clientSize.height) 261 | // y = 0; 262 | //else 263 | y = (this.clientSize.height - sz.height) / 2; 264 | w = clientSize.width; 265 | h = sz.height; 266 | } 267 | else if(tfmt.alignment & TextAlignment.BOTTOM) 268 | { 269 | // Graphics.drawText() does not support bottom alignment 270 | // if the text is multiline, so need to do extra work. 271 | Size sz; 272 | sz = ea.graphics.measureText(text, font, tfmt); 273 | x = 0; 274 | //if(sz.height >= this.clientSize.height) 275 | // y = 0; 276 | //else 277 | y = this.clientSize.height - sz.height; 278 | w = clientSize.width; 279 | h = sz.height; 280 | } 281 | else 282 | { 283 | x = 0; 284 | y = 0; 285 | w = clientSize.width; 286 | h = clientSize.height; 287 | } 288 | 289 | Color c; 290 | //c = foreColor; 291 | c = foreColor.solidColor(backColor); 292 | 293 | if(enabled) 294 | { 295 | ea.graphics.drawText(text, font, c, Rect(x, y, w, h), tfmt); 296 | } 297 | else 298 | { 299 | version(LABEL_GRAYSTRING) 300 | { 301 | // GrayString() is pretty ugly. 302 | GrayStringA(ea.graphics.handle, null, &_disabledOutputProc, 303 | cast(LPARAM)cast(void*)this, -1, x, y, w, h); 304 | } 305 | else 306 | { 307 | ea.graphics.drawTextDisabled(text, font, c, backColor, Rect(x, y, w, h), tfmt); 308 | } 309 | } 310 | 311 | super.onPaint(ea); 312 | } 313 | 314 | 315 | /+ 316 | protected override void onHandleCreated(EventArgs ea) 317 | { 318 | super.onHandleCreated(ea); 319 | 320 | /+ 321 | if(autosz) 322 | doAutoSize(text); 323 | +/ 324 | } 325 | +/ 326 | 327 | 328 | protected override void onEnabledChanged(EventArgs ea) 329 | { 330 | invalidate(false); 331 | 332 | super.onEnabledChanged(ea); 333 | } 334 | 335 | 336 | protected override void onFontChanged(EventArgs ea) 337 | { 338 | if(autosz) 339 | doAutoSize(text); 340 | 341 | invalidate(false); 342 | 343 | super.onFontChanged(ea); 344 | } 345 | 346 | 347 | protected override void wndProc(ref Message m) 348 | { 349 | switch(m.msg) 350 | { 351 | case WM_GETDLGCODE: 352 | super.wndProc(m); 353 | //if(useMnemonic) 354 | m.result |= DLGC_STATIC; 355 | break; 356 | 357 | default: 358 | super.wndProc(m); 359 | } 360 | } 361 | 362 | 363 | protected override bool processMnemonic(dchar charCode) 364 | { 365 | if(visible && enabled) 366 | { 367 | if(isMnemonic(charCode, text)) 368 | { 369 | select(true, true); 370 | return true; 371 | } 372 | } 373 | return false; 374 | } 375 | 376 | 377 | private: 378 | TextFormat _tfmt; 379 | bool autosz = false; 380 | 381 | 382 | final @property void tfmt(TextFormat tf) // setter 383 | { 384 | _tfmt = tf; 385 | } 386 | 387 | 388 | final @property TextFormat tfmt() // getter 389 | { 390 | /+ 391 | // This causes it to invert. 392 | if(rightToLeft) 393 | _tfmt.formatFlags = _tfmt.formatFlags | TextFormatFlags.DIRECTION_RIGHT_TO_LEFT; 394 | else 395 | _tfmt.formatFlags = _tfmt.formatFlags & ~TextFormatFlags.DIRECTION_RIGHT_TO_LEFT; 396 | +/ 397 | 398 | return _tfmt; 399 | } 400 | } 401 | 402 | 403 | version(LABEL_GRAYSTRING) 404 | { 405 | private extern(Windows) BOOL _disabledOutputProc(HDC hdc, LPARAM lpData, int cchData) 406 | { 407 | BOOL result = TRUE; 408 | try 409 | { 410 | scope Graphics g = new Graphics(hdc, false); 411 | Label l; 412 | with(l = cast(Label)cast(void*)lpData) 413 | { 414 | g.drawText(text, font, foreColor, 415 | Rect(0, 0, clientSize.width, clientSize.height), tfmt); 416 | } 417 | } 418 | catch(DThrowable e) 419 | { 420 | Application.onThreadException(e); 421 | result = FALSE; 422 | } 423 | return result; 424 | } 425 | } 426 | 427 | -------------------------------------------------------------------------------- /source/dfl/messagebox.d: -------------------------------------------------------------------------------- 1 | // Written by Christopher E. Miller 2 | // See the included license.txt for copyright and license details. 3 | 4 | 5 | /// 6 | module dfl.messagebox; 7 | 8 | private import dfl.internal.winapi, dfl.internal.dlib, dfl.base; 9 | 10 | 11 | /// 12 | enum MsgBoxButtons 13 | { 14 | ABORT_RETRY_IGNORE = MB_ABORTRETRYIGNORE, /// 15 | OK = MB_OK, /// ditto 16 | OK_CANCEL = MB_OKCANCEL, /// ditto 17 | RETRY_CANCEL = MB_RETRYCANCEL, /// ditto 18 | YES_NO = MB_YESNO, /// ditto 19 | YES_NO_CANCEL = MB_YESNOCANCEL, /// ditto 20 | } 21 | 22 | 23 | /// 24 | enum MsgBoxIcon 25 | { 26 | NONE = 0, /// 27 | 28 | ASTERISK = MB_ICONASTERISK, /// ditto 29 | ERROR = MB_ICONERROR, /// ditto 30 | EXCLAMATION = MB_ICONEXCLAMATION, /// ditto 31 | HAND = MB_ICONHAND, /// ditto 32 | INFORMATION = MB_ICONINFORMATION, /// ditto 33 | QUESTION = MB_ICONQUESTION, /// ditto 34 | STOP = MB_ICONSTOP, /// ditto 35 | WARNING = MB_ICONWARNING, /// ditto 36 | } 37 | 38 | 39 | enum MsgBoxDefaultButton 40 | { 41 | BUTTON1 = MB_DEFBUTTON1, /// 42 | BUTTON2 = MB_DEFBUTTON2, /// ditto 43 | BUTTON3 = MB_DEFBUTTON3, /// ditto 44 | 45 | // Extra. 46 | BUTTON4 = MB_DEFBUTTON4, 47 | } 48 | 49 | 50 | /// 51 | enum MsgBoxOptions 52 | { 53 | DEFAULT_DESKTOP_ONLY = MB_DEFAULT_DESKTOP_ONLY, /// 54 | RIGHT_ALIGN = MB_RIGHT, /// ditto 55 | LEFT_ALIGN = MB_RTLREADING, /// ditto 56 | SERVICE_NOTIFICATION = MB_SERVICE_NOTIFICATION, /// ditto 57 | } 58 | 59 | 60 | /// 61 | DialogResult msgBox(Dstring txt) // docmain 62 | { 63 | return cast(DialogResult)dfl.internal.utf.messageBox(GetActiveWindow(), txt, "\0", MB_OK); 64 | } 65 | 66 | /// ditto 67 | DialogResult msgBox(IWindow owner, Dstring txt) // docmain 68 | { 69 | return cast(DialogResult)dfl.internal.utf.messageBox(owner ? owner.handle : GetActiveWindow(), 70 | txt, "\0", MB_OK); 71 | } 72 | 73 | /// ditto 74 | DialogResult msgBox(Dstring txt, Dstring caption) // docmain 75 | { 76 | return cast(DialogResult)dfl.internal.utf.messageBox(GetActiveWindow(), txt, caption, MB_OK); 77 | } 78 | 79 | /// ditto 80 | DialogResult msgBox(IWindow owner, Dstring txt, Dstring caption) // docmain 81 | { 82 | return cast(DialogResult)dfl.internal.utf.messageBox(owner ? owner.handle : GetActiveWindow(), 83 | txt, caption, MB_OK); 84 | } 85 | 86 | /// ditto 87 | DialogResult msgBox(Dstring txt, Dstring caption, MsgBoxButtons buttons) // docmain 88 | { 89 | return cast(DialogResult)dfl.internal.utf.messageBox(GetActiveWindow(), txt, caption, buttons); 90 | } 91 | 92 | /// ditto 93 | DialogResult msgBox(IWindow owner, Dstring txt, Dstring caption, 94 | MsgBoxButtons buttons) // docmain 95 | { 96 | return cast(DialogResult)dfl.internal.utf.messageBox(owner ? owner.handle : GetActiveWindow(), 97 | txt, caption, buttons); 98 | } 99 | 100 | /// ditto 101 | DialogResult msgBox(Dstring txt, Dstring caption, MsgBoxButtons buttons, 102 | MsgBoxIcon icon) // docmain 103 | { 104 | return cast(DialogResult)dfl.internal.utf.messageBox(GetActiveWindow(), txt, 105 | caption, buttons | icon); 106 | } 107 | 108 | /// ditto 109 | DialogResult msgBox(IWindow owner, Dstring txt, Dstring caption, MsgBoxButtons buttons, 110 | MsgBoxIcon icon) // docmain 111 | { 112 | return cast(DialogResult)dfl.internal.utf.messageBox(owner ? owner.handle : GetActiveWindow(), 113 | txt, caption, buttons | icon); 114 | } 115 | 116 | /// ditto 117 | DialogResult msgBox(Dstring txt, Dstring caption, MsgBoxButtons buttons, MsgBoxIcon icon, 118 | MsgBoxDefaultButton defaultButton) // docmain 119 | { 120 | return cast(DialogResult)dfl.internal.utf.messageBox(GetActiveWindow(), txt, 121 | caption, buttons | icon | defaultButton); 122 | } 123 | 124 | /// ditto 125 | DialogResult msgBox(IWindow owner, Dstring txt, Dstring caption, MsgBoxButtons buttons, 126 | MsgBoxIcon icon, MsgBoxDefaultButton defaultButton) // docmain 127 | { 128 | return cast(DialogResult)dfl.internal.utf.messageBox(owner ? owner.handle : GetActiveWindow(), 129 | txt, caption, buttons | icon | defaultButton); 130 | } 131 | 132 | /// ditto 133 | DialogResult msgBox(IWindow owner, Dstring txt, Dstring caption, MsgBoxButtons buttons, 134 | MsgBoxIcon icon, MsgBoxDefaultButton defaultButton, MsgBoxOptions options) // docmain 135 | { 136 | return cast(DialogResult)dfl.internal.utf.messageBox(owner ? owner.handle : GetActiveWindow(), 137 | txt, caption, buttons | icon | defaultButton | options); 138 | } 139 | 140 | 141 | deprecated final class MessageBox 142 | { 143 | private this() {} 144 | 145 | 146 | static: 147 | deprecated alias msgBox show; 148 | } 149 | 150 | 151 | deprecated alias msgBox messageBox; 152 | 153 | deprecated alias MsgBoxOptions MessageBoxOptions; 154 | deprecated alias MsgBoxDefaultButton MessageBoxDefaultButton; 155 | deprecated alias MsgBoxButtons MessageBoxButtons; 156 | deprecated alias MsgBoxIcon MessageBoxIcon; 157 | 158 | -------------------------------------------------------------------------------- /source/dfl/notifyicon.d: -------------------------------------------------------------------------------- 1 | // Written by Christopher E. Miller 2 | // See the included license.txt for copyright and license details. 3 | 4 | 5 | /// 6 | module dfl.notifyicon; 7 | 8 | private import dfl.internal.winapi, dfl.base, dfl.drawing; 9 | private import dfl.control, dfl.form, dfl.application; 10 | private import dfl.event, dfl.internal.utf, dfl.internal.dlib; 11 | 12 | version(DFL_NO_MENUS) 13 | { 14 | } 15 | else 16 | { 17 | private import dfl.menu; 18 | } 19 | 20 | 21 | /// 22 | class NotifyIcon // docmain 23 | { 24 | version(DFL_NO_MENUS) 25 | { 26 | } 27 | else 28 | { 29 | /// 30 | final @property void contextMenu(ContextMenu menu) // setter 31 | { 32 | this.cmenu = menu; 33 | } 34 | 35 | /// ditto 36 | final @property ContextMenu contextMenu() // getter 37 | { 38 | return cmenu; 39 | } 40 | } 41 | 42 | 43 | /// 44 | final @property void icon(Icon ico) // setter 45 | { 46 | _icon = ico; 47 | nid.hIcon = ico ? ico.handle : null; 48 | 49 | if(visible) 50 | { 51 | nid.uFlags = NIF_ICON; 52 | Shell_NotifyIconA(NIM_MODIFY, &nid); 53 | } 54 | } 55 | 56 | /// ditto 57 | final @property Icon icon() // getter 58 | { 59 | return _icon; 60 | } 61 | 62 | 63 | /// 64 | // Must be less than 64 chars. 65 | // To-do: hold reference to setter's string, use that for getter.. ? 66 | final @property void text(Dstring txt) // setter 67 | { 68 | if(txt.length >= nid.szTip.length) 69 | throw new DflException("Notify icon text too long"); 70 | 71 | // To-do: support Unicode. 72 | 73 | txt = unsafeAnsi(txt); // ... 74 | nid.szTip[txt.length] = 0; 75 | nid.szTip[0 .. txt.length] = txt[]; 76 | tipLen = cast(int)txt.length; 77 | 78 | if(visible) 79 | { 80 | nid.uFlags = NIF_TIP; 81 | Shell_NotifyIconA(NIM_MODIFY, &nid); 82 | } 83 | } 84 | 85 | /// ditto 86 | final @property Dstring text() // getter 87 | { 88 | //return nid.szTip[0 .. tipLen]; // Returning possibly mutated text! 89 | //return nid.szTip[0 .. tipLen].dup; 90 | //return nid.szTip[0 .. tipLen].idup; // Needed in D2. Doesn't work in D1. 91 | return cast(Dstring)nid.szTip[0 .. tipLen].dup; // Needed in D2. Doesn't work in D1. 92 | } 93 | 94 | 95 | /// 96 | final @property void visible(bool byes) // setter 97 | { 98 | if(byes) 99 | { 100 | if(!nid.uID) 101 | { 102 | nid.uID = allocNotifyIconID(); 103 | assert(nid.uID); 104 | allNotifyIcons[nid.uID] = this; 105 | } 106 | 107 | _forceAdd(); 108 | } 109 | else if(nid.uID) 110 | { 111 | _forceDelete(); 112 | 113 | //delete allNotifyIcons[nid.uID]; 114 | allNotifyIcons.remove(nid.uID); 115 | nid.uID = 0; 116 | } 117 | } 118 | 119 | /// ditto 120 | final @property bool visible() // getter 121 | { 122 | return nid.uID != 0; 123 | } 124 | 125 | 126 | /// 127 | final void show() 128 | { 129 | visible = true; 130 | } 131 | 132 | /// ditto 133 | final void hide() 134 | { 135 | visible = false; 136 | } 137 | 138 | 139 | //EventHandler click; 140 | Event!(NotifyIcon, EventArgs) click; /// 141 | //EventHandler doubleClick; 142 | Event!(NotifyIcon, EventArgs) doubleClick; /// 143 | //MouseEventHandler mouseDown; 144 | Event!(NotifyIcon, MouseEventArgs) mouseDown; /// 145 | //MouseEventHandler mouseUp; 146 | Event!(NotifyIcon, MouseEventArgs) mouseUp; /// 147 | //MouseEventHandler mouseMove; 148 | Event!(NotifyIcon, MouseEventArgs) mouseMove; /// 149 | 150 | 151 | this() 152 | { 153 | if(!ctrlNotifyIcon) 154 | _init(); 155 | 156 | nid.cbSize = nid.sizeof; 157 | nid.hWnd = ctrlNotifyIcon.handle; 158 | nid.uID = 0; 159 | nid.uCallbackMessage = WM_NOTIFYICON; 160 | nid.hIcon = null; 161 | nid.szTip[0] = '\0'; 162 | } 163 | 164 | 165 | ~this() 166 | { 167 | if(nid.uID) 168 | { 169 | _forceDelete(); 170 | //delete allNotifyIcons[nid.uID]; 171 | allNotifyIcons.remove(nid.uID); 172 | } 173 | 174 | //delete allNotifyIcons[nid.uID]; 175 | //allNotifyIcons.remove(nid.uID); 176 | 177 | /+ 178 | if(!allNotifyIcons.length) 179 | { 180 | delete ctrlNotifyIcon; 181 | ctrlNotifyIcon = null; 182 | } 183 | +/ 184 | } 185 | 186 | 187 | /// 188 | // Extra. 189 | void minimize(IWindow win) 190 | { 191 | LONG style; 192 | HWND hwnd; 193 | 194 | hwnd = win.handle; 195 | style = GetWindowLongA(hwnd, GWL_STYLE); 196 | 197 | if(style & WS_VISIBLE) 198 | { 199 | ShowOwnedPopups(hwnd, FALSE); 200 | 201 | if(!(style & WS_MINIMIZE) && _animation()) 202 | { 203 | RECT myRect, areaRect; 204 | 205 | GetWindowRect(hwnd, &myRect); 206 | _area(areaRect); 207 | DrawAnimatedRects(hwnd, 3, &myRect, &areaRect); 208 | } 209 | 210 | ShowWindow(hwnd, SW_HIDE); 211 | } 212 | } 213 | 214 | 215 | /// 216 | // Extra. 217 | void restore(IWindow win) 218 | { 219 | LONG style; 220 | HWND hwnd; 221 | 222 | hwnd = win.handle; 223 | style = GetWindowLongA(hwnd, GWL_STYLE); 224 | 225 | if(!(style & WS_VISIBLE)) 226 | { 227 | if(style & WS_MINIMIZE) 228 | { 229 | ShowWindow(hwnd, SW_RESTORE); 230 | } 231 | else 232 | { 233 | if(_animation()) 234 | { 235 | RECT myRect, areaRect; 236 | 237 | GetWindowRect(hwnd, &myRect); 238 | _area(areaRect); 239 | DrawAnimatedRects(hwnd, 3, &areaRect, &myRect); 240 | } 241 | 242 | ShowWindow(hwnd, SW_SHOW); 243 | 244 | ShowOwnedPopups(hwnd, TRUE); 245 | } 246 | } 247 | else 248 | { 249 | if(style & WS_MINIMIZE) 250 | ShowWindow(hwnd, SW_RESTORE); 251 | } 252 | 253 | SetForegroundWindow(hwnd); 254 | } 255 | 256 | 257 | private: 258 | 259 | NOTIFYICONDATA nid; 260 | int tipLen = 0; 261 | version(DFL_NO_MENUS) 262 | { 263 | } 264 | else 265 | { 266 | ContextMenu cmenu; 267 | } 268 | Icon _icon; 269 | 270 | 271 | package final void _forceAdd() 272 | { 273 | nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; 274 | Shell_NotifyIconA(NIM_ADD, &nid); 275 | } 276 | 277 | 278 | package final void _forceDelete() 279 | { 280 | Shell_NotifyIconA(NIM_DELETE, &nid); 281 | } 282 | 283 | 284 | // Returns true if min/restore animation is on. 285 | static bool _animation() 286 | { 287 | ANIMATIONINFO ai; 288 | 289 | ai.cbSize = ai.sizeof; 290 | SystemParametersInfoA(SPI_GETANIMATION, ai.sizeof, &ai, 0); 291 | 292 | return ai.iMinAnimate ? true : false; 293 | } 294 | 295 | 296 | // Gets the tray area. 297 | static void _area(out RECT rect) 298 | { 299 | HWND hwTaskbar, hw; 300 | 301 | hwTaskbar = FindWindowExA(null, null, "Shell_TrayWnd", null); 302 | if(hwTaskbar) 303 | { 304 | hw = FindWindowExA(hwTaskbar, null, "TrayNotifyWnd", null); 305 | if(hw) 306 | { 307 | GetWindowRect(hw, &rect); 308 | return; 309 | } 310 | } 311 | 312 | APPBARDATA abd; 313 | 314 | abd.cbSize = abd.sizeof; 315 | if(SHAppBarMessage(ABM_GETTASKBARPOS, &abd)) 316 | { 317 | switch(abd.uEdge) 318 | { 319 | case ABE_LEFT: 320 | case ABE_RIGHT: 321 | rect.top = abd.rc.bottom - 100; 322 | rect.bottom = abd.rc.bottom - 16; 323 | rect.left = abd.rc.left; 324 | rect.right = abd.rc.right; 325 | break; 326 | 327 | case ABE_TOP: 328 | case ABE_BOTTOM: 329 | rect.top = abd.rc.top; 330 | rect.bottom = abd.rc.bottom; 331 | rect.left = abd.rc.right - 100; 332 | rect.right = abd.rc.right - 16; 333 | break; 334 | 335 | default: 336 | } 337 | } 338 | else if(hwTaskbar) 339 | { 340 | GetWindowRect(hwTaskbar, &rect); 341 | if(rect.right - rect.left > 150) 342 | rect.left = rect.right - 150; 343 | if(rect.bottom - rect.top > 30) 344 | rect.top = rect.bottom - 30; 345 | } 346 | else 347 | { 348 | SystemParametersInfoA(SPI_GETWORKAREA, 0, &rect, 0); 349 | rect.left = rect.right - 150; 350 | rect.top = rect.bottom - 30; 351 | } 352 | } 353 | } 354 | 355 | 356 | package: 357 | 358 | 359 | enum UINT WM_NOTIFYICON = WM_USER + 34; // -wparam- is id, -lparam- is the mouse message such as WM_LBUTTONDBLCLK. 360 | UINT wmTaskbarCreated; 361 | NotifyIcon[UINT] allNotifyIcons; // Indexed by ID. 362 | UINT lastId = 1; 363 | NotifyIconControl ctrlNotifyIcon; 364 | 365 | 366 | class NotifyIconControl: Control 367 | { 368 | override void createHandle() 369 | { 370 | //if(created) 371 | if(isHandleCreated) 372 | return; 373 | 374 | if(killing) 375 | { 376 | create_err: 377 | throw new DflException("Notify icon initialization failure"); 378 | } 379 | 380 | Application.creatingControl(this); 381 | hwnd = CreateWindowExA(wexstyle, CONTROL_CLASSNAME.ptr, "NotifyIcon", 0, 0, 0, 0, 0, null, null, 382 | Application.getInstance(), null); 383 | if(!hwnd) 384 | goto create_err; 385 | } 386 | 387 | 388 | protected override void wndProc(ref Message msg) 389 | { 390 | if(msg.msg == WM_NOTIFYICON) 391 | { 392 | if(cast(UINT)msg.wParam in allNotifyIcons) 393 | { 394 | NotifyIcon ni; 395 | Point pt; 396 | 397 | ni = allNotifyIcons[cast(UINT)msg.wParam]; 398 | 399 | switch(cast(UINT)msg.lParam) // msg. 400 | { 401 | case WM_MOUSEMOVE: 402 | pt = Cursor.position; 403 | ni.mouseMove(ni, new MouseEventArgs(Control.mouseButtons(), 0, pt.x, pt.y, 0)); 404 | break; 405 | 406 | case WM_LBUTTONUP: 407 | pt = Cursor.position; 408 | ni.mouseUp(ni, new MouseEventArgs(MouseButtons.LEFT, 1, pt.x, pt.y, 0)); 409 | 410 | ni.click(ni, EventArgs.empty); 411 | break; 412 | 413 | case WM_RBUTTONUP: 414 | pt = Cursor.position; 415 | ni.mouseUp(ni, new MouseEventArgs(MouseButtons.RIGHT, 1, pt.x, pt.y, 0)); 416 | 417 | version(DFL_NO_MENUS) 418 | { 419 | } 420 | else 421 | { 422 | if(ni.cmenu) 423 | ni.cmenu.show(ctrlNotifyIcon, pt); 424 | } 425 | break; 426 | 427 | case WM_LBUTTONDOWN: 428 | pt = Cursor.position; 429 | ni.mouseDown(ni, new MouseEventArgs(MouseButtons.LEFT, 0, pt.x, pt.y, 0)); 430 | break; 431 | 432 | case WM_RBUTTONDOWN: 433 | pt = Cursor.position; 434 | ni.mouseDown(ni, new MouseEventArgs(MouseButtons.RIGHT, 0, pt.x, pt.y, 0)); 435 | break; 436 | 437 | case WM_LBUTTONDBLCLK: 438 | ni.doubleClick(ni, EventArgs.empty); 439 | break; 440 | 441 | default: 442 | } 443 | } 444 | } 445 | else if(msg.msg == wmTaskbarCreated) 446 | { 447 | // Show all visible NotifyIcon's. 448 | foreach(NotifyIcon ni; allNotifyIcons) 449 | { 450 | if(ni.visible) 451 | ni._forceAdd(); 452 | } 453 | } 454 | 455 | super.wndProc(msg); 456 | } 457 | } 458 | 459 | 460 | static ~this() 461 | { 462 | // Due to all items not being destructed at program exit, 463 | // remove all visible notify icons because the OS won't. 464 | foreach(NotifyIcon ni; allNotifyIcons) 465 | { 466 | if(ni.visible) 467 | ni._forceDelete(); 468 | } 469 | 470 | allNotifyIcons = null; 471 | } 472 | 473 | 474 | UINT allocNotifyIconID() 475 | { 476 | UINT prev; 477 | prev = lastId; 478 | for(;;) 479 | { 480 | lastId++; 481 | if(lastId == ushort.max) 482 | lastId = 1; 483 | if(lastId == prev) 484 | throw new DflException("Too many notify icons"); 485 | 486 | if(!(lastId in allNotifyIcons)) 487 | break; 488 | } 489 | return lastId; 490 | } 491 | 492 | 493 | void _init() 494 | { 495 | wmTaskbarCreated = RegisterWindowMessageA("TaskbarCreated"); 496 | 497 | ctrlNotifyIcon = new NotifyIconControl; 498 | ctrlNotifyIcon.visible = false; 499 | } 500 | 501 | -------------------------------------------------------------------------------- /source/dfl/package.d: -------------------------------------------------------------------------------- 1 | // Written by Christopher E. Miller 2 | // See the included license.txt for copyright and license details. 3 | 4 | 5 | /// Imports all of DFL's public interface. 6 | module dfl; 7 | 8 | 9 | version(bud) 10 | version = build; 11 | version(DFL_NO_BUD_DEF) 12 | version = DFL_NO_BUILD_DEF; 13 | 14 | 15 | //$(TOC pragmas, Pragmas) 16 | // $(TOC_SUB pragmas,pragma_build, build) 17 | // $(TOC_SUB pragmas,pragma_build_def, build def) 18 | // $(TOC_SUB pragmas,pragma_export_version, export version) 19 | // $(TOC_SUB pragmas,pragma_ignore, ignore) 20 | // $(TOC_SUB pragmas,pragma_include, include) 21 | // $(TOC_SUB pragmas,pragma_link, link) 22 | 23 | version(build) 24 | { 25 | version(WINE) 26 | { 27 | } 28 | else 29 | { 30 | version(DFL_NO_LIB) 31 | { 32 | } 33 | else 34 | { 35 | pragma(link, "dfl_build"); 36 | 37 | pragma(link, "ws2_32"); 38 | pragma(link, "gdi32"); 39 | pragma(link, "comctl32"); 40 | pragma(link, "advapi32"); 41 | pragma(link, "comdlg32"); 42 | pragma(link, "ole32"); 43 | pragma(link, "uuid"); 44 | } 45 | 46 | version(DFL_NO_BUILD_DEF) 47 | { 48 | } 49 | else 50 | { 51 | pragma(build_def, "EXETYPE NT"); 52 | version(gui) 53 | { 54 | pragma(build_def, "SUBSYSTEM WINDOWS,4.0"); 55 | } 56 | else 57 | { 58 | pragma(build_def, "SUBSYSTEM CONSOLE,4.0"); 59 | } 60 | } 61 | } 62 | } 63 | // pragma(link, "SUBSYSTEM WINDOWS,4.0"); 64 | 65 | 66 | 67 | 68 | public import dfl.base, dfl.menu, dfl.control, dfl.usercontrol, 69 | dfl.form, dfl.drawing, dfl.panel, dfl.event, 70 | dfl.application, dfl.button, dfl.socket, 71 | dfl.timer, dfl.environment, dfl.label, dfl.textbox, 72 | dfl.listbox, dfl.splitter, dfl.groupbox, dfl.messagebox, 73 | dfl.registry, dfl.notifyicon, dfl.collections, dfl.data, 74 | dfl.clipboard, dfl.commondialog, dfl.richtextbox, dfl.tooltip, 75 | dfl.combobox, dfl.treeview, dfl.picturebox, dfl.tabcontrol, 76 | dfl.listview, dfl.statusbar, dfl.progressbar, dfl.resources, 77 | dfl.imagelist, dfl.toolbar, 78 | dfl.internal.utf,dfl.internal.com,dfl.internal.winapi,dfl.internal.wincom; 79 | 80 | -------------------------------------------------------------------------------- /source/dfl/panel.d: -------------------------------------------------------------------------------- 1 | // Written by Christopher E. Miller 2 | // See the included license.txt for copyright and license details. 3 | 4 | 5 | /// 6 | module dfl.panel; 7 | 8 | private import dfl.control, dfl.base, dfl.internal.winapi; 9 | 10 | 11 | /// 12 | class Panel: ContainerControl // docmain 13 | { 14 | /// 15 | @property void borderStyle(BorderStyle bs) // setter 16 | { 17 | final switch(bs) 18 | { 19 | case BorderStyle.FIXED_3D: 20 | _style(_style() & ~WS_BORDER); 21 | _exStyle(_exStyle() | WS_EX_CLIENTEDGE); 22 | break; 23 | 24 | case BorderStyle.FIXED_SINGLE: 25 | _exStyle(_exStyle() & ~WS_EX_CLIENTEDGE); 26 | _style(_style() | WS_BORDER); 27 | break; 28 | 29 | case BorderStyle.NONE: 30 | _style(_style() & ~WS_BORDER); 31 | _exStyle(_exStyle() & ~WS_EX_CLIENTEDGE); 32 | break; 33 | } 34 | 35 | if(created) 36 | { 37 | redrawEntire(); 38 | } 39 | } 40 | 41 | /// ditto 42 | @property BorderStyle borderStyle() // getter 43 | { 44 | if(_exStyle() & WS_EX_CLIENTEDGE) 45 | return BorderStyle.FIXED_3D; 46 | else if(_style() & WS_BORDER) 47 | return BorderStyle.FIXED_SINGLE; 48 | return BorderStyle.NONE; 49 | } 50 | 51 | 52 | this() 53 | { 54 | //ctrlStyle |= ControlStyles.SELECTABLE | ControlStyles.CONTAINER_CONTROL; 55 | ctrlStyle |= ControlStyles.CONTAINER_CONTROL; 56 | /+ wstyle |= WS_TABSTOP; +/ // Should WS_TABSTOP be set? 57 | //wexstyle |= WS_EX_CONTROLPARENT; // Allow tabbing through children. ? 58 | } 59 | } 60 | 61 | -------------------------------------------------------------------------------- /source/dfl/picturebox.d: -------------------------------------------------------------------------------- 1 | // Written by Christopher E. Miller 2 | // See the included license.txt for copyright and license details. 3 | 4 | 5 | /// 6 | module dfl.picturebox; 7 | 8 | private import dfl.control, dfl.base, dfl.drawing, dfl.event; 9 | private import dfl.internal.winapi; 10 | 11 | 12 | /// 13 | enum PictureBoxSizeMode: ubyte 14 | { 15 | /// 16 | NORMAL, // Image at upper left of control. 17 | /// ditto 18 | AUTO_SIZE, // Control sizes to fit image size. 19 | /// ditto 20 | CENTER_IMAGE, // Image at center of control. 21 | /// ditto 22 | STRETCH_IMAGE, // Image stretched to fit control. 23 | } 24 | 25 | 26 | /// 27 | class PictureBox: Control // docmain 28 | { 29 | this() 30 | { 31 | //resizeRedraw = true; // Redrawn manually in onResize() when necessary. 32 | } 33 | 34 | 35 | /// 36 | final @property void image(Image img) // setter 37 | { 38 | if(this.img is img) 39 | return; 40 | 41 | if(_mode == PictureBoxSizeMode.AUTO_SIZE) 42 | { 43 | if(img) 44 | clientSize = img.size; 45 | else 46 | clientSize = Size(0, 0); 47 | } 48 | 49 | this.img = img; 50 | 51 | if(created) 52 | invalidate(); 53 | 54 | onImageChanged(EventArgs.empty); 55 | } 56 | 57 | /// ditto 58 | final @property Image image() // getter 59 | { 60 | return img; 61 | } 62 | 63 | 64 | /// 65 | final @property void sizeMode(PictureBoxSizeMode sm) // setter 66 | { 67 | if(_mode == sm) 68 | return; 69 | 70 | final switch(sm) 71 | { 72 | case PictureBoxSizeMode.AUTO_SIZE: 73 | if(img) 74 | clientSize = img.size; 75 | else 76 | clientSize = Size(0, 0); 77 | break; 78 | 79 | case PictureBoxSizeMode.NORMAL: 80 | break; 81 | 82 | case PictureBoxSizeMode.CENTER_IMAGE: 83 | break; 84 | 85 | case PictureBoxSizeMode.STRETCH_IMAGE: 86 | break; 87 | } 88 | 89 | _mode = sm; 90 | 91 | if(created) 92 | invalidate(); 93 | 94 | onSizeModeChanged(EventArgs.empty); 95 | } 96 | 97 | /// ditto 98 | final @property PictureBoxSizeMode sizeMode() // getter 99 | { 100 | return _mode; 101 | } 102 | 103 | 104 | /// 105 | @property void borderStyle(BorderStyle bs) // setter 106 | { 107 | final switch(bs) 108 | { 109 | case BorderStyle.FIXED_3D: 110 | _style(_style() & ~WS_BORDER); 111 | _exStyle(_exStyle() | WS_EX_CLIENTEDGE); 112 | break; 113 | 114 | case BorderStyle.FIXED_SINGLE: 115 | _exStyle(_exStyle() & ~WS_EX_CLIENTEDGE); 116 | _style(_style() | WS_BORDER); 117 | break; 118 | 119 | case BorderStyle.NONE: 120 | _style(_style() & ~WS_BORDER); 121 | _exStyle(_exStyle() & ~WS_EX_CLIENTEDGE); 122 | break; 123 | } 124 | 125 | if(created) 126 | { 127 | redrawEntire(); 128 | } 129 | } 130 | 131 | /// ditto 132 | @property BorderStyle borderStyle() // getter 133 | { 134 | if(_exStyle() & WS_EX_CLIENTEDGE) 135 | return BorderStyle.FIXED_3D; 136 | else if(_style() & WS_BORDER) 137 | return BorderStyle.FIXED_SINGLE; 138 | return BorderStyle.NONE; 139 | } 140 | 141 | 142 | //EventHandler sizeModeChanged; 143 | Event!(PictureBox, EventArgs) sizeModeChanged; /// 144 | //EventHandler imageChanged; 145 | Event!(PictureBox, EventArgs) imageChanged; /// 146 | 147 | 148 | protected: 149 | 150 | /// 151 | void onSizeModeChanged(EventArgs ea) 152 | { 153 | sizeModeChanged(this, ea); 154 | } 155 | 156 | 157 | /// 158 | void onImageChanged(EventArgs ea) 159 | { 160 | imageChanged(this, ea); 161 | } 162 | 163 | 164 | override void onPaint(PaintEventArgs ea) 165 | { 166 | if(img) 167 | { 168 | final switch(_mode) 169 | { 170 | case PictureBoxSizeMode.NORMAL: 171 | case PictureBoxSizeMode.AUTO_SIZE: // Drawn the same as normal. 172 | img.draw(ea.graphics, Point(0, 0)); 173 | break; 174 | 175 | case PictureBoxSizeMode.CENTER_IMAGE: 176 | { 177 | Size isz; 178 | isz = img.size; 179 | img.draw(ea.graphics, Point((clientSize.width - isz.width) / 2, 180 | (clientSize.height - isz.height) / 2)); 181 | } 182 | break; 183 | 184 | case PictureBoxSizeMode.STRETCH_IMAGE: 185 | img.drawStretched(ea.graphics, Rect(0, 0, clientSize.width, clientSize.height)); 186 | break; 187 | } 188 | } 189 | 190 | super.onPaint(ea); 191 | } 192 | 193 | 194 | override void onResize(EventArgs ea) 195 | { 196 | if(PictureBoxSizeMode.CENTER_IMAGE == _mode || PictureBoxSizeMode.STRETCH_IMAGE == _mode) 197 | invalidate(); 198 | 199 | super.onResize(ea); 200 | } 201 | 202 | 203 | private: 204 | PictureBoxSizeMode _mode = PictureBoxSizeMode.NORMAL; 205 | Image img = null; 206 | } 207 | 208 | -------------------------------------------------------------------------------- /source/dfl/progressbar.d: -------------------------------------------------------------------------------- 1 | // Written by Christopher E. Miller 2 | // See the included license.txt for copyright and license details. 3 | 4 | 5 | /// 6 | module dfl.progressbar; 7 | 8 | private import dfl.base, dfl.control, dfl.drawing, dfl.application, 9 | dfl.event; 10 | private import dfl.internal.winapi; 11 | 12 | 13 | private extern(Windows) void _initProgressbar(); 14 | 15 | 16 | /// 17 | class ProgressBar: ControlSuperClass // docmain 18 | { 19 | this() 20 | { 21 | _initProgressbar(); 22 | 23 | wexstyle |= WS_EX_CLIENTEDGE; 24 | wclassStyle = progressbarClassStyle; 25 | } 26 | 27 | 28 | /// 29 | final @property void maximum(int max) // setter 30 | { 31 | if(max <= 0 /+ || max < _min +/) 32 | { 33 | //bad_max: 34 | //throw new DflException("Unable to set progress bar maximum value"); 35 | if(max) 36 | return; 37 | } 38 | 39 | if(created) 40 | { 41 | prevwproc(PBM_SETRANGE, 0, MAKELPARAM(_min, max)); 42 | } 43 | 44 | _max = max; 45 | 46 | if(_val > max) 47 | _val = max; // ? 48 | } 49 | 50 | /// ditto 51 | final @property int maximum() // getter 52 | { 53 | return _max; 54 | } 55 | 56 | 57 | /// 58 | final @property void minimum(int min) // setter 59 | { 60 | if(min < 0 /+ || min > _max +/) 61 | { 62 | //bad_min: 63 | //throw new DflException("Unable to set progress bar minimum value"); 64 | return; 65 | } 66 | 67 | if(created) 68 | { 69 | prevwproc(PBM_SETRANGE, 0, MAKELPARAM(min, _max)); 70 | } 71 | 72 | _min = min; 73 | 74 | if(_val < min) 75 | _val = min; // ? 76 | } 77 | 78 | /// ditto 79 | final @property int minimum() // getter 80 | { 81 | return _min; 82 | } 83 | 84 | 85 | /// 86 | final @property void step(int stepby) // setter 87 | { 88 | if(stepby <= 0 /+ || stepby > _max +/) 89 | { 90 | //bad_max: 91 | //throw new DflException("Unable to set progress bar step value"); 92 | if(stepby) 93 | return; 94 | } 95 | 96 | if(created) 97 | { 98 | prevwproc(PBM_SETSTEP, stepby, 0); 99 | } 100 | 101 | _step = stepby; 102 | } 103 | 104 | /// ditto 105 | final @property int step() // getter 106 | { 107 | return _step; 108 | } 109 | 110 | 111 | /// 112 | final @property void value(int setval) // setter 113 | { 114 | if(setval < _min || setval > _max) 115 | { 116 | //throw new DflException("Progress bar value out of minimum/maximum range"); 117 | //return; 118 | if(setval > _max) 119 | setval = _max; 120 | else 121 | setval = _min; 122 | } 123 | 124 | if(created) 125 | { 126 | prevwproc(PBM_SETPOS, setval, 0); 127 | } 128 | 129 | _val = setval; 130 | } 131 | 132 | /// ditto 133 | final @property int value() // getter 134 | { 135 | return _val; 136 | } 137 | 138 | 139 | /// 140 | final void increment(int incby) 141 | { 142 | int newpos = _val + incby; 143 | if(newpos < _min) 144 | newpos = _min; 145 | if(newpos > _max) 146 | newpos = _max; 147 | 148 | if(created) 149 | { 150 | prevwproc(PBM_SETPOS, newpos, 0); 151 | } 152 | 153 | _val = newpos; 154 | } 155 | 156 | 157 | /// 158 | final void performStep() 159 | { 160 | increment(_step); 161 | } 162 | 163 | 164 | protected override void onHandleCreated(EventArgs ea) 165 | { 166 | super.onHandleCreated(ea); 167 | 168 | if(_min != MIN_INIT || _max != MAX_INIT) 169 | { 170 | prevwproc(PBM_SETRANGE, 0, MAKELPARAM(_min, _max)); 171 | } 172 | 173 | if(_step != STEP_INIT) 174 | { 175 | prevwproc(PBM_SETSTEP, _step, 0); 176 | } 177 | 178 | if(_val != VAL_INIT) 179 | { 180 | prevwproc(PBM_SETPOS, _val, 0); 181 | } 182 | } 183 | 184 | 185 | protected override @property Size defaultSize() // getter 186 | { 187 | return Size(100, 23); 188 | } 189 | 190 | 191 | static @property Color defaultForeColor() // getter 192 | { 193 | return SystemColors.highlight; 194 | } 195 | 196 | 197 | protected override void createParams(ref CreateParams cp) 198 | { 199 | super.createParams(cp); 200 | 201 | cp.className = PROGRESSBAR_CLASSNAME; 202 | } 203 | 204 | 205 | protected override void prevWndProc(ref Message msg) 206 | { 207 | //msg.result = CallWindowProcA(progressbarPrevWndProc, msg.hWnd, msg.msg, msg.wParam, msg.lParam); 208 | msg.result = dfl.internal.utf.callWindowProc(progressbarPrevWndProc, msg.hWnd, msg.msg, msg.wParam, msg.lParam); 209 | } 210 | 211 | 212 | private: 213 | 214 | enum MIN_INIT = 0; 215 | enum MAX_INIT = 100; 216 | enum STEP_INIT = 10; 217 | enum VAL_INIT = 0; 218 | 219 | int _min = MIN_INIT, _max = MAX_INIT, _step = STEP_INIT, _val = VAL_INIT; 220 | 221 | 222 | package: 223 | final: 224 | LRESULT prevwproc(UINT msg, WPARAM wparam, LPARAM lparam) 225 | { 226 | //return CallWindowProcA(progressbarPrevWndProc, hwnd, msg, wparam, lparam); 227 | return dfl.internal.utf.callWindowProc(progressbarPrevWndProc, hwnd, msg, wparam, lparam); 228 | } 229 | } 230 | 231 | -------------------------------------------------------------------------------- /source/dfl/resources.d: -------------------------------------------------------------------------------- 1 | // Written by Christopher E. Miller 2 | // See the included license.txt for copyright and license details. 3 | 4 | 5 | /// 6 | module dfl.resources; 7 | 8 | private import dfl.internal.dlib; 9 | 10 | private import dfl.internal.utf, dfl.internal.winapi, dfl.base, dfl.drawing; 11 | 12 | 13 | version(DFL_NO_RESOURCES) 14 | { 15 | } 16 | else 17 | { 18 | /// 19 | class Resources // docmain 20 | { 21 | /// 22 | this(HINSTANCE inst, WORD language = 0, bool owned = false) 23 | { 24 | this.hinst = inst; 25 | this.lang = language; 26 | this._owned = owned; 27 | } 28 | 29 | /// ditto 30 | // Note: libName gets unloaded and may take down all its resources with it. 31 | this(Dstring libName, WORD language = 0) 32 | { 33 | HINSTANCE inst; 34 | inst = loadLibraryEx(libName, LOAD_LIBRARY_AS_DATAFILE); 35 | if(!inst) 36 | throw new DflException("Unable to load resources from '" ~ libName ~ "'"); 37 | this(inst, language, true); // Owned. 38 | } 39 | 40 | /+ // Let's not depend on Application; the user can do so if they wish. 41 | /// ditto 42 | this(WORD language = 0) 43 | { 44 | this(Application.getInstance(), language); 45 | } 46 | +/ 47 | 48 | 49 | /// 50 | void dispose() 51 | { 52 | assert(_owned); 53 | //if(hinst != Application.getInstance()) // ? 54 | FreeLibrary(hinst); 55 | hinst = null; 56 | } 57 | 58 | 59 | /// 60 | final @property WORD language() // getter 61 | { 62 | return lang; 63 | } 64 | 65 | 66 | /// 67 | final Icon getIcon(int id, bool defaultSize = true) 68 | in 69 | { 70 | assert(id >= WORD.min && id <= WORD.max); 71 | } 72 | body 73 | { 74 | /+ 75 | HICON hi; 76 | hi = LoadIconA(hinst, cast(LPCSTR)cast(WORD)id); 77 | if(!hi) 78 | return null; 79 | return Icon.fromHandle(hi); 80 | +/ 81 | HICON hi; 82 | hi = cast(HICON)LoadImageA(hinst, cast(LPCSTR)cast(WORD)id, IMAGE_ICON, 83 | 0, 0, defaultSize ? (LR_DEFAULTSIZE | LR_SHARED) : 0); 84 | if(!hi) 85 | return null; 86 | return new Icon(hi, true); // Owned. 87 | } 88 | 89 | /// ditto 90 | final Icon getIcon(Dstring name, bool defaultSize = true) 91 | { 92 | /+ 93 | HICON hi; 94 | hi = LoadIconA(hinst, unsafeStringz(name)); 95 | if(!hi) 96 | return null; 97 | return Icon.fromHandle(hi); 98 | +/ 99 | HICON hi; 100 | hi = cast(HICON)dfl.internal.utf.loadImage(hinst, name, IMAGE_ICON, 101 | 0, 0, defaultSize ? (LR_DEFAULTSIZE | LR_SHARED) : 0); 102 | if(!hi) 103 | return null; 104 | return new Icon(hi, true); // Owned. 105 | } 106 | 107 | /// ditto 108 | final Icon getIcon(int id, int width, int height) 109 | in 110 | { 111 | assert(id >= WORD.min && id <= WORD.max); 112 | } 113 | body 114 | { 115 | // Can't have size 0 (plus causes Windows to use the actual size). 116 | //if(width <= 0 || height <= 0) 117 | // _noload("icon"); 118 | HICON hi; 119 | hi = cast(HICON)LoadImageA(hinst, cast(LPCSTR)cast(WORD)id, IMAGE_ICON, 120 | width, height, 0); 121 | if(!hi) 122 | return null; 123 | return new Icon(hi, true); // Owned. 124 | } 125 | 126 | /// ditto 127 | final Icon getIcon(Dstring name, int width, int height) 128 | { 129 | // Can't have size 0 (plus causes Windows to use the actual size). 130 | //if(width <= 0 || height <= 0) 131 | // _noload("icon"); 132 | HICON hi; 133 | hi = cast(HICON)dfl.internal.utf.loadImage(hinst, name, IMAGE_ICON, 134 | width, height, 0); 135 | if(!hi) 136 | return null; 137 | return new Icon(hi, true); // Owned. 138 | } 139 | 140 | deprecated alias getIcon loadIcon; 141 | 142 | 143 | /// 144 | final Bitmap getBitmap(int id) 145 | in 146 | { 147 | assert(id >= WORD.min && id <= WORD.max); 148 | } 149 | body 150 | { 151 | HBITMAP h; 152 | h = cast(HBITMAP)LoadImageA(hinst, cast(LPCSTR)cast(WORD)id, IMAGE_BITMAP, 153 | 0, 0, 0); 154 | if(!h) 155 | return null; 156 | return new Bitmap(h, true); // Owned. 157 | } 158 | 159 | /// ditto 160 | final Bitmap getBitmap(Dstring name) 161 | { 162 | HBITMAP h; 163 | h = cast(HBITMAP)loadImage(hinst, name, IMAGE_BITMAP, 164 | 0, 0, 0); 165 | if(!h) 166 | return null; 167 | return new Bitmap(h, true); // Owned. 168 | } 169 | 170 | deprecated alias getBitmap loadBitmap; 171 | 172 | 173 | /// 174 | final Cursor getCursor(int id) 175 | in 176 | { 177 | assert(id >= WORD.min && id <= WORD.max); 178 | } 179 | body 180 | { 181 | HCURSOR h; 182 | h = cast(HCURSOR)LoadImageA(hinst, cast(LPCSTR)cast(WORD)id, IMAGE_CURSOR, 183 | 0, 0, 0); 184 | if(!h) 185 | return null; 186 | return new Cursor(h, true); // Owned. 187 | } 188 | 189 | /// ditto 190 | final Cursor getCursor(Dstring name) 191 | { 192 | HCURSOR h; 193 | h = cast(HCURSOR)loadImage(hinst, name, IMAGE_CURSOR, 194 | 0, 0, 0); 195 | if(!h) 196 | return null; 197 | return new Cursor(h, true); // Owned. 198 | } 199 | 200 | deprecated alias getCursor loadCursor; 201 | 202 | 203 | /// 204 | final Dstring getString(int id) 205 | in 206 | { 207 | assert(id >= WORD.min && id <= WORD.max); 208 | } 209 | body 210 | { 211 | // Not casting to wDstring because a resource isn't guaranteed to be the same size. 212 | wchar* ws = cast(wchar*)_getData(cast(LPCWSTR)RT_STRING, cast(LPCWSTR)cast(WORD)(id / 16 + 1)).ptr; 213 | Dstring result; 214 | if(ws) 215 | { 216 | int i; 217 | for(i = 0; i < (id & 15); i++) 218 | { 219 | ws += 1 + cast(size_t)*ws; 220 | } 221 | result = utf16stringtoUtf8string((ws + 1)[0 .. cast(size_t)*ws]); 222 | } 223 | return result; 224 | } 225 | 226 | deprecated alias getString loadString; 227 | 228 | 229 | // Used internally 230 | // NOTE: win9x doesn't like these strings to be on the heap! 231 | final void[] _getData(LPCWSTR type, LPCWSTR name) // internal 232 | { 233 | HRSRC hrc; 234 | hrc = FindResourceExW(hinst, type, name, lang); 235 | if(!hrc) 236 | return null; 237 | HGLOBAL hg = LoadResource(hinst, hrc); 238 | if(!hg) 239 | return null; 240 | LPVOID pv = LockResource(hg); 241 | if(!pv) 242 | return null; 243 | return pv[0 .. SizeofResource(hinst, hrc)]; 244 | } 245 | 246 | /// 247 | final void[] getData(int type, int id) 248 | in 249 | { 250 | assert(type >= WORD.min && type <= WORD.max); 251 | assert(id >= WORD.min && id <= WORD.max); 252 | } 253 | body 254 | { 255 | return _getData(cast(LPCWSTR)type, cast(LPCWSTR)id); 256 | } 257 | 258 | /// ditto 259 | final void[] getData(Dstring type, int id) 260 | in 261 | { 262 | assert(id >= WORD.min && id <= WORD.max); 263 | } 264 | body 265 | { 266 | return _getData(utf8stringToUtf16stringz(type), cast(LPCWSTR)id); 267 | } 268 | 269 | /// ditto 270 | final void[] getData(int type, Dstring name) 271 | in 272 | { 273 | assert(type >= WORD.min && type <= WORD.max); 274 | } 275 | body 276 | { 277 | return _getData(cast(LPCWSTR)type, utf8stringToUtf16stringz(name)); 278 | } 279 | 280 | /// ditto 281 | final void[] getData(Dstring type, Dstring name) 282 | { 283 | return _getData(utf8stringToUtf16stringz(type), utf8stringToUtf16stringz(name)); 284 | } 285 | 286 | 287 | ~this() 288 | { 289 | if(_owned) 290 | dispose(); 291 | } 292 | 293 | 294 | private: 295 | 296 | HINSTANCE hinst; 297 | WORD lang = 0; 298 | bool _owned = false; 299 | 300 | 301 | void _noload(Dstring type) 302 | { 303 | throw new DflException("Unable to load " ~ type ~ " resource"); 304 | } 305 | } 306 | } 307 | 308 | -------------------------------------------------------------------------------- /source/dfl/splitter.d: -------------------------------------------------------------------------------- 1 | // Written by Christopher E. Miller 2 | // See the included license.txt for copyright and license details. 3 | 4 | 5 | /// 6 | module dfl.splitter; 7 | 8 | private import dfl.control, dfl.internal.winapi, dfl.base, dfl.drawing; 9 | private import dfl.event; 10 | 11 | 12 | /// 13 | class SplitterEventArgs: EventArgs 14 | { 15 | /// 16 | this(int x, int y, int splitX, int splitY) 17 | { 18 | _x = x; 19 | _y = y; 20 | _splitX = splitX; 21 | _splitY = splitY; 22 | } 23 | 24 | 25 | /// 26 | final @property int x() // getter 27 | { 28 | return _x; 29 | } 30 | 31 | 32 | /// 33 | final @property int y() // getter 34 | { 35 | return _y; 36 | } 37 | 38 | 39 | /// 40 | final @property void splitX(int val) // setter 41 | { 42 | _splitX = val; 43 | } 44 | 45 | /// ditto 46 | final @property int splitX() // getter 47 | { 48 | return _splitX; 49 | } 50 | 51 | 52 | /// 53 | final @property void splitY(int val) // setter 54 | { 55 | _splitY = val; 56 | } 57 | 58 | /// ditto 59 | final @property int splitY() // getter 60 | { 61 | return _splitY; 62 | } 63 | 64 | 65 | private: 66 | int _x, _y, _splitX, _splitY; 67 | } 68 | 69 | 70 | /// 71 | class Splitter: Control // docmain 72 | { 73 | this() 74 | { 75 | // DMD 0.95: need 'this' to access member dock 76 | this.dock = DockStyle.LEFT; 77 | 78 | if(HBRUSH.init == hbrxor) 79 | inithbrxor(); 80 | } 81 | 82 | 83 | /+ 84 | override @property void anchor(AnchorStyles a) // setter 85 | { 86 | throw new DflException("Splitter cannot be anchored"); 87 | } 88 | 89 | alias Control.anchor anchor; // Overload. 90 | +/ 91 | 92 | 93 | override @property void dock(DockStyle ds) // setter 94 | { 95 | switch(ds) 96 | { 97 | case DockStyle.LEFT: 98 | case DockStyle.RIGHT: 99 | //cursor = new Cursor(LoadCursorA(null, IDC_SIZEWE), false); 100 | cursor = Cursors.vSplit; 101 | break; 102 | 103 | case DockStyle.TOP: 104 | case DockStyle.BOTTOM: 105 | //cursor = new Cursor(LoadCursorA(null, IDC_SIZENS), false); 106 | cursor = Cursors.hSplit; 107 | break; 108 | 109 | default: 110 | throw new DflException("Invalid splitter dock"); 111 | } 112 | 113 | super.dock(ds); 114 | } 115 | 116 | alias Control.dock dock; // Overload. 117 | 118 | 119 | package void initsplit(int sx, int sy) 120 | { 121 | capture = true; 122 | 123 | downing = true; 124 | //downpos = Point(mea.x, mea.y); 125 | 126 | switch(dock) 127 | { 128 | case DockStyle.TOP: 129 | case DockStyle.BOTTOM: 130 | downpos = sy; 131 | lastpos = 0; 132 | drawxorClient(0, lastpos); 133 | break; 134 | 135 | default: // LEFT / RIGHT. 136 | downpos = sx; 137 | lastpos = 0; 138 | drawxorClient(lastpos, 0); 139 | } 140 | } 141 | 142 | 143 | final void resumeSplit(int sx, int sy) // package 144 | { 145 | if(Control.mouseButtons & MouseButtons.LEFT) 146 | { 147 | initsplit(sx, sy); 148 | 149 | if(cursor) 150 | Cursor.current = cursor; 151 | } 152 | } 153 | 154 | // /// ditto 155 | final void resumeSplit() // package 156 | { 157 | Point pt = pointToClient(Cursor.position); 158 | return resumeSplit(pt.x, pt.y); 159 | } 160 | 161 | 162 | /// 163 | @property void movingGrip(bool byes) // setter 164 | { 165 | if(mgrip == byes) 166 | return; 167 | 168 | this.mgrip = byes; 169 | 170 | if(created) 171 | { 172 | invalidate(); 173 | } 174 | } 175 | 176 | /// ditto 177 | @property bool movingGrip() // getter 178 | { 179 | return mgrip; 180 | } 181 | 182 | deprecated alias movingGrip moveingGrip; 183 | deprecated alias movingGrip moveGrip; 184 | deprecated alias movingGrip sizingGrip; 185 | 186 | 187 | protected override void onPaint(PaintEventArgs ea) 188 | { 189 | super.onPaint(ea); 190 | 191 | if(mgrip) 192 | { 193 | ea.graphics.drawMoveGrip(displayRectangle, DockStyle.LEFT == dock || DockStyle.RIGHT == dock); 194 | } 195 | } 196 | 197 | 198 | protected override void onResize(EventArgs ea) 199 | { 200 | if(mgrip) 201 | { 202 | invalidate(); 203 | } 204 | 205 | resize(this, ea); 206 | } 207 | 208 | 209 | protected override void onMouseDown(MouseEventArgs mea) 210 | { 211 | super.onMouseDown(mea); 212 | 213 | if(mea.button == MouseButtons.LEFT && 1 == mea.clicks) 214 | { 215 | initsplit(mea.x, mea.y); 216 | } 217 | } 218 | 219 | 220 | protected override void onMouseMove(MouseEventArgs mea) 221 | { 222 | super.onMouseMove(mea); 223 | 224 | if(downing) 225 | { 226 | switch(dock) 227 | { 228 | case DockStyle.TOP: 229 | case DockStyle.BOTTOM: 230 | drawxorClient(0, mea.y - downpos, 0, lastpos); 231 | lastpos = mea.y - downpos; 232 | break; 233 | 234 | default: // LEFT / RIGHT. 235 | drawxorClient(mea.x - downpos, 0, lastpos, 0); 236 | lastpos = mea.x - downpos; 237 | } 238 | 239 | scope sea = new SplitterEventArgs(mea.x, mea.y, left, top); 240 | onSplitterMoving(sea); 241 | } 242 | } 243 | 244 | 245 | protected override void onMove(EventArgs ea) 246 | { 247 | super.onMove(ea); 248 | 249 | if(downing) // ? 250 | { 251 | Point curpos = Cursor.position; 252 | curpos = pointToClient(curpos); 253 | scope sea = new SplitterEventArgs(curpos.x, curpos.y, left, top); 254 | onSplitterMoved(sea); 255 | } 256 | } 257 | 258 | 259 | final Control getSplitControl() // package 260 | { 261 | Control splat; // Splitted. 262 | // DMD 0.95: need 'this' to access member dock 263 | //switch(dock()) 264 | final switch(this.dock()) 265 | { 266 | case DockStyle.LEFT: 267 | foreach(Control ctrl; parent.controls()) 268 | { 269 | if(DockStyle.LEFT != ctrl.dock) //if(this.dock != ctrl.dock) 270 | continue; 271 | // DMD 0.95: overloads int(Object o) and int(Control ctrl) both match argument list for opEquals 272 | //if(ctrl == this) 273 | if(ctrl == cast(Control)this) 274 | return splat; 275 | splat = ctrl; 276 | } 277 | break; 278 | 279 | case DockStyle.RIGHT: 280 | foreach(Control ctrl; parent.controls()) 281 | { 282 | if(DockStyle.RIGHT != ctrl.dock) //if(this.dock != ctrl.dock) 283 | continue; 284 | // DMD 0.95: overloads int(Object o) and int(Control ctrl) both match argument list for opEquals 285 | //if(ctrl == this) 286 | if(ctrl == cast(Control)this) 287 | return splat; 288 | splat = ctrl; 289 | } 290 | break; 291 | 292 | case DockStyle.TOP: 293 | foreach(Control ctrl; parent.controls()) 294 | { 295 | if(DockStyle.TOP != ctrl.dock) //if(this.dock != ctrl.dock) 296 | continue; 297 | // DMD 0.95: overloads int(Object o) and int(Control ctrl) both match argument list for opEquals 298 | //if(ctrl == this) 299 | if(ctrl == cast(Control)this) 300 | return splat; 301 | splat = ctrl; 302 | } 303 | break; 304 | 305 | case DockStyle.BOTTOM: 306 | foreach(Control ctrl; parent.controls()) 307 | { 308 | if(DockStyle.BOTTOM != ctrl.dock) //if(this.dock != ctrl.dock) 309 | continue; 310 | // DMD 0.95: overloads int(Object o) and int(Control ctrl) both match argument list for opEquals 311 | //if(ctrl == this) 312 | if(ctrl == cast(Control)this) 313 | return splat; 314 | splat = ctrl; 315 | } 316 | break; 317 | 318 | case DockStyle.FILL: 319 | assert("DockStyle.FILL is not allowed in Splitter"); 320 | break; 321 | 322 | case DockStyle.NONE: 323 | assert("DockStyle.NONE is not allowed in Splitter"); 324 | break; 325 | } 326 | return null; 327 | } 328 | 329 | 330 | protected override void onMouseUp(MouseEventArgs mea) 331 | { 332 | if(downing) 333 | { 334 | capture = false; 335 | 336 | downing = false; 337 | 338 | if(mea.button != MouseButtons.LEFT) 339 | { 340 | // Abort. 341 | switch(dock) 342 | { 343 | case DockStyle.TOP: 344 | case DockStyle.BOTTOM: 345 | drawxorClient(0, lastpos); 346 | break; 347 | 348 | default: // LEFT / RIGHT. 349 | drawxorClient(lastpos, 0); 350 | } 351 | super.onMouseUp(mea); 352 | return; 353 | } 354 | 355 | int adj, val, vx; 356 | auto splat = getSplitControl(); // Splitted. 357 | if(splat) 358 | { 359 | // DMD 0.95: need 'this' to access member dock 360 | //switch(dock()) 361 | switch(this.dock()) 362 | { 363 | case DockStyle.LEFT: 364 | drawxorClient(lastpos, 0); 365 | //val = left - splat.left + mea.x - downpos.x; 366 | val = left - splat.left + mea.x - downpos; 367 | if(val < msize) 368 | val = msize; 369 | splat.width = val; 370 | break; 371 | 372 | case DockStyle.RIGHT: 373 | drawxorClient(lastpos, 0); 374 | //adj = right - splat.left + mea.x - downpos.x; 375 | adj = right - splat.left + mea.x - downpos; 376 | val = splat.width - adj; 377 | vx = splat.left + adj; 378 | if(val < msize) 379 | { 380 | vx -= msize - val; 381 | val = msize; 382 | } 383 | splat.bounds = Rect(vx, splat.top, val, splat.height); 384 | break; 385 | 386 | case DockStyle.TOP: 387 | drawxorClient(0, lastpos); 388 | //val = top - splat.top + mea.y - downpos.y; 389 | val = top - splat.top + mea.y - downpos; 390 | if(val < msize) 391 | val = msize; 392 | splat.height = val; 393 | break; 394 | 395 | case DockStyle.BOTTOM: 396 | drawxorClient(0, lastpos); 397 | //adj = bottom - splat.top + mea.y - downpos.y; 398 | adj = bottom - splat.top + mea.y - downpos; 399 | val = splat.height - adj; 400 | vx = splat.top + adj; 401 | if(val < msize) 402 | { 403 | vx -= msize - val; 404 | val = msize; 405 | } 406 | splat.bounds = Rect(splat.left, vx, splat.width, val); 407 | break; 408 | 409 | default: 410 | } 411 | } 412 | 413 | // This is needed when the moved control first overlaps the splitter and the splitter 414 | // gets bumped over, causing a little area to not be updated correctly. 415 | // I'll fix it someday. 416 | parent.invalidate(true); 417 | 418 | // Event.. 419 | } 420 | 421 | super.onMouseUp(mea); 422 | } 423 | 424 | 425 | /+ 426 | // Not quite sure how to implement this yet. 427 | // Might need to scan all controls until one of: 428 | // Control with opposite dock (right if left dock): stay -mextra- away from it, 429 | // Control with fill dock: that control can't have less than -mextra- width, 430 | // Reached end of child controls: stay -mextra- away from the edge. 431 | 432 | /// 433 | final @property void minExtra(int min) // setter 434 | { 435 | mextra = min; 436 | } 437 | 438 | /// ditto 439 | final @property int minExtra() // getter 440 | { 441 | return mextra; 442 | } 443 | +/ 444 | 445 | 446 | /// 447 | final @property void minSize(int min) // setter 448 | { 449 | msize = min; 450 | } 451 | 452 | /// ditto 453 | final @property int minSize() // getter 454 | { 455 | return msize; 456 | } 457 | 458 | 459 | /// 460 | final @property void splitPosition(int pos) // setter 461 | { 462 | auto splat = getSplitControl(); // Splitted. 463 | if(splat) 464 | { 465 | // DMD 0.95: need 'this' to access member dock 466 | //switch(dock()) 467 | switch(this.dock()) 468 | { 469 | case DockStyle.LEFT: 470 | case DockStyle.RIGHT: 471 | splat.width = pos; 472 | break; 473 | 474 | case DockStyle.TOP: 475 | case DockStyle.BOTTOM: 476 | splat.height = pos; 477 | break; 478 | 479 | default: 480 | } 481 | } 482 | } 483 | 484 | /// ditto 485 | // -1 if not docked to a control. 486 | final @property int splitPosition() // getter 487 | { 488 | auto splat = getSplitControl(); // Splitted. 489 | if(splat) 490 | { 491 | // DMD 0.95: need 'this' to access member dock 492 | //switch(dock()) 493 | switch(this.dock()) 494 | { 495 | case DockStyle.LEFT: 496 | case DockStyle.RIGHT: 497 | return splat.width; 498 | 499 | case DockStyle.TOP: 500 | case DockStyle.BOTTOM: 501 | return splat.height; 502 | 503 | default: 504 | } 505 | } 506 | return -1; 507 | } 508 | 509 | 510 | //SplitterEventHandler splitterMoved; 511 | Event!(Splitter, SplitterEventArgs) splitterMoved; /// 512 | //SplitterEventHandler splitterMoving; 513 | Event!(Splitter, SplitterEventArgs) splitterMoving; /// 514 | 515 | 516 | protected: 517 | 518 | override @property Size defaultSize() // getter 519 | { 520 | //return Size(GetSystemMetrics(SM_CXSIZEFRAME), GetSystemMetrics(SM_CYSIZEFRAME)); 521 | int sx = GetSystemMetrics(SM_CXSIZEFRAME); 522 | int sy = GetSystemMetrics(SM_CYSIZEFRAME); 523 | // Need a bit extra room for the move-grips. 524 | if(sx < 5) 525 | sx = 5; 526 | if(sy < 5) 527 | sy = 5; 528 | return Size(sx, sy); 529 | } 530 | 531 | 532 | /// 533 | void onSplitterMoving(SplitterEventArgs sea) 534 | { 535 | splitterMoving(this, sea); 536 | } 537 | 538 | 539 | /// 540 | void onSplitterMoved(SplitterEventArgs sea) 541 | { 542 | splitterMoving(this, sea); 543 | } 544 | 545 | 546 | private: 547 | 548 | bool downing = false; 549 | bool mgrip = true; 550 | //Point downpos; 551 | int downpos; 552 | int lastpos; 553 | int msize = 25; // Min size of control that's being sized from the splitter. 554 | int mextra = 25; // Min size of the control on the opposite side. 555 | 556 | static HBRUSH hbrxor; 557 | 558 | 559 | static void inithbrxor() 560 | { 561 | static ubyte[] bmbits = [0xAA, 0, 0x55, 0, 0xAA, 0, 0x55, 0, 562 | 0xAA, 0, 0x55, 0, 0xAA, 0, 0x55, 0, ]; 563 | 564 | HBITMAP hbm; 565 | hbm = CreateBitmap(8, 8, 1, 1, bmbits.ptr); 566 | hbrxor = CreatePatternBrush(hbm); 567 | DeleteObject(hbm); 568 | } 569 | 570 | 571 | static void drawxor(HDC hdc, Rect r) 572 | { 573 | SetBrushOrgEx(hdc, r.x, r.y, null); 574 | HGDIOBJ hbrold = SelectObject(hdc, hbrxor); 575 | PatBlt(hdc, r.x, r.y, r.width, r.height, PATINVERT); 576 | SelectObject(hdc, hbrold); 577 | } 578 | 579 | 580 | void drawxorClient(HDC hdc, int x, int y) 581 | { 582 | POINT pt; 583 | pt.x = x; 584 | pt.y = y; 585 | //ClientToScreen(handle, &pt); 586 | MapWindowPoints(handle, parent.handle, &pt, 1); 587 | 588 | drawxor(hdc, Rect(pt.x, pt.y, width, height)); 589 | } 590 | 591 | 592 | void drawxorClient(int x, int y, int xold = int.min, int yold = int.min) 593 | { 594 | HDC hdc; 595 | //hdc = GetWindowDC(null); 596 | hdc = GetDCEx(parent.handle, null, DCX_CACHE); 597 | 598 | if(xold != int.min) 599 | drawxorClient(hdc, xold, yold); 600 | 601 | drawxorClient(hdc, x, y); 602 | 603 | ReleaseDC(null, hdc); 604 | } 605 | } 606 | 607 | -------------------------------------------------------------------------------- /source/dfl/statusbar.d: -------------------------------------------------------------------------------- 1 | // Written by Christopher E. Miller 2 | // See the included license.txt for copyright and license details. 3 | 4 | 5 | /// 6 | module dfl.statusbar; 7 | 8 | 9 | private import dfl.control, dfl.base, dfl.internal.winapi, dfl.event, 10 | dfl.collections, dfl.internal.utf, dfl.internal.dlib, dfl.application; 11 | 12 | private import dfl.internal.dlib; 13 | 14 | 15 | private extern(Windows) void _initStatusbar(); 16 | 17 | 18 | /+ 19 | enum StatusBarPanelAutoSize: ubyte 20 | { 21 | NONE, 22 | CONTENTS, 23 | SPRING, 24 | } 25 | +/ 26 | 27 | 28 | /// 29 | enum StatusBarPanelBorderStyle: ubyte 30 | { 31 | NONE, /// 32 | SUNKEN, /// ditto 33 | RAISED /// ditto 34 | } 35 | 36 | 37 | /// 38 | class StatusBarPanel: DObject 39 | { 40 | /// 41 | this(Dstring text) 42 | { 43 | this._txt = text; 44 | } 45 | 46 | /// ditto 47 | this(Dstring text, int width) 48 | { 49 | this._txt = text; 50 | this._width = width; 51 | } 52 | 53 | /// ditto 54 | this() 55 | { 56 | } 57 | 58 | 59 | override Dstring toString() 60 | { 61 | return _txt; 62 | } 63 | 64 | 65 | override Dequ opEquals(Object o) 66 | { 67 | return _txt == getObjectString(o); // ? 68 | } 69 | 70 | Dequ opEquals(StatusBarPanel pnl) 71 | { 72 | return _txt == pnl._txt; 73 | } 74 | 75 | Dequ opEquals(Dstring val) 76 | { 77 | return _txt == val; 78 | } 79 | 80 | 81 | override int opCmp(Object o) 82 | { 83 | return stringICmp(_txt, getObjectString(o)); // ? 84 | } 85 | 86 | int opCmp(StatusBarPanel pnl) 87 | { 88 | return stringICmp(_txt, pnl._txt); 89 | } 90 | 91 | int opCmp(Dstring val) 92 | { 93 | return stringICmp(_txt, val); 94 | } 95 | 96 | 97 | /+ 98 | /// 99 | final @property void alignment(HorizontalAlignment ha) // setter 100 | { 101 | 102 | } 103 | 104 | /// ditto 105 | final @property HorizontalAlignment alignment() // getter 106 | { 107 | //LEFT 108 | } 109 | +/ 110 | 111 | 112 | /+ 113 | /// 114 | final @property void autoSize(StatusBarPanelAutoSize asize) // setter 115 | { 116 | 117 | } 118 | 119 | /// ditto 120 | final @property StatusBarPanelAutoSize autoSize() // getter 121 | { 122 | //NONE 123 | } 124 | +/ 125 | 126 | 127 | /// 128 | final @property void borderStyle(StatusBarPanelBorderStyle bs) // setter 129 | { 130 | switch(bs) 131 | { 132 | case StatusBarPanelBorderStyle.NONE: 133 | _utype = (_utype & ~SBT_POPOUT) | SBT_NOBORDERS; 134 | break; 135 | 136 | case StatusBarPanelBorderStyle.RAISED: 137 | _utype = (_utype & ~SBT_NOBORDERS) | SBT_POPOUT; 138 | break; 139 | 140 | case StatusBarPanelBorderStyle.SUNKEN: 141 | _utype &= ~(SBT_NOBORDERS | SBT_POPOUT); 142 | break; 143 | 144 | default: 145 | assert(0); 146 | } 147 | 148 | if(_parent && _parent.isHandleCreated) 149 | { 150 | _parent.panels._fixtexts(); // Also fixes styles. 151 | } 152 | } 153 | 154 | /// ditto 155 | final @property StatusBarPanelBorderStyle borderStyle() // getter 156 | { 157 | if(_utype & SBT_POPOUT) 158 | return StatusBarPanelBorderStyle.RAISED; 159 | if(_utype & SBT_NOBORDERS) 160 | return StatusBarPanelBorderStyle.NONE; 161 | return StatusBarPanelBorderStyle.RAISED; 162 | } 163 | 164 | 165 | // icon 166 | 167 | 168 | /+ 169 | /// 170 | final @property void minWidth(int mw) // setter 171 | in 172 | { 173 | assert(mw >= 0); 174 | } 175 | body 176 | { 177 | 178 | } 179 | 180 | /// ditto 181 | final @property int minWidth() // getter 182 | { 183 | //10 184 | } 185 | +/ 186 | 187 | 188 | /// 189 | final @property StatusBar parent() // getter 190 | { 191 | return _parent; 192 | } 193 | 194 | 195 | // style 196 | 197 | 198 | /// 199 | final @property void text(Dstring txt) // setter 200 | { 201 | if(_parent && _parent.isHandleCreated) 202 | { 203 | int idx = _parent.panels.indexOf(this); 204 | assert(-1 != idx); 205 | _parent._sendidxtext(idx, _utype, txt); 206 | } 207 | 208 | this._txt = txt; 209 | } 210 | 211 | /// ditto 212 | final @property Dstring text() // getter 213 | { 214 | return _txt; 215 | } 216 | 217 | 218 | /+ 219 | /// 220 | final @property void toolTipText(Dstring txt) // setter 221 | { 222 | 223 | } 224 | 225 | /// ditto 226 | final @property Dstring toolTipText() // getter 227 | { 228 | //null 229 | } 230 | +/ 231 | 232 | 233 | /// 234 | final @property void width(int w) // setter 235 | { 236 | _width = w; 237 | 238 | if(_parent && _parent.isHandleCreated) 239 | { 240 | _parent.panels._fixwidths(); 241 | } 242 | } 243 | 244 | /// ditto 245 | final @property int width() // getter 246 | { 247 | return _width; 248 | } 249 | 250 | 251 | private: 252 | 253 | Dstring _txt = null; 254 | int _width = 100; 255 | StatusBar _parent = null; 256 | WPARAM _utype = 0; // StatusBarPanelBorderStyle.SUNKEN. 257 | } 258 | 259 | 260 | /+ 261 | /// 262 | class StatusBarPanelClickEventArgs: MouseEventArgs 263 | { 264 | /// 265 | this(StatusBarPanel sbpanel, MouseButtons btn, int clicks, int x, int y) 266 | { 267 | this._sbpanel = sbpanel; 268 | super(btn, clicks, x, y, 0); 269 | } 270 | 271 | 272 | private: 273 | StatusBarPanel _sbpanel; 274 | } 275 | +/ 276 | 277 | 278 | /// 279 | class StatusBar: ControlSuperClass // docmain 280 | { 281 | /// 282 | class StatusBarPanelCollection 283 | { 284 | protected this(StatusBar sb) 285 | in 286 | { 287 | assert(sb.lpanels is null); 288 | } 289 | body 290 | { 291 | this.sb = sb; 292 | } 293 | 294 | 295 | private: 296 | 297 | StatusBar sb; 298 | package StatusBarPanel[] _panels; 299 | 300 | 301 | package void _fixwidths() 302 | { 303 | assert(isHandleCreated); 304 | 305 | UINT[20] _pws = void; 306 | UINT[] pws = _pws; 307 | if(_panels.length > _pws.length) 308 | pws = new UINT[_panels.length]; 309 | UINT right = 0; 310 | foreach(idx, pnl; _panels) 311 | { 312 | if(-1 == pnl.width) 313 | { 314 | pws[idx] = -1; 315 | } 316 | else 317 | { 318 | right += pnl.width; 319 | pws[idx] = right; 320 | } 321 | } 322 | sb.prevwproc(SB_SETPARTS, cast(WPARAM)_panels.length, cast(LPARAM)pws.ptr); 323 | } 324 | 325 | 326 | void _fixtexts() 327 | { 328 | assert(isHandleCreated); 329 | 330 | if(dfl.internal.utf.useUnicode) 331 | { 332 | foreach(idx, pnl; _panels) 333 | { 334 | sb.prevwproc(SB_SETTEXTW, cast(WPARAM)idx | pnl._utype, cast(LPARAM)dfl.internal.utf.toUnicodez(pnl._txt)); 335 | } 336 | } 337 | else 338 | { 339 | foreach(idx, pnl; _panels) 340 | { 341 | sb.prevwproc(SB_SETTEXTA, cast(WPARAM)idx | pnl._utype, cast(LPARAM)dfl.internal.utf.toAnsiz(pnl._txt)); 342 | } 343 | } 344 | } 345 | 346 | 347 | void _setcurparts() 348 | { 349 | assert(isHandleCreated); 350 | 351 | _fixwidths(); 352 | 353 | _fixtexts(); 354 | } 355 | 356 | 357 | void _removed(size_t idx, Object val) 358 | { 359 | if(size_t.max == idx) // Clear all. 360 | { 361 | if(sb.isHandleCreated) 362 | { 363 | sb.prevwproc(SB_SETPARTS, 0, 0); // 0 parts. 364 | } 365 | } 366 | else 367 | { 368 | if(sb.isHandleCreated) 369 | { 370 | _setcurparts(); 371 | } 372 | } 373 | } 374 | 375 | 376 | void _added(size_t idx, StatusBarPanel val) 377 | { 378 | if(val._parent) 379 | throw new DflException("StatusBarPanel already belongs to a StatusBar"); 380 | 381 | val._parent = sb; 382 | 383 | if(sb.isHandleCreated) 384 | { 385 | _setcurparts(); 386 | } 387 | } 388 | 389 | 390 | void _adding(size_t idx, StatusBarPanel val) 391 | { 392 | if(_panels.length >= 254) // Since SB_SETTEXT with 255 has special meaning. 393 | throw new DflException("Too many status bar panels"); 394 | } 395 | 396 | 397 | public: 398 | 399 | mixin ListWrapArray!(StatusBarPanel, _panels, 400 | _adding, _added, 401 | _blankListCallback!(StatusBarPanel), _removed, 402 | true, /+true+/ false, false) _wraparray; 403 | } 404 | 405 | 406 | /// 407 | this() 408 | { 409 | _initStatusbar(); 410 | 411 | _issimple = true; 412 | wstyle |= SBARS_SIZEGRIP; 413 | wclassStyle = statusbarClassStyle; 414 | //height = ?; 415 | dock = DockStyle.BOTTOM; 416 | 417 | lpanels = new StatusBarPanelCollection(this); 418 | } 419 | 420 | 421 | // backColor / font / foreColor ... 422 | 423 | 424 | override @property void dock(DockStyle ds) // setter 425 | { 426 | switch(ds) 427 | { 428 | case DockStyle.BOTTOM: 429 | case DockStyle.TOP: 430 | super.dock = ds; 431 | break; 432 | 433 | default: 434 | throw new DflException("Invalid status bar dock"); 435 | } 436 | } 437 | 438 | alias Control.dock dock; // Overload. 439 | 440 | 441 | /// 442 | final @property StatusBarPanelCollection panels() // getter 443 | { 444 | return lpanels; 445 | } 446 | 447 | 448 | /// 449 | final @property void showPanels(bool byes) // setter 450 | { 451 | if(!byes == _issimple) 452 | return; 453 | 454 | if(isHandleCreated) 455 | { 456 | prevwproc(SB_SIMPLE, cast(WPARAM)!byes, 0); 457 | 458 | /+ // It's kept in sync even if simple. 459 | if(byes) 460 | { 461 | panels._setcurparts(); 462 | } 463 | +/ 464 | 465 | if(!byes) 466 | { 467 | _sendidxtext(255, 0, _simpletext); 468 | } 469 | } 470 | 471 | _issimple = !byes; 472 | } 473 | 474 | /// ditto 475 | final @property bool showPanels() // getter 476 | { 477 | return !_issimple; 478 | } 479 | 480 | 481 | /// 482 | final @property void sizingGrip(bool byes) // setter 483 | { 484 | if(byes == sizingGrip) 485 | return; 486 | 487 | if(byes) 488 | _style(_style() | SBARS_SIZEGRIP); 489 | else 490 | _style(_style() & ~SBARS_SIZEGRIP); 491 | } 492 | 493 | /// ditto 494 | final @property bool sizingGrip() // getter 495 | { 496 | if(wstyle & SBARS_SIZEGRIP) 497 | return true; 498 | return false; 499 | } 500 | 501 | 502 | override @property void text(Dstring txt) // setter 503 | { 504 | if(isHandleCreated && !showPanels) 505 | { 506 | _sendidxtext(255, 0, txt); 507 | } 508 | 509 | this._simpletext = txt; 510 | 511 | onTextChanged(EventArgs.empty); 512 | } 513 | 514 | /// ditto 515 | override @property Dstring text() // getter 516 | { 517 | return this._simpletext; 518 | } 519 | 520 | 521 | protected override void onHandleCreated(EventArgs ea) 522 | { 523 | super.onHandleCreated(ea); 524 | 525 | if(_issimple) 526 | { 527 | prevwproc(SB_SIMPLE, cast(WPARAM)true, 0); 528 | panels._setcurparts(); 529 | if(_simpletext.length) 530 | _sendidxtext(255, 0, _simpletext); 531 | } 532 | else 533 | { 534 | panels._setcurparts(); 535 | prevwproc(SB_SIMPLE, cast(WPARAM)false, 0); 536 | } 537 | } 538 | 539 | 540 | protected override void createParams(ref CreateParams cp) 541 | { 542 | super.createParams(cp); 543 | 544 | cp.className = STATUSBAR_CLASSNAME; 545 | } 546 | 547 | 548 | protected override void prevWndProc(ref Message msg) 549 | { 550 | //msg.result = CallWindowProcA(statusbarPrevWndProc, msg.hWnd, msg.msg, msg.wParam, msg.lParam); 551 | msg.result = dfl.internal.utf.callWindowProc(statusbarPrevWndProc, msg.hWnd, msg.msg, msg.wParam, msg.lParam); 552 | } 553 | 554 | 555 | /+ 556 | protected override void createHandle() 557 | { 558 | //CreateStatusWindow 559 | } 560 | +/ 561 | 562 | 563 | //StatusBarPanelClickEventHandler panelClick; 564 | //Event!(StatusBar, StatusBarPanelClickEventArgs) panelClick; /// 565 | 566 | 567 | protected: 568 | 569 | // onDrawItem ... 570 | 571 | 572 | /+ 573 | /// 574 | void onPanelClick(StatusBarPanelClickEventArgs ea) 575 | { 576 | panelClick(this, ea); 577 | } 578 | +/ 579 | 580 | 581 | private: 582 | 583 | StatusBarPanelCollection lpanels; 584 | Dstring _simpletext = null; 585 | bool _issimple = true; 586 | 587 | 588 | package: 589 | final: 590 | 591 | LRESULT prevwproc(UINT msg, WPARAM wparam, LPARAM lparam) 592 | { 593 | //return CallWindowProcA(statusbarPrevWndProc, hwnd, msg, wparam, lparam); 594 | return dfl.internal.utf.callWindowProc(statusbarPrevWndProc, hwnd, msg, wparam, lparam); 595 | } 596 | 597 | 598 | void _sendidxtext(int idx, WPARAM utype, Dstring txt) 599 | { 600 | assert(isHandleCreated); 601 | 602 | if(dfl.internal.utf.useUnicode) 603 | prevwproc(SB_SETTEXTW, cast(WPARAM)idx | utype, cast(LPARAM)dfl.internal.utf.toUnicodez(txt)); 604 | else 605 | prevwproc(SB_SETTEXTA, cast(WPARAM)idx | utype, cast(LPARAM)dfl.internal.utf.toAnsiz(txt)); 606 | } 607 | } 608 | 609 | -------------------------------------------------------------------------------- /source/dfl/timer.d: -------------------------------------------------------------------------------- 1 | // Written by Christopher E. Miller 2 | // See the included license.txt for copyright and license details. 3 | 4 | 5 | /// 6 | module dfl.timer; 7 | 8 | private import dfl.internal.winapi, dfl.event, dfl.base, dfl.application, 9 | dfl.internal.dlib; 10 | 11 | 12 | /// 13 | class Timer // docmain 14 | { 15 | //EventHandler tick; 16 | Event!(Timer, EventArgs) tick; /// 17 | 18 | 19 | /// 20 | @property void enabled(bool on) // setter 21 | { 22 | if(on) 23 | start(); 24 | else 25 | stop(); 26 | } 27 | 28 | /// ditto 29 | @property bool enabled() // getter 30 | { 31 | return timerId != 0; 32 | } 33 | 34 | 35 | /// 36 | final @property void interval(uint timeout) // setter 37 | { 38 | if(!timeout) 39 | throw new DflException("Invalid timer interval"); 40 | 41 | if(this._timeout != timeout) 42 | { 43 | this._timeout = timeout; 44 | 45 | if(timerId) 46 | { 47 | // I don't know if this is the correct behavior. 48 | // Reset the timer for the new timeout... 49 | stop(); 50 | start(); 51 | } 52 | } 53 | } 54 | 55 | /// ditto 56 | final @property size_t interval() // getter 57 | { 58 | return _timeout; 59 | } 60 | 61 | 62 | /// 63 | final void start() 64 | { 65 | if(timerId) 66 | return; 67 | 68 | assert(_timeout > 0); 69 | 70 | timerId = SetTimer(null, 0, _timeout, &timerProc); 71 | if(!timerId) 72 | throw new DflException("Unable to start timer"); 73 | allTimers[timerId] = this; 74 | } 75 | 76 | /// ditto 77 | final void stop() 78 | { 79 | if(timerId) 80 | { 81 | //delete allTimers[timerId]; 82 | allTimers.remove(timerId); 83 | KillTimer(null, timerId); 84 | timerId = 0; 85 | } 86 | } 87 | 88 | 89 | /// 90 | this() 91 | { 92 | } 93 | 94 | /// ditto 95 | this(void delegate(Timer) dg) 96 | { 97 | this(); 98 | if(dg) 99 | { 100 | this._dg = dg; 101 | tick ~= &_dgcall; 102 | } 103 | } 104 | 105 | /// ditto 106 | this(void delegate(Object, EventArgs) dg) 107 | { 108 | assert(dg !is null); 109 | 110 | this(); 111 | tick ~= dg; 112 | } 113 | 114 | /// ditto 115 | this(void delegate(Timer, EventArgs) dg) 116 | { 117 | assert(dg !is null); 118 | 119 | this(); 120 | tick ~= dg; 121 | } 122 | 123 | 124 | ~this() 125 | { 126 | dispose(); 127 | } 128 | 129 | 130 | protected: 131 | 132 | void dispose() 133 | { 134 | stop(); 135 | } 136 | 137 | 138 | /// 139 | void onTick(EventArgs ea) 140 | { 141 | tick(this, ea); 142 | } 143 | 144 | 145 | private: 146 | uint _timeout = 100; 147 | uint timerId = 0; 148 | void delegate(Timer) _dg; 149 | 150 | 151 | void _dgcall(Object sender, EventArgs ea) 152 | { 153 | assert(_dg !is null); 154 | _dg(this); 155 | } 156 | } 157 | 158 | 159 | private: 160 | 161 | Timer[size_t] allTimers; 162 | 163 | 164 | extern(Windows) void timerProc(HWND hwnd, UINT uMsg, size_t idEvent, DWORD dwTime) nothrow 165 | { 166 | try 167 | { 168 | if(idEvent in allTimers) 169 | { 170 | allTimers[idEvent].onTick(EventArgs.empty); 171 | } 172 | else 173 | { 174 | debug(APP_PRINT) 175 | cprintf("Unknown timer 0x%X.\n", idEvent); 176 | } 177 | } 178 | catch(DThrowable e) 179 | { 180 | Application.onThreadException(e); 181 | } 182 | } 183 | 184 | -------------------------------------------------------------------------------- /source/dfl/tooltip.d: -------------------------------------------------------------------------------- 1 | // Written by Christopher E. Miller 2 | // See the included license.txt for copyright and license details. 3 | 4 | 5 | /// 6 | module dfl.tooltip; 7 | 8 | 9 | private import dfl.internal.dlib, dfl.internal.clib; 10 | 11 | private import dfl.control, dfl.base, dfl.application, dfl.internal.winapi, 12 | dfl.internal.utf; 13 | 14 | 15 | /// 16 | class ToolTip // docmain 17 | { 18 | package this(DWORD style) 19 | { 20 | _initCommonControls(ICC_TREEVIEW_CLASSES); // Includes tooltip. 21 | 22 | hwtt = CreateWindowExA(WS_EX_TOPMOST | WS_EX_TOOLWINDOW, _TOOLTIPS_CLASSA.ptr, 23 | "", style, 0, 0, 50, 50, null, null, null, null); 24 | if(!hwtt) 25 | throw new DflException("Unable to create tooltip"); 26 | } 27 | 28 | 29 | this() 30 | { 31 | this(cast(DWORD)WS_POPUP); 32 | } 33 | 34 | 35 | ~this() 36 | { 37 | removeAll(); // Fixes ref count. 38 | DestroyWindow(hwtt); 39 | } 40 | 41 | 42 | /// 43 | final @property HWND handle() // getter 44 | { 45 | return hwtt; 46 | } 47 | 48 | 49 | /// 50 | final @property void active(bool byes) // setter 51 | { 52 | SendMessageA(hwtt, TTM_ACTIVATE, byes, 0); // ? 53 | _active = byes; 54 | } 55 | 56 | /// ditto 57 | final @property bool active() // getter 58 | { 59 | return _active; 60 | } 61 | 62 | 63 | /// 64 | // Sets autoPopDelay, initialDelay and reshowDelay. 65 | final @property void automaticDelay(DWORD ms) // setter 66 | { 67 | SendMessageA(hwtt, TTM_SETDELAYTIME, TTDT_AUTOMATIC, ms); 68 | } 69 | 70 | /+ 71 | /// ditto 72 | final @property DWORD automaticDelay() // getter 73 | { 74 | } 75 | +/ 76 | 77 | 78 | /// 79 | final @property void autoPopDelay(DWORD ms) // setter 80 | { 81 | SendMessageA(hwtt, TTM_SETDELAYTIME, TTDT_AUTOPOP, ms); 82 | } 83 | 84 | /+ 85 | /// ditto 86 | final @property DWORD autoPopDelay() // getter 87 | { 88 | } 89 | +/ 90 | 91 | 92 | /// 93 | final @property void initialDelay(DWORD ms) // setter 94 | { 95 | SendMessageA(hwtt, TTM_SETDELAYTIME, TTDT_INITIAL, ms); 96 | } 97 | 98 | /+ 99 | /// ditto 100 | final @property DWORD initialDelay() // getter 101 | { 102 | } 103 | +/ 104 | 105 | 106 | /// 107 | final @property void reshowDelay(DWORD ms) // setter 108 | { 109 | SendMessageA(hwtt, TTM_SETDELAYTIME, TTDT_RESHOW, ms); 110 | } 111 | 112 | /+ 113 | /// ditto 114 | final @property DWORD reshowDelay() // getter 115 | { 116 | } 117 | +/ 118 | 119 | 120 | /// 121 | final @property void showAlways(bool byes) // setter 122 | { 123 | LONG wl; 124 | wl = GetWindowLongA(hwtt, GWL_STYLE); 125 | if(byes) 126 | { 127 | if(wl & TTS_ALWAYSTIP) 128 | return; 129 | wl |= TTS_ALWAYSTIP; 130 | } 131 | else 132 | { 133 | if(!(wl & TTS_ALWAYSTIP)) 134 | return; 135 | wl &= ~TTS_ALWAYSTIP; 136 | } 137 | SetWindowLongA(hwtt, GWL_STYLE, wl); 138 | } 139 | 140 | /// ditto 141 | final @property bool showAlways() // getter 142 | { 143 | return (GetWindowLongA(hwtt, GWL_STYLE) & TTS_ALWAYSTIP) != 0; 144 | } 145 | 146 | 147 | /// 148 | // Remove all tooltip text associated with this instance. 149 | final void removeAll() 150 | { 151 | TOOLINFOA tool; 152 | tool.cbSize = TOOLINFOA.sizeof; 153 | while(SendMessageA(hwtt, TTM_ENUMTOOLSA, 0, cast(LPARAM)&tool)) 154 | { 155 | SendMessageA(hwtt, TTM_DELTOOLA, 0, cast(LPARAM)&tool); 156 | Application.refCountDec(cast(void*)this); 157 | } 158 | } 159 | 160 | 161 | /// 162 | // WARNING: possible buffer overflow. 163 | final Dstring getToolTip(Control ctrl) 164 | { 165 | Dstring result; 166 | TOOLINFOA tool; 167 | tool.cbSize = TOOLINFOA.sizeof; 168 | tool.uFlags = TTF_IDISHWND; 169 | tool.hwnd = ctrl.handle; 170 | tool.uId = cast(UINT)ctrl.handle; 171 | 172 | if(dfl.internal.utf.useUnicode) 173 | { 174 | tool.lpszText = cast(typeof(tool.lpszText))dfl.internal.clib.malloc((MAX_TIP_TEXT_LENGTH + 1) * wchar.sizeof); 175 | if(!tool.lpszText) 176 | throw new OomException; 177 | scope(exit) 178 | dfl.internal.clib.free(tool.lpszText); 179 | tool.lpszText[0 .. 2] = 0; 180 | SendMessageA(hwtt, TTM_GETTEXTW, 0, cast(LPARAM)&tool); 181 | if(!(cast(wchar*)tool.lpszText)[0]) 182 | result = null; 183 | else 184 | result = fromUnicodez(cast(wchar*)tool.lpszText); 185 | } 186 | else 187 | { 188 | tool.lpszText = cast(typeof(tool.lpszText))dfl.internal.clib.malloc(MAX_TIP_TEXT_LENGTH + 1); 189 | if(!tool.lpszText) 190 | throw new OomException; 191 | scope(exit) 192 | dfl.internal.clib.free(tool.lpszText); 193 | tool.lpszText[0] = 0; 194 | SendMessageA(hwtt, TTM_GETTEXTA, 0, cast(LPARAM)&tool); 195 | if(!tool.lpszText[0]) 196 | result = null; 197 | else 198 | result = fromAnsiz(tool.lpszText); // Assumes fromAnsiz() copies. 199 | } 200 | return result; 201 | } 202 | 203 | /// ditto 204 | final void setToolTip(Control ctrl, Dstring text) 205 | in 206 | { 207 | try 208 | { 209 | ctrl.createControl(); 210 | } 211 | catch(DThrowable o) 212 | { 213 | assert(0); // If -ctrl- is a child, make sure the parent is set before setting tool tip text. 214 | //throw o; 215 | } 216 | } 217 | body 218 | { 219 | TOOLINFOA tool; 220 | tool.cbSize = TOOLINFOA.sizeof; 221 | tool.uFlags = TTF_IDISHWND; 222 | tool.hwnd = ctrl.handle; 223 | tool.uId = cast(UINT)ctrl.handle; 224 | 225 | if(!text.length) 226 | { 227 | if(SendMessageA(hwtt, TTM_GETTOOLINFOA, 0, cast(LPARAM)&tool)) 228 | { 229 | // Remove. 230 | 231 | SendMessageA(hwtt, TTM_DELTOOLA, 0, cast(LPARAM)&tool); 232 | 233 | Application.refCountDec(cast(void*)this); 234 | } 235 | return; 236 | } 237 | 238 | // Hack to help prevent getToolTip() overflow. 239 | if(text.length > MAX_TIP_TEXT_LENGTH) 240 | text = text[0 .. MAX_TIP_TEXT_LENGTH]; 241 | 242 | if(SendMessageA(hwtt, TTM_GETTOOLINFOA, 0, cast(LPARAM)&tool)) 243 | { 244 | // Update. 245 | 246 | if(dfl.internal.utf.useUnicode) 247 | { 248 | tool.lpszText = cast(typeof(tool.lpszText))toUnicodez(text); 249 | SendMessageA(hwtt, TTM_UPDATETIPTEXTW, 0, cast(LPARAM)&tool); 250 | } 251 | else 252 | { 253 | tool.lpszText = cast(typeof(tool.lpszText))unsafeAnsiz(text); 254 | SendMessageA(hwtt, TTM_UPDATETIPTEXTA, 0, cast(LPARAM)&tool); 255 | } 256 | } 257 | else 258 | { 259 | // Add. 260 | 261 | /+ 262 | // TOOLINFOA.rect is ignored if TTF_IDISHWND. 263 | tool.rect.left = 0; 264 | tool.rect.top = 0; 265 | tool.rect.right = ctrl.clientSize.width; 266 | tool.rect.bottom = ctrl.clientSize.height; 267 | +/ 268 | tool.uFlags |= TTF_SUBCLASS; // Not a good idea ? 269 | LRESULT lr; 270 | if(dfl.internal.utf.useUnicode) 271 | { 272 | tool.lpszText = cast(typeof(tool.lpszText))toUnicodez(text); 273 | lr = SendMessageA(hwtt, TTM_ADDTOOLW, 0, cast(LPARAM)&tool); 274 | } 275 | else 276 | { 277 | tool.lpszText = cast(typeof(tool.lpszText))unsafeAnsiz(text); 278 | lr = SendMessageA(hwtt, TTM_ADDTOOLA, 0, cast(LPARAM)&tool); 279 | } 280 | 281 | if(lr) 282 | Application.refCountInc(cast(void*)this); 283 | } 284 | } 285 | 286 | 287 | private: 288 | enum _TOOLTIPS_CLASSA = "tooltips_class32"; 289 | enum size_t MAX_TIP_TEXT_LENGTH = 2045; 290 | 291 | HWND hwtt; // Tooltip control handle. 292 | bool _active = true; 293 | } 294 | 295 | -------------------------------------------------------------------------------- /source/dfl/usercontrol.d: -------------------------------------------------------------------------------- 1 | // Written by Christopher E. Miller 2 | // See the included license.txt for copyright and license details. 3 | 4 | 5 | /// 6 | module dfl.usercontrol; 7 | 8 | private import dfl.control; 9 | 10 | 11 | /// 12 | class UserControl: ContainerControl // docmain 13 | { 14 | // ? 15 | } 16 | 17 | --------------------------------------------------------------------------------