├── .gitattributes ├── .gitignore ├── CanvasLayoutDemo ├── CanvasLayoutDemo.vcxproj ├── CanvasLayoutDemo.vcxproj.filters └── Main.cpp ├── DirectUI.sln ├── DirectUI ├── Application.cpp ├── Application.h ├── Brushes.cpp ├── Brushes.h ├── Buttons.cpp ├── Buttons.h ├── Colors.cpp ├── Colors.h ├── Core.cpp ├── Core.h ├── CoreUI.cpp ├── CoreUI.h ├── DirectUI.h ├── DirectUI.vcxproj ├── DirectUI.vcxproj.filters ├── Layout.cpp ├── Layout.h ├── ReadMe.txt ├── Shapes.cpp ├── Shapes.h ├── Text.cpp ├── Text.h ├── Window.cpp ├── Window.h ├── debug.h ├── dx.h ├── handle.h ├── pch.cpp └── pch.h ├── HelloWorld ├── HelloWorld.cpp ├── HelloWorld.h ├── HelloWorld.ico ├── HelloWorld.vcxproj ├── HelloWorld.vcxproj.filters ├── small.ico ├── stdafx.cpp ├── stdafx.h └── targetver.h ├── HitTesting ├── HitTesting.vcxproj ├── HitTesting.vcxproj.filters └── Main.cpp ├── LICENSE ├── README.md ├── SimpleDataBinding ├── Main.cpp ├── SimpleDataBinding.vcxproj └── SimpleDataBinding.vcxproj.filters └── TextDemo ├── Main.cpp ├── TextDemo.vcxproj └── TextDemo.vcxproj.filters /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc -------------------------------------------------------------------------------- /CanvasLayoutDemo/CanvasLayoutDemo.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {8876F5EC-7DAF-4B5C-9787-FE79D02EC43C} 24 | Win32Proj 25 | CanvasLayoutDemo 26 | 10.0.17763.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v141 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v141 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v141 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v141 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | true 78 | 79 | 80 | false 81 | 82 | 83 | false 84 | 85 | 86 | 87 | 88 | 89 | Level3 90 | Disabled 91 | _DEBUG;_WINDOWS;%(PreprocessorDefinitions) 92 | 93 | 94 | Windows 95 | 96 | 97 | 98 | 99 | 100 | 101 | Level3 102 | Disabled 103 | WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) 104 | 105 | 106 | Windows 107 | 108 | 109 | 110 | 111 | Level3 112 | 113 | 114 | MaxSpeed 115 | true 116 | true 117 | WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 118 | 119 | 120 | Windows 121 | true 122 | true 123 | 124 | 125 | 126 | 127 | Level3 128 | 129 | 130 | MaxSpeed 131 | true 132 | true 133 | NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 134 | 135 | 136 | Windows 137 | true 138 | true 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | {42fbcd14-632d-48e5-828a-19278be94184} 147 | 148 | 149 | 150 | 151 | 152 | -------------------------------------------------------------------------------- /CanvasLayoutDemo/CanvasLayoutDemo.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | -------------------------------------------------------------------------------- /CanvasLayoutDemo/Main.cpp: -------------------------------------------------------------------------------- 1 | #include "..\DirectUI\DirectUI.h" 2 | 3 | using namespace DirectUI; 4 | 5 | int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR lpCmdLine, int) { 6 | Application app; 7 | app.Initialize(); 8 | 9 | Window mainWindow(L"CanvasLayout Demo"); 10 | mainWindow.ClearColor(Colors::Brown()); 11 | 12 | auto canvas = Create(); 13 | auto e1 = Create(); 14 | e1->Fill(Create(Colors::Red()))->Width(100)->Height(100); 15 | canvas->X(e1, 50); 16 | canvas->Y(e1, 50); 17 | canvas->AddChild(e1); 18 | 19 | auto r1 = Create(); 20 | r1->Fill(Create(Colors::Cyan()))->Width(200)->Height(150); 21 | canvas->X(r1, 230); 22 | canvas->Y(r1, 350); 23 | canvas->AddChild(r1); 24 | 25 | mainWindow.Content(canvas); 26 | 27 | app.Run(); 28 | 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /DirectUI.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26430.16 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DirectUI", "DirectUI\DirectUI.vcxproj", "{42FBCD14-632D-48E5-828A-19278BE94184}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{46056F72-CC88-4D5F-8F93-E74AC9998FC0}" 9 | EndProject 10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HelloWorld", "HelloWorld\HelloWorld.vcxproj", "{B95D657E-CCF5-424A-9CFE-2DBBF2175D67}" 11 | EndProject 12 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CanvasLayoutDemo", "CanvasLayoutDemo\CanvasLayoutDemo.vcxproj", "{8876F5EC-7DAF-4B5C-9787-FE79D02EC43C}" 13 | EndProject 14 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TextDemo", "TextDemo\TextDemo.vcxproj", "{7B7CDA34-2E88-48D7-8E20-7CEC65C8DFE1}" 15 | EndProject 16 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HitTesting", "HitTesting\HitTesting.vcxproj", "{571FA848-C61F-4316-89DB-88C3B2CC3736}" 17 | EndProject 18 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Basic", "Basic", "{54EC50A8-BB7F-4661-80D2-0D25EC118C3F}" 19 | EndProject 20 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SimpleDataBinding", "SimpleDataBinding\SimpleDataBinding.vcxproj", "{EC50FDAE-6101-4C4C-9DBE-B250530A6E66}" 21 | EndProject 22 | Global 23 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 24 | Debug|x64 = Debug|x64 25 | Debug|x86 = Debug|x86 26 | Release|x64 = Release|x64 27 | Release|x86 = Release|x86 28 | EndGlobalSection 29 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 30 | {42FBCD14-632D-48E5-828A-19278BE94184}.Debug|x64.ActiveCfg = Debug|x64 31 | {42FBCD14-632D-48E5-828A-19278BE94184}.Debug|x64.Build.0 = Debug|x64 32 | {42FBCD14-632D-48E5-828A-19278BE94184}.Debug|x86.ActiveCfg = Debug|Win32 33 | {42FBCD14-632D-48E5-828A-19278BE94184}.Debug|x86.Build.0 = Debug|Win32 34 | {42FBCD14-632D-48E5-828A-19278BE94184}.Release|x64.ActiveCfg = Release|x64 35 | {42FBCD14-632D-48E5-828A-19278BE94184}.Release|x64.Build.0 = Release|x64 36 | {42FBCD14-632D-48E5-828A-19278BE94184}.Release|x86.ActiveCfg = Release|Win32 37 | {42FBCD14-632D-48E5-828A-19278BE94184}.Release|x86.Build.0 = Release|Win32 38 | {B95D657E-CCF5-424A-9CFE-2DBBF2175D67}.Debug|x64.ActiveCfg = Debug|x64 39 | {B95D657E-CCF5-424A-9CFE-2DBBF2175D67}.Debug|x64.Build.0 = Debug|x64 40 | {B95D657E-CCF5-424A-9CFE-2DBBF2175D67}.Debug|x86.ActiveCfg = Debug|Win32 41 | {B95D657E-CCF5-424A-9CFE-2DBBF2175D67}.Debug|x86.Build.0 = Debug|Win32 42 | {B95D657E-CCF5-424A-9CFE-2DBBF2175D67}.Release|x64.ActiveCfg = Release|x64 43 | {B95D657E-CCF5-424A-9CFE-2DBBF2175D67}.Release|x64.Build.0 = Release|x64 44 | {B95D657E-CCF5-424A-9CFE-2DBBF2175D67}.Release|x86.ActiveCfg = Release|Win32 45 | {B95D657E-CCF5-424A-9CFE-2DBBF2175D67}.Release|x86.Build.0 = Release|Win32 46 | {8876F5EC-7DAF-4B5C-9787-FE79D02EC43C}.Debug|x64.ActiveCfg = Debug|x64 47 | {8876F5EC-7DAF-4B5C-9787-FE79D02EC43C}.Debug|x64.Build.0 = Debug|x64 48 | {8876F5EC-7DAF-4B5C-9787-FE79D02EC43C}.Debug|x86.ActiveCfg = Debug|Win32 49 | {8876F5EC-7DAF-4B5C-9787-FE79D02EC43C}.Debug|x86.Build.0 = Debug|Win32 50 | {8876F5EC-7DAF-4B5C-9787-FE79D02EC43C}.Release|x64.ActiveCfg = Release|x64 51 | {8876F5EC-7DAF-4B5C-9787-FE79D02EC43C}.Release|x64.Build.0 = Release|x64 52 | {8876F5EC-7DAF-4B5C-9787-FE79D02EC43C}.Release|x86.ActiveCfg = Release|Win32 53 | {8876F5EC-7DAF-4B5C-9787-FE79D02EC43C}.Release|x86.Build.0 = Release|Win32 54 | {7B7CDA34-2E88-48D7-8E20-7CEC65C8DFE1}.Debug|x64.ActiveCfg = Debug|x64 55 | {7B7CDA34-2E88-48D7-8E20-7CEC65C8DFE1}.Debug|x64.Build.0 = Debug|x64 56 | {7B7CDA34-2E88-48D7-8E20-7CEC65C8DFE1}.Debug|x86.ActiveCfg = Debug|Win32 57 | {7B7CDA34-2E88-48D7-8E20-7CEC65C8DFE1}.Debug|x86.Build.0 = Debug|Win32 58 | {7B7CDA34-2E88-48D7-8E20-7CEC65C8DFE1}.Release|x64.ActiveCfg = Release|x64 59 | {7B7CDA34-2E88-48D7-8E20-7CEC65C8DFE1}.Release|x64.Build.0 = Release|x64 60 | {7B7CDA34-2E88-48D7-8E20-7CEC65C8DFE1}.Release|x86.ActiveCfg = Release|Win32 61 | {7B7CDA34-2E88-48D7-8E20-7CEC65C8DFE1}.Release|x86.Build.0 = Release|Win32 62 | {571FA848-C61F-4316-89DB-88C3B2CC3736}.Debug|x64.ActiveCfg = Debug|x64 63 | {571FA848-C61F-4316-89DB-88C3B2CC3736}.Debug|x64.Build.0 = Debug|x64 64 | {571FA848-C61F-4316-89DB-88C3B2CC3736}.Debug|x86.ActiveCfg = Debug|Win32 65 | {571FA848-C61F-4316-89DB-88C3B2CC3736}.Debug|x86.Build.0 = Debug|Win32 66 | {571FA848-C61F-4316-89DB-88C3B2CC3736}.Release|x64.ActiveCfg = Release|x64 67 | {571FA848-C61F-4316-89DB-88C3B2CC3736}.Release|x64.Build.0 = Release|x64 68 | {571FA848-C61F-4316-89DB-88C3B2CC3736}.Release|x86.ActiveCfg = Release|Win32 69 | {571FA848-C61F-4316-89DB-88C3B2CC3736}.Release|x86.Build.0 = Release|Win32 70 | {EC50FDAE-6101-4C4C-9DBE-B250530A6E66}.Debug|x64.ActiveCfg = Debug|x64 71 | {EC50FDAE-6101-4C4C-9DBE-B250530A6E66}.Debug|x64.Build.0 = Debug|x64 72 | {EC50FDAE-6101-4C4C-9DBE-B250530A6E66}.Debug|x86.ActiveCfg = Debug|Win32 73 | {EC50FDAE-6101-4C4C-9DBE-B250530A6E66}.Debug|x86.Build.0 = Debug|Win32 74 | {EC50FDAE-6101-4C4C-9DBE-B250530A6E66}.Release|x64.ActiveCfg = Release|x64 75 | {EC50FDAE-6101-4C4C-9DBE-B250530A6E66}.Release|x64.Build.0 = Release|x64 76 | {EC50FDAE-6101-4C4C-9DBE-B250530A6E66}.Release|x86.ActiveCfg = Release|Win32 77 | {EC50FDAE-6101-4C4C-9DBE-B250530A6E66}.Release|x86.Build.0 = Release|Win32 78 | EndGlobalSection 79 | GlobalSection(SolutionProperties) = preSolution 80 | HideSolutionNode = FALSE 81 | EndGlobalSection 82 | GlobalSection(NestedProjects) = preSolution 83 | {B95D657E-CCF5-424A-9CFE-2DBBF2175D67} = {54EC50A8-BB7F-4661-80D2-0D25EC118C3F} 84 | {8876F5EC-7DAF-4B5C-9787-FE79D02EC43C} = {54EC50A8-BB7F-4661-80D2-0D25EC118C3F} 85 | {7B7CDA34-2E88-48D7-8E20-7CEC65C8DFE1} = {54EC50A8-BB7F-4661-80D2-0D25EC118C3F} 86 | {571FA848-C61F-4316-89DB-88C3B2CC3736} = {54EC50A8-BB7F-4661-80D2-0D25EC118C3F} 87 | {54EC50A8-BB7F-4661-80D2-0D25EC118C3F} = {46056F72-CC88-4D5F-8F93-E74AC9998FC0} 88 | {EC50FDAE-6101-4C4C-9DBE-B250530A6E66} = {54EC50A8-BB7F-4661-80D2-0D25EC118C3F} 89 | EndGlobalSection 90 | EndGlobal 91 | -------------------------------------------------------------------------------- /DirectUI/Application.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "Application.h" 3 | #include "Window.h" 4 | 5 | using namespace DirectUI; 6 | using namespace std; 7 | 8 | Application* Application::_app; 9 | 10 | Application::Application() { 11 | if (_app) 12 | throw std::exception("only a single Application object must exist"); 13 | _app = this; 14 | 15 | } 16 | 17 | bool Application::Initialize() { 18 | if (!RegisterWindowClass()) 19 | return false; 20 | 21 | _d2dfactory = DX::Direct2D::CreateFactory(); 22 | if (!_d2dfactory) 23 | return false; 24 | 25 | _dwriteFactory = DX::DirectWrite::CreateFactory(); 26 | 27 | _d3dDevice = DX::Direct3D::CreateDevice(); 28 | 29 | OnInit(); 30 | return true; 31 | } 32 | 33 | bool Application::RegisterWindowClass() { 34 | WNDCLASS wc {}; 35 | wc.hCursor = LoadCursor(nullptr, IDC_ARROW); 36 | wc.hInstance = ::GetModuleHandle(nullptr); 37 | wc.lpszClassName = DirectUIWindowClassName; 38 | wc.style = CS_HREDRAW | CS_VREDRAW; 39 | wc.lpfnWndProc = TopLevelWindowProc; 40 | return ::RegisterClass(&wc) ? true : false; 41 | } 42 | 43 | void Application::CreateDeviceSwapChainBitmap(const DX::Dxgi::SwapChain& swapChain, const DX::Direct2D::DeviceContext& target) { 44 | using namespace DX::Direct2D; 45 | using namespace DX; 46 | 47 | auto props = BitmapProperties1(BitmapOptions::Target | BitmapOptions::CannotDraw, 48 | PixelFormat(Dxgi::Format::B8G8R8A8_UNORM, AlphaMode::Ignore)); 49 | 50 | target.SetTarget(target.CreateBitmapFromDxgiSurface(swapChain, props)); 51 | } 52 | 53 | void Application::RemoveWindow(HWND hWnd) { 54 | _windows.erase(hWnd); 55 | if (_windows.size() == 0) 56 | ::PostQuitMessage(0); 57 | } 58 | 59 | bool Application::CreateDeviceContextAndSwapChain(HWND hWnd, DX::Direct2D::DeviceContext& dc, DX::Dxgi::SwapChain1& swapChain) { 60 | using namespace DX; 61 | 62 | dc = _d2dfactory.CreateDevice(_d3dDevice).CreateDeviceContext(); 63 | ASSERT(dc); 64 | auto dxgi = _d3dDevice.GetDxgiFactory(); 65 | 66 | Dxgi::SwapChainDescription1 description; 67 | description.SwapEffect = Dxgi::SwapEffect::Discard; 68 | 69 | swapChain = dxgi.CreateSwapChainForHwnd(_d3dDevice, hWnd, description); 70 | ASSERT(swapChain); 71 | CreateDeviceSwapChainBitmap(swapChain, dc); 72 | 73 | _dpi = _d2dfactory.GetDesktopDpi(); 74 | dc.SetDpi(_dpi, _dpi); 75 | 76 | return true; 77 | } 78 | 79 | LRESULT Application::TopLevelWindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { 80 | return Current()->WindowProc(hWnd, message, wParam, lParam); 81 | } 82 | 83 | LRESULT Application::WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { 84 | auto it = _windows.find(hWnd); 85 | if (it == _windows.end()) 86 | return ::DefWindowProc(hWnd, message, wParam, lParam); 87 | 88 | return it->second->WindowProc(message, wParam, lParam); 89 | } 90 | 91 | void Application::OnInit() { 92 | ::CoInitialize(nullptr); 93 | } 94 | 95 | void Application::OnExit() { 96 | ::CoUninitialize(); 97 | } 98 | 99 | int Application::Run() { 100 | MSG msg; 101 | while (auto result = GetMessage(&msg, 0, 0, 0)) { 102 | if (-1 != result) { 103 | ::TranslateMessage(&msg); 104 | ::DispatchMessage(&msg); 105 | } 106 | } 107 | 108 | return 0; 109 | } 110 | -------------------------------------------------------------------------------- /DirectUI/Application.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Core.h" 4 | 5 | namespace DirectUI { 6 | class Window; 7 | 8 | static const wchar_t* DirectUIWindowClassName = L"DirectUIWindowClassName"; 9 | 10 | class Application : public DependencyObject { 11 | friend class Window; 12 | 13 | public: 14 | Application(); 15 | 16 | static Application* Current() { 17 | return _app; 18 | } 19 | 20 | bool Initialize(); 21 | virtual int Run(); 22 | 23 | DX::Direct2D::Factory1& D2DFactory() { 24 | return _d2dfactory; 25 | } 26 | 27 | DX::DirectWrite::Factory2& DWriteFactory() { 28 | return _dwriteFactory; 29 | } 30 | 31 | float GetDpi() const { 32 | return _dpi; 33 | } 34 | 35 | protected: 36 | virtual void OnInit(); 37 | virtual void OnExit(); 38 | 39 | virtual bool RegisterWindowClass(); 40 | 41 | virtual LRESULT WindowProc(HWND, UINT, WPARAM, LPARAM); 42 | 43 | bool CreateDeviceContextAndSwapChain(HWND, DX::Direct2D::DeviceContext& dc, DX::Dxgi::SwapChain1& swapChain); 44 | 45 | private: 46 | static LRESULT CALLBACK TopLevelWindowProc(HWND, UINT, WPARAM, LPARAM); 47 | static void CreateDeviceSwapChainBitmap(const DX::Dxgi::SwapChain& swapChain, const DX::Direct2D::DeviceContext& target); 48 | static bool ResizeSwapChainBitmap(DX::Direct2D::DeviceContext& target); 49 | void RemoveWindow(HWND hWnd); 50 | 51 | void AddWindow(HWND hWnd, Window* window) { 52 | _windows[hWnd] = window; 53 | } 54 | 55 | private: 56 | std::map _windows; 57 | DX::Direct3D::Device1 _d3dDevice; 58 | DX::Direct2D::Factory1 _d2dfactory; 59 | DX::Dxgi::SwapChain1 _swapChain; 60 | DX::DirectWrite::Factory2 _dwriteFactory; 61 | float _dpi; 62 | 63 | static Application* _app; 64 | }; 65 | } 66 | 67 | -------------------------------------------------------------------------------- /DirectUI/Brushes.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "Brushes.h" 3 | #include "Colors.h" 4 | #include "CoreUI.h" 5 | 6 | using namespace DirectUI; 7 | 8 | DEFINE_DP_WITH_FLAGS(Brush, Opacity, float, 1.0f, PropertyMetadataFlags::AffectsParentRender); 9 | 10 | DEFINE_DP_WITH_FLAGS(SolidColorBrush, Color, DX::Color, Colors::White(), PropertyMetadataFlags::AffectsParentRender); 11 | 12 | SolidColorBrush::SolidColorBrush(const DX::Color& color) { 13 | SetValue(ColorProperty, color, false); 14 | } 15 | 16 | DX::Direct2D::Brush& SolidColorBrush::GetBrush(DX::Direct2D::DeviceContext& dc) { 17 | if (!_brush) 18 | _brush = dc.CreateSolidColorBrush(Color()); 19 | return _brush; 20 | } 21 | 22 | Ref Brushes::AliceBlue() { 23 | static auto brush = Create(Colors::AliceBlue()); 24 | return brush; 25 | } 26 | 27 | Ref Brushes::AntiqueWhite() { 28 | static auto brush = Create(Colors::AntiqueWhite()); 29 | return brush; 30 | } 31 | 32 | Ref Brushes::Aqua() { 33 | static auto brush = Create(Colors::Aqua()); 34 | return brush; 35 | } 36 | 37 | Ref Brushes::Aquamarine() { 38 | static auto brush = Create(Colors::Aquamarine()); 39 | return brush; 40 | } 41 | 42 | Ref Brushes::Azure() { 43 | static auto brush = Create(Colors::Azure()); 44 | return brush; 45 | } 46 | 47 | Ref Brushes::Beige() { 48 | static auto brush = Create(Colors::Beige()); 49 | return brush; 50 | } 51 | 52 | Ref Brushes::Bisque() { 53 | static auto brush = Create(Colors::Bisque()); 54 | return brush; 55 | } 56 | 57 | Ref Brushes::Black() { 58 | static auto brush = Create(Colors::Black()); 59 | return brush; 60 | } 61 | 62 | Ref Brushes::BlanchedAlmond() { 63 | static auto brush = Create(Colors::BlanchedAlmond()); 64 | return brush; 65 | } 66 | 67 | Ref Brushes::Blue() { 68 | static auto brush = Create(Colors::Blue()); 69 | return brush; 70 | } 71 | 72 | Ref Brushes::BlueViolet() { 73 | static auto brush = Create(Colors::BlueViolet()); 74 | return brush; 75 | } 76 | 77 | Ref Brushes::Brown() { 78 | static auto brush = Create(Colors::Brown()); 79 | return brush; 80 | } 81 | 82 | Ref Brushes::BurlyWood() { 83 | static auto brush = Create(Colors::BurlyWood()); 84 | return brush; 85 | } 86 | 87 | Ref Brushes::CadetBlue() { 88 | static auto brush = Create(Colors::CadetBlue()); 89 | return brush; 90 | } 91 | 92 | Ref Brushes::Chartreuse() { 93 | static auto brush = Create(Colors::Chartreuse()); 94 | return brush; 95 | } 96 | 97 | Ref Brushes::Chocolate() { 98 | static auto brush = Create(Colors::Chocolate()); 99 | return brush; 100 | } 101 | 102 | Ref Brushes::Coral() { 103 | static auto brush = Create(Colors::Coral()); 104 | return brush; 105 | } 106 | 107 | Ref Brushes::CornflowerBlue() { 108 | static auto brush = Create(Colors::CornflowerBlue()); 109 | return brush; 110 | } 111 | 112 | Ref Brushes::Cornsilk() { 113 | static auto brush = Create(Colors::Cornsilk()); 114 | return brush; 115 | } 116 | 117 | Ref Brushes::Crimson() { 118 | static auto brush = Create(Colors::Crimson()); 119 | return brush; 120 | } 121 | 122 | Ref Brushes::Cyan() { 123 | static auto brush = Create(Colors::Cyan()); 124 | return brush; 125 | } 126 | 127 | Ref Brushes::DarkBlue() { 128 | static auto brush = Create(Colors::DarkBlue()); 129 | return brush; 130 | } 131 | 132 | Ref Brushes::DarkCyan() { 133 | static auto brush = Create(Colors::DarkCyan()); 134 | return brush; 135 | } 136 | 137 | Ref Brushes::DarkGoldenrod() { 138 | static auto brush = Create(Colors::DarkGoldenrod()); 139 | return brush; 140 | } 141 | 142 | Ref Brushes::DarkGray() { 143 | static auto brush = Create(Colors::DarkGray()); 144 | return brush; 145 | } 146 | 147 | Ref Brushes::DarkGreen() { 148 | static auto brush = Create(Colors::DarkGreen()); 149 | return brush; 150 | } 151 | 152 | Ref Brushes::DarkKhaki() { 153 | static auto brush = Create(Colors::DarkKhaki()); 154 | return brush; 155 | } 156 | 157 | Ref Brushes::DarkMagenta() { 158 | static auto brush = Create(Colors::DarkMagenta()); 159 | return brush; 160 | } 161 | 162 | Ref Brushes::DarkOliveGreen() { 163 | static auto brush = Create(Colors::DarkOliveGreen()); 164 | return brush; 165 | } 166 | 167 | Ref Brushes::DarkOrange() { 168 | static auto brush = Create(Colors::DarkOrange()); 169 | return brush; 170 | } 171 | 172 | Ref Brushes::DarkOrchid() { 173 | static auto brush = Create(Colors::DarkOrchid()); 174 | return brush; 175 | } 176 | 177 | Ref Brushes::DarkRed() { 178 | static auto brush = Create(Colors::DarkRed()); 179 | return brush; 180 | } 181 | 182 | Ref Brushes::DarkSalmon() { 183 | static auto brush = Create(Colors::DarkSalmon()); 184 | return brush; 185 | } 186 | 187 | Ref Brushes::DarkSeaGreen() { 188 | static auto brush = Create(Colors::DarkSeaGreen()); 189 | return brush; 190 | } 191 | 192 | Ref Brushes::DarkSlateBlue() { 193 | static auto brush = Create(Colors::DarkSlateBlue()); 194 | return brush; 195 | } 196 | 197 | Ref Brushes::DarkSlateGray() { 198 | static auto brush = Create(Colors::DarkSlateGray()); 199 | return brush; 200 | } 201 | 202 | Ref Brushes::DarkTurquoise() { 203 | static auto brush = Create(Colors::DarkTurquoise()); 204 | return brush; 205 | } 206 | 207 | Ref Brushes::DarkViolet() { 208 | static auto brush = Create(Colors::DarkViolet()); 209 | return brush; 210 | } 211 | 212 | Ref Brushes::DeepPink() { 213 | static auto brush = Create(Colors::DeepPink()); 214 | return brush; 215 | } 216 | 217 | Ref Brushes::DeepSkyBlue() { 218 | static auto brush = Create(Colors::DeepSkyBlue()); 219 | return brush; 220 | } 221 | 222 | Ref Brushes::DimGray() { 223 | static auto brush = Create(Colors::DimGray()); 224 | return brush; 225 | } 226 | 227 | Ref Brushes::DodgerBlue() { 228 | static auto brush = Create(Colors::DodgerBlue()); 229 | return brush; 230 | } 231 | 232 | Ref Brushes::Firebrick() { 233 | static auto brush = Create(Colors::Firebrick()); 234 | return brush; 235 | } 236 | 237 | Ref Brushes::FloralWhite() { 238 | static auto brush = Create(Colors::FloralWhite()); 239 | return brush; 240 | } 241 | 242 | Ref Brushes::ForestGreen() { 243 | static auto brush = Create(Colors::ForestGreen()); 244 | return brush; 245 | } 246 | 247 | Ref Brushes::Fuchsia() { 248 | static auto brush = Create(Colors::Fuchsia()); 249 | return brush; 250 | } 251 | 252 | Ref Brushes::Gainsboro() { 253 | static auto brush = Create(Colors::Gainsboro()); 254 | return brush; 255 | } 256 | 257 | Ref Brushes::GhostWhite() { 258 | static auto brush = Create(Colors::GhostWhite()); 259 | return brush; 260 | } 261 | 262 | Ref Brushes::Gold() { 263 | static auto brush = Create(Colors::Gold()); 264 | return brush; 265 | } 266 | 267 | Ref Brushes::Goldenrod() { 268 | static auto brush = Create(Colors::Goldenrod()); 269 | return brush; 270 | } 271 | 272 | Ref Brushes::Gray() { 273 | static auto brush = Create(Colors::Gray()); 274 | return brush; 275 | } 276 | 277 | Ref Brushes::Green() { 278 | static auto brush = Create(Colors::Green()); 279 | return brush; 280 | } 281 | 282 | Ref Brushes::GreenYellow() { 283 | static auto brush = Create(Colors::GreenYellow()); 284 | return brush; 285 | } 286 | 287 | Ref Brushes::Honeydew() { 288 | static auto brush = Create(Colors::Honeydew()); 289 | return brush; 290 | } 291 | 292 | Ref Brushes::HotPink() { 293 | static auto brush = Create(Colors::HotPink()); 294 | return brush; 295 | } 296 | 297 | Ref Brushes::IndianRed() { 298 | static auto brush = Create(Colors::IndianRed()); 299 | return brush; 300 | } 301 | 302 | Ref Brushes::Indigo() { 303 | static auto brush = Create(Colors::Indigo()); 304 | return brush; 305 | } 306 | 307 | Ref Brushes::Ivory() { 308 | static auto brush = Create(Colors::Ivory()); 309 | return brush; 310 | } 311 | 312 | Ref Brushes::Khaki() { 313 | static auto brush = Create(Colors::Khaki()); 314 | return brush; 315 | } 316 | 317 | Ref Brushes::Lavender() { 318 | static auto brush = Create(Colors::Lavender()); 319 | return brush; 320 | } 321 | 322 | Ref Brushes::LavenderBlush() { 323 | static auto brush = Create(Colors::LavenderBlush()); 324 | return brush; 325 | } 326 | 327 | Ref Brushes::LawnGreen() { 328 | static auto brush = Create(Colors::LawnGreen()); 329 | return brush; 330 | } 331 | 332 | Ref Brushes::LemonChiffon() { 333 | static auto brush = Create(Colors::LemonChiffon()); 334 | return brush; 335 | } 336 | 337 | Ref Brushes::LightBlue() { 338 | static auto brush = Create(Colors::LightBlue()); 339 | return brush; 340 | } 341 | 342 | Ref Brushes::LightCoral() { 343 | static auto brush = Create(Colors::LightCoral()); 344 | return brush; 345 | } 346 | 347 | Ref Brushes::LightCyan() { 348 | static auto brush = Create(Colors::LightCyan()); 349 | return brush; 350 | } 351 | 352 | Ref Brushes::LightGoldenrodYellow() { 353 | static auto brush = Create(Colors::LightGoldenrodYellow()); 354 | return brush; 355 | } 356 | 357 | Ref Brushes::LightGray() { 358 | static auto brush = Create(Colors::LightGray()); 359 | return brush; 360 | } 361 | 362 | Ref Brushes::LightGreen() { 363 | static auto brush = Create(Colors::LightGreen()); 364 | return brush; 365 | } 366 | 367 | Ref Brushes::LightPink() { 368 | static auto brush = Create(Colors::LightPink()); 369 | return brush; 370 | } 371 | 372 | Ref Brushes::LightSalmon() { 373 | static auto brush = Create(Colors::LightSalmon()); 374 | return brush; 375 | } 376 | 377 | Ref Brushes::LightSeaGreen() { 378 | static auto brush = Create(Colors::LightSeaGreen()); 379 | return brush; 380 | } 381 | 382 | Ref Brushes::LightSkyBlue() { 383 | static auto brush = Create(Colors::LightSkyBlue()); 384 | return brush; 385 | } 386 | 387 | Ref Brushes::LightSlateGray() { 388 | static auto brush = Create(Colors::LightSlateGray()); 389 | return brush; 390 | } 391 | 392 | Ref Brushes::LightSteelBlue() { 393 | static auto brush = Create(Colors::LightSteelBlue()); 394 | return brush; 395 | } 396 | 397 | Ref Brushes::LightYellow() { 398 | static auto brush = Create(Colors::LightYellow()); 399 | return brush; 400 | } 401 | 402 | Ref Brushes::Lime() { 403 | static auto brush = Create(Colors::Lime()); 404 | return brush; 405 | } 406 | 407 | Ref Brushes::LimeGreen() { 408 | static auto brush = Create(Colors::LimeGreen()); 409 | return brush; 410 | } 411 | 412 | Ref Brushes::Linen() { 413 | static auto brush = Create(Colors::Linen()); 414 | return brush; 415 | } 416 | 417 | Ref Brushes::Magenta() { 418 | static auto brush = Create(Colors::Magenta()); 419 | return brush; 420 | } 421 | 422 | Ref Brushes::Maroon() { 423 | static auto brush = Create(Colors::Maroon()); 424 | return brush; 425 | } 426 | 427 | Ref Brushes::MediumAquamarine() { 428 | static auto brush = Create(Colors::MediumAquamarine()); 429 | return brush; 430 | } 431 | 432 | Ref Brushes::MediumBlue() { 433 | static auto brush = Create(Colors::MediumBlue()); 434 | return brush; 435 | } 436 | 437 | Ref Brushes::MediumOrchid() { 438 | static auto brush = Create(Colors::MediumOrchid()); 439 | return brush; 440 | } 441 | 442 | Ref Brushes::MediumPurple() { 443 | static auto brush = Create(Colors::MediumPurple()); 444 | return brush; 445 | } 446 | 447 | Ref Brushes::MediumSeaGreen() { 448 | static auto brush = Create(Colors::MediumSeaGreen()); 449 | return brush; 450 | } 451 | 452 | Ref Brushes::MediumSlateBlue() { 453 | static auto brush = Create(Colors::MediumSlateBlue()); 454 | return brush; 455 | } 456 | 457 | Ref Brushes::MediumSpringGreen() { 458 | static auto brush = Create(Colors::MediumSpringGreen()); 459 | return brush; 460 | } 461 | 462 | Ref Brushes::MediumTurquoise() { 463 | static auto brush = Create(Colors::MediumTurquoise()); 464 | return brush; 465 | } 466 | 467 | Ref Brushes::MediumVioletRed() { 468 | static auto brush = Create(Colors::MediumVioletRed()); 469 | return brush; 470 | } 471 | 472 | Ref Brushes::MidnightBlue() { 473 | static auto brush = Create(Colors::MidnightBlue()); 474 | return brush; 475 | } 476 | 477 | Ref Brushes::MintCream() { 478 | static auto brush = Create(Colors::MintCream()); 479 | return brush; 480 | } 481 | 482 | Ref Brushes::MistyRose() { 483 | static auto brush = Create(Colors::MistyRose()); 484 | return brush; 485 | } 486 | 487 | Ref Brushes::Moccasin() { 488 | static auto brush = Create(Colors::Moccasin()); 489 | return brush; 490 | } 491 | 492 | Ref Brushes::NavajoWhite() { 493 | static auto brush = Create(Colors::NavajoWhite()); 494 | return brush; 495 | } 496 | 497 | Ref Brushes::Navy() { 498 | static auto brush = Create(Colors::Navy()); 499 | return brush; 500 | } 501 | 502 | Ref Brushes::OldLace() { 503 | static auto brush = Create(Colors::OldLace()); 504 | return brush; 505 | } 506 | 507 | Ref Brushes::Olive() { 508 | static auto brush = Create(Colors::Olive()); 509 | return brush; 510 | } 511 | 512 | Ref Brushes::OliveDrab() { 513 | static auto brush = Create(Colors::OliveDrab()); 514 | return brush; 515 | } 516 | 517 | Ref Brushes::Orange() { 518 | static auto brush = Create(Colors::Orange()); 519 | return brush; 520 | } 521 | 522 | Ref Brushes::OrangeRed() { 523 | static auto brush = Create(Colors::OrangeRed()); 524 | return brush; 525 | } 526 | 527 | Ref Brushes::Orchid() { 528 | static auto brush = Create(Colors::Orchid()); 529 | return brush; 530 | } 531 | 532 | Ref Brushes::PaleGoldenrod() { 533 | static auto brush = Create(Colors::PaleGoldenrod()); 534 | return brush; 535 | } 536 | 537 | Ref Brushes::PaleGreen() { 538 | static auto brush = Create(Colors::PaleGreen()); 539 | return brush; 540 | } 541 | 542 | Ref Brushes::PaleTurquoise() { 543 | static auto brush = Create(Colors::PaleTurquoise()); 544 | return brush; 545 | } 546 | 547 | Ref Brushes::PaleVioletRed() { 548 | static auto brush = Create(Colors::PaleVioletRed()); 549 | return brush; 550 | } 551 | 552 | Ref Brushes::PapayaWhip() { 553 | static auto brush = Create(Colors::PapayaWhip()); 554 | return brush; 555 | } 556 | 557 | Ref Brushes::PeachPuff() { 558 | static auto brush = Create(Colors::PeachPuff()); 559 | return brush; 560 | } 561 | 562 | Ref Brushes::Peru() { 563 | static auto brush = Create(Colors::Peru()); 564 | return brush; 565 | } 566 | 567 | Ref Brushes::Pink() { 568 | static auto brush = Create(Colors::Pink()); 569 | return brush; 570 | } 571 | 572 | Ref Brushes::Plum() { 573 | static auto brush = Create(Colors::Plum()); 574 | return brush; 575 | } 576 | 577 | Ref Brushes::PowderBlue() { 578 | static auto brush = Create(Colors::PowderBlue()); 579 | return brush; 580 | } 581 | 582 | Ref Brushes::Purple() { 583 | static auto brush = Create(Colors::Purple()); 584 | return brush; 585 | } 586 | 587 | Ref Brushes::Red() { 588 | static auto brush = Create(Colors::Red()); 589 | return brush; 590 | } 591 | 592 | Ref Brushes::RosyBrown() { 593 | static auto brush = Create(Colors::RosyBrown()); 594 | return brush; 595 | } 596 | 597 | Ref Brushes::RoyalBlue() { 598 | static auto brush = Create(Colors::RoyalBlue()); 599 | return brush; 600 | } 601 | 602 | Ref Brushes::SaddleBrown() { 603 | static auto brush = Create(Colors::SaddleBrown()); 604 | return brush; 605 | } 606 | 607 | Ref Brushes::Salmon() { 608 | static auto brush = Create(Colors::Salmon()); 609 | return brush; 610 | } 611 | 612 | Ref Brushes::SandyBrown() { 613 | static auto brush = Create(Colors::SandyBrown()); 614 | return brush; 615 | } 616 | 617 | Ref Brushes::SeaGreen() { 618 | static auto brush = Create(Colors::SeaGreen()); 619 | return brush; 620 | } 621 | 622 | Ref Brushes::SeaShell() { 623 | static auto brush = Create(Colors::SeaShell()); 624 | return brush; 625 | } 626 | 627 | Ref Brushes::Sienna() { 628 | static auto brush = Create(Colors::Sienna()); 629 | return brush; 630 | } 631 | 632 | Ref Brushes::Silver() { 633 | static auto brush = Create(Colors::Silver()); 634 | return brush; 635 | } 636 | 637 | Ref Brushes::SkyBlue() { 638 | static auto brush = Create(Colors::SkyBlue()); 639 | return brush; 640 | } 641 | 642 | Ref Brushes::SlateBlue() { 643 | static auto brush = Create(Colors::SlateBlue()); 644 | return brush; 645 | } 646 | 647 | Ref Brushes::SlateGray() { 648 | static auto brush = Create(Colors::SlateGray()); 649 | return brush; 650 | } 651 | 652 | Ref Brushes::Snow() { 653 | static auto brush = Create(Colors::Snow()); 654 | return brush; 655 | } 656 | 657 | Ref Brushes::SpringGreen() { 658 | static auto brush = Create(Colors::SpringGreen()); 659 | return brush; 660 | } 661 | 662 | Ref Brushes::SteelBlue() { 663 | static auto brush = Create(Colors::SteelBlue()); 664 | return brush; 665 | } 666 | 667 | Ref Brushes::Tan() { 668 | static auto brush = Create(Colors::Tan()); 669 | return brush; 670 | } 671 | 672 | Ref Brushes::Teal() { 673 | static auto brush = Create(Colors::Teal()); 674 | return brush; 675 | } 676 | 677 | Ref Brushes::Thistle() { 678 | static auto brush = Create(Colors::Thistle()); 679 | return brush; 680 | } 681 | 682 | Ref Brushes::Tomato() { 683 | static auto brush = Create(Colors::Tomato()); 684 | return brush; 685 | } 686 | 687 | Ref Brushes::Transparent() { 688 | static auto brush = Create(Colors::Transparent()); 689 | return brush; 690 | } 691 | 692 | Ref Brushes::Turquoise() { 693 | static auto brush = Create(Colors::Turquoise()); 694 | return brush; 695 | } 696 | 697 | Ref Brushes::Violet() { 698 | static auto brush = Create(Colors::Violet()); 699 | return brush; 700 | } 701 | 702 | Ref Brushes::Wheat() { 703 | static auto brush = Create(Colors::Wheat()); 704 | return brush; 705 | } 706 | 707 | Ref Brushes::White() { 708 | static auto brush = Create(Colors::White()); 709 | return brush; 710 | } 711 | 712 | Ref Brushes::WhiteSmoke() { 713 | static auto brush = Create(Colors::WhiteSmoke()); 714 | return brush; 715 | } 716 | 717 | Ref Brushes::Yellow() { 718 | static auto brush = Create(Colors::Yellow()); 719 | return brush; 720 | } 721 | 722 | Ref Brushes::YellowGreen() { 723 | static auto brush = Create(Colors::YellowGreen()); 724 | return brush; 725 | } 726 | 727 | -------------------------------------------------------------------------------- /DirectUI/Brushes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Core.h" 4 | 5 | namespace DirectUI { 6 | class Brush abstract : public DeviceDependentResource { 7 | public: 8 | DECLARE_DP(Brush, Opacity, float); 9 | 10 | virtual DX::Direct2D::Brush& GetBrush(DX::Direct2D::DeviceContext& dc) = 0; 11 | DX::Direct2D::Brush& operator()(DX::Direct2D::DeviceContext& dc) { 12 | return GetBrush(dc); 13 | } 14 | 15 | protected: 16 | }; 17 | 18 | class SolidColorBrush final : public Brush { 19 | DECLARE_DP(SolidColorBrush, Color, DX::Color); 20 | 21 | public: 22 | SolidColorBrush(const DX::Color& color); 23 | 24 | DX::Direct2D::Brush& GetBrush(DX::Direct2D::DeviceContext& dc); 25 | 26 | private: 27 | DX::Direct2D::SolidColorBrush _brush; 28 | }; 29 | 30 | class GradientBrush abstract : public Brush { 31 | }; 32 | 33 | class LinearGradientBrush sealed : public GradientBrush { 34 | }; 35 | 36 | class RadialGradientBrush sealed : public GradientBrush { 37 | }; 38 | 39 | class BitmapBrush sealed : public Brush { 40 | }; 41 | 42 | class Brushes abstract final { 43 | public: 44 | static Ref AliceBlue(); 45 | static Ref AntiqueWhite(); 46 | static Ref Aqua(); 47 | static Ref Aquamarine(); 48 | static Ref Azure(); 49 | static Ref Beige(); 50 | static Ref Bisque(); 51 | static Ref Black(); 52 | static Ref BlanchedAlmond(); 53 | static Ref Blue(); 54 | static Ref BlueViolet(); 55 | static Ref Brown(); 56 | static Ref BurlyWood(); 57 | static Ref CadetBlue(); 58 | static Ref Chartreuse(); 59 | static Ref Chocolate(); 60 | static Ref Coral(); 61 | static Ref CornflowerBlue(); 62 | static Ref Cornsilk(); 63 | static Ref Crimson(); 64 | static Ref Cyan(); 65 | static Ref DarkBlue(); 66 | static Ref DarkCyan(); 67 | static Ref DarkGoldenrod(); 68 | static Ref DarkGray(); 69 | static Ref DarkGreen(); 70 | static Ref DarkKhaki(); 71 | static Ref DarkMagenta(); 72 | static Ref DarkOliveGreen(); 73 | static Ref DarkOrange(); 74 | static Ref DarkOrchid(); 75 | static Ref DarkRed(); 76 | static Ref DarkSalmon(); 77 | static Ref DarkSeaGreen(); 78 | static Ref DarkSlateBlue(); 79 | static Ref DarkSlateGray(); 80 | static Ref DarkTurquoise(); 81 | static Ref DarkViolet(); 82 | static Ref DeepPink(); 83 | static Ref DeepSkyBlue(); 84 | static Ref DimGray(); 85 | static Ref DodgerBlue(); 86 | static Ref Firebrick(); 87 | static Ref FloralWhite(); 88 | static Ref ForestGreen(); 89 | static Ref Fuchsia(); 90 | static Ref Gainsboro(); 91 | static Ref GhostWhite(); 92 | static Ref Gold(); 93 | static Ref Goldenrod(); 94 | static Ref Gray(); 95 | static Ref Green(); 96 | static Ref GreenYellow(); 97 | static Ref Honeydew(); 98 | static Ref HotPink(); 99 | static Ref IndianRed(); 100 | static Ref Indigo(); 101 | static Ref Ivory(); 102 | static Ref Khaki(); 103 | static Ref Lavender(); 104 | static Ref LavenderBlush(); 105 | static Ref LawnGreen(); 106 | static Ref LemonChiffon(); 107 | static Ref LightBlue(); 108 | static Ref LightCoral(); 109 | static Ref LightCyan(); 110 | static Ref LightGoldenrodYellow(); 111 | static Ref LightGray(); 112 | static Ref LightGreen(); 113 | static Ref LightPink(); 114 | static Ref LightSalmon(); 115 | static Ref LightSeaGreen(); 116 | static Ref LightSkyBlue(); 117 | static Ref LightSlateGray(); 118 | static Ref LightSteelBlue(); 119 | static Ref LightYellow(); 120 | static Ref Lime(); 121 | static Ref LimeGreen(); 122 | static Ref Linen(); 123 | static Ref Magenta(); 124 | static Ref Maroon(); 125 | static Ref MediumAquamarine(); 126 | static Ref MediumBlue(); 127 | static Ref MediumOrchid(); 128 | static Ref MediumPurple(); 129 | static Ref MediumSeaGreen(); 130 | static Ref MediumSlateBlue(); 131 | static Ref MediumSpringGreen(); 132 | static Ref MediumTurquoise(); 133 | static Ref MediumVioletRed(); 134 | static Ref MidnightBlue(); 135 | static Ref MintCream(); 136 | static Ref MistyRose(); 137 | static Ref Moccasin(); 138 | static Ref NavajoWhite(); 139 | static Ref Navy(); 140 | static Ref OldLace(); 141 | static Ref Olive(); 142 | static Ref OliveDrab(); 143 | static Ref Orange(); 144 | static Ref OrangeRed(); 145 | static Ref Orchid(); 146 | static Ref PaleGoldenrod(); 147 | static Ref PaleGreen(); 148 | static Ref PaleTurquoise(); 149 | static Ref PaleVioletRed(); 150 | static Ref PapayaWhip(); 151 | static Ref PeachPuff(); 152 | static Ref Peru(); 153 | static Ref Pink(); 154 | static Ref Plum(); 155 | static Ref PowderBlue(); 156 | static Ref Purple(); 157 | static Ref Red(); 158 | static Ref RosyBrown(); 159 | static Ref RoyalBlue(); 160 | static Ref SaddleBrown(); 161 | static Ref Salmon(); 162 | static Ref SandyBrown(); 163 | static Ref SeaGreen(); 164 | static Ref SeaShell(); 165 | static Ref Sienna(); 166 | static Ref Silver(); 167 | static Ref SkyBlue(); 168 | static Ref SlateBlue(); 169 | static Ref SlateGray(); 170 | static Ref Snow(); 171 | static Ref SpringGreen(); 172 | static Ref SteelBlue(); 173 | static Ref Tan(); 174 | static Ref Teal(); 175 | static Ref Thistle(); 176 | static Ref Tomato(); 177 | static Ref Transparent(); 178 | static Ref Turquoise(); 179 | static Ref Violet(); 180 | static Ref Wheat(); 181 | static Ref White(); 182 | static Ref WhiteSmoke(); 183 | static Ref Yellow(); 184 | static Ref YellowGreen(); 185 | }; 186 | 187 | } 188 | 189 | -------------------------------------------------------------------------------- /DirectUI/Buttons.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "Buttons.h" 3 | 4 | using namespace DirectUI; 5 | using namespace DX; 6 | using namespace DX::Direct2D; 7 | 8 | // ButtonBase 9 | 10 | DEFINE_DP(ButtonBase, CornerRadius, SizeF, SizeF(0, 0)); 11 | 12 | DEFINE_EVENT(ButtonBase, Click, EventArgs, Direct); 13 | 14 | ButtonBase::ButtonBase() { 15 | MouseUpEvent.AddHandler(this, [this](auto& source, const auto& args) { 16 | OnClick(); 17 | return true; 18 | }); 19 | } 20 | 21 | void ButtonBase::Measure(const DX::SizeF& maximumSize) { 22 | auto content = Content(); 23 | if (content) { 24 | content->Measure(maximumSize); 25 | auto size = content->GetDesiredSize(); 26 | auto padding = Padding(); 27 | size.Width += padding.Left + padding.Right; 28 | size.Height += padding.Top + padding.Bottom; 29 | 30 | SetDesiredSize(size); 31 | } 32 | else { 33 | UIElement::Measure(maximumSize); 34 | } 35 | } 36 | 37 | void ButtonBase::OnDraw(DeviceContext& dc, const RectF& bounds) { 38 | auto background = Background(); 39 | if (background) { 40 | auto& radius = CornerRadius(); 41 | if (radius.Width + radius.Height == 0) 42 | dc.FillRectangle(bounds, background->GetBrush(dc)); 43 | else { 44 | RoundedRect rr(bounds, radius.Width, radius.Height); 45 | dc.FillRoundedRectangle(rr, background->GetBrush(dc)); 46 | } 47 | } 48 | auto content = Content(); 49 | if (content) { 50 | auto padding = Padding(); 51 | RectF contentBounds(bounds); 52 | contentBounds.MoveSize(padding.Left, padding.Top, padding.Right, padding.Bottom); 53 | content->Draw(dc, contentBounds); 54 | } 55 | } 56 | 57 | void ButtonBase::OnClick() { 58 | ClickEvent.RaiseEvent(*this, EventArgs()); 59 | } 60 | 61 | // Button 62 | 63 | void Button::OnDraw(DeviceContext& dc, const RectF& bounds) { 64 | ButtonBase::OnDraw(dc, bounds); 65 | } 66 | -------------------------------------------------------------------------------- /DirectUI/Buttons.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CoreUI.h" 4 | 5 | namespace DirectUI { 6 | class ButtonBase abstract : public ContentControl { 7 | DECLARE_DP(ButtonBase, CornerRadius, DX::SizeF); 8 | 9 | DECLARE_EVENT(Click, EventArgs); 10 | 11 | public: 12 | void Measure(const DX::SizeF& size) override; 13 | 14 | protected: 15 | virtual void OnClick(); 16 | 17 | ButtonBase(); 18 | 19 | void OnDraw(DX::Direct2D::DeviceContext& dc, const DX::RectF& bounds) override; 20 | }; 21 | 22 | class Button : public ButtonBase { 23 | public: 24 | void OnDraw(DX::Direct2D::DeviceContext& dc, const DX::RectF& bounds) override; 25 | }; 26 | 27 | class ToggleButton : public ButtonBase { 28 | DECLARE_DP(ToggleButton, IsChecked, bool); 29 | }; 30 | } 31 | -------------------------------------------------------------------------------- /DirectUI/Colors.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "Colors.h" 3 | 4 | using namespace DirectUI; 5 | using namespace DX; 6 | 7 | const Color& Colors::AliceBlue() { 8 | static Color color(0.8713671f, 0.9386857f, 1.0f, 1.0f); 9 | return color; 10 | } 11 | const Color& Colors::AntiqueWhite() { 12 | static Color color(0.9559733f, 0.8307699f, 0.6795425f, 1.0f); 13 | return color; 14 | } 15 | const Color& Colors::Aqua() { 16 | static Color color(0.0f, 1.0f, 1.0f, 1.0f); 17 | return color; 18 | } 19 | const Color& Colors::Aquamarine() { 20 | static Color color(0.2122308f, 1.0f, 0.6583748f, 1.0f); 21 | return color; 22 | } 23 | const Color& Colors::Azure() { 24 | static Color color(0.8713671f, 1.0f, 1.0f, 1.0f); 25 | return color; 26 | } 27 | const Color& Colors::Beige() { 28 | static Color color(0.9130986f, 0.9130986f, 0.7156935f, 1.0f); 29 | return color; 30 | } 31 | const Color& Colors::Bisque() { 32 | static Color color(1.0f, 0.7758222f, 0.5520114f, 1.0f); 33 | return color; 34 | } 35 | const Color& Colors::Black() { 36 | static Color color(0.0f, 0.0f, 0.0f, 1.0f); 37 | return color; 38 | } 39 | const Color& Colors::BlanchedAlmond() { 40 | static Color color(1.0f, 0.8307699f, 0.6104956f, 1.0f); 41 | return color; 42 | } 43 | const Color& Colors::Blue() { 44 | static Color color(0.0f, 0.0f, 1.0f, 1.0f); 45 | return color; 46 | } 47 | const Color& Colors::BlueViolet() { 48 | static Color color(0.2541521f, 0.02415763f, 0.7605245f, 1.0f); 49 | return color; 50 | } 51 | const Color& Colors::Brown() { 52 | static Color color(0.3762621f, 0.02315337f, 0.02315337f, 1.0f); 53 | return color; 54 | } 55 | const Color& Colors::BurlyWood() { 56 | static Color color(0.7304608f, 0.4793202f, 0.2422811f, 1.0f); 57 | return color; 58 | } 59 | const Color& Colors::CadetBlue() { 60 | static Color color(0.1144354f, 0.3419144f, 0.3515326f, 1.0f); 61 | return color; 62 | } 63 | const Color& Colors::Chartreuse() { 64 | static Color color(0.2122308f, 1.0f, 0.0f, 1.0f); 65 | return color; 66 | } 67 | const Color& Colors::Chocolate() { 68 | static Color color(0.6444797f, 0.1412633f, 0.01298303f, 1.0f); 69 | return color; 70 | } 71 | const Color& Colors::Coral() { 72 | static Color color(1.0f, 0.2122308f, 0.08021982f, 1.0f); 73 | return color; 74 | } 75 | const Color& Colors::CornflowerBlue() { 76 | static Color color(0.1274377f, 0.3005438f, 0.8468732f, 1.0f); 77 | return color; 78 | } 79 | const Color& Colors::Cornsilk() { 80 | static Color color(1.0f, 0.9386857f, 0.7156935f, 1.0f); 81 | return color; 82 | } 83 | const Color& Colors::Crimson() { 84 | static Color color(0.7156935f, 0.00699541f, 0.0451862f, 1.0f); 85 | return color; 86 | } 87 | const Color& Colors::Cyan() { 88 | static Color color(0.0f, 1.0f, 1.0f, 1.0f); 89 | return color; 90 | } 91 | const Color& Colors::DarkBlue() { 92 | static Color color(0.0f, 0.0f, 0.2581829f, 1.0f); 93 | return color; 94 | } 95 | const Color& Colors::DarkCyan() { 96 | static Color color(0.0f, 0.2581829f, 0.2581829f, 1.0f); 97 | return color; 98 | } 99 | const Color& Colors::DarkGoldenrod() { 100 | static Color color(0.4793202f, 0.2383976f, 0.003346536f, 1.0f); 101 | return color; 102 | } 103 | const Color& Colors::DarkGray() { 104 | static Color color(0.3967552f, 0.3967552f, 0.3967552f, 1.0f); 105 | return color; 106 | } 107 | const Color& Colors::DarkGreen() { 108 | static Color color(0.0f, 0.1274377f, 0.0f, 1.0f); 109 | return color; 110 | } 111 | const Color& Colors::DarkKhaki() { 112 | static Color color(0.5088813f, 0.4735315f, 0.1470273f, 1.0f); 113 | return color; 114 | } 115 | const Color& Colors::DarkMagenta() { 116 | static Color color(0.2581829f, 0.0f, 0.2581829f, 1.0f); 117 | return color; 118 | } 119 | const Color& Colors::DarkOliveGreen() { 120 | static Color color(0.09084171f, 0.1470273f, 0.02842604f, 1.0f); 121 | return color; 122 | } 123 | const Color& Colors::DarkOrange() { 124 | static Color color(1.0f, 0.2622507f, 0.0f, 1.0f); 125 | return color; 126 | } 127 | const Color& Colors::DarkOrchid() { 128 | static Color color(0.3185468f, 0.03189603f, 0.6038274f, 1.0f); 129 | return color; 130 | } 131 | const Color& Colors::DarkRed() { 132 | static Color color(0.2581829f, 0.0f, 0.0f, 1.0f); 133 | return color; 134 | } 135 | const Color& Colors::DarkSalmon() { 136 | static Color color(0.8148466f, 0.3049873f, 0.1946178f, 1.0f); 137 | return color; 138 | } 139 | const Color& Colors::DarkSeaGreen() { 140 | static Color color(0.2746773f, 0.5028865f, 0.2746773f, 1.0f); 141 | return color; 142 | } 143 | const Color& Colors::DarkSlateBlue() { 144 | static Color color(0.06480327f, 0.04666509f, 0.2581829f, 1.0f); 145 | return color; 146 | } 147 | const Color& Colors::DarkSlateGray() { 148 | static Color color(0.02842604f, 0.07818742f, 0.07818742f, 1.0f); 149 | return color; 150 | } 151 | const Color& Colors::DarkTurquoise() { 152 | static Color color(0.0f, 0.6172066f, 0.6375968f, 1.0f); 153 | return color; 154 | } 155 | const Color& Colors::DarkViolet() { 156 | static Color color(0.2961383f, 0.0f, 0.6514056f, 1.0f); 157 | return color; 158 | } 159 | const Color& Colors::DeepPink() { 160 | static Color color(1.0f, 0.00699541f, 0.2917706f, 1.0f); 161 | return color; 162 | } 163 | const Color& Colors::DeepSkyBlue() { 164 | static Color color(0.0f, 0.5209956f, 1.0f, 1.0f); 165 | return color; 166 | } 167 | const Color& Colors::DimGray() { 168 | static Color color(0.1412633f, 0.1412633f, 0.1412633f, 1.0f); 169 | return color; 170 | } 171 | const Color& Colors::DodgerBlue() { 172 | static Color color(0.01298303f, 0.2788943f, 1.0f, 1.0f); 173 | return color; 174 | } 175 | const Color& Colors::Firebrick() { 176 | static Color color(0.4452012f, 0.01599629f, 0.01599629f, 1.0f); 177 | return color; 178 | } 179 | const Color& Colors::FloralWhite() { 180 | static Color color(1.0f, 0.9559733f, 0.8713671f, 1.0f); 181 | return color; 182 | } 183 | const Color& Colors::ForestGreen() { 184 | static Color color(0.01599629f, 0.2581829f, 0.01599629f, 1.0f); 185 | return color; 186 | } 187 | const Color& Colors::Fuchsia() { 188 | static Color color(1.0f, 0.0f, 1.0f, 1.0f); 189 | return color; 190 | } 191 | const Color& Colors::Gainsboro() { 192 | static Color color(0.7156935f, 0.7156935f, 0.7156935f, 1.0f); 193 | return color; 194 | } 195 | const Color& Colors::GhostWhite() { 196 | static Color color(0.9386857f, 0.9386857f, 1.0f, 1.0f); 197 | return color; 198 | } 199 | const Color& Colors::Gold() { 200 | static Color color(1.0f, 0.6795425f, 0.0f, 1.0f); 201 | return color; 202 | } 203 | const Color& Colors::Goldenrod() { 204 | static Color color(0.7011019f, 0.3762621f, 0.01444384f, 1.0f); 205 | return color; 206 | } 207 | const Color& Colors::Gray() { 208 | static Color color(0.2158605f, 0.2158605f, 0.2158605f, 1.0f); 209 | return color; 210 | } 211 | const Color& Colors::Green() { 212 | static Color color(0.0f, 0.2158605f, 0.0f, 1.0f); 213 | return color; 214 | } 215 | const Color& Colors::GreenYellow() { 216 | static Color color(0.4178851f, 1.0f, 0.02842604f, 1.0f); 217 | return color; 218 | } 219 | const Color& Colors::Honeydew() { 220 | static Color color(0.8713671f, 1.0f, 0.8713671f, 1.0f); 221 | return color; 222 | } 223 | const Color& Colors::HotPink() { 224 | static Color color(1.0f, 0.1412633f, 0.456411f, 1.0f); 225 | return color; 226 | } 227 | const Color& Colors::IndianRed() { 228 | static Color color(0.6104956f, 0.1070231f, 0.1070231f, 1.0f); 229 | return color; 230 | } 231 | const Color& Colors::Indigo() { 232 | static Color color(0.07036009f, 0.0f, 0.223228f, 1.0f); 233 | return color; 234 | } 235 | const Color& Colors::Ivory() { 236 | static Color color(1.0f, 1.0f, 0.8713671f, 1.0f); 237 | return color; 238 | } 239 | const Color& Colors::Khaki() { 240 | static Color color(0.8713671f, 0.7912979f, 0.2622507f, 1.0f); 241 | return color; 242 | } 243 | const Color& Colors::Lavender() { 244 | static Color color(0.7912979f, 0.7912979f, 0.9559733f, 1.0f); 245 | return color; 246 | } 247 | const Color& Colors::LavenderBlush() { 248 | static Color color(1.0f, 0.8713671f, 0.9130986f, 1.0f); 249 | return color; 250 | } 251 | const Color& Colors::LawnGreen() { 252 | static Color color(0.2015563f, 0.9734453f, 0.0f, 1.0f); 253 | return color; 254 | } 255 | const Color& Colors::LemonChiffon() { 256 | static Color color(1.0f, 0.9559733f, 0.6104956f, 1.0f); 257 | return color; 258 | } 259 | const Color& Colors::LightBlue() { 260 | static Color color(0.4178851f, 0.6866853f, 0.7912979f, 1.0f); 261 | return color; 262 | } 263 | const Color& Colors::LightCoral() { 264 | static Color color(0.8713671f, 0.2158605f, 0.2158605f, 1.0f); 265 | return color; 266 | } 267 | const Color& Colors::LightCyan() { 268 | static Color color(0.7454042f, 1.0f, 1.0f, 1.0f); 269 | return color; 270 | } 271 | const Color& Colors::LightGoldenrodYellow() { 272 | static Color color(0.9559733f, 0.9559733f, 0.6444797f, 1.0f); 273 | return color; 274 | } 275 | const Color& Colors::LightGray() { 276 | static Color color(0.6514056f, 0.6514056f, 0.6514056f, 1.0f); 277 | return color; 278 | } 279 | const Color& Colors::LightGreen() { 280 | static Color color(0.2788943f, 0.8549926f, 0.2788943f, 1.0f); 281 | return color; 282 | } 283 | const Color& Colors::LightPink() { 284 | static Color color(1.0f, 0.4677838f, 0.5332764f, 1.0f); 285 | return color; 286 | } 287 | const Color& Colors::LightSalmon() { 288 | static Color color(1.0f, 0.3515326f, 0.1946178f, 1.0f); 289 | return color; 290 | } 291 | const Color& Colors::LightSeaGreen() { 292 | static Color color(0.01444384f, 0.4452012f, 0.4019778f, 1.0f); 293 | return color; 294 | } 295 | const Color& Colors::LightSkyBlue() { 296 | static Color color(0.2422811f, 0.6172066f, 0.9559733f, 1.0f); 297 | return color; 298 | } 299 | const Color& Colors::LightSlateGray() { 300 | static Color color(0.184475f, 0.2462013f, 0.3185468f, 1.0f); 301 | return color; 302 | } 303 | const Color& Colors::LightSteelBlue() { 304 | static Color color(0.4341536f, 0.5520114f, 0.7304608f, 1.0f); 305 | return color; 306 | } 307 | const Color& Colors::LightYellow() { 308 | static Color color(1.0f, 1.0f, 0.7454042f, 1.0f); 309 | return color; 310 | } 311 | const Color& Colors::Lime() { 312 | static Color color(0.0f, 1.0f, 0.0f, 1.0f); 313 | return color; 314 | } 315 | const Color& Colors::LimeGreen() { 316 | static Color color(0.03189603f, 0.6104956f, 0.03189603f, 1.0f); 317 | return color; 318 | } 319 | const Color& Colors::Linen() { 320 | static Color color(0.9559733f, 0.8713671f, 0.7912979f, 1.0f); 321 | return color; 322 | } 323 | const Color& Colors::Magenta() { 324 | static Color color(1.0f, 0.0f, 1.0f, 1.0f); 325 | return color; 326 | } 327 | const Color& Colors::Maroon() { 328 | static Color color(0.2158605f, 0.0f, 0.0f, 1.0f); 329 | return color; 330 | } 331 | const Color& Colors::MediumAquamarine() { 332 | static Color color(0.1328683f, 0.6104956f, 0.4019778f, 1.0f); 333 | return color; 334 | } 335 | const Color& Colors::MediumBlue() { 336 | static Color color(0.0f, 0.0f, 0.6104956f, 1.0f); 337 | return color; 338 | } 339 | const Color& Colors::MediumOrchid() { 340 | static Color color(0.4910209f, 0.09084171f, 0.6514056f, 1.0f); 341 | return color; 342 | } 343 | const Color& Colors::MediumPurple() { 344 | static Color color(0.2917706f, 0.1620294f, 0.7083758f, 1.0f); 345 | return color; 346 | } 347 | const Color& Colors::MediumSeaGreen() { 348 | static Color color(0.0451862f, 0.4507858f, 0.1651322f, 1.0f); 349 | return color; 350 | } 351 | const Color& Colors::MediumSlateBlue() { 352 | static Color color(0.1980693f, 0.1384316f, 0.8549926f, 1.0f); 353 | return color; 354 | } 355 | const Color& Colors::MediumSpringGreen() { 356 | static Color color(0.0f, 0.9559733f, 0.3231432f, 1.0f); 357 | return color; 358 | } 359 | const Color& Colors::MediumTurquoise() { 360 | static Color color(0.06480327f, 0.6375968f, 0.6038274f, 1.0f); 361 | return color; 362 | } 363 | const Color& Colors::MediumVioletRed() { 364 | static Color color(0.5711249f, 0.007499032f, 0.2345506f, 1.0f); 365 | return color; 366 | } 367 | const Color& Colors::MidnightBlue() { 368 | static Color color(0.009721218f, 0.009721218f, 0.1620294f, 1.0f); 369 | return color; 370 | } 371 | const Color& Colors::MintCream() { 372 | static Color color(0.9130986f, 1.0f, 0.9559733f, 1.0f); 373 | return color; 374 | } 375 | const Color& Colors::MistyRose() { 376 | static Color color(1.0f, 0.7758222f, 0.7529422f, 1.0f); 377 | return color; 378 | } 379 | const Color& Colors::Moccasin() { 380 | static Color color(1.0f, 0.7758222f, 0.462077f, 1.0f); 381 | return color; 382 | } 383 | const Color& Colors::NavajoWhite() { 384 | static Color color(1.0f, 0.7304608f, 0.4178851f, 1.0f); 385 | return color; 386 | } 387 | const Color& Colors::Navy() { 388 | static Color color(0.0f, 0.0f, 0.2158605f, 1.0f); 389 | return color; 390 | } 391 | const Color& Colors::OldLace() { 392 | static Color color(0.9822506f, 0.9130986f, 0.7912979f, 1.0f); 393 | return color; 394 | } 395 | const Color& Colors::Olive() { 396 | static Color color(0.2158605f, 0.2158605f, 0.0f, 1.0f); 397 | return color; 398 | } 399 | const Color& Colors::OliveDrab() { 400 | static Color color(0.1470273f, 0.2704978f, 0.01680738f, 1.0f); 401 | return color; 402 | } 403 | const Color& Colors::Orange() { 404 | static Color color(1.0f, 0.3762621f, 0.0f, 1.0f); 405 | return color; 406 | } 407 | const Color& Colors::OrangeRed() { 408 | static Color color(1.0f, 0.05951124f, 0.0f, 1.0f); 409 | return color; 410 | } 411 | const Color& Colors::Orchid() { 412 | static Color color(0.7011019f, 0.1620294f, 0.6724432f, 1.0f); 413 | return color; 414 | } 415 | const Color& Colors::PaleGoldenrod() { 416 | static Color color(0.8549926f, 0.8069522f, 0.4019778f, 1.0f); 417 | return color; 418 | } 419 | const Color& Colors::PaleGreen() { 420 | static Color color(0.3139887f, 0.9646863f, 0.3139887f, 1.0f); 421 | return color; 422 | } 423 | const Color& Colors::PaleTurquoise() { 424 | static Color color(0.4286905f, 0.8549926f, 0.8549926f, 1.0f); 425 | return color; 426 | } 427 | const Color& Colors::PaleVioletRed() { 428 | static Color color(0.7083758f, 0.1620294f, 0.2917706f, 1.0f); 429 | return color; 430 | } 431 | const Color& Colors::PapayaWhip() { 432 | static Color color(1.0f, 0.8631572f, 0.6653873f, 1.0f); 433 | return color; 434 | } 435 | const Color& Colors::PeachPuff() { 436 | static Color color(1.0f, 0.7011019f, 0.4851499f, 1.0f); 437 | return color; 438 | } 439 | const Color& Colors::Peru() { 440 | static Color color(0.6104956f, 0.2345506f, 0.04970657f, 1.0f); 441 | return color; 442 | } 443 | const Color& Colors::Pink() { 444 | static Color color(1.0f, 0.5271151f, 0.5972018f, 1.0f); 445 | return color; 446 | } 447 | const Color& Colors::Plum() { 448 | static Color color(0.7230551f, 0.3515326f, 0.7230551f, 1.0f); 449 | return color; 450 | } 451 | const Color& Colors::PowderBlue() { 452 | static Color color(0.4341536f, 0.7454042f, 0.7912979f, 1.0f); 453 | return color; 454 | } 455 | const Color& Colors::Purple() { 456 | static Color color(0.2158605f, 0.0f, 0.2158605f, 1.0f); 457 | return color; 458 | } 459 | const Color& Colors::Red() { 460 | static Color color(1.0f, 0.0f, 0.0f, 1.0f); 461 | return color; 462 | } 463 | const Color& Colors::RosyBrown() { 464 | static Color color(0.5028865f, 0.2746773f, 0.2746773f, 1.0f); 465 | return color; 466 | } 467 | const Color& Colors::RoyalBlue() { 468 | static Color color(0.05286065f, 0.1412633f, 0.7529422f, 1.0f); 469 | return color; 470 | } 471 | const Color& Colors::SaddleBrown() { 472 | static Color color(0.2581829f, 0.05951124f, 0.006512091f, 1.0f); 473 | return color; 474 | } 475 | const Color& Colors::Salmon() { 476 | static Color color(0.9559733f, 0.2158605f, 0.1682694f, 1.0f); 477 | return color; 478 | } 479 | const Color& Colors::SandyBrown() { 480 | static Color color(0.9046612f, 0.3712377f, 0.1169707f, 1.0f); 481 | return color; 482 | } 483 | const Color& Colors::SeaGreen() { 484 | static Color color(0.02732089f, 0.2581829f, 0.09530747f, 1.0f); 485 | return color; 486 | } 487 | const Color& Colors::SeaShell() { 488 | static Color color(1.0f, 0.9130986f, 0.8549926f, 1.0f); 489 | return color; 490 | } 491 | const Color& Colors::Sienna() { 492 | static Color color(0.3515326f, 0.08437621f, 0.02624122f, 1.0f); 493 | return color; 494 | } 495 | const Color& Colors::Silver() { 496 | static Color color(0.5271151f, 0.5271151f, 0.5271151f, 1.0f); 497 | return color; 498 | } 499 | const Color& Colors::SkyBlue() { 500 | static Color color(0.2422811f, 0.6172066f, 0.8307699f, 1.0f); 501 | return color; 502 | } 503 | const Color& Colors::SlateBlue() { 504 | static Color color(0.1441285f, 0.1022417f, 0.6104956f, 1.0f); 505 | return color; 506 | } 507 | const Color& Colors::SlateGray() { 508 | static Color color(0.1620294f, 0.2158605f, 0.2788943f, 1.0f); 509 | return color; 510 | } 511 | const Color& Colors::Snow() { 512 | static Color color(1.0f, 0.9559733f, 0.9559733f, 1.0f); 513 | return color; 514 | } 515 | const Color& Colors::SpringGreen() { 516 | static Color color(0.0f, 1.0f, 0.2122308f, 1.0f); 517 | return color; 518 | } 519 | const Color& Colors::SteelBlue() { 520 | static Color color(0.06124605f, 0.223228f, 0.456411f, 1.0f); 521 | return color; 522 | } 523 | const Color& Colors::Tan() { 524 | static Color color(0.6444797f, 0.456411f, 0.2622507f, 1.0f); 525 | return color; 526 | } 527 | const Color& Colors::Teal() { 528 | static Color color(0.0f, 0.2158605f, 0.2158605f, 1.0f); 529 | return color; 530 | } 531 | const Color& Colors::Thistle() { 532 | static Color color(0.6866853f, 0.5209956f, 0.6866853f, 1.0f); 533 | return color; 534 | } 535 | const Color& Colors::Tomato() { 536 | static Color color(1.0f, 0.1247718f, 0.06301001f, 1.0f); 537 | return color; 538 | } 539 | const Color& Colors::Transparent() { 540 | static Color color(1.0f, 1.0f, 1.0f, 0.0f); 541 | return color; 542 | } 543 | const Color& Colors::Turquoise() { 544 | static Color color(0.05126946f, 0.7454042f, 0.6307572f, 1.0f); 545 | return color; 546 | } 547 | const Color& Colors::Violet() { 548 | static Color color(0.8549926f, 0.223228f, 0.8549926f, 1.0f); 549 | return color; 550 | } 551 | const Color& Colors::Wheat() { 552 | static Color color(0.9130986f, 0.7304608f, 0.4507858f, 1.0f); 553 | return color; 554 | } 555 | const Color& Colors::White() { 556 | static Color color(1.0f, 1.0f, 1.0f, 1.0f); 557 | return color; 558 | } 559 | const Color& Colors::WhiteSmoke() { 560 | static Color color(0.9130986f, 0.9130986f, 0.9130986f, 1.0f); 561 | return color; 562 | } 563 | const Color& Colors::Yellow() { 564 | static Color color(1.0f, 1.0f, 0.0f, 1.0f); 565 | return color; 566 | } 567 | const Color& Colors::YellowGreen() { 568 | static Color color(0.3231432f, 0.6104956f, 0.03189603f, 1.0f); 569 | return color; 570 | } 571 | -------------------------------------------------------------------------------- /DirectUI/Colors.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace DirectUI { 4 | struct Colors final abstract { 5 | static const DX::Color& AliceBlue(); 6 | static const DX::Color& AntiqueWhite(); 7 | static const DX::Color& Aqua(); 8 | static const DX::Color& Aquamarine(); 9 | static const DX::Color& Azure(); 10 | static const DX::Color& Beige(); 11 | static const DX::Color& Bisque(); 12 | static const DX::Color& Black(); 13 | static const DX::Color& BlanchedAlmond(); 14 | static const DX::Color& Blue(); 15 | static const DX::Color& BlueViolet(); 16 | static const DX::Color& Brown(); 17 | static const DX::Color& BurlyWood(); 18 | static const DX::Color& CadetBlue(); 19 | static const DX::Color& Chartreuse(); 20 | static const DX::Color& Chocolate(); 21 | static const DX::Color& Coral(); 22 | static const DX::Color& CornflowerBlue(); 23 | static const DX::Color& Cornsilk(); 24 | static const DX::Color& Crimson(); 25 | static const DX::Color& Cyan(); 26 | static const DX::Color& DarkBlue(); 27 | static const DX::Color& DarkCyan(); 28 | static const DX::Color& DarkGoldenrod(); 29 | static const DX::Color& DarkGray(); 30 | static const DX::Color& DarkGreen(); 31 | static const DX::Color& DarkKhaki(); 32 | static const DX::Color& DarkMagenta(); 33 | static const DX::Color& DarkOliveGreen(); 34 | static const DX::Color& DarkOrange(); 35 | static const DX::Color& DarkOrchid(); 36 | static const DX::Color& DarkRed(); 37 | static const DX::Color& DarkSalmon(); 38 | static const DX::Color& DarkSeaGreen(); 39 | static const DX::Color& DarkSlateBlue(); 40 | static const DX::Color& DarkSlateGray(); 41 | static const DX::Color& DarkTurquoise(); 42 | static const DX::Color& DarkViolet(); 43 | static const DX::Color& DeepPink(); 44 | static const DX::Color& DeepSkyBlue(); 45 | static const DX::Color& DimGray(); 46 | static const DX::Color& DodgerBlue(); 47 | static const DX::Color& Firebrick(); 48 | static const DX::Color& FloralWhite(); 49 | static const DX::Color& ForestGreen(); 50 | static const DX::Color& Fuchsia(); 51 | static const DX::Color& Gainsboro(); 52 | static const DX::Color& GhostWhite(); 53 | static const DX::Color& Gold(); 54 | static const DX::Color& Goldenrod(); 55 | static const DX::Color& Gray(); 56 | static const DX::Color& Green(); 57 | static const DX::Color& GreenYellow(); 58 | static const DX::Color& Honeydew(); 59 | static const DX::Color& HotPink(); 60 | static const DX::Color& IndianRed(); 61 | static const DX::Color& Indigo(); 62 | static const DX::Color& Ivory(); 63 | static const DX::Color& Khaki(); 64 | static const DX::Color& Lavender(); 65 | static const DX::Color& LavenderBlush(); 66 | static const DX::Color& LawnGreen(); 67 | static const DX::Color& LemonChiffon(); 68 | static const DX::Color& LightBlue(); 69 | static const DX::Color& LightCoral(); 70 | static const DX::Color& LightCyan(); 71 | static const DX::Color& LightGoldenrodYellow(); 72 | static const DX::Color& LightGray(); 73 | static const DX::Color& LightGreen(); 74 | static const DX::Color& LightPink(); 75 | static const DX::Color& LightSalmon(); 76 | static const DX::Color& LightSeaGreen(); 77 | static const DX::Color& LightSkyBlue(); 78 | static const DX::Color& LightSlateGray(); 79 | static const DX::Color& LightSteelBlue(); 80 | static const DX::Color& LightYellow(); 81 | static const DX::Color& Lime(); 82 | static const DX::Color& LimeGreen(); 83 | static const DX::Color& Linen(); 84 | static const DX::Color& Magenta(); 85 | static const DX::Color& Maroon(); 86 | static const DX::Color& MediumAquamarine(); 87 | static const DX::Color& MediumBlue(); 88 | static const DX::Color& MediumOrchid(); 89 | static const DX::Color& MediumPurple(); 90 | static const DX::Color& MediumSeaGreen(); 91 | static const DX::Color& MediumSlateBlue(); 92 | static const DX::Color& MediumSpringGreen(); 93 | static const DX::Color& MediumTurquoise(); 94 | static const DX::Color& MediumVioletRed(); 95 | static const DX::Color& MidnightBlue(); 96 | static const DX::Color& MintCream(); 97 | static const DX::Color& MistyRose(); 98 | static const DX::Color& Moccasin(); 99 | static const DX::Color& NavajoWhite(); 100 | static const DX::Color& Navy(); 101 | static const DX::Color& OldLace(); 102 | static const DX::Color& Olive(); 103 | static const DX::Color& OliveDrab(); 104 | static const DX::Color& Orange(); 105 | static const DX::Color& OrangeRed(); 106 | static const DX::Color& Orchid(); 107 | static const DX::Color& PaleGoldenrod(); 108 | static const DX::Color& PaleGreen(); 109 | static const DX::Color& PaleTurquoise(); 110 | static const DX::Color& PaleVioletRed(); 111 | static const DX::Color& PapayaWhip(); 112 | static const DX::Color& PeachPuff(); 113 | static const DX::Color& Peru(); 114 | static const DX::Color& Pink(); 115 | static const DX::Color& Plum(); 116 | static const DX::Color& PowderBlue(); 117 | static const DX::Color& Purple(); 118 | static const DX::Color& Red(); 119 | static const DX::Color& RosyBrown(); 120 | static const DX::Color& RoyalBlue(); 121 | static const DX::Color& SaddleBrown(); 122 | static const DX::Color& Salmon(); 123 | static const DX::Color& SandyBrown(); 124 | static const DX::Color& SeaGreen(); 125 | static const DX::Color& SeaShell(); 126 | static const DX::Color& Sienna(); 127 | static const DX::Color& Silver(); 128 | static const DX::Color& SkyBlue(); 129 | static const DX::Color& SlateBlue(); 130 | static const DX::Color& SlateGray(); 131 | static const DX::Color& Snow(); 132 | static const DX::Color& SpringGreen(); 133 | static const DX::Color& SteelBlue(); 134 | static const DX::Color& Tan(); 135 | static const DX::Color& Teal(); 136 | static const DX::Color& Thistle(); 137 | static const DX::Color& Tomato(); 138 | static const DX::Color& Transparent(); 139 | static const DX::Color& Turquoise(); 140 | static const DX::Color& Violet(); 141 | static const DX::Color& Wheat(); 142 | static const DX::Color& White(); 143 | static const DX::Color& WhiteSmoke(); 144 | static const DX::Color& Yellow(); 145 | static const DX::Color& YellowGreen(); 146 | }; 147 | } 148 | -------------------------------------------------------------------------------- /DirectUI/Core.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "Core.h" 3 | #include "CoreUI.h" 4 | 5 | using namespace DirectUI; 6 | 7 | const UIElement* DependencyObject::GetParent() const { 8 | auto element = DynamicAs(); 9 | return element ? element->GetParent() : nullptr; 10 | } 11 | 12 | -------------------------------------------------------------------------------- /DirectUI/Core.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace DirectUI { 4 | class UIElement; 5 | class Window; 6 | 7 | struct DirectUIException : std::exception { 8 | DirectUIException(const char* message) : std::exception(message) {} 9 | }; 10 | 11 | template 12 | using Ref = std::shared_ptr; 13 | 14 | template class DependencyProperty; 15 | 16 | template 17 | static Ref Create(Types&&... args) { 18 | return std::make_shared(std::forward(args)...); 19 | } 20 | 21 | template 22 | static Ref Create(std::initializer_list> list) { 23 | return std::make_shared(list); 24 | } 25 | 26 | class UIElement; 27 | 28 | enum class BindingMode { 29 | Default, 30 | OneWay, 31 | TwoWay, 32 | OneTime 33 | }; 34 | 35 | class DependencyObject abstract { 36 | public: 37 | template 38 | R* SetValue(DependencyProperty& dp, const T& value, bool checkForChange = true) { 39 | dp.SetValue(*this, value, checkForChange); 40 | return static_cast(this); 41 | } 42 | 43 | template 44 | R* SetValueRef(DependencyProperty& dp, const T& value, bool checkForChange = true) { 45 | dp.SetValue(*this, value, checkForChange); 46 | return static_cast(this); 47 | } 48 | 49 | template 50 | const T& GetValue(const DependencyProperty& dp) const { 51 | return dp.GetValue(*this); 52 | } 53 | 54 | template 55 | TObject& As() const { 56 | return static_cast(*this); 57 | } 58 | 59 | template 60 | const TObject* DynamicAs() const { 61 | return dynamic_cast(this); 62 | } 63 | 64 | const UIElement* GetParent() const; 65 | 66 | virtual void Invalidate() {} 67 | virtual void InvalidateLayout(bool = true) { } 68 | 69 | Window* GetWindow() const { 70 | return _window; 71 | } 72 | 73 | virtual void SetWindow(Window* window) { 74 | _window = window; 75 | } 76 | 77 | template 78 | void BindTo(DependencyProperty& targetDP, DependencyObject& source, DependencyProperty& sourceDP, BindingMode mode = BindingMode::Default) { 79 | targetDP.BindTo(*this, source, sourceDP, mode); 80 | } 81 | 82 | protected: 83 | DependencyObject() { 84 | } 85 | 86 | private: 87 | Window* _window = nullptr; 88 | }; 89 | 90 | enum class PropertyMetadataFlags { 91 | None = 0, 92 | AffectsRender = 1, 93 | AffectsLayout = 2, 94 | Inherit = 4, 95 | AffectsParentRender = 8, 96 | }; 97 | DEFINE_ENUM_FLAG_OPERATORS(PropertyMetadataFlags); 98 | 99 | template 100 | class DependencyProperty { 101 | public: 102 | using PropertyChangedHandler = std::function&, const T&, const T&)>; 103 | 104 | DependencyProperty(const char* name, const T& defaultValue = T(), PropertyMetadataFlags flags = PropertyMetadataFlags::None) 105 | : _name(name), _defaultValue(defaultValue), _flags(flags) { } 106 | 107 | const std::string& GetName() const { 108 | return _name; 109 | } 110 | 111 | PropertyMetadataFlags GetFlags() const { 112 | return _flags; 113 | } 114 | 115 | const T& GetDefaultValue() const { 116 | return _defaultValue; 117 | } 118 | 119 | template 120 | Type& SetValue(Type& object, const T& value, bool checkForChange = true) { 121 | if (checkForChange) { 122 | const auto& oldValue = GetValue(object); 123 | _values[&object] = value; 124 | InvokeHandlers(object, *this, oldValue, value); 125 | 126 | // check if render is affected 127 | if ((_flags & (PropertyMetadataFlags::AffectsLayout)) == PropertyMetadataFlags::AffectsLayout) { 128 | object.InvalidateLayout(); 129 | } 130 | else if ((_flags & (PropertyMetadataFlags::AffectsRender)) == PropertyMetadataFlags::AffectsRender) { 131 | object.Invalidate(); 132 | } 133 | } 134 | else { 135 | _values[&object] = value; 136 | } 137 | 138 | return object; 139 | } 140 | 141 | const T& GetValue(const DependencyObject& object) const { 142 | auto it = _values.find(&object); 143 | if (it != _values.end()) 144 | return it->second; 145 | 146 | if ((_flags & PropertyMetadataFlags::Inherit) == PropertyMetadataFlags::Inherit) { 147 | auto parent = object.GetParent(); 148 | if (parent) 149 | return GetValue(*parent); 150 | } 151 | return _defaultValue; 152 | } 153 | 154 | void BindTo(DependencyObject& target, DependencyObject& source, DependencyProperty& sourceDP, BindingMode mode = BindingMode::Default) { 155 | sourceDP.RegisterPropertyChangedHandler(&source, [&target, this](auto& object, auto&, const T&, const T& newValue) { 156 | target.SetValue(*this, newValue); 157 | }); 158 | } 159 | 160 | void RegisterPropertyChangedHandler(DependencyObject* object, PropertyChangedHandler handler) { 161 | _handlers[object].push_back(handler); 162 | } 163 | 164 | void RegisterPropertyChangedHandler(DependencyObject& object, PropertyChangedHandler handler) { 165 | _handlers[&object].push_back(handler); 166 | } 167 | 168 | void InvokeHandlers(DependencyObject& object, DependencyProperty& dp, const T& oldValue, const T& newValue) { 169 | auto it = _handlers.find(&object); 170 | if (it == _handlers.end()) 171 | return; 172 | 173 | for (auto& handler : it->second) 174 | handler(object, dp, oldValue, newValue); 175 | } 176 | 177 | private: 178 | T _defaultValue; 179 | std::map _values; 180 | std::string _name; 181 | PropertyMetadataFlags _flags; 182 | std::map> _handlers; 183 | }; 184 | 185 | class DeviceDependentResource abstract : public DependencyObject { 186 | protected: 187 | DeviceDependentResource() { } 188 | 189 | private: 190 | }; 191 | } 192 | 193 | #define DECLARE_DP2(class, name, type) \ 194 | public: static DependencyProperty name##Property; \ 195 | class* name(const type& value) { return SetValueRef(name##Property, value); } \ 196 | const type& name() const { return GetValue(name##Property); } 197 | 198 | #define DECLARE_DP(class, name, type) \ 199 | public: static DependencyProperty name##Property; \ 200 | class* name(const type& value) { return SetValue(name##Property, value); } \ 201 | const type& name() const { return GetValue(name##Property); } 202 | 203 | #define DECLARE_DP_REF(class, name, type) \ 204 | public: static DependencyProperty name##Property; \ 205 | Ref& name(const type& value) { return SetValue(name##Property, value); } \ 206 | const type& name() const { return GetValue(name##Property); } 207 | 208 | #define DEFINE_DP(class, name, type, defaultValue) \ 209 | DependencyProperty class::name##Property(#name, defaultValue) 210 | 211 | #define DEFINE_DP_WITH_FLAGS(class, name, type, defaultValue, flags) \ 212 | DependencyProperty class::name##Property(#name, defaultValue, flags) 213 | 214 | #define DECLARE_AP(name, type) \ 215 | static DependencyProperty name##Property; \ 216 | static void name(UIElement& element, type value) { \ 217 | element.SetValue(name##Property, value); \ 218 | } \ 219 | static type name(UIElement& element) { \ 220 | return element.GetValue(name##Property); \ 221 | } \ 222 | static void name(Ref element, type value) { \ 223 | element->SetValue(name##Property, value); \ 224 | } 225 | 226 | #define DEFINE_AP(class, name, type, defaultValue) \ 227 | DependencyProperty class::name##Property(#name, defaultValue); 228 | 229 | 230 | -------------------------------------------------------------------------------- /DirectUI/CoreUI.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "CoreUI.h" 3 | #include "Window.h" 4 | #include "Application.h" 5 | 6 | using namespace DirectUI; 7 | using namespace DX; 8 | 9 | DEFINE_DP_WITH_FLAGS(UIElement, Visibility, VisibilityType, VisibilityType::Visible, PropertyMetadataFlags::AffectsRender | PropertyMetadataFlags::AffectsLayout); 10 | DEFINE_DP_WITH_FLAGS(UIElement, IsEnabled, bool, true, PropertyMetadataFlags::AffectsRender); 11 | 12 | DEFINE_DP_WITH_FLAGS(UIElement, Background, Ref, nullptr, PropertyMetadataFlags::AffectsRender); 13 | DEFINE_DP_WITH_FLAGS(UIElement, Width, float, D2D1::FloatMax(), PropertyMetadataFlags::AffectsLayout); 14 | DEFINE_DP_WITH_FLAGS(UIElement, Height, float, D2D1::FloatMax(), PropertyMetadataFlags::AffectsLayout); 15 | DEFINE_DP_WITH_FLAGS(UIElement, HorizontalAlignment, HorizontalAlignmentType, HorizontalAlignmentType::Stretch, PropertyMetadataFlags::AffectsLayout); 16 | DEFINE_DP_WITH_FLAGS(UIElement, VerticalAlignment, VerticalAlignmentType, VerticalAlignmentType::Stretch, PropertyMetadataFlags::AffectsLayout); 17 | DEFINE_DP(UIElement, UserData, PVOID, nullptr); 18 | 19 | DEFINE_DP_WITH_FLAGS(UIElement, FontSize, float, 12.0f, PropertyMetadataFlags::AffectsRender | PropertyMetadataFlags::AffectsLayout | PropertyMetadataFlags::Inherit); 20 | DEFINE_DP_WITH_FLAGS(UIElement, FontFamily, std::wstring, L"Arial", PropertyMetadataFlags::AffectsRender | PropertyMetadataFlags::Inherit); 21 | DEFINE_DP_WITH_FLAGS(UIElement, FontWeight, DirectWrite::FontWeight, DirectWrite::FontWeight::Normal, PropertyMetadataFlags::AffectsRender); 22 | DEFINE_DP_WITH_FLAGS(UIElement, FontStyle, DirectWrite::FontStyle, DirectWrite::FontStyle::Normal, PropertyMetadataFlags::AffectsRender); 23 | 24 | DEFINE_DP_WITH_FLAGS(UIElement, Margin, Thickness, Thickness(), PropertyMetadataFlags::AffectsLayout); 25 | 26 | DEFINE_DP_WITH_FLAGS(Control, Padding, Thickness, Thickness(), PropertyMetadataFlags::AffectsLayout); 27 | 28 | DEFINE_DP_WITH_FLAGS(ContentControl, Content, Ref, nullptr, PropertyMetadataFlags::AffectsRender | PropertyMetadataFlags::AffectsLayout); 29 | 30 | UIElement* UIElement::HitTestCore(const DX::Point2F& point) { 31 | if (_geometry.Get() == nullptr || Background() == nullptr) 32 | return nullptr; 33 | 34 | return _geometry.FillContainsPoint(point) ? this : nullptr; 35 | } 36 | 37 | void UIElement::Measure(const SizeF& maximumSize) { 38 | if (Visibility() == VisibilityType::Collapsed) { 39 | SetDesiredSize(SizeF(0, 0)); 40 | return; 41 | } 42 | 43 | auto width = Width(), height = Height(); 44 | SetDesiredSize(SizeF(width == D2D1::FloatMax() ? maximumSize.Width : width, 45 | height == D2D1::FloatMax() ? maximumSize.Height : height)); 46 | } 47 | 48 | void UIElement::Draw(DX::Direct2D::DeviceContext& dc, const DX::RectF& bounds) { 49 | _bounds = bounds; 50 | 51 | if (Visibility() != VisibilityType::Visible || bounds.IsEmpty()) 52 | return; 53 | 54 | _geometry = Application::Current()->D2DFactory().CreateRectangleGeometry(bounds); 55 | 56 | OnDraw(dc, bounds); 57 | } 58 | 59 | UIElement* UIElement::HitTest(const DX::Point2F& point) { 60 | if (!IsEnabled() || Visibility() != VisibilityType::Visible) 61 | return nullptr; 62 | return HitTestCore(point); 63 | } 64 | 65 | void UIElement::Invalidate() { 66 | if(GetWindow()) 67 | GetWindow()->Invalidate(GetBounds()); 68 | } 69 | 70 | void UIElement::InvalidateLayout(bool invalid) { 71 | if (GetWindow()) 72 | GetWindow()->InvalidateLayout(invalid); 73 | } 74 | 75 | DEFINE_EVENT(UIElement, MouseDown, MouseEventArgs, Bubbling); 76 | DEFINE_EVENT(UIElement, MouseUp, MouseEventArgs, Bubbling); 77 | DEFINE_EVENT(UIElement, MouseMove, MouseEventArgs, Bubbling); 78 | DEFINE_EVENT(UIElement, MouseDoubleClick, MouseEventArgs, Bubbling); 79 | 80 | // Control 81 | 82 | bool Control::DoCustomRendering(DX::Direct2D::DeviceContext& dc, const DX::RectF& bounds) { 83 | if (_renderer) { 84 | _renderer(this, dc, bounds); 85 | return true; 86 | } 87 | return false; 88 | } 89 | 90 | // ContentControl 91 | 92 | ContentControl::ContentControl() { 93 | ContentProperty.RegisterPropertyChangedHandler(*this, [this](auto&, auto&, const auto& oldValue, const auto& newValue) { 94 | if (oldValue) 95 | oldValue->SetParent(nullptr); 96 | if (newValue) 97 | newValue->SetParent(this); 98 | }); 99 | } 100 | 101 | void ContentControl::OnDraw(DX::Direct2D::DeviceContext& dc, const DX::RectF& bounds) { 102 | auto content = Content(); 103 | if (content) { 104 | auto padding = Padding(); 105 | RectF contentBounds(bounds); 106 | contentBounds.MoveSize(padding.Left, padding.Top, padding.Right, padding.Bottom); 107 | 108 | content->Draw(dc, contentBounds); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /DirectUI/CoreUI.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Core.h" 4 | #include "Brushes.h" 5 | 6 | #define DECLARE_CONVERT(target, source, name) \ 7 | target name(source value); 8 | 9 | #define DEFINE_CONVERT(target, source, name) \ 10 | inline target name(source value) { return static_cast(value); } 11 | 12 | #define DECLARE_EVENT(name, args) \ 13 | static RoutedEvent name##Event; 14 | 15 | #define DEFINE_EVENT(class, name, args, strategy) \ 16 | RoutedEvent class::name##Event(#name, RoutingStrategy::strategy); 17 | 18 | namespace DirectUI { 19 | struct Thickness { 20 | float Left, Top, Right, Bottom; 21 | 22 | Thickness(float left, float top, float right, float bottom) 23 | : Left(left), Top(top), Right(right), Bottom(bottom) { } 24 | Thickness(float uniform = 0) : Thickness(uniform, uniform, uniform, uniform) { } 25 | Thickness(float width, float height) : Thickness(width, height, width, height) { } 26 | }; 27 | 28 | class Visual abstract : public DependencyObject { 29 | }; 30 | 31 | enum class HorizontalAlignmentType { 32 | Left, Right, Center, Stretch 33 | }; 34 | 35 | enum class VerticalAlignmentType { 36 | Top, Bottom, Center, Stretch 37 | }; 38 | 39 | enum class MouseButton { 40 | None, 41 | Left = MK_LBUTTON, 42 | Middle = MK_MBUTTON, 43 | Right = MK_RBUTTON, 44 | AllButtons = Left | Middle | Right 45 | }; 46 | 47 | enum class MouseKeys { 48 | Shift = 4, 49 | Control = 8, 50 | AllKeys = Shift | Control 51 | }; 52 | DEFINE_ENUM_FLAG_OPERATORS(MouseKeys); 53 | 54 | struct EventArgs { }; 55 | 56 | struct MouseEventArgs : EventArgs { 57 | MouseButton Button; 58 | MouseKeys Keys; 59 | DX::Point2F Position; 60 | }; 61 | 62 | enum class VisibilityType { 63 | Visible, 64 | Hidden, 65 | Collapsed 66 | }; 67 | 68 | enum class RoutingStrategy { 69 | Direct, 70 | Bubbling 71 | }; 72 | 73 | template 74 | using EventHandler = std::function; 75 | 76 | template 77 | class RoutedEvent final { 78 | public: 79 | RoutedEvent(const std::string& name, RoutingStrategy strategy) 80 | : _name(name), _strategy(strategy) { 81 | } 82 | 83 | RoutingStrategy GetStrategy() const { 84 | return _strategy; 85 | } 86 | 87 | template> 88 | void AddHandler(UIElement& element, const Callable& handler) { 89 | _handlers[&element].push_back(handler); 90 | } 91 | 92 | template> 93 | void AddHandler(UIElement* element, const Callable& handler) { 94 | _handlers[element].push_back(handler); 95 | } 96 | 97 | void RemoveHandler(const EventHandler& handler) { } 98 | 99 | template 100 | void RaiseEvent(Type& source, const TArgs& args) { 101 | auto it = _handlers.find(&source); 102 | if (it == _handlers.end()) 103 | return; 104 | 105 | bool handled = false; 106 | for (auto& handler : it->second) { 107 | handled = handler(source, args); 108 | if (handled) 109 | return; 110 | } 111 | if (GetStrategy() == RoutingStrategy::Direct) 112 | return; 113 | 114 | } 115 | 116 | private: 117 | RoutingStrategy _strategy; 118 | std::string _name; 119 | std::map>> _handlers; 120 | }; 121 | 122 | class UIElement abstract : public Visual { 123 | friend class Window; 124 | 125 | DECLARE_DP(UIElement, IsEnabled, bool); 126 | DECLARE_DP(UIElement, Visibility, VisibilityType); 127 | DECLARE_DP(UIElement, Margin, Thickness); 128 | DECLARE_DP(UIElement, Background, Ref); 129 | DECLARE_DP(UIElement, Width, float); 130 | DECLARE_DP(UIElement, Height, float); 131 | DECLARE_DP(UIElement, HorizontalAlignment, HorizontalAlignmentType); 132 | DECLARE_DP(UIElement, VerticalAlignment, VerticalAlignmentType); 133 | DECLARE_DP(UIElement, UserData, PVOID); 134 | DECLARE_DP(UIElement, FontSize, float); 135 | DECLARE_DP(UIElement, FontFamily, std::wstring); 136 | DECLARE_DP(UIElement, FontWeight, DX::DirectWrite::FontWeight); 137 | DECLARE_DP(UIElement, FontStyle, DX::DirectWrite::FontStyle); 138 | 139 | private: 140 | UIElement(const UIElement&) = delete; 141 | UIElement& operator=(const UIElement&) = delete; 142 | 143 | public: 144 | void Draw(DX::Direct2D::DeviceContext& dc, const DX::RectF& bounds); 145 | virtual void Measure(const DX::SizeF& size); 146 | UIElement* HitTest(const DX::Point2F& point); 147 | 148 | const DX::SizeF& GetDesiredSize() const { 149 | return _desiredSize; 150 | } 151 | 152 | UIElement* GetParent() const { 153 | return _parent; 154 | } 155 | 156 | void SetParent(UIElement* parent) { 157 | ASSERT(_parent == nullptr); 158 | if (_parent) 159 | throw DirectUIException("parent cannot be changed without unloading from the visual tree"); 160 | _parent = parent; 161 | } 162 | 163 | template> 164 | UIElement& AddEventHandler(RoutedEvent& event, const Callable& handler) { 165 | event.AddHandler(this, handler); 166 | return *this; 167 | } 168 | 169 | UIElement& AddEventHandler(RoutedEvent& event, const EventHandler& handler) { 170 | event.AddHandler(this, handler); 171 | return *this; 172 | } 173 | 174 | const DX::RectF& GetBounds() const { 175 | return _bounds; 176 | } 177 | 178 | void Invalidate() override; 179 | void InvalidateLayout(bool = true) override; 180 | 181 | public: 182 | // events 183 | DECLARE_EVENT(MouseDown, MouseEventArgs); 184 | DECLARE_EVENT(MouseUp, MouseEventArgs); 185 | DECLARE_EVENT(MouseMove, MouseEventArgs); 186 | DECLARE_EVENT(MouseDoubleClick, MouseEventArgs); 187 | 188 | protected: 189 | virtual void OnDraw(DX::Direct2D::DeviceContext& dc, const DX::RectF& bounds) = 0; 190 | 191 | virtual UIElement* HitTestCore(const DX::Point2F& point); 192 | 193 | protected: 194 | UIElement() : _parent(nullptr) { 195 | } 196 | 197 | void SetDesiredSize(const DX::SizeF& size) { 198 | _desiredSize = size; 199 | } 200 | 201 | private: 202 | DX::SizeF _desiredSize; 203 | UIElement* _parent; 204 | DX::RectF _bounds{}; 205 | DX::Direct2D::Geometry _geometry; 206 | }; 207 | 208 | class Control abstract : public UIElement { 209 | DECLARE_DP(Control, Padding, Thickness); 210 | 211 | public: 212 | template 213 | void SetRenderer(Callable&& renderer) { 214 | _renderer = renderer; 215 | } 216 | 217 | protected: 218 | bool DoCustomRendering(DX::Direct2D::DeviceContext& dc, const DX::RectF& bounds); 219 | 220 | protected: 221 | std::function _renderer; 222 | }; 223 | 224 | class ContentControl : public Control { 225 | DECLARE_DP(ContentControl, Content, Ref); 226 | 227 | public: 228 | ContentControl(); 229 | 230 | protected: 231 | void OnDraw(DX::Direct2D::DeviceContext& dc, const DX::RectF& bounds) override; 232 | }; 233 | } 234 | -------------------------------------------------------------------------------- /DirectUI/DirectUI.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "dx.h" 9 | #include "Core.h" 10 | #include "CoreUI.h" 11 | #include "Application.h" 12 | #include "Window.h" 13 | #include "Colors.h" 14 | #include "Brushes.h" 15 | #include "Layout.h" 16 | #include "Shapes.h" 17 | #include "Buttons.h" 18 | #include "Text.h" 19 | -------------------------------------------------------------------------------- /DirectUI/DirectUI.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | Create 46 | Create 47 | Create 48 | Create 49 | 50 | 51 | 52 | 53 | 54 | 55 | 15.0 56 | {42FBCD14-632D-48E5-828A-19278BE94184} 57 | Win32Proj 58 | DirectUI 59 | 10.0.17763.0 60 | 61 | 62 | 63 | StaticLibrary 64 | true 65 | v141 66 | Unicode 67 | 68 | 69 | StaticLibrary 70 | false 71 | v141 72 | true 73 | Unicode 74 | 75 | 76 | StaticLibrary 77 | true 78 | v141 79 | Unicode 80 | 81 | 82 | StaticLibrary 83 | false 84 | v141 85 | true 86 | Unicode 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | Use 110 | Level3 111 | Disabled 112 | WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) 113 | pch.h 114 | true 115 | 116 | 117 | Windows 118 | 119 | 120 | 121 | 122 | Use 123 | Level3 124 | Disabled 125 | _DEBUG;_LIB;%(PreprocessorDefinitions) 126 | pch.h 127 | true 128 | 129 | 130 | Windows 131 | 132 | 133 | 134 | 135 | Level3 136 | Use 137 | MaxSpeed 138 | true 139 | true 140 | WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) 141 | pch.h 142 | true 143 | 144 | 145 | Windows 146 | true 147 | true 148 | 149 | 150 | 151 | 152 | Level3 153 | Use 154 | MaxSpeed 155 | true 156 | true 157 | NDEBUG;_LIB;%(PreprocessorDefinitions) 158 | pch.h 159 | true 160 | 161 | 162 | Windows 163 | true 164 | true 165 | 166 | 167 | 168 | 169 | 170 | -------------------------------------------------------------------------------- /DirectUI/DirectUI.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | Header Files 35 | 36 | 37 | Header Files 38 | 39 | 40 | Header Files 41 | 42 | 43 | Header Files 44 | 45 | 46 | Header Files 47 | 48 | 49 | Header Files 50 | 51 | 52 | Header Files 53 | 54 | 55 | Header Files 56 | 57 | 58 | 59 | 60 | Source Files 61 | 62 | 63 | Source Files 64 | 65 | 66 | Source Files 67 | 68 | 69 | Source Files 70 | 71 | 72 | Header Files 73 | 74 | 75 | Source Files 76 | 77 | 78 | Source Files 79 | 80 | 81 | Source Files 82 | 83 | 84 | Source Files 85 | 86 | 87 | Source Files 88 | 89 | 90 | Source Files 91 | 92 | 93 | -------------------------------------------------------------------------------- /DirectUI/Layout.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "Layout.h" 3 | #include "Application.h" 4 | 5 | using namespace DirectUI; 6 | using namespace DX; 7 | 8 | // StackLayout 9 | 10 | DEFINE_DP_WITH_FLAGS(StackLayout, Orientation, LayoutOrientation, LayoutOrientation::Vertical, PropertyMetadataFlags::AffectsLayout); 11 | 12 | LayoutBase& LayoutBase::AddChild(Ref child) { 13 | ASSERT(child->GetParent() == nullptr); 14 | if (child->GetParent()) 15 | throw std::exception("element can only have one parent"); 16 | 17 | _children.push_back(child); 18 | child->SetParent(this); 19 | child->SetWindow(GetWindow()); 20 | 21 | return *this; 22 | } 23 | 24 | Ref LayoutBase::GetChild(int index) const { 25 | if (index < 0 || index >= static_cast(_children.size())) 26 | throw std::out_of_range("child index out of range"); 27 | 28 | return _children[index]; 29 | } 30 | 31 | LayoutBase& LayoutBase::RemoveChild(int index) { 32 | if (index < 0 || index >= static_cast(_children.size())) 33 | throw std::out_of_range("child index out of range"); 34 | GetChild(index)->SetParent(nullptr); 35 | GetChild(index)->SetWindow(nullptr); 36 | _children.erase(_children.begin() + index); 37 | return *this; 38 | } 39 | 40 | void LayoutBase::OnDraw(DX::Direct2D::DeviceContext& dc, const DX::RectF& bounds) { 41 | auto background = Background(); 42 | if (background) { 43 | _geometry = Application::Current()->D2DFactory().CreateRectangleGeometry(bounds); 44 | dc.FillRectangle(bounds, background->GetBrush(dc)); 45 | } 46 | else { 47 | _geometry.Reset(); 48 | } 49 | } 50 | 51 | void LayoutBase::SetWindow(Window* window) { 52 | UIElement::SetWindow(window); 53 | 54 | for (auto& element : _children) 55 | element->SetWindow(window); 56 | } 57 | 58 | UIElement* LayoutBase::HitTestCore(const Point2F& point) { 59 | UIElement* source = nullptr; 60 | 61 | for (auto it = _children.rbegin(); it != _children.rend(); ++it) { 62 | if (source = (*it)->HitTest(point)) 63 | break; 64 | } 65 | 66 | if (!source &&_geometry && _geometry.FillContainsPoint(point)) 67 | source = this; 68 | 69 | return source; 70 | } 71 | 72 | // StackLayout 73 | 74 | void StackLayout::OnDraw(DX::Direct2D::DeviceContext& dc, const DX::RectF& bounds) { 75 | LayoutBase::OnDraw(dc, bounds); 76 | 77 | if (Orientation() == LayoutOrientation::Horizontal) { 78 | float x = 0; 79 | for (auto& element : _children) { 80 | x += element->Margin().Left; 81 | const auto& size = element->GetDesiredSize(); 82 | element->Draw(dc, DX::RectF(DX::Point2F(bounds.Left + x, bounds.Top), size.Width, size.Height)); 83 | x += size.Width + element->Margin().Right; 84 | } 85 | } 86 | else { 87 | float y = 0; 88 | for (auto& element : _children) { 89 | y += element->Margin().Top; 90 | const auto& size = element->GetDesiredSize(); 91 | element->Draw(dc, DX::RectF(DX::Point2F(bounds.Left, bounds.Top + y), size.Width, size.Height)); 92 | y += size.Height + element->Margin().Bottom; 93 | } 94 | } 95 | } 96 | 97 | void StackLayout::Measure(const DX::SizeF& maximumSize) { 98 | SizeF size{}; 99 | auto orientation = Orientation(); 100 | 101 | float max = 0; 102 | for (auto& element : _children) { 103 | element->Measure(maximumSize); 104 | const auto& desiredSize = element->GetDesiredSize(); 105 | const auto& margin = element->Margin(); 106 | 107 | if (orientation == LayoutOrientation::Horizontal) { 108 | size.Width += desiredSize.Width + margin.Left + margin.Right; 109 | if (size.Height > max) 110 | max = size.Height; 111 | } 112 | else { 113 | size.Height += desiredSize.Height + margin.Top + margin.Bottom; 114 | if (size.Height > max) 115 | max = size.Height; 116 | } 117 | } 118 | if (orientation == LayoutOrientation::Horizontal) 119 | SetDesiredSize(SizeF(size.Width, max)); 120 | else 121 | SetDesiredSize(SizeF(max, size.Height)); 122 | } 123 | 124 | // CanvasLayout 125 | 126 | DEFINE_AP(CanvasLayout, X, float, 0.0f) 127 | DEFINE_AP(CanvasLayout, Y, float, 0.0f) 128 | 129 | void CanvasLayout::Measure(const DX::SizeF& maximumSize) { 130 | for (auto& element : _children) { 131 | element->Measure(maximumSize); 132 | } 133 | SetDesiredSize(maximumSize); 134 | } 135 | 136 | void CanvasLayout::OnDraw(DX::Direct2D::DeviceContext& dc, const DX::RectF& bounds) { 137 | for (auto& element : _children) { 138 | const auto& size = element->GetDesiredSize(); 139 | element->Draw(dc, DX::RectF(Point2F(X(*element), Y(*element)), size.Width, size.Height)); 140 | } 141 | } 142 | 143 | // UniformGridLayout 144 | 145 | DEFINE_DP(UniformGridLayout, Rows, int, 1); 146 | DEFINE_DP(UniformGridLayout, Columns, int, 1); 147 | 148 | DEFINE_AP(UniformGridLayout, Row, int, 0); 149 | DEFINE_AP(UniformGridLayout, Column, int, 0); 150 | 151 | void UniformGridLayout::OnDraw(DX::Direct2D::DeviceContext& dc, const DX::RectF& bounds) { 152 | LayoutBase::OnDraw(dc, bounds); 153 | 154 | float width = bounds.Width() / ChildrenCount(); 155 | float height = bounds.Height() / ChildrenCount(); 156 | 157 | int rows = Rows(), columns = Columns(); 158 | 159 | for (auto& element : _children) { 160 | int row = Row(*element), col = Column(*element); 161 | const auto& size = element->GetDesiredSize(); 162 | element->Draw(dc, RectF(Point2F(bounds.Left + width * col, bounds.Top + height * row), size.Width, size.Height)); 163 | } 164 | 165 | } 166 | void UniformGridLayout::Measure(const DX::SizeF& maximumSize) { 167 | int rows = Rows(), columns = Columns(); 168 | float width = Width(), height = Height(); 169 | if (width > maximumSize.Width) 170 | width = maximumSize.Width; 171 | if (height > maximumSize.Height) 172 | height = maximumSize.Height; 173 | 174 | float cellwidth = width / columns; 175 | float cellheight = height / rows; 176 | 177 | for (auto& element : _children) { 178 | element->Measure(SizeF(cellwidth, cellheight)); 179 | } 180 | SetDesiredSize(SizeF(width, height)); 181 | } 182 | 183 | -------------------------------------------------------------------------------- /DirectUI/Layout.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CoreUI.h" 4 | 5 | namespace DirectUI { 6 | class LayoutBase abstract : public UIElement { 7 | public: 8 | LayoutBase& AddChild(Ref element); 9 | template 10 | LayoutBase& AddChildren(Iterator begin, Iterator end); 11 | Ref GetChild(int index) const; 12 | LayoutBase& RemoveChild(Ref element); 13 | LayoutBase& RemoveChild(int index); 14 | 15 | int ChildrenCount() { 16 | return static_cast(_children.size()); 17 | } 18 | 19 | void SetWindow(Window* window) override; 20 | 21 | void OnDraw(DX::Direct2D::DeviceContext& dc, const DX::RectF& bounds) override; 22 | 23 | protected: 24 | LayoutBase(std::initializer_list> elements = {}) : UIElement() { 25 | for (auto& element : elements) 26 | AddChild(element); 27 | } 28 | 29 | UIElement* HitTestCore(const DX::Point2F& point) override; 30 | 31 | protected: 32 | std::vector> _children; 33 | DX::Direct2D::Geometry _geometry; 34 | }; 35 | 36 | enum class LayoutOrientation { 37 | Horizontal, 38 | Vertical 39 | }; 40 | 41 | // StackLayout 42 | 43 | class StackLayout final : public LayoutBase { 44 | DECLARE_DP(StackLayout, Orientation, LayoutOrientation); 45 | 46 | public: 47 | StackLayout(std::initializer_list> controls = {}) : LayoutBase(controls) { } 48 | 49 | void OnDraw(DX::Direct2D::DeviceContext& dc, const DX::RectF& bounds) override; 50 | void Measure(const DX::SizeF& maximumSize) override; 51 | }; 52 | 53 | // CanvasLayout 54 | 55 | class CanvasLayout final : public LayoutBase { 56 | public: 57 | DECLARE_AP(X, float); 58 | DECLARE_AP(Y, float); 59 | 60 | public: 61 | void Measure(const DX::SizeF& maximumSize) override; 62 | 63 | protected: 64 | 65 | void OnDraw(DX::Direct2D::DeviceContext& dc, const DX::RectF& bounds) override; 66 | }; 67 | 68 | // UniformGridLayout 69 | 70 | class UniformGridLayout final : public LayoutBase { 71 | DECLARE_DP(UniformGridLayout, Rows, int); 72 | DECLARE_DP(UniformGridLayout, Columns, int); 73 | 74 | DECLARE_AP(Row, int); 75 | DECLARE_AP(Column, int); 76 | 77 | public: 78 | void Measure(const DX::SizeF& maximumSize) override; 79 | 80 | protected: 81 | void OnDraw(DX::Direct2D::DeviceContext& dc, const DX::RectF& bounds) override; 82 | }; 83 | } 84 | -------------------------------------------------------------------------------- /DirectUI/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | STATIC LIBRARY : DirectUI Project Overview 3 | ======================================================================== 4 | 5 | AppWizard has created this DirectUI library project for you. 6 | 7 | No source files were created as part of your project. 8 | 9 | 10 | DirectUI.vcxproj 11 | This is the main project file for VC++ projects generated using an Application Wizard. 12 | It contains information about the version of Visual C++ that generated the file, and 13 | information about the platforms, configurations, and project features selected with the 14 | Application Wizard. 15 | 16 | DirectUI.vcxproj.filters 17 | This is the filters file for VC++ projects generated using an Application Wizard. 18 | It contains information about the association between the files in your project 19 | and the filters. This association is used in the IDE to show grouping of files with 20 | similar extensions under a specific node (for e.g. ".cpp" files are associated with the 21 | "Source Files" filter). 22 | 23 | ///////////////////////////////////////////////////////////////////////////// 24 | Other notes: 25 | 26 | AppWizard uses "TODO:" comments to indicate parts of the source code you 27 | should add to or customize. 28 | 29 | ///////////////////////////////////////////////////////////////////////////// 30 | -------------------------------------------------------------------------------- /DirectUI/Shapes.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "Shapes.h" 3 | #include "Application.h" 4 | 5 | using namespace DirectUI; 6 | using namespace DX; 7 | 8 | DEFINE_DP_WITH_FLAGS(Shape, Fill, Ref, nullptr, PropertyMetadataFlags::AffectsRender); 9 | DEFINE_DP_WITH_FLAGS(Shape, Stroke, Ref, nullptr, PropertyMetadataFlags::AffectsRender); 10 | DEFINE_DP_WITH_FLAGS(Shape, StrokeWidth, float, 1.0f, PropertyMetadataFlags::AffectsRender); 11 | 12 | // Shape 13 | 14 | void Shape::Measure(const SizeF& maximumSize) { 15 | SizeF size{}; 16 | if (Width() != D2D1::FloatMax()) 17 | size.Width = Width(); 18 | if (Height() != D2D1::FloatMax()) 19 | size.Height = Height(); 20 | SetDesiredSize(size); 21 | } 22 | 23 | void Shape::OnDraw(Direct2D::DeviceContext& dc, const RectF& bounds) { 24 | auto fill = Fill(); 25 | auto stroke = Stroke(); 26 | _geometry = CalculateGeometry(bounds); 27 | 28 | if (fill) 29 | dc.FillGeometry(_geometry, fill->GetBrush(dc)); 30 | if (stroke) 31 | dc.DrawGeometry(_geometry, stroke->GetBrush(dc), StrokeWidth()); 32 | } 33 | 34 | UIElement* Shape::HitTestCore(const Point2F& point) { 35 | if (!_geometry) 36 | return nullptr; 37 | 38 | if (Fill() && _geometry.FillContainsPoint(point)) 39 | return this; 40 | if (Stroke() && _geometry.StrokeContainsPoint(point, StrokeWidth())) 41 | return this; 42 | 43 | return nullptr; 44 | } 45 | 46 | // Rectangle 47 | 48 | Direct2D::Geometry Rectangle::CalculateGeometry(const DX::RectF& bounds) { 49 | return Application::Current()->D2DFactory().CreateRectangleGeometry(bounds); 50 | } 51 | 52 | // Ellipse 53 | 54 | Direct2D::Geometry Ellipse::CalculateGeometry(const DX::RectF& bounds) { 55 | auto radiusx = bounds.Width() / 2.0f, radiusy = bounds.Height() / 2.0f; 56 | Direct2D::Ellipse ellipse(Point2F(bounds.Left + radiusx, bounds.Top + radiusy), radiusx, radiusy); 57 | 58 | return Application::Current()->D2DFactory().CreateEllipseGeometry(ellipse); 59 | } 60 | -------------------------------------------------------------------------------- /DirectUI/Shapes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CoreUI.h" 4 | 5 | namespace DirectUI { 6 | class Shape abstract : public UIElement { 7 | DECLARE_DP(Shape, StrokeWidth, float); 8 | DECLARE_DP(Shape, Stroke, Ref); 9 | DECLARE_DP(Shape, Fill, Ref); 10 | 11 | public: 12 | void Measure(const DX::SizeF& maximumSize) override; 13 | void OnDraw(DX::Direct2D::DeviceContext& dc, const DX::RectF& bounds) override; 14 | 15 | protected: 16 | Shape() : UIElement() { } 17 | 18 | virtual DX::Direct2D::Geometry CalculateGeometry(const DX::RectF&) = 0; 19 | UIElement* HitTestCore(const DX::Point2F&) override; 20 | 21 | private: 22 | DX::Direct2D::Geometry _geometry; 23 | }; 24 | 25 | class Rectangle final : public Shape { 26 | public: 27 | 28 | protected: 29 | DX::Direct2D::Geometry CalculateGeometry(const DX::RectF&) override; 30 | 31 | }; 32 | 33 | class Ellipse final : public Shape { 34 | public: 35 | 36 | protected: 37 | DX::Direct2D::Geometry CalculateGeometry(const DX::RectF&) override; 38 | }; 39 | 40 | } 41 | 42 | -------------------------------------------------------------------------------- /DirectUI/Text.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "Text.h" 3 | #include "Colors.h" 4 | #include "Application.h" 5 | 6 | using namespace DirectUI; 7 | using namespace DX; 8 | 9 | DEFINE_DP_WITH_FLAGS(TextBlock, Foreground, Ref, Brushes::Black(), PropertyMetadataFlags::AffectsRender); 10 | DEFINE_DP_WITH_FLAGS(TextBlock, Text, std::wstring, L"", PropertyMetadataFlags::AffectsRender | PropertyMetadataFlags::AffectsLayout); 11 | DEFINE_DP_WITH_FLAGS(TextBlock, Underline, bool, false, PropertyMetadataFlags::AffectsRender); 12 | DEFINE_DP_WITH_FLAGS(TextBlock, Strikethrough, bool, false, PropertyMetadataFlags::AffectsRender); 13 | DEFINE_DP_WITH_FLAGS(TextBlock, TextAlignment, DirectWrite::TextAlignment, DirectWrite::TextAlignment::Leading, PropertyMetadataFlags::AffectsRender); 14 | DEFINE_DP_WITH_FLAGS(TextBlock, ReadingDirection, DirectWrite::ReadingDirection, DirectWrite::ReadingDirection::LeftToRight, PropertyMetadataFlags::AffectsRender); 15 | 16 | //DEFINE_CONVERT(DirectWrite::TextAlignment, TextAlignmentType, ToDirectWrite); 17 | //DEFINE_CONVERT(DirectWrite::FontWeight, FontWeightType, ToDirectWrite); 18 | //DEFINE_CONVERT(DirectWrite::FontStyle, FontStyleType, ToDirectWrite); 19 | //DEFINE_CONVERT(DirectWrite::ReadingDirection, ReadingDirectionType, ToDirectWrite); 20 | 21 | void TextBlock::Measure(const DX::SizeF& maximumSize) { 22 | auto& factory = Application::Current()->DWriteFactory(); 23 | 24 | DX::SizeF size; 25 | 26 | _format = factory.CreateTextFormat(FontFamily().c_str(), FontWeight(), FontStyle(), DX::DirectWrite::FontStretch::Normal, FontSize()); 27 | _format.SetReadingDirection(ReadingDirection()); 28 | 29 | _layout = factory.CreateTextLayout(Text().c_str(), static_cast(Text().size()), _format, maximumSize.Width, maximumSize.Height); 30 | _layout.SetTextAlignment(TextAlignment()); 31 | auto metrics = _layout.GetMetrics(); 32 | size.Width = metrics.Width; 33 | size.Height = metrics.Height; 34 | 35 | SetDesiredSize(size); 36 | } 37 | 38 | void TextBlock::OnDraw(DX::Direct2D::DeviceContext& dc, const DX::RectF& bounds) { 39 | auto background = Background(); 40 | if (background) { 41 | dc.FillRectangle(bounds, background->GetBrush(dc)); 42 | } 43 | auto foreground = Foreground(); 44 | if (foreground) 45 | dc.DrawTextLayout(bounds.TopLeft(), _layout, foreground->GetBrush(dc)); 46 | } 47 | 48 | UIElement* TextBlock::HitTestCore(const DX::Point2F& point) { 49 | if (!_layout) 50 | return nullptr; 51 | bool isTrailingHit, isInside; 52 | DX::DirectWrite::HitTestMetrics metrics; 53 | _layout.HitTestPoint(point.X, point.Y, &isTrailingHit, &isInside, metrics); 54 | return isInside ? this : nullptr; 55 | } 56 | -------------------------------------------------------------------------------- /DirectUI/Text.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CoreUI.h" 4 | 5 | namespace DirectUI { 6 | class TextBlock final : public UIElement { 7 | DECLARE_DP(TextBlock, Foreground, Ref); 8 | DECLARE_DP2(TextBlock, Text, std::wstring); 9 | DECLARE_DP(TextBlock, Underline, bool); 10 | DECLARE_DP(TextBlock, Strikethrough, bool); 11 | DECLARE_DP(TextBlock, TextAlignment, DX::DirectWrite::TextAlignment); 12 | DECLARE_DP(TextBlock, ReadingDirection, DX::DirectWrite::ReadingDirection); 13 | 14 | public: 15 | void Measure(const DX::SizeF& maximumSize) override; 16 | void OnDraw(DX::Direct2D::DeviceContext& dc, const DX::RectF& bounds) override; 17 | 18 | protected: 19 | UIElement* HitTestCore(const DX::Point2F& point) override; 20 | 21 | private: 22 | DX::DirectWrite::TextFormat _format; 23 | DX::DirectWrite::TextLayout _layout; 24 | }; 25 | 26 | } -------------------------------------------------------------------------------- /DirectUI/Window.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "Window.h" 3 | #include "Application.h" 4 | #include "Colors.h" 5 | #include "Buttons.h" 6 | 7 | using namespace DirectUI; 8 | using namespace DX; 9 | 10 | Window* Window::_current = nullptr; 11 | 12 | DEFINE_DP_WITH_FLAGS(Window, ClearColor, Color, Colors::BlueViolet(), PropertyMetadataFlags::AffectsRender); 13 | 14 | Window::Window(const wchar_t* title) { 15 | _hWnd = ::CreateWindowW(DirectUIWindowClassName, title, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 16 | CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 17 | nullptr, nullptr, ::GetModuleHandle(nullptr), nullptr); 18 | 19 | if (!_hWnd) 20 | throw std::exception("Failed to create window"); 21 | 22 | SetWindow(this); 23 | Application::Current()->AddWindow(_hWnd, this); 24 | 25 | ContentProperty.RegisterPropertyChangedHandler(this, [this](auto&, auto&, auto& oldContent, auto& newContent) { 26 | if (oldContent) { 27 | // oldContent->SetParent(nullptr); 28 | oldContent->SetWindow(nullptr); 29 | } 30 | if (newContent) { 31 | // newContent->SetParent(this); 32 | newContent->SetWindow(this); 33 | } 34 | }); 35 | } 36 | 37 | bool Window::ResizeSwapChainBitmap() 38 | { 39 | _dc.SetTarget(); 40 | 41 | if (S_OK == _swapChain.ResizeBuffers()) { 42 | Application::CreateDeviceSwapChainBitmap(_swapChain, _dc); 43 | return true; 44 | } 45 | else 46 | { 47 | ReleaseDevice(); 48 | return false; 49 | } 50 | } 51 | 52 | void Window::ReleaseDevice() { 53 | _dc.Reset(); 54 | _swapChain.Reset(); 55 | } 56 | 57 | LRESULT Window::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { 58 | using namespace std; 59 | 60 | switch (message) { 61 | case WM_PAINT: 62 | PAINTSTRUCT ps; 63 | ::BeginPaint(_hWnd, &ps); 64 | Render(); 65 | ::EndPaint(_hWnd, &ps); 66 | break; 67 | 68 | case WM_DISPLAYCHANGE: 69 | Render(); 70 | break; 71 | 72 | case WM_DESTROY: 73 | Application::Current()->RemoveWindow(_hWnd); 74 | 75 | break; 76 | 77 | case WM_RBUTTONDOWN: 78 | case WM_MBUTTONDOWN: 79 | case WM_LBUTTONDOWN: 80 | DispatchMouseEvent(UIElement::MouseDownEvent, wParam, lParam); 81 | return 0; 82 | 83 | case WM_RBUTTONUP: 84 | case WM_MBUTTONUP: 85 | case WM_LBUTTONUP: 86 | DispatchMouseEvent(UIElement::MouseUpEvent, wParam, lParam); 87 | return 0; 88 | 89 | case WM_MOUSEMOVE: 90 | DispatchMouseEvent(UIElement::MouseMoveEvent, wParam, lParam); 91 | return 0; 92 | 93 | case WM_LBUTTONDBLCLK: 94 | DispatchMouseEvent(UIElement::MouseDoubleClickEvent, wParam, lParam); 95 | return 0; 96 | 97 | case WM_SIZE: 98 | if (SIZE_MINIMIZED != wParam) { 99 | if (ResizeSwapChainBitmap()) { 100 | Render(); 101 | } 102 | } 103 | break; 104 | } 105 | 106 | return ::DefWindowProc(_hWnd, message, wParam, lParam); 107 | } 108 | 109 | void Window::DispatchMouseEvent(RoutedEvent& event, WPARAM wParam, LPARAM lParam) { 110 | auto args = GetMouseEventArgs(wParam, lParam); 111 | auto source = std::get<0>(args); 112 | event.RaiseEvent(*source, std::get<1>(args)); 113 | } 114 | 115 | std::tuple Window::GetMouseEventArgs(WPARAM wParam, LPARAM lParam) { 116 | MouseEventArgs args; 117 | args.Button = static_cast(wParam & static_cast(MouseButton::AllButtons)); 118 | args.Keys = static_cast(wParam & static_cast(MouseKeys::AllKeys)); 119 | int x = GET_X_LPARAM(lParam), y = GET_Y_LPARAM(lParam); 120 | float dpi = Application::Current()->GetDpi(); 121 | 122 | Point2F point(x * 96 / dpi, y * 96 / dpi); 123 | args.Position = point; 124 | 125 | UIElement* source = this; 126 | auto content = Content(); 127 | if (content) { 128 | source = content->HitTest(point); 129 | } 130 | if (source == nullptr) 131 | source = this; 132 | 133 | return std::make_tuple(source, args); 134 | } 135 | 136 | void Window::Render() { 137 | using namespace DX; 138 | 139 | if (!_dc) { 140 | bool success = Application::Current()->CreateDeviceContextAndSwapChain(_hWnd, _dc, _swapChain); 141 | ASSERT(success); 142 | } 143 | 144 | _current = this; 145 | 146 | if (_isLayoutInvalid) { 147 | auto content = Content(); 148 | if (content) 149 | content->Measure(_dc.GetSize()); 150 | _isLayoutInvalid = false; 151 | } 152 | 153 | _dc.BeginDraw(); 154 | _dc.Clear(ClearColor()); 155 | Draw(_dc); 156 | _dc.EndDraw(); 157 | 158 | _current = nullptr; 159 | 160 | _swapChain.Present(); 161 | } 162 | 163 | void Window::Invalidate() { 164 | ::InvalidateRect(_hWnd, nullptr, FALSE); 165 | } 166 | 167 | void Window::Invalidate(const DX::RectF & rect) { 168 | if (rect.IsEmpty()) 169 | return; 170 | 171 | RECT rc = { (int)rect.Left, (int)rect.Top, (int)rect.Right, (int)rect.Bottom }; 172 | ::InvalidateRect(_hWnd, &rc, FALSE); 173 | } 174 | 175 | void Window::InvalidateLayout(bool invalid) { 176 | _isLayoutInvalid = invalid; 177 | Invalidate(); 178 | } 179 | 180 | void Window::Draw(Direct2D::DeviceContext& dc) { 181 | auto size = dc.GetSize(); 182 | auto& content = Content(); 183 | if (content) 184 | content->Draw(dc, RectF(0, 0, size.Width, size.Height)); 185 | } 186 | -------------------------------------------------------------------------------- /DirectUI/Window.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CoreUI.h" 4 | 5 | namespace DirectUI { 6 | class Window : public ContentControl { 7 | friend class Application; 8 | 9 | DECLARE_DP(Window, ClearColor, DX::Color); 10 | 11 | public: 12 | Window(const wchar_t* = nullptr); 13 | 14 | static Window* GetCurrent() { 15 | return _current; 16 | } 17 | 18 | virtual ~Window() { 19 | ReleaseDevice(); 20 | } 21 | 22 | virtual void Render(); 23 | void Measure(const DX::SizeF&) override { }; 24 | 25 | void Invalidate(const DX::RectF& rect); 26 | void Invalidate(); 27 | void InvalidateLayout(bool invalid); 28 | 29 | protected: 30 | void Draw(DX::Direct2D::DeviceContext& dc); 31 | 32 | UIElement* HitTestCore(const DX::Point2F& point) override { 33 | return nullptr; 34 | } 35 | 36 | DX::Direct2D::DeviceContext& GetDeviceContext() { 37 | return _dc; 38 | } 39 | 40 | DX::Dxgi::SwapChain1& GetSwapChain() { 41 | return _swapChain; 42 | } 43 | 44 | bool ResizeSwapChainBitmap(); 45 | void ReleaseDevice(); 46 | 47 | private: 48 | void DispatchMouseEvent(RoutedEvent&, WPARAM wParam, LPARAM lParam); 49 | LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); 50 | 51 | std::tuple GetMouseEventArgs(WPARAM, LPARAM); 52 | 53 | private: 54 | HWND _hWnd; 55 | DX::Direct2D::DeviceContext _dc; 56 | DX::Dxgi::SwapChain1 _swapChain; 57 | bool _isLayoutInvalid = true; 58 | static Window* _current; 59 | }; 60 | 61 | } 62 | -------------------------------------------------------------------------------- /DirectUI/debug.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef _DEBUG 4 | #include 5 | #include 6 | #include 7 | #endif 8 | 9 | #ifdef _DEBUG 10 | #define ASSERT _ASSERTE 11 | #define VERIFY ASSERT 12 | #define VERIFY_(result, expression) ASSERT(result == expression) 13 | #else 14 | #define ASSERT __noop 15 | #define VERIFY(expression) (expression) 16 | #define VERIFY_(result, expression) (expression) 17 | #endif 18 | 19 | #ifdef _DEBUG 20 | struct Tracer 21 | { 22 | char const * m_filename; 23 | unsigned m_line; 24 | 25 | Tracer(char const * filename, unsigned const line) : 26 | m_filename { filename }, 27 | m_line { line } 28 | { 29 | 30 | } 31 | 32 | template 33 | auto operator()(wchar_t const * format, Args... args) const -> void 34 | { 35 | wchar_t buffer [400]; 36 | 37 | auto count = swprintf_s(buffer, 38 | L"%S(%d): ", 39 | m_filename, 40 | m_line); 41 | 42 | ASSERT(-1 != count); 43 | 44 | ASSERT(-1 != _snwprintf_s(buffer + count, 45 | _countof(buffer) - count, 46 | _countof(buffer) - count - 1, 47 | format, 48 | args...)); 49 | 50 | OutputDebugString(buffer); 51 | } 52 | 53 | template 54 | auto operator()(char const * format, Args... args) const -> void { 55 | char buffer[400]; 56 | 57 | auto count = sprintf_s(buffer, 58 | "%s(%d): ", 59 | m_filename, 60 | m_line); 61 | 62 | ASSERT(-1 != count); 63 | 64 | ASSERT(-1 != _snprintf_s(buffer + count, 65 | _countof(buffer) - count, 66 | _countof(buffer) - count - 1, 67 | format, 68 | args...)); 69 | 70 | OutputDebugStringA(buffer); 71 | } 72 | }; 73 | #endif 74 | 75 | #ifdef _DEBUG 76 | #define TRACE Tracer(__FILE__, __LINE__) 77 | #else 78 | #define TRACE __noop 79 | #endif 80 | -------------------------------------------------------------------------------- /DirectUI/handle.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "debug.h" 5 | 6 | namespace KennyKerr 7 | { 8 | template 9 | class unique_handle 10 | { 11 | using pointer = typename Traits::pointer; 12 | 13 | pointer m_value; 14 | 15 | auto close() throw() -> void 16 | { 17 | if (*this) 18 | { 19 | Traits::close(m_value); 20 | } 21 | } 22 | 23 | public: 24 | 25 | unique_handle(unique_handle const &) = delete; 26 | auto operator=(unique_handle const &) -> unique_handle & = delete; 27 | 28 | explicit unique_handle(pointer value = Traits::invalid()) throw() : 29 | m_value { value } 30 | { 31 | } 32 | 33 | unique_handle(unique_handle && other) throw() : 34 | m_value { other.release() } 35 | { 36 | } 37 | 38 | auto operator=(unique_handle && other) throw() -> unique_handle & 39 | { 40 | if (this != &other) 41 | { 42 | reset(other.release()); 43 | } 44 | 45 | return *this; 46 | } 47 | 48 | ~unique_handle() throw() 49 | { 50 | close(); 51 | } 52 | 53 | explicit operator bool() const throw() 54 | { 55 | return m_value != Traits::invalid(); 56 | } 57 | 58 | auto get() const throw() -> pointer 59 | { 60 | return m_value; 61 | } 62 | 63 | auto get_address_of() throw() -> pointer * 64 | { 65 | ASSERT(!*this); 66 | return &m_value; 67 | } 68 | 69 | auto release() throw() -> pointer 70 | { 71 | auto value = m_value; 72 | m_value = Traits::invalid(); 73 | return value; 74 | } 75 | 76 | auto reset(pointer value = Traits::invalid()) throw() -> bool 77 | { 78 | if (m_value != value) 79 | { 80 | close(); 81 | m_value = value; 82 | } 83 | 84 | return static_cast(*this); 85 | } 86 | 87 | auto swap(unique_handle & other) throw() -> void 88 | { 89 | std::swap(m_value, other.m_value); 90 | } 91 | }; 92 | 93 | template 94 | auto swap(unique_handle & left, 95 | unique_handle & right) throw() -> void 96 | { 97 | left.swap(right); 98 | } 99 | 100 | template 101 | auto operator==(unique_handle const & left, 102 | unique_handle const & right) throw() -> bool 103 | { 104 | return left.get() == right.get(); 105 | } 106 | 107 | template 108 | auto operator!=(unique_handle const & left, 109 | unique_handle const & right) throw() -> bool 110 | { 111 | return left.get() != right.get(); 112 | } 113 | 114 | template 115 | auto operator<(unique_handle const & left, 116 | unique_handle const & right) throw() -> bool 117 | { 118 | return left.get() < right.get(); 119 | } 120 | 121 | template 122 | auto operator>=(unique_handle const & left, 123 | unique_handle const & right) throw() -> bool 124 | { 125 | return left.get() >= right.get(); 126 | } 127 | 128 | template 129 | auto operator>(unique_handle const & left, 130 | unique_handle const & right) throw() -> bool 131 | { 132 | return left.get() > right.get(); 133 | } 134 | 135 | template 136 | auto operator<=(unique_handle const & left, 137 | unique_handle const & right) throw() -> bool 138 | { 139 | return left.get() <= right.get(); 140 | } 141 | 142 | struct null_handle_traits 143 | { 144 | using pointer = HANDLE; 145 | 146 | static auto invalid() throw() -> pointer 147 | { 148 | return nullptr; 149 | } 150 | 151 | static auto close(pointer value) throw() -> void 152 | { 153 | VERIFY(CloseHandle(value)); 154 | } 155 | }; 156 | 157 | struct invalid_handle_traits 158 | { 159 | using pointer = HANDLE; 160 | 161 | static auto invalid() throw() -> pointer 162 | { 163 | return INVALID_HANDLE_VALUE; 164 | } 165 | 166 | static auto close(pointer value) throw() -> void 167 | { 168 | VERIFY(CloseHandle(value)); 169 | } 170 | }; 171 | 172 | using null_handle = unique_handle; 173 | using invalid_handle = unique_handle; 174 | } 175 | -------------------------------------------------------------------------------- /DirectUI/pch.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | -------------------------------------------------------------------------------- /DirectUI/pch.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Debug.h" 4 | #include "handle.h" 5 | #include "dx.h" 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | -------------------------------------------------------------------------------- /HelloWorld/HelloWorld.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "..\DirectUI\DirectUI.h" 3 | #include 4 | #include 5 | 6 | using namespace DirectUI; 7 | 8 | int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR lpCmdLine, int) { 9 | Application app; 10 | app.Initialize(); 11 | 12 | Window window1(L"Hello, World!"); 13 | auto stack = Create(); 14 | stack->Background(Create(Colors::DarkCyan())); 15 | 16 | auto r1 = Create(); 17 | r1->Fill(Create(Colors::Yellow()))->StrokeWidth(5)->Width(200)->Height(150); 18 | 19 | stack->AddChild(r1); 20 | 21 | auto r2 = Create(); 22 | r2->Fill(Create(Colors::Red()))->StrokeWidth(5)->Width(100)->Height(120); 23 | stack->AddChild(r2); 24 | 25 | auto r3 = Create(); 26 | r3->Fill(Create(Colors::LawnGreen()))->StrokeWidth(10)->Width(50)->Height(50); 27 | auto b1 = Create(Colors::Orange()); 28 | b1->Opacity(.6f); 29 | r3->Stroke(b1); 30 | stack->AddChild(r3); 31 | 32 | window1.Content(stack); 33 | 34 | auto b3 = Create(Colors::DarkCyan()); 35 | auto b4 = Create(Colors::LightBlue()); 36 | std::atomic done(false); 37 | 38 | auto t = std::thread([&done](auto r1, auto b3, auto b4) { 39 | while (!done) { 40 | r1->Fill(b3); 41 | std::this_thread::sleep_for(std::chrono::milliseconds(500)); 42 | r1->Fill(b4); 43 | std::this_thread::sleep_for(std::chrono::milliseconds(500)); 44 | } 45 | }, r1, b3, b4); 46 | 47 | auto rv = app.Run(); 48 | done = true; 49 | t.join(); 50 | return rv; 51 | } 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /HelloWorld/HelloWorld.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | -------------------------------------------------------------------------------- /HelloWorld/HelloWorld.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DirectUI/00b7709ced648a77e14e5fc89e16f545b0577129/HelloWorld/HelloWorld.ico -------------------------------------------------------------------------------- /HelloWorld/HelloWorld.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {B95D657E-CCF5-424A-9CFE-2DBBF2175D67} 24 | Win32Proj 25 | HelloWorld 26 | 10.0.17763.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v141 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v141 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v141 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v141 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | true 78 | 79 | 80 | false 81 | 82 | 83 | false 84 | 85 | 86 | 87 | NotUsing 88 | Level3 89 | Disabled 90 | WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) 91 | 92 | 93 | Windows 94 | 95 | 96 | 97 | 98 | NotUsing 99 | Level3 100 | Disabled 101 | _DEBUG;_WINDOWS;%(PreprocessorDefinitions) 102 | 103 | 104 | Windows 105 | 106 | 107 | 108 | 109 | Level3 110 | NotUsing 111 | MaxSpeed 112 | true 113 | true 114 | WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 115 | 116 | 117 | Windows 118 | true 119 | true 120 | 121 | 122 | 123 | 124 | Level3 125 | NotUsing 126 | MaxSpeed 127 | true 128 | true 129 | NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 130 | 131 | 132 | Windows 133 | true 134 | true 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | {42fbcd14-632d-48e5-828a-19278be94184} 143 | 144 | 145 | 146 | 147 | 148 | -------------------------------------------------------------------------------- /HelloWorld/HelloWorld.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | 14 | 15 | Source Files 16 | 17 | 18 | -------------------------------------------------------------------------------- /HelloWorld/small.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zodiacon/DirectUI/00b7709ced648a77e14e5fc89e16f545b0577129/HelloWorld/small.ico -------------------------------------------------------------------------------- /HelloWorld/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // HelloWorld.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /HelloWorld/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #include "targetver.h" 9 | 10 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 11 | // Windows Header Files: 12 | #include 13 | 14 | // C RunTime Header Files 15 | #include 16 | #include 17 | 18 | #include "..\DirectUI\DirectUI.h" 19 | -------------------------------------------------------------------------------- /HelloWorld/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /HitTesting/HitTesting.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {571FA848-C61F-4316-89DB-88C3B2CC3736} 24 | Win32Proj 25 | HitTesting 26 | 10.0.17763.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v141 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v141 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v141 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v141 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | true 78 | 79 | 80 | false 81 | 82 | 83 | false 84 | 85 | 86 | 87 | 88 | 89 | Level3 90 | Disabled 91 | _DEBUG;_WINDOWS;%(PreprocessorDefinitions) 92 | 93 | 94 | Windows 95 | 96 | 97 | 98 | 99 | 100 | 101 | Level3 102 | Disabled 103 | WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) 104 | 105 | 106 | Windows 107 | 108 | 109 | 110 | 111 | Level3 112 | 113 | 114 | MaxSpeed 115 | true 116 | true 117 | WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 118 | 119 | 120 | Windows 121 | true 122 | true 123 | 124 | 125 | 126 | 127 | Level3 128 | 129 | 130 | MaxSpeed 131 | true 132 | true 133 | NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 134 | 135 | 136 | Windows 137 | true 138 | true 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | {42fbcd14-632d-48e5-828a-19278be94184} 147 | 148 | 149 | 150 | 151 | 152 | -------------------------------------------------------------------------------- /HitTesting/HitTesting.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | -------------------------------------------------------------------------------- /HitTesting/Main.cpp: -------------------------------------------------------------------------------- 1 | #include "..\DirectUI\DirectUI.h" 2 | 3 | using namespace DirectUI; 4 | using namespace DX::DirectWrite; 5 | 6 | int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR lpCmdLine, int) { 7 | Application app; 8 | app.Initialize(); 9 | 10 | bool yellow = false; 11 | 12 | Window mainWindow(L"Hit Testing Demo"); 13 | mainWindow.ClearColor(Colors::Lime()); 14 | 15 | DX::Color old[10]; 16 | auto canvas = Create(); 17 | for (int i = 0; i < 10; i++) { 18 | auto grid = Create(); 19 | float c = i / 10.0f; 20 | grid->Width(100)->Height(100)->Background(Create(DX::Color(c, c, c)))->Width(100)->Height(100);; 21 | auto tb = Create(); 22 | const wchar_t text[] = { (const wchar_t)(i + L'0'), L'\0' }; 23 | tb->Foreground(Create(Colors::Red()))->TextAlignment(TextAlignment::Center)->Text(text)->FontSize(30); 24 | 25 | grid->AddEventHandler(UIElement::MouseDownEvent, [&yellow](auto& source, const auto& args) { 26 | source.Background(yellow ? Brushes::Blue() : Brushes::Yellow()); 27 | yellow = !yellow; 28 | return false; 29 | }); 30 | 31 | grid->AddChild(tb); 32 | 33 | canvas->X(grid, i * 50.0f + 20); 34 | canvas->Y(grid, i * 50.0f + 20); 35 | canvas->AddChild(grid); 36 | } 37 | 38 | mainWindow.Content(canvas); 39 | 40 | return app.Run(); 41 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Pavel Yosifovich 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DirectUI 2 | DirectUI is an attempt to create a native UI framework for Windows desktop applications inspired by the Windows Presentation Foundation (WPF). 3 | 4 | Direct2D is used as the graphics API for the UI. 5 | 6 | The DirectX headers are based on Kenny Kerr's excellent C++ wrappers (with some extensions). 7 | -------------------------------------------------------------------------------- /SimpleDataBinding/Main.cpp: -------------------------------------------------------------------------------- 1 | #include "..\DirectUI\DirectUI.h" 2 | #include 3 | 4 | using namespace DirectUI; 5 | 6 | 7 | struct Person : DependencyObject { 8 | DECLARE_DP(Person, Name, std::wstring); 9 | DECLARE_DP(Person, Age, int); 10 | 11 | void ModifyAge() { 12 | Age(Age() + 1); 13 | } 14 | }; 15 | 16 | DEFINE_DP(Person, Name, std::wstring, L"Bart"); 17 | DEFINE_DP(Person, Age, int, 10); 18 | 19 | int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR lpCmdLine, int) { 20 | Application app; 21 | app.Initialize(); 22 | 23 | Person p; 24 | 25 | auto nameTB = Create(); 26 | nameTB->BindTo(TextBlock::TextProperty, p, Person::NameProperty); 27 | nameTB->Text(L"Hello")->Foreground(Brushes::Yellow())->FontSize(30); 28 | 29 | auto button = Create