├── 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 | 
72 |
73 | in DUB:
74 |
75 | 
76 |
77 | in VS2010
78 |
79 | 
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 |
--------------------------------------------------------------------------------