├── .editorconfig
├── .gitattributes
├── .github
└── workflows
│ └── build.yml
├── .gitignore
├── Directory.Build.props
├── LICENSE
├── NuGet.config
├── README.md
├── Samples.sln
├── docs
├── BASICCONCEPTS.md
└── screenshots
│ ├── SCREENSHOTS.md
│ ├── docking.png
│ ├── drawing.png
│ ├── sdf_shapes.png
│ ├── sdf_text.png
│ ├── text_shapes.png
│ ├── ui_basic.png
│ ├── ui_experimental.png
│ ├── ui_extended.png
│ ├── ui_extended2.png
│ └── ui_layouts.png
├── licenses
├── NanoGUI.LICENSE.txt
├── NanoUI.LICENSE.txt
├── NanoVG.LICENSE.txt
└── README.md
├── samples
├── FNAExample
│ ├── ConvertUtils.cs
│ ├── FNAExample.csproj
│ ├── FNARenderer.Resources.cs
│ ├── FNARenderer.Textures.cs
│ ├── FNARenderer.cs
│ ├── InputMappings.cs
│ ├── NanoUIGame.cs
│ ├── Program.cs
│ ├── README.md
│ └── Resources
│ │ ├── Effect.fx
│ │ ├── Effect.fxb
│ │ └── Macros.fxh
├── MonoGameExample
│ ├── InputMappings.cs
│ ├── MGRenderer.Resources.cs
│ ├── MGRenderer.Textures.cs
│ ├── MGRenderer.cs
│ ├── MonoGameExample.csproj
│ ├── NanoUIGame.cs
│ ├── Program.cs
│ └── Resources
│ │ ├── Effect.dx11.mgfxo
│ │ ├── Effect.fx
│ │ ├── Effect.ogl.mgfxo
│ │ └── Macros.fxh
├── NanoUIDemos
│ ├── Assets
│ │ ├── fonts
│ │ │ ├── Inconsolata-Regular.ttf
│ │ │ ├── NotoSansTC-Regular.ttf
│ │ │ ├── Roboto-Black.ttf
│ │ │ ├── Roboto-BlackItalic.ttf
│ │ │ ├── Roboto-Bold.ttf
│ │ │ ├── Roboto-BoldItalic.ttf
│ │ │ ├── Roboto-Italic.ttf
│ │ │ ├── Roboto-Light.ttf
│ │ │ ├── Roboto-LightItalic.ttf
│ │ │ ├── Roboto-Medium.ttf
│ │ │ ├── Roboto-MediumItalic.ttf
│ │ │ ├── Roboto-Regular.ttf
│ │ │ ├── Roboto-Thin.ttf
│ │ │ ├── Roboto-ThinItalic.ttf
│ │ │ ├── fa-brands-400.ttf
│ │ │ ├── fa-regular-400.ttf
│ │ │ └── fa-solid-900.ttf
│ │ ├── images
│ │ │ ├── image0.png
│ │ │ ├── image1.png
│ │ │ ├── image10.png
│ │ │ ├── image11.png
│ │ │ ├── image2.png
│ │ │ ├── image3.png
│ │ │ ├── image4.png
│ │ │ ├── image5.png
│ │ │ ├── image6.png
│ │ │ ├── image7.png
│ │ │ ├── image8.png
│ │ │ └── image9.png
│ │ ├── landscape.png
│ │ ├── shaders
│ │ │ ├── NanoUI.frag.glsl
│ │ │ ├── NanoUI.frag.hlsl
│ │ │ ├── NanoUI.vert.glsl
│ │ │ └── NanoUI.vert.hlsl
│ │ └── svg
│ │ │ ├── decoration.svg
│ │ │ ├── testBasic.svg
│ │ │ ├── text.svg
│ │ │ ├── tiger.svg
│ │ │ └── tiger2.svg
│ ├── DemoAssets.cs
│ ├── DemoBase.cs
│ ├── DemoFactory.cs
│ ├── Drawing
│ │ ├── DrawingDemo.cs
│ │ ├── SDFTextDemo.cs
│ │ ├── SvgDemo.cs
│ │ └── TextShapesDemo.cs
│ ├── Experimental
│ │ ├── Components
│ │ │ ├── Editors
│ │ │ │ ├── BoolEditor.cs
│ │ │ │ ├── ColorEditor.cs
│ │ │ │ ├── EnumEditor.cs
│ │ │ │ ├── IPropertyEditor.cs
│ │ │ │ ├── NumericEditor.cs
│ │ │ │ ├── StringEditor.cs
│ │ │ │ ├── StructEditor.cs
│ │ │ │ └── Vector2Editor.cs
│ │ │ ├── UIDial.cs
│ │ │ ├── UIGraph.cs
│ │ │ ├── UIPerformanceGraph.cs
│ │ │ ├── UIPropertyGrid.cs
│ │ │ ├── UIPropertyGridCategoryPanel.cs
│ │ │ ├── UIRoundMeter.cs
│ │ │ ├── UISearchBox.cs
│ │ │ ├── UISeparator.cs
│ │ │ ├── UISwitchBox.cs
│ │ │ ├── UITextArea.cs
│ │ │ └── UIToleranceBar.cs
│ │ ├── ThemeEXT.cs
│ │ └── Utils
│ │ │ └── CategorySorter.cs
│ ├── NanoUIDemos.csproj
│ ├── PerfGraph.cs
│ └── UI
│ │ ├── UIBasicDemo.cs
│ │ ├── UIDockingDemo.cs
│ │ ├── UIExperimentalDemo.cs
│ │ ├── UIExtended2Demo.cs
│ │ ├── UIExtendedDemo.cs
│ │ └── UILayoutDemo.cs
├── README.md
└── VeldridExample
│ ├── InputMappings.cs
│ ├── Program.cs
│ ├── README.md
│ ├── Shaders
│ ├── VeldridShaderCreator.cs
│ ├── shader.frag
│ └── shader.vert
│ ├── VeldridExample.csproj
│ ├── VeldridRenderer.Resources.cs
│ ├── VeldridRenderer.Textures.cs
│ └── VeldridRenderer.cs
└── source
├── Common
├── ArrayBuffer.cs
├── Brushes.cs
├── Category.cs
├── Color.cs
├── ColumnDefinition.cs
├── CornerRadius.cs
├── Enums.cs
├── FontAwesomeIcon.cs
├── GlyphPosition.cs
├── GlyphShapeCommand.cs
├── Inputs.cs
├── MinMax.cs
├── Paint.cs
├── Rect.cs
├── Shortcut.cs
├── TextRow.cs
├── TextureDesc.cs
├── Thickness.cs
└── UnsafeBuffer.cs
├── Components
├── Bars
│ ├── UIMenubar.cs
│ ├── UITitlebar.cs
│ ├── UIToolbar.cs
│ └── UIWidgetbar.cs
├── Buttons
│ ├── UINumericUpDown.cs
│ ├── UIToolButton.cs
│ └── UIUpDownButton.cs
├── Colors
│ ├── UIAlphaBar.cs
│ ├── UIColorPicker.cs
│ └── UIColorWheel.cs
├── Dialogs
│ ├── UIColorDialog.cs
│ ├── UIDialog.cs
│ ├── UIFileDialog.cs
│ ├── UIFolderDialog.cs
│ ├── UIMessageBox.cs
│ └── UIMultilineMessageBox.cs
├── Docking
│ ├── DockArea.cs
│ ├── DockContainer.cs
│ ├── DockHit.cs
│ ├── DockNode.Methods.cs
│ ├── DockNode.cs
│ ├── DockTabWidget.cs
│ ├── DockTitlebar.cs
│ └── DockWindow.cs
├── Files
│ ├── FileFolderInfo.cs
│ ├── UIFileFolderDetails.cs
│ ├── UIFileFolderDropdown.cs
│ ├── UIFileFolderFlow.cs
│ ├── UIFileFolderList.cs
│ └── UIFileFolderTree.cs
├── Menus
│ ├── UIContextMenu.cs
│ ├── UIMenu.cs
│ ├── UIMenuItem.cs
│ ├── UIMenuSeparator.cs
│ └── UIMenuSubmenu.cs
├── Scrolling
│ ├── IScrollable.cs
│ ├── UIScrollPanel.cs
│ └── UIScrollbar.cs
├── Simple
│ ├── UIFileIcon.cs
│ ├── UIFileIconText.cs
│ ├── UIIcon.cs
│ ├── UIIconText.cs
│ ├── UIImage.cs
│ ├── UISeparator.cs
│ ├── UIShortcut.cs
│ └── UIText.cs
├── UIButton.cs
├── UICheckBox.cs
├── UICollapsablePanel.cs
├── UIComboBox.cs
├── UIEnumDropDown.cs
├── UIGrid.cs
├── UIGridView.cs
├── UIImageViewer.cs
├── UILabel.cs
├── UIListBox.cs
├── UINumericTextBox.cs
├── UIPanel.cs
├── UIPopup.cs
├── UIPopupButton.cs
├── UIProgressbar.cs
├── UIScrollableLabel.cs
├── UISlider.cs
├── UISpinner.cs
├── UISplitPanel.cs
├── UISplitter.cs
├── UISvgWidget.cs
├── UITabWidget.cs
├── UITextField.cs
├── UITooltip.cs
├── UIWidget.cs
├── UIWidgetEXT.cs
├── UIWindow.cs
├── Views
│ ├── IViewItem.cs
│ ├── Items
│ │ ├── FlowItem.cs
│ │ ├── RowItem.cs
│ │ └── TreeItem.cs
│ ├── UIDropDownView.cs
│ ├── UIFlowView.cs
│ ├── UIListView.cs
│ ├── UITableView.cs
│ ├── UITreeView.cs
│ ├── UIViewItemWidget.cs
│ ├── UIViewPanel.cs
│ └── UIViewWidget.cs
└── WidgetList.cs
├── Fonts
├── Data
│ ├── Font.cs
│ ├── FontAtlas.cs
│ ├── FontAtlasNode.cs
│ ├── FontEnums.cs
│ ├── FontState.cs
│ ├── FontTextIter.cs
│ ├── Glyph.cs
│ └── GlyphQuad.cs
├── Fontstash.Atlas.cs
├── Fontstash.Extended.cs
├── Fontstash.Utils.cs
├── Fontstash.cs
├── SafeStbTrueTypeManager.cs
├── SafeTrueType
│ ├── Bmp.cs
│ ├── Buf.cs
│ ├── CharStringContext.cs
│ ├── Common.cs
│ ├── FakePtr.cs
│ ├── FontInfo.cs
│ └── RectPackContext.cs
├── StbTrueTypeManager.cs
└── TrueType
│ ├── CRuntime.cs
│ ├── StbTrueType.Bitmap.cs
│ ├── StbTrueType.Buf.cs
│ ├── StbTrueType.CharString.cs
│ ├── StbTrueType.Common.cs
│ ├── StbTrueType.FontInfo.cs
│ ├── StbTrueType.Heap.cs
│ ├── StbTrueType.OldRasterizer.cs
│ ├── StbTrueType.RectPack.cs
│ └── StbTrueType.cs
├── Globals.cs
├── IFontManager.cs
├── INvgRenderer.cs
├── Layouts
├── FlowLayout.cs
├── GridLayout.cs
├── GroupLayout.cs
├── Layout.cs
├── SplitLayout.cs
└── StackLayout.cs
├── NanoUI.csproj
├── Nvg
├── Data
│ ├── NvgBounds.cs
│ ├── NvgParams.cs
│ ├── NvgPath.cs
│ ├── NvgPathCommand.cs
│ ├── NvgPathCommandType.cs
│ ├── NvgPoint.cs
│ ├── NvgPointFlags.cs
│ ├── NvgScissor.cs
│ └── NvgState.cs
├── NvgContext.Paths.cs
├── NvgContext.Svg.cs
├── NvgContext.Text.cs
├── NvgContext.Utils.cs
└── NvgContext.cs
├── README.md
├── Rendering
├── Data
│ ├── DrawCall.cs
│ ├── DrawCommand.cs
│ ├── FillStrokeInfo.cs
│ ├── FragmentUniform.cs
│ └── Vertex.cs
├── DrawCache.Commands.cs
├── DrawCache.Indices.cs
├── DrawCache.cs
└── DrawEnums.cs
├── Serializers
├── JsonBaseConverters.cs
├── JsonNumericsConverters.cs
├── NumericsArrayConverter.cs
└── ThemeSerializer.cs
├── Styles
├── BorderStyle.cs
├── CommonStyle.cs
├── DockingStyle.cs
├── FilesStyle.cs
├── FontsStyle.cs
├── PointerStyle.cs
├── ScrollbarStyle.cs
└── WindowStyle.cs
├── Svg
├── Data
│ ├── SvgGradientStop.cs
│ ├── SvgLinearGradient.cs
│ ├── SvgPath.cs
│ ├── SvgRadialGradient.cs
│ ├── SvgShape.cs
│ ├── SvgStyle.cs
│ ├── SvgXmlAttribute.cs
│ ├── SvgXmlElement.cs
│ ├── SvgXmlPath.cs
│ ├── SvgXmlPathCommand.cs
│ ├── SvgXmlPathCommandType.cs
│ └── SvgXmlPoints.cs
├── SvgArcUtils.cs
├── SvgManager.Attributes.cs
├── SvgManager.Create.cs
├── SvgManager.PathCommands.cs
├── SvgManager.cs
└── SvgXmlUtils.cs
├── UIScreen.cs
├── UITheme.cs
└── Utils
├── ConvertUtils.cs
├── DefaultTheme.cs
├── MathUtils.cs
├── MemoryUtils.cs
└── StringUtils.cs
/.editorconfig:
--------------------------------------------------------------------------------
1 | ; This file is for unifying the coding style for different editors and IDEs.
2 | ; More information at http://EditorConfig.org
3 |
4 | root = true
5 |
6 | [*]
7 | end_of_line = CRLF
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 | indent_style = space
11 |
12 | # Xml project files
13 | [*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj,props,targets}]
14 | indent_size = 2
15 |
16 | [*.cs]
17 | indent_size = 4
18 |
19 | # Avoid "this." and "Me." if not necessary
20 | dotnet_style_qualification_for_field = false:suggestion
21 | dotnet_style_qualification_for_property = false:suggestion
22 | dotnet_style_qualification_for_method = false:suggestion
23 | dotnet_style_qualification_for_event = false:suggestion
24 |
25 | # Use language keywords instead of framework type names for type references
26 | dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
27 | dotnet_style_predefined_type_for_member_access = true:suggestion
28 |
29 | # Don't use "var"
30 | csharp_style_var_for_built_in_types = false:suggestion
31 | csharp_style_var_when_type_is_apparent = false:suggestion
32 | csharp_style_var_elsewhere = false:suggestion
33 |
34 | # Newline settings
35 | csharp_new_line_before_open_brace = all
36 | csharp_new_line_before_else = true
37 | csharp_new_line_before_catch = true
38 | csharp_new_line_before_finally = true
39 | csharp_new_line_before_members_in_object_initializers = true
40 | csharp_new_line_before_members_in_anonymous_types = true
41 |
42 | # License header
43 | file_header_template = Copyright (c) Klaus Bergius.\nLicensed under the MIT License (MIT).
44 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Autodetect text files and ensure that we normalise their
2 | # line endings to lf internally. When checked out they may
3 | # use different line endings.
4 | * text=auto
5 |
6 | # Check out with crlf (Windows) line endings
7 | *.sln text eol=crlf
8 | *.csproj text eol=crlf
9 | *.cs text diff=csharp eol=crlf
10 | *.resx text eol=crlf
11 | *.vsixmanifest text eol=crlf
12 | packages.config text eol=crlf
13 | App.config text eol=crlf
14 | *.bat text eol=crlf
15 | *.cmd text eol=crlf
16 | *.snippet text eol=crlf
17 | *.manifest text eol=crlf
18 | *.licenseheader text eol=crlf
19 |
20 | # Check out with lf (UNIX) line endings
21 | *.sh text eol=lf
22 | .gitignore text eol=lf
23 | .gitattributes text eol=lf
24 | *.md text eol=lf
25 | .travis.yml text eol=lf
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | # This workflow will build a .NET project
2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net
3 |
4 | name: Build
5 |
6 | on:
7 | push:
8 | branches: [ "main" ]
9 | paths-ignore:
10 | - '*.md'
11 | - 'LICENSE'
12 | - 'docs/**'
13 | - 'samples/FNAExample/**'
14 | pull_request:
15 | branches: [ "main" ]
16 | paths-ignore:
17 | - '*.md'
18 | - 'LICENSE'
19 | - 'docs/**'
20 | - 'samples/FNAExample/**'
21 |
22 | jobs:
23 | build:
24 |
25 | runs-on: ubuntu-latest
26 |
27 | steps:
28 | - uses: actions/checkout@v4
29 | - name: Setup .NET
30 | uses: actions/setup-dotnet@v4
31 | with:
32 | dotnet-version: 8.0.x
33 | - name: Restore dependencies
34 | run: dotnet restore
35 | - name: Build
36 | run: dotnet build --no-restore
37 | - name: Test
38 | run: dotnet test --no-build --verbosity normal
39 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## A streamlined .gitignore for modern .NET projects
2 | ## including temporary files, build results, and
3 | ## files generated by popular .NET tools. If you are
4 | ## developing with Visual Studio, the VS .gitignore
5 | ## https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
6 | ## has more thorough IDE-specific entries.
7 | ##
8 | ## Get latest from https://github.com/github/gitignore/blob/main/Dotnet.gitignore
9 |
10 | # Build results
11 | [Dd]ebug/
12 | [Dd]ebugPublic/
13 | [Rr]elease/
14 | [Rr]eleases/
15 | x64/
16 | x86/
17 | [Ww][Ii][Nn]32/
18 | [Aa][Rr][Mm]/
19 | [Aa][Rr][Mm]64/
20 | bld/
21 | [Bb]in/
22 | [Oo]bj/
23 | [Ll]og/
24 | [Ll]ogs/
25 |
26 | # .NET Core
27 | project.lock.json
28 | project.fragment.lock.json
29 | artifacts/
30 |
31 | # ASP.NET Scaffolding
32 | ScaffoldingReadMe.txt
33 |
34 | # NuGet Packages
35 | *.nupkg
36 | # NuGet Symbol Packages
37 | *.snupkg
38 |
39 | # Others
40 | ~$*
41 | *~
42 | CodeCoverage/
43 |
44 | # MSBuild Binary and Structured Log
45 | *.binlog
46 |
47 | # MSTest test Results
48 | [Tt]est[Rr]esult*/
49 | [Bb]uild[Ll]og.*
50 |
51 | # NUnit
52 | *.VisualState.xml
53 | TestResult.xml
54 | nunit-*.xml
55 | *.vs
56 |
--------------------------------------------------------------------------------
/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | Debug
4 | $(MSBuildThisFileDirectory)
5 |
6 |
7 |
8 | https://github.com/kbergius/NanoUI
9 | git
10 | true
11 |
12 |
13 |
14 | true
15 | 12.0
16 | disable
17 | enable
18 | true
19 | strict
20 | preview
21 | $(MSBuildThisFileDirectory)NuGet.config
22 | true
23 | true
24 |
25 |
26 |
27 | Klaus Bergius
28 | Copyright (c) Klaus Bergius
29 | NanoUI
30 | MIT
31 | true
32 | $(RepositoryUrl)
33 | dotnet gui ui drawing csharp graphics cross-platform
34 |
35 |
36 |
37 |
38 | portable
39 | true
40 | true
41 | true
42 | snupkg
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2025 Klaus Bergius
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 |
--------------------------------------------------------------------------------
/NuGet.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Samples.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.3.32922.545
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{E94958C3-5109-4384-A9CB-E165EC5754CE}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NanoUIDemos", "samples\NanoUIDemos\NanoUIDemos.csproj", "{33CED804-2C8B-4E40-9B38-98E513572D8B}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NanoUI", "source\NanoUI.csproj", "{5430BD17-1224-4E66-8A3F-FC15556CC869}"
11 | EndProject
12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VeldridExample", "samples\VeldridExample\VeldridExample.csproj", "{FF71A6C9-56DB-4263-E789-D6FF34659985}"
13 | EndProject
14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoGameExample", "samples\MonoGameExample\MonoGameExample.csproj", "{D171D21B-9B60-2DEC-8329-7A3671366BA8}"
15 | EndProject
16 | Global
17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
18 | Debug|Any CPU = Debug|Any CPU
19 | Release|Any CPU = Release|Any CPU
20 | EndGlobalSection
21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
22 | {33CED804-2C8B-4E40-9B38-98E513572D8B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23 | {33CED804-2C8B-4E40-9B38-98E513572D8B}.Debug|Any CPU.Build.0 = Debug|Any CPU
24 | {33CED804-2C8B-4E40-9B38-98E513572D8B}.Release|Any CPU.ActiveCfg = Release|Any CPU
25 | {33CED804-2C8B-4E40-9B38-98E513572D8B}.Release|Any CPU.Build.0 = Release|Any CPU
26 | {5430BD17-1224-4E66-8A3F-FC15556CC869}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {5430BD17-1224-4E66-8A3F-FC15556CC869}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {5430BD17-1224-4E66-8A3F-FC15556CC869}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {5430BD17-1224-4E66-8A3F-FC15556CC869}.Release|Any CPU.Build.0 = Release|Any CPU
30 | {FF71A6C9-56DB-4263-E789-D6FF34659985}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
31 | {FF71A6C9-56DB-4263-E789-D6FF34659985}.Debug|Any CPU.Build.0 = Debug|Any CPU
32 | {FF71A6C9-56DB-4263-E789-D6FF34659985}.Release|Any CPU.ActiveCfg = Release|Any CPU
33 | {FF71A6C9-56DB-4263-E789-D6FF34659985}.Release|Any CPU.Build.0 = Release|Any CPU
34 | {D171D21B-9B60-2DEC-8329-7A3671366BA8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
35 | {D171D21B-9B60-2DEC-8329-7A3671366BA8}.Debug|Any CPU.Build.0 = Debug|Any CPU
36 | {D171D21B-9B60-2DEC-8329-7A3671366BA8}.Release|Any CPU.ActiveCfg = Release|Any CPU
37 | {D171D21B-9B60-2DEC-8329-7A3671366BA8}.Release|Any CPU.Build.0 = Release|Any CPU
38 | EndGlobalSection
39 | GlobalSection(SolutionProperties) = preSolution
40 | HideSolutionNode = FALSE
41 | EndGlobalSection
42 | GlobalSection(NestedProjects) = preSolution
43 | {33CED804-2C8B-4E40-9B38-98E513572D8B} = {E94958C3-5109-4384-A9CB-E165EC5754CE}
44 | {FF71A6C9-56DB-4263-E789-D6FF34659985} = {E94958C3-5109-4384-A9CB-E165EC5754CE}
45 | {D171D21B-9B60-2DEC-8329-7A3671366BA8} = {E94958C3-5109-4384-A9CB-E165EC5754CE}
46 | EndGlobalSection
47 | GlobalSection(ExtensibilityGlobals) = postSolution
48 | SolutionGuid = {08FE0BD8-4253-419D-9FBF-7F9671C9AAC2}
49 | EndGlobalSection
50 | EndGlobal
51 |
--------------------------------------------------------------------------------
/docs/BASICCONCEPTS.md:
--------------------------------------------------------------------------------
1 | This document is a brief introduction to the basic concepts of the NanoUI. You can find in the code, how the things described here are implemented.
2 |
3 |
4 | # Drawing Layer
5 |
6 | This is the real engine in the NanoUI. It handles all commands passed to it and creates valid draw commands. When you are going to render the ui, you just loop through draw commands that are created and get vertices, indices and uniforms, that you send to your graphics engine.
7 |
8 | Functions in drawing layer are mostly internal and you should consider it as a black box.
9 |
10 | You issue commands to the drawing layer through its API, that is in **NvgContext** class.
11 |
12 |
13 | # UI layer
14 |
15 | UI layer is the extendable part of the NanoUI. It basically consist widgets, that are arranged in tree.
16 |
17 | ### UIWidget
18 | **UIWidget** is the base class in UI layer. It provides most common properties and functions. All other widgets are derived from this component.
19 | When you extend/override functionality in this class, you probably should also call same function in the base class, since there is often functionality that needs to be executed to keep UI layer consistent.
20 |
21 | ### WidgetList
22 | **WidgetList** is a special class, that holds all (parent) widget's childs. There are some helper methods to interact with this list, but the most important part is the order of child widgets in this list:
23 |
24 | - when NanoUI tries to find which child widget should handle user input (mouse, keyboard events etc), it loops the list **backwards** (from the last to the first)
25 | - in drawing phase the looping is done **forwards** (from the first to the last). This ensures that you can have any kind of transparency with overlapping widgets.
26 |
27 | **WidgetList** is a property in **UIWidget** class, so every widget can act as a container or layer.
28 |
29 | ### UIWindow
30 | **UIWindow** is the only widget that provides the opportunity to reposition and resize widget with mouse dragging.
31 |
32 | ### UIScreen
33 | **UIScreen** is the root widget in the widget tree. It is itself also derived from the **UIWidget**, but its main purpose is to orchestrate all the widgets in the widget tree. When you want to send user input events to NanoUI, you send the event to the **UIScreen** and it passes it to the correct widget.
34 |
35 | # Layouting
36 |
37 | NanoUI uses relative positioning system and uses top-left coordinate as position "anchor". This means that every widget knows only their position in their parent's space. So for example position (0, 0) means that widget is positioned in the top-left corner of its parent space.
38 |
39 | Layouts are defined in separate classes and can be dynamically changed at the runtime. When you attach specific layout class to the widget, you must also call either **PerformLayout** or **RequestLayoutUpdate** in order to really process layout calculations and set child widgets' positions & sizes.
40 |
41 | # Theming / styling
42 |
43 | NanoUI uses dynamic styling. The **UITheme** class, that consists all styling information is only stored in the **UIScreen**. When widget wants to use its styling property, it must ask that from the **UIScreen's** theme.
44 |
45 | However you can "hard code" styling information also directly to any individual widget.
46 |
--------------------------------------------------------------------------------
/docs/screenshots/SCREENSHOTS.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | 
4 |
5 | 
6 |
7 | 
8 |
9 | 
10 |
11 | 
12 |
13 | 
14 |
15 | 
16 |
17 | 
18 |
--------------------------------------------------------------------------------
/docs/screenshots/docking.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/docs/screenshots/docking.png
--------------------------------------------------------------------------------
/docs/screenshots/drawing.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/docs/screenshots/drawing.png
--------------------------------------------------------------------------------
/docs/screenshots/sdf_shapes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/docs/screenshots/sdf_shapes.png
--------------------------------------------------------------------------------
/docs/screenshots/sdf_text.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/docs/screenshots/sdf_text.png
--------------------------------------------------------------------------------
/docs/screenshots/text_shapes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/docs/screenshots/text_shapes.png
--------------------------------------------------------------------------------
/docs/screenshots/ui_basic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/docs/screenshots/ui_basic.png
--------------------------------------------------------------------------------
/docs/screenshots/ui_experimental.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/docs/screenshots/ui_experimental.png
--------------------------------------------------------------------------------
/docs/screenshots/ui_extended.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/docs/screenshots/ui_extended.png
--------------------------------------------------------------------------------
/docs/screenshots/ui_extended2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/docs/screenshots/ui_extended2.png
--------------------------------------------------------------------------------
/docs/screenshots/ui_layouts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/docs/screenshots/ui_layouts.png
--------------------------------------------------------------------------------
/licenses/NanoGUI.LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2019 Wenzel Jakob , All rights reserved.
2 |
3 | Redistribution and use in source and binary forms, with or without
4 | modification, are permitted provided that the following conditions are met:
5 |
6 | 1. Redistributions of source code must retain the above copyright notice, this
7 | list of conditions and the following disclaimer.
8 |
9 | 2. Redistributions in binary form must reproduce the above copyright notice,
10 | this list of conditions and the following disclaimer in the documentation
11 | and/or other materials provided with the distribution.
12 |
13 | 3. Neither the name of the copyright holder nor the names of its contributors
14 | may be used to endorse or promote products derived from this software
15 | without specific prior written permission.
16 |
17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
21 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 |
28 | You are under no obligation whatsoever to provide any bug fixes, patches, or
29 | upgrades to the features, functionality or performance of the source code
30 | ("Enhancements") to anyone; however, if you choose to make your Enhancements
31 | available either publicly, or directly to the author of this software, without
32 | imposing a separate written license agreement for such Enhancements, then you
33 | hereby grant the following license: a non-exclusive, royalty-free perpetual
34 | license to install, use, modify, prepare derivative works, incorporate into
35 | other computer software, distribute, and sublicense such enhancements or
36 | derivative works thereof, in binary and source code form.
37 |
--------------------------------------------------------------------------------
/licenses/NanoUI.LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2025 Klaus Bergius
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 |
--------------------------------------------------------------------------------
/licenses/NanoVG.LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013 Mikko Mononen memon@inside.org
2 |
3 | This software is provided 'as-is', without any express or implied
4 | warranty. In no event will the authors be held liable for any damages
5 | arising from the use of this software.
6 |
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it
9 | freely, subject to the following restrictions:
10 |
11 | 1. The origin of this software must not be misrepresented; you must not
12 | claim that you wrote the original software. If you use this software
13 | in a product, an acknowledgment in the product documentation would be
14 | appreciated but is not required.
15 | 2. Altered source versions must be plainly marked as such, and must not be
16 | misrepresented as being the original software.
17 | 3. This notice may not be removed or altered from any source distribution.
18 |
19 |
--------------------------------------------------------------------------------
/licenses/README.md:
--------------------------------------------------------------------------------
1 | **NanoUI** is MIT licensed.
2 |
3 | **NanoUI** consists modified ports from the [NanoVG](https://github.com/memononen/nanovg) library (**Zlib** license).
4 |
5 | Additionally **NanoUI's** UI layer is more or less inspired by [NanoGUI](https://github.com/wjakob/nanogui) (**BSD style** license).
6 |
7 | Also **NanoUI** consists a port of the [StbTrueType](https://github.com/nothings/stb) (**Public Domain** license).
8 |
9 | ---
10 |
11 | All these licenses are permissive, free, open-source and commercial-friendly software licenses.
12 |
--------------------------------------------------------------------------------
/samples/FNAExample/ConvertUtils.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Xna.Framework;
2 | using System.Runtime.CompilerServices;
3 |
4 | namespace FNAExample
5 | {
6 | internal static class ConvertUtils
7 | {
8 | public static Vector2 ToFna(this System.Numerics.Vector2 v)
9 | {
10 | return Unsafe.As(ref v);
11 | }
12 |
13 | public static Vector4 ToFna(this System.Numerics.Vector4 v)
14 | {
15 | return Unsafe.As(ref v);
16 | }
17 |
18 | public static Matrix ToFna(this System.Numerics.Matrix4x4 m)
19 | {
20 | return Unsafe.As(ref m);
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/samples/FNAExample/FNAExample.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net8.0
6 | disable
7 | enable
8 | True
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/samples/FNAExample/Program.cs:
--------------------------------------------------------------------------------
1 | namespace FNAExample
2 | {
3 | internal class Program
4 | {
5 | static void Main(string[] args)
6 | {
7 | using (var game = new NanoUIGame())
8 | {
9 | game.Run();
10 | }
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/samples/FNAExample/README.md:
--------------------------------------------------------------------------------
1 | FNA example doesn't run out-of-box, since FNA doesn't provide official NuGet. You have to setup it first.
2 |
3 | **Note:** I had to add NPE hack in the beginning of the **SDL3_FNAPlatform.PollEvents** method
4 |
5 | ```cs
6 | if(textInputControlDown == null)
7 | {
8 | textInputControlDown = new bool[7];
9 | }
10 | ```
11 |
12 | There could be better solution.
13 |
--------------------------------------------------------------------------------
/samples/FNAExample/Resources/Effect.fx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/FNAExample/Resources/Effect.fx
--------------------------------------------------------------------------------
/samples/FNAExample/Resources/Effect.fxb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/FNAExample/Resources/Effect.fxb
--------------------------------------------------------------------------------
/samples/FNAExample/Resources/Macros.fxh:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------
2 | // Macros.fxh
3 | //
4 | // Microsoft XNA Community Game Platform
5 | // Copyright (C) Microsoft Corporation. All rights reserved.
6 | //-----------------------------------------------------------------------------
7 |
8 | #ifdef SM4
9 |
10 | // Macros for targetting shader model 4.0 (DX11)
11 |
12 | #define TECHNIQUE(name, vsname, psname ) \
13 | technique name { pass { VertexShader = compile vs_4_0_level_9_1 vsname (); PixelShader = compile ps_4_0_level_9_1 psname(); } }
14 |
15 | #define BEGIN_CONSTANTS cbuffer Parameters : register(b0) {
16 | #define MATRIX_CONSTANTS
17 | #define END_CONSTANTS };
18 |
19 | #define _vs(r)
20 | #define _ps(r)
21 | #define _cb(r)
22 |
23 | #define DECLARE_TEXTURE(Name, index) \
24 | Texture2D Name : register(t##index); \
25 | sampler Name##Sampler : register(s##index)
26 |
27 | #define DECLARE_CUBEMAP(Name, index) \
28 | TextureCube Name : register(t##index); \
29 | sampler Name##Sampler : register(s##index)
30 |
31 | #define SAMPLE_TEXTURE(Name, texCoord) Name.Sample(Name##Sampler, texCoord)
32 | #define SAMPLE_CUBEMAP(Name, texCoord) Name.Sample(Name##Sampler, texCoord)
33 |
34 |
35 | #else
36 |
37 |
38 | // Macros for targetting shader model 2.0 (DX9)
39 |
40 | #define TECHNIQUE(name, vsname, psname ) \
41 | technique name { pass { VertexShader = compile vs_2_0 vsname (); PixelShader = compile ps_2_0 psname(); } }
42 |
43 | #define BEGIN_CONSTANTS
44 | #define MATRIX_CONSTANTS
45 | #define END_CONSTANTS
46 |
47 | #define _vs(r) : register(vs, r)
48 | #define _ps(r) : register(ps, r)
49 | #define _cb(r)
50 |
51 | #define DECLARE_TEXTURE(Name, index) \
52 | texture2D Name; \
53 | sampler Name##Sampler : register(s##index) = sampler_state { Texture = (Name); };
54 |
55 | #define DECLARE_CUBEMAP(Name, index) \
56 | textureCUBE Name; \
57 | sampler Name##Sampler : register(s##index) = sampler_state { Texture = (Name); };
58 |
59 | #define SAMPLE_TEXTURE(Name, texCoord) tex2D(Name##Sampler, texCoord)
60 | #define SAMPLE_CUBEMAP(Name, texCoord) texCUBE(Name##Sampler, texCoord)
61 |
62 | #endif
63 |
--------------------------------------------------------------------------------
/samples/MonoGameExample/MonoGameExample.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net8.0
6 | disable
7 | enable
8 | True
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/samples/MonoGameExample/Program.cs:
--------------------------------------------------------------------------------
1 | namespace MonoGameExample
2 | {
3 | public class Program
4 | {
5 | static void Main(string[] args)
6 | {
7 | using (var game = new NanoUIGame())
8 | {
9 | game.Run();
10 | }
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/samples/MonoGameExample/Resources/Effect.dx11.mgfxo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/MonoGameExample/Resources/Effect.dx11.mgfxo
--------------------------------------------------------------------------------
/samples/MonoGameExample/Resources/Effect.fx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/MonoGameExample/Resources/Effect.fx
--------------------------------------------------------------------------------
/samples/MonoGameExample/Resources/Effect.ogl.mgfxo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/MonoGameExample/Resources/Effect.ogl.mgfxo
--------------------------------------------------------------------------------
/samples/MonoGameExample/Resources/Macros.fxh:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------
2 | // Macros.fxh
3 | //
4 | // Microsoft XNA Community Game Platform
5 | // Copyright (C) Microsoft Corporation. All rights reserved.
6 | //-----------------------------------------------------------------------------
7 |
8 | #ifdef SM4
9 |
10 | // Macros for targetting shader model 4.0 (DX11)
11 |
12 | #define TECHNIQUE(name, vsname, psname ) \
13 | technique name { pass { VertexShader = compile vs_4_0_level_9_1 vsname (); PixelShader = compile ps_4_0_level_9_1 psname(); } }
14 |
15 | #define BEGIN_CONSTANTS cbuffer Parameters : register(b0) {
16 | #define MATRIX_CONSTANTS
17 | #define END_CONSTANTS };
18 |
19 | #define _vs(r)
20 | #define _ps(r)
21 | #define _cb(r)
22 |
23 | #define DECLARE_TEXTURE(Name, index) \
24 | Texture2D Name : register(t##index); \
25 | sampler Name##Sampler : register(s##index)
26 |
27 | #define DECLARE_CUBEMAP(Name, index) \
28 | TextureCube Name : register(t##index); \
29 | sampler Name##Sampler : register(s##index)
30 |
31 | #define SAMPLE_TEXTURE(Name, texCoord) Name.Sample(Name##Sampler, texCoord)
32 | #define SAMPLE_CUBEMAP(Name, texCoord) Name.Sample(Name##Sampler, texCoord)
33 |
34 |
35 | #else
36 |
37 |
38 | // Macros for targetting shader model 2.0 (DX9)
39 |
40 | #define TECHNIQUE(name, vsname, psname ) \
41 | technique name { pass { VertexShader = compile vs_2_0 vsname (); PixelShader = compile ps_2_0 psname(); } }
42 |
43 | #define BEGIN_CONSTANTS
44 | #define MATRIX_CONSTANTS
45 | #define END_CONSTANTS
46 |
47 | #define _vs(r) : register(vs, r)
48 | #define _ps(r) : register(ps, r)
49 | #define _cb(r)
50 |
51 | #define DECLARE_TEXTURE(Name, index) \
52 | texture2D Name; \
53 | sampler Name##Sampler : register(s##index) = sampler_state { Texture = (Name); };
54 |
55 | #define DECLARE_CUBEMAP(Name, index) \
56 | textureCUBE Name; \
57 | sampler Name##Sampler : register(s##index) = sampler_state { Texture = (Name); };
58 |
59 | #define SAMPLE_TEXTURE(Name, texCoord) tex2D(Name##Sampler, texCoord)
60 | #define SAMPLE_CUBEMAP(Name, texCoord) texCUBE(Name##Sampler, texCoord)
61 |
62 | #endif
63 |
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Assets/fonts/Inconsolata-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/NanoUIDemos/Assets/fonts/Inconsolata-Regular.ttf
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Assets/fonts/NotoSansTC-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/NanoUIDemos/Assets/fonts/NotoSansTC-Regular.ttf
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Assets/fonts/Roboto-Black.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/NanoUIDemos/Assets/fonts/Roboto-Black.ttf
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Assets/fonts/Roboto-BlackItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/NanoUIDemos/Assets/fonts/Roboto-BlackItalic.ttf
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Assets/fonts/Roboto-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/NanoUIDemos/Assets/fonts/Roboto-Bold.ttf
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Assets/fonts/Roboto-BoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/NanoUIDemos/Assets/fonts/Roboto-BoldItalic.ttf
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Assets/fonts/Roboto-Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/NanoUIDemos/Assets/fonts/Roboto-Italic.ttf
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Assets/fonts/Roboto-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/NanoUIDemos/Assets/fonts/Roboto-Light.ttf
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Assets/fonts/Roboto-LightItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/NanoUIDemos/Assets/fonts/Roboto-LightItalic.ttf
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Assets/fonts/Roboto-Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/NanoUIDemos/Assets/fonts/Roboto-Medium.ttf
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Assets/fonts/Roboto-MediumItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/NanoUIDemos/Assets/fonts/Roboto-MediumItalic.ttf
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Assets/fonts/Roboto-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/NanoUIDemos/Assets/fonts/Roboto-Regular.ttf
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Assets/fonts/Roboto-Thin.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/NanoUIDemos/Assets/fonts/Roboto-Thin.ttf
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Assets/fonts/Roboto-ThinItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/NanoUIDemos/Assets/fonts/Roboto-ThinItalic.ttf
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Assets/fonts/fa-brands-400.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/NanoUIDemos/Assets/fonts/fa-brands-400.ttf
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Assets/fonts/fa-regular-400.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/NanoUIDemos/Assets/fonts/fa-regular-400.ttf
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Assets/fonts/fa-solid-900.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/NanoUIDemos/Assets/fonts/fa-solid-900.ttf
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Assets/images/image0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/NanoUIDemos/Assets/images/image0.png
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Assets/images/image1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/NanoUIDemos/Assets/images/image1.png
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Assets/images/image10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/NanoUIDemos/Assets/images/image10.png
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Assets/images/image11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/NanoUIDemos/Assets/images/image11.png
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Assets/images/image2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/NanoUIDemos/Assets/images/image2.png
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Assets/images/image3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/NanoUIDemos/Assets/images/image3.png
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Assets/images/image4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/NanoUIDemos/Assets/images/image4.png
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Assets/images/image5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/NanoUIDemos/Assets/images/image5.png
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Assets/images/image6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/NanoUIDemos/Assets/images/image6.png
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Assets/images/image7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/NanoUIDemos/Assets/images/image7.png
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Assets/images/image8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/NanoUIDemos/Assets/images/image8.png
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Assets/images/image9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/NanoUIDemos/Assets/images/image9.png
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Assets/landscape.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/NanoUIDemos/Assets/landscape.png
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Assets/shaders/NanoUI.frag.glsl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/NanoUIDemos/Assets/shaders/NanoUI.frag.glsl
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Assets/shaders/NanoUI.frag.hlsl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/NanoUIDemos/Assets/shaders/NanoUI.frag.hlsl
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Assets/shaders/NanoUI.vert.glsl:
--------------------------------------------------------------------------------
1 | #version 450
2 |
3 | layout(location = 0) in vec2 vertex;
4 | layout(location = 1) in vec2 tcoord;
5 |
6 | layout(set = 0, binding = 0) uniform TransformBuffer
7 | {
8 | mat4 transformMat;
9 | };
10 |
11 | layout(location = 0) out vec2 fpos;
12 | layout(location = 1) out vec2 ftcoord;
13 |
14 | void main()
15 | {
16 | ftcoord = tcoord;
17 | fpos = vertex;
18 |
19 | gl_Position = transformMat * vec4(vertex, 0, 1);
20 | }
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Assets/shaders/NanoUI.vert.hlsl:
--------------------------------------------------------------------------------
1 | cbuffer UniformBlock : register(b0, space1)
2 | {
3 | float4x4 MatrixTransform : packoffset(c0);
4 | };
5 |
6 | struct Input
7 | {
8 | float2 Position : POSITION;
9 | float2 UV : TEXCOORD0;
10 | };
11 |
12 | struct Output
13 | {
14 | float4 Position : SV_Position; // vertex position
15 | float2 Ftcoord : TEXCOORD0; // float 2 tex coord
16 | float2 Fpos : TEXCOORD1; // float 2 position
17 | };
18 |
19 | Output main(Input input)
20 | {
21 | Output output;
22 | output.Position = mul(MatrixTransform, float4(input.Position, 0, 1.0f));
23 | output.Ftcoord = input.UV;
24 | output.Fpos = input.Position;
25 |
26 | return output;
27 | }
28 |
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Assets/svg/decoration.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Assets/svg/text.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
34 |
--------------------------------------------------------------------------------
/samples/NanoUIDemos/DemoAssets.cs:
--------------------------------------------------------------------------------
1 | using NanoUI;
2 | using NanoUIDemos.Experimental;
3 | using NanoUI.Nvg;
4 | using NanoUI.Styles;
5 |
6 | namespace NanoUIDemos
7 | {
8 | // Note: images are in PNG format (maximum portability).
9 | internal static class DemoAssets
10 | {
11 | public const string FontNormal = "./Assets/fonts/Roboto-Regular.ttf";
12 | public const string FontBold = "./Assets/fonts/Roboto-Bold.ttf";
13 | public const string FontIcons = "./Assets/fonts/fa-solid-900.ttf";
14 |
15 | static int[] _textures = new int[12];
16 |
17 | public static int[] Textures => _textures;
18 |
19 | static int _testTexture;
20 |
21 | public static int TestTexture => _testTexture;
22 |
23 | public static void InitTestTextures(NvgContext ctx)
24 | {
25 | for (uint i = 0; i < 12; i++)
26 | {
27 | string file = "./Assets/images/image" + i + ".png";
28 | _textures[i] = ctx.CreateTexture(file);
29 |
30 | if (_textures[i] < 0)
31 | {
32 | Console.Error.WriteLine("Could not load " + file);
33 | Environment.Exit(-1);
34 | }
35 | }
36 |
37 | // test image
38 | string file2 = "./Assets/landscape.png";
39 | _testTexture = ctx.CreateTexture(file2);
40 | }
41 |
42 | public static UITheme GetTheme(NvgContext ctx)
43 | {
44 | // init fonts
45 | FontsStyle fonts = new FontsStyle()
46 | {
47 | DefaultFontType = "Normal",
48 | DefaultIconsType = "Icons",
49 | };
50 |
51 | fonts.FontTypes.Add("Normal", FontNormal);
52 | fonts.FontTypes.Add("Bold", FontBold);
53 | fonts.FontTypes.Add("Icons", FontIcons);
54 |
55 | // create default theme
56 | ThemeEXT theme = UITheme.CreateDefault(ctx, fonts);
57 | theme.Save("DefaultTheme.json");
58 |
59 | // create
60 | ThemeEXT? loadTheme = UITheme.Load(ctx, "DefaultTheme.json");
61 |
62 | if(loadTheme != null)
63 | {
64 | loadTheme.PopulateExt();
65 |
66 | // this is just for testing
67 | InitTestTextures(ctx);
68 |
69 | return loadTheme;
70 | }
71 |
72 | // this is just for testing
73 | InitTestTextures(ctx);
74 |
75 | return theme;
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/samples/NanoUIDemos/DemoFactory.cs:
--------------------------------------------------------------------------------
1 | using NanoUI;
2 | using NanoUI.Common;
3 | using NanoUIDemos.Drawing;
4 | using NanoUI.Nvg;
5 | using NanoUIDemos.UI;
6 | using System.Numerics;
7 |
8 | namespace NanoUIDemos
9 | {
10 | public enum DemoType
11 | {
12 | Docking,
13 | Drawing,
14 | SDFText,
15 | SvgShapes,
16 | TextShapes,
17 | UIBasic,
18 | UIExtended,
19 | UIExtended2,
20 | UIExperimental,
21 | UILayouts
22 | }
23 |
24 | public static class DemoFactory
25 | {
26 | public static DemoBase CreateDemo(NvgContext ctx, DemoType demoType, Vector2 windoSize)
27 | {
28 | if(demoType == DemoType.Drawing)
29 | {
30 | // no screen
31 | return new DrawingDemo(ctx, windoSize);
32 | }
33 | else if (demoType == DemoType.TextShapes)
34 | {
35 | // no screen
36 | return new TextShapesDemo(ctx, windoSize);
37 | }
38 | else if (demoType == DemoType.SDFText)
39 | {
40 | // no screen
41 | return new SDFTextDemo(ctx, windoSize);
42 | }
43 | else if (demoType == DemoType.SvgShapes)
44 | {
45 | // no screen
46 | return new SvgDemo(ctx, windoSize);
47 | }
48 |
49 | // get default theme
50 | var theme = DemoAssets.GetTheme(ctx);
51 |
52 | // create screen
53 | var screen = new UIScreen(theme, windoSize);
54 | screen.BackgroundFocused = screen.BackgroundUnfocused = new SolidBrush(new Color(0.3f, 0.3f, 0.32f, 1.0f));
55 |
56 | switch (demoType)
57 | {
58 | case DemoType.Docking:
59 | return new UIDockingDemo(screen);
60 | case DemoType.UIExperimental:
61 | return new UIExperimentalDemo(screen);
62 | case DemoType.UIExtended:
63 | return new UIExtendedDemo(screen, ctx);
64 | case DemoType.UIExtended2:
65 | return new UIExtended2Demo(screen);
66 | case DemoType.UILayouts:
67 | return new UILayoutDemo(screen);
68 | default:
69 | return new UIBasicDemo(screen);
70 | }
71 | }
72 | }
73 | }
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Drawing/SvgDemo.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Nvg;
2 | using System.Numerics;
3 |
4 | namespace NanoUIDemos.Drawing
5 | {
6 | public class SvgDemo : DemoBase
7 | {
8 | // note: these are needed for performance stats
9 | public static int _fontNormal, _fontBold;
10 |
11 | private readonly NvgContext _ctx;
12 | Vector2 _windoSize;
13 |
14 | static int _svgShape;
15 | static int _svgTextShape;
16 |
17 | public SvgDemo(NvgContext ctx, Vector2 windowSize)
18 | :base(null)
19 | {
20 | _ctx = ctx;
21 | _windoSize = windowSize;
22 |
23 | // note: there is no theme - so we manually load fonts
24 | _fontNormal = _ctx.CreateFont("normal", DemoAssets.FontNormal);
25 | if (_fontNormal == -1)
26 | {
27 | Console.Error.WriteLine("Could not add font regular.");
28 | Environment.Exit(-1);
29 | }
30 | _fontBold = _ctx.CreateFont("bold", DemoAssets.FontBold);
31 | if (_fontBold == -1)
32 | {
33 | Console.Error.WriteLine("Could not add font bold.");
34 | Environment.Exit(-1);
35 | }
36 |
37 | // init test textures
38 | //DemoAssets.InitTestTextures(_ctx);
39 |
40 | // Create svg
41 | string path = "./Assets/svg/tiger.svg";
42 | //path = "./Assets/svg/testBasic.svg";
43 |
44 | _svgShape = ctx.CreateSvg(path);
45 |
46 | _svgTextShape = ctx.CreateSvg("./Assets/svg/text.svg");
47 | }
48 |
49 | #region Inputs
50 |
51 | public override bool OnPointerMove(Vector2 pointerPos, Vector2 rel)
52 | {
53 | return false;
54 | }
55 |
56 | #endregion
57 |
58 | float _deltaSeconds;
59 | float t;
60 | public override void Update(float deltaSeconds)
61 | {
62 | _deltaSeconds = deltaSeconds;
63 | t += deltaSeconds;
64 | }
65 |
66 | public override void ScreenResize(Vector2 size, NvgContext ctx)
67 | {
68 | _windoSize = size;
69 | }
70 |
71 | float scale = 0.5f;
72 | float sign = 1;
73 | public override void Draw(NvgContext ctx)
74 | {
75 | if(_svgShape >= 0)
76 | {
77 | if (scale > 2.5f)
78 | {
79 | sign = -1;
80 | }
81 | else if (scale < 0.5f)
82 | {
83 | sign = 1;
84 | }
85 |
86 | scale += sign * _deltaSeconds * 0.5f;
87 |
88 | ctx.SaveState();
89 |
90 | ctx.Scale(scale);
91 | //ctx.Skew(float.DegreesToRadians(30), 0);
92 | //ctx.Translate(new Vector2(_windoSize.X * 0.3f, 100));
93 | //ctx.Rotate(t, new Vector2(_windoSize.X * 0.3f));
94 |
95 | _ctx.DrawSvg(_svgShape);
96 | _ctx.DrawSvg(_svgTextShape);
97 |
98 | ctx.RestoreState();
99 | }
100 | }
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Experimental/Components/Editors/BoolEditor.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Components;
2 | using NanoUI.Nvg;
3 | using System.Reflection;
4 |
5 | namespace NanoUIDemos.Experimental.Components.Editors
6 | {
7 | // todo: if we want to have BoolEditor configurable, we should not inherit from widget &
8 | // have CheckBox as child
9 | public class BoolEditor : UICheckBox, IPropertyEditor
10 | {
11 | Func? _getValue;
12 | Action? _setValue;
13 | PropertyInfo? _propertyInfo;
14 |
15 | bool _currentValue;
16 |
17 | public BoolEditor(UIWidget parent)
18 | : base(parent, string.Empty)
19 | {
20 | // todo : in CheckBox
21 | IconExtraScale = 0.8f;
22 | }
23 |
24 | public void InitEditor(
25 | PropertyInfo propertyInfo,
26 | Func getValue,
27 | Action setValue)
28 | {
29 | _getValue = getValue;
30 | _setValue = setValue;
31 | _propertyInfo = propertyInfo;
32 |
33 | CheckedChanged += (val) =>
34 | {
35 | _currentValue = val;
36 |
37 | setValue?.Invoke(propertyInfo, val);
38 | };
39 | }
40 |
41 | public override void Draw(NvgContext ctx)
42 | {
43 | // if used as combined field, func & property info are null
44 | if (_getValue != null && _propertyInfo != null)
45 | {
46 | SetValue(_getValue.Invoke(_propertyInfo));
47 | }
48 |
49 | base.Draw(ctx);
50 | }
51 |
52 | // call from Draw
53 | void SetValue(object? value)
54 | {
55 | if (value == null)
56 | return;
57 |
58 | // parse
59 | if (bool.TryParse(value.ToString(), out bool val))
60 | {
61 | if (_currentValue == val)
62 | return;
63 |
64 | _currentValue = val;
65 |
66 | Checked = val;
67 | }
68 | }
69 |
70 | // we use prorotype editor when creating new editor
71 | public IPropertyEditor Clone(UIWidget parent)
72 | {
73 | return new BoolEditor(parent);
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Experimental/Components/Editors/EnumEditor.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Components;
2 | using NanoUI.Nvg;
3 | using System.Reflection;
4 |
5 | namespace NanoUIDemos.Experimental.Components.Editors
6 | {
7 | public class EnumEditor : UIEnumDropDown, IPropertyEditor
8 | where TEnum :struct, Enum
9 | {
10 | Func? _getValue;
11 | Action? _setValue;
12 | PropertyInfo? _propertyInfo;
13 |
14 | TEnum _currentValue = default;
15 |
16 | public EnumEditor(UIWidget parent)
17 | : base(parent)
18 | {
19 |
20 | }
21 |
22 | public void InitEditor(
23 | PropertyInfo propertyInfo,
24 | Func getValue,
25 | Action setValue)
26 | {
27 | _getValue = getValue;
28 | _setValue = setValue;
29 | _propertyInfo = propertyInfo;
30 |
31 | SelectedChanged += (val) =>
32 | {
33 | _currentValue = val;
34 | setValue?.Invoke(propertyInfo, val);
35 | };
36 | }
37 |
38 | public override void Draw(NvgContext ctx)
39 | {
40 | // if used as combined field, func & property info are null
41 | if (_getValue != null && _propertyInfo != null)
42 | {
43 | SetValue(_getValue.Invoke(_propertyInfo));
44 | }
45 |
46 | base.Draw(ctx);
47 | }
48 |
49 | // call from Draw
50 | void SetValue(object? value)
51 | {
52 | if (value == null)
53 | return;
54 |
55 | TEnum val = (TEnum)value;
56 |
57 | if (_currentValue.Equals(val))
58 | return;
59 |
60 | _currentValue = val;
61 |
62 | SetSelected(val);
63 | }
64 |
65 | // we use prorotype editor when creating new editor
66 | public IPropertyEditor Clone(UIWidget parent)
67 | {
68 | return new EnumEditor(parent);
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Experimental/Components/Editors/IPropertyEditor.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Components;
2 | using System.Reflection;
3 |
4 | namespace NanoUIDemos.Experimental.Components.Editors
5 | {
6 | public interface IPropertyEditor
7 | {
8 | // we set id so user can search for spesific editor in propertygrid
9 | // id is set to
10 | string? Name { get; internal set; }
11 |
12 | void InitEditor(PropertyInfo propertyInfo,
13 | Func getValue,
14 | Action setValue);
15 |
16 | // we use prorotype editor when creating new editor (no need to Activator.CreateInstance)
17 | // parent is set to category content panel
18 | IPropertyEditor Clone(UIWidget parent);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Experimental/Components/Editors/StringEditor.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Components;
2 | using NanoUI.Nvg;
3 | using System.Reflection;
4 |
5 | namespace NanoUIDemos.Experimental.Components.Editors
6 | {
7 | // todo: if we want to have StringEditor configurable, we should not inherit from widget &
8 | // have TextBox as child
9 | public class StringEditor : UITextField, IPropertyEditor
10 | {
11 | Func? _getValue;
12 | Action? _setValue;
13 | PropertyInfo? _propertyInfo;
14 |
15 | string _currentValue = string.Empty;
16 |
17 | public StringEditor(UIWidget parent)
18 | : base(parent)
19 | {
20 | Editable = true;
21 | }
22 |
23 | public void InitEditor(
24 | PropertyInfo propertyInfo,
25 | Func getValue,
26 | Action setValue)
27 | {
28 | _getValue = getValue;
29 | _setValue = setValue;
30 | _propertyInfo = propertyInfo;
31 |
32 | // wrap change
33 | TextChanged += (val) =>
34 | {
35 | _currentValue = val;
36 | setValue?.Invoke(propertyInfo, val);
37 | };
38 | }
39 |
40 | public override void Draw(NvgContext ctx)
41 | {
42 | // if used as combined field, func & property info are null
43 | if (_getValue != null && _propertyInfo != null)
44 | {
45 | SetValue(_getValue.Invoke(_propertyInfo));
46 | }
47 |
48 | base.Draw(ctx);
49 | }
50 |
51 | // call from Draw
52 | void SetValue(object? value)
53 | {
54 | if (value == null)
55 | return;
56 |
57 | string? str = value.ToString();
58 |
59 | if (str == null || _currentValue == str)
60 | return;
61 |
62 | _currentValue = str;
63 |
64 | Text = str;
65 | }
66 |
67 | // we use prorotype editor when creating new editor
68 | public IPropertyEditor Clone(UIWidget parent)
69 | {
70 | return new StringEditor(parent);
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Experimental/Components/Editors/StructEditor.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 | using NanoUI.Components;
3 | using System;
4 | using System.Numerics;
5 | using System.Reflection;
6 |
7 | namespace NanoUIDemos.Experimental.Components.Editors
8 | {
9 | // TODO : Handle structs by creating new category in propertygrid & looping properties
10 | /*public class StructEditor : Widget, IPropertyEditor
11 | {
12 | public StructEditor()
13 | : base(null)
14 | {
15 | GridLayout layout =
16 | new GridLayout(Orientation.Horizontal, 2,
17 | LayoutAlignment.Maximum, 0, 5);
18 |
19 | // set columns (label, widget)
20 | //layout.SetColAlignment(new LayoutAlignment[] { LayoutAlignment.Maximum, LayoutAlignment.Fill });
21 | layout.SetColAlignment(new LayoutAlignment[] { LayoutAlignment.Minimum, LayoutAlignment.Fill });
22 | // SETS TO ALIGN TOP
23 | layout.SetRowAlignment(LayoutAlignment.Minimum);
24 |
25 | layout.SetSpacing(0, 10);
26 | Layout = layout;
27 | }
28 |
29 | //public void SetValue(PropertyInfo propertyInfo, object? obj)
30 | public void SetValue(PropertyInfo propertyInfo, object? value, Action action)
31 |
32 | {
33 | if (value == null)
34 | return;
35 |
36 |
37 | }
38 |
39 | public override void Draw(NvgContext ctx)
40 | {
41 | base.Draw(ctx);
42 | }
43 | }*/
44 | }
45 |
--------------------------------------------------------------------------------
/samples/NanoUIDemos/Experimental/Components/UIPropertyGridCategoryPanel.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Components;
2 | using NanoUIDemos.Experimental.Components.Editors;
3 | using NanoUI.Nvg;
4 | using System.Numerics;
5 |
6 | namespace NanoUIDemos.Experimental.Components
7 | {
8 | public class UIPropertyGridCategoryPanel : UICollapsablePanel
9 | {
10 | // Parent is UIPropertyGridPanel
11 | // We must get labels with there
12 | UIPropertyGridPanel _propertyGridPanel;
13 |
14 | public UIPropertyGridCategoryPanel(UIPropertyGridPanel widget)
15 | : base(widget)
16 | {
17 | _propertyGridPanel = widget;
18 | }
19 |
20 | #region Events
21 |
22 | public override void OnCollapseChanged(bool collapsed)
23 | {
24 | Content.Visible = !collapsed;
25 |
26 | // This should be because we must find vscroll
27 | if (Parent != null && Parent.Parent != null)
28 | {
29 | RequestLayoutUpdate(Parent.Parent);
30 | }
31 | else
32 | {
33 | RequestLayoutUpdate(Parent);
34 | }
35 | }
36 |
37 | #endregion
38 |
39 | #region Layout
40 |
41 | public override void PerformLayout(NvgContext ctx)
42 | {
43 | // set fixed width so we can calculate editors widths
44 | if(Parent != null)
45 | FixedSize = new Vector2(Parent.Size.X, 0);
46 |
47 | // set editor widths
48 | foreach (var child in Content.Children.AsReadOnlySpan())
49 | {
50 | if (child is IPropertyEditor)
51 | {
52 | child.FixedSize = new Vector2(GetEditorWidth(), 0);
53 | }
54 | }
55 |
56 | base.PerformLayout(ctx);
57 | }
58 |
59 | int GetEditorWidth()
60 | {
61 | // todo: magical numbers
62 | return (int)(FixedSize.X - _propertyGridPanel.LabelsWidth - 20);
63 | }
64 |
65 | #endregion
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/samples/README.md:
--------------------------------------------------------------------------------
1 | **Note:** You can view other demos changing **_demoType** in:
2 |
3 | * **Program.cs** (VeldridExample)
4 | * **NanoUIGame.cs** (MonoGameExample & FNAExample)
5 |
--------------------------------------------------------------------------------
/samples/VeldridExample/README.md:
--------------------------------------------------------------------------------
1 | This example uses several external libraries:
2 |
3 | - [Silk.NET](https://github.com/dotnet/Silk.NET)
4 | - [Veldrid](https://github.com/veldrid/veldrid)
5 | - [StbImageSharp](https://github.com/StbSharp/StbImageSharp)
6 |
7 | See licences from the external sites.
8 |
--------------------------------------------------------------------------------
/samples/VeldridExample/Shaders/shader.frag:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kbergius/NanoUI/ee700f8af4140ba4cfd8a271da005be57d4eb389/samples/VeldridExample/Shaders/shader.frag
--------------------------------------------------------------------------------
/samples/VeldridExample/Shaders/shader.vert:
--------------------------------------------------------------------------------
1 | #version 450
2 |
3 | layout(location = 0) in vec2 vertex;
4 | layout(location = 1) in vec2 tcoord;
5 |
6 | layout(set = 0, binding = 0) uniform TransformBuffer
7 | {
8 | mat4 transformMat;
9 | };
10 |
11 | layout(location = 0) out vec2 fpos;
12 | layout(location = 1) out vec2 ftcoord;
13 |
14 | void main()
15 | {
16 | ftcoord = tcoord;
17 | fpos = vertex;
18 |
19 | gl_Position = transformMat * vec4(vertex, 0, 1);
20 | }
--------------------------------------------------------------------------------
/samples/VeldridExample/VeldridExample.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | VeldridExample
6 | disable
7 | VeldridExample
8 | net8.0
9 | True
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | Never
20 |
21 |
22 | Never
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/source/Common/Category.cs:
--------------------------------------------------------------------------------
1 | namespace NanoUI.Common
2 | {
3 | ///
4 | /// Used in property grid to combine properties to categories
5 | ///
6 | public struct Category
7 | {
8 | ///
9 | /// Category id.
10 | ///
11 | public string Id;
12 |
13 | ///
14 | /// DisplayText.
15 | ///
16 | public string DisplayText;
17 |
18 | ///
19 | /// SortKey. Used in sorting.
20 | ///
21 | public int SortKey;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/source/Common/ColumnDefinition.cs:
--------------------------------------------------------------------------------
1 | namespace NanoUI.Common
2 | {
3 | // todo: alignments
4 |
5 | ///
6 | /// ColumnDefinition.
7 | ///
8 | public struct ColumnDefinition
9 | {
10 | ///
11 | /// Width.
12 | ///
13 | public int Width { get; set; }
14 |
15 | ///
16 | /// Stretch.
17 | ///
18 | public bool Stretch { get; set; }
19 |
20 | ///
21 | /// Ctor,
22 | ///
23 | /// Width
24 | /// Stretch
25 | public ColumnDefinition(int width, bool stretch = false)
26 | {
27 | Width = width;
28 | Stretch = stretch;
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/source/Common/CornerRadius.cs:
--------------------------------------------------------------------------------
1 | namespace NanoUI.Common
2 | {
3 | ///
4 | /// CornerRadius.
5 | ///
6 | public struct CornerRadius
7 | {
8 | ///
9 | /// TopLeft.
10 | ///
11 | public float TopLeft { get; set; }
12 |
13 | ///
14 | /// TopRight.
15 | ///
16 | public float TopRight { get; set; }
17 |
18 | ///
19 | /// BottomLeft.
20 | ///
21 | public float BottomLeft { get; set; }
22 |
23 | ///
24 | /// BottomRight.
25 | ///
26 | public float BottomRight { get; set; }
27 |
28 | ///
29 | /// Ctor.
30 | ///
31 | /// Rounding all corners
32 | public CornerRadius(float rounding)
33 | {
34 | TopLeft = TopRight = BottomLeft = BottomRight = rounding;
35 | }
36 |
37 | ///
38 | /// Ctor.
39 | ///
40 | /// TopLeft
41 | /// TopRight
42 | /// BottomLeft
43 | /// BottomRight
44 | public CornerRadius(float topLeft, float topRight, float bottomLeft, float bottomRight)
45 | {
46 | TopLeft = topLeft;
47 | TopRight = topRight;
48 | BottomLeft = bottomLeft;
49 | BottomRight = bottomRight;
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/source/Common/GlyphPosition.cs:
--------------------------------------------------------------------------------
1 | namespace NanoUI.Common
2 | {
3 | ///
4 | /// GlyphPosition.
5 | ///
6 | public struct GlyphPosition
7 | {
8 | ///
9 | /// Index of glyph in passed text
10 | ///
11 | public int Index;
12 |
13 | ///
14 | /// The X-coordinate of the logical glyph position
15 | ///
16 | public float X;
17 |
18 | ///
19 | /// The smallest X-bound of the glyph shape
20 | ///
21 | public float MinX;
22 |
23 | ///
24 | /// The largest X-bound of the glyph shape
25 | ///
26 | public float MaxX;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/source/Common/GlyphShapeCommand.cs:
--------------------------------------------------------------------------------
1 | using System.Numerics;
2 |
3 | namespace NanoUI.Common
4 | {
5 | ///
6 | /// GlyphShapeCommand is used when glyphs are rendered with shapes.
7 | ///
8 | public struct GlyphShapeCommand
9 | {
10 | // note: in drawText converts this to NvgPathCommand
11 | // note2:
12 | // - MoveTo uses P0
13 | // - LineTo uses P0
14 | // - BezierTo uses P0 & P1 & P2 (P0 & P1 are control points, P2 is end point)
15 | // - QuadTo uses P0 as control point, P1 as endpoint
16 | // note3: this is nearly identical to NvgPathCommand, but we don't use it since it is internal
17 |
18 | ///
19 | /// GlyphShapeCommandType
20 | ///
21 | public GlyphShapeCommandType CommandType;
22 |
23 | ///
24 | /// Position0
25 | ///
26 | public Vector2 P0;
27 |
28 | ///
29 | /// Position1
30 | ///
31 | public Vector2 P1;
32 |
33 | ///
34 | /// Position2
35 | ///
36 | public Vector2 P2;
37 |
38 | ///
39 | /// Winding
40 | ///
41 | public Winding Winding;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/source/Common/MinMax.cs:
--------------------------------------------------------------------------------
1 | namespace NanoUI.Common
2 | {
3 | // todo : check Min < Max
4 |
5 | ///
6 | /// MinMax.
7 | ///
8 | public struct MinMax
9 | {
10 | ///
11 | /// Min
12 | ///
13 | public float Min { get; set; }
14 |
15 | ///
16 | /// Max
17 | ///
18 | public float Max { get; set; }
19 |
20 | ///
21 | /// Ctor.
22 | ///
23 | public MinMax() { }
24 |
25 | ///
26 | /// Ctor.
27 | ///
28 | /// Min
29 | /// Max
30 | public MinMax(float min, float max)
31 | {
32 | Min = min;
33 | Max = max;
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/source/Common/Shortcut.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 |
3 | namespace NanoUI.Common
4 | {
5 | ///
6 | /// Shortcut for menus.
7 | ///
8 | public struct Shortcut
9 | {
10 | ///
11 | /// Key. Default Key.Unknown.
12 | ///
13 | public Key Key;
14 |
15 | ///
16 | /// KeyModifiers. Default KeyModifiers.None.
17 | ///
18 | public KeyModifiers Modifiers;
19 |
20 | ///
21 | /// Ctor.
22 | ///
23 | /// Key
24 | public Shortcut(Key key)
25 | {
26 | Key = key;
27 | }
28 |
29 | ///
30 | /// Ctor.
31 | ///
32 | /// Key
33 | /// Key modifiers
34 | public Shortcut(Key key, KeyModifiers modifiers)
35 | {
36 | Key = key;
37 | Modifiers = modifiers;
38 | }
39 |
40 | ///
41 | /// Checks if Key + KeyModifiers match shortcut.
42 | ///
43 | /// Key
44 | /// Key modifiers
45 | /// Success
46 | public bool Match(Key key, KeyModifiers modifiers)
47 | {
48 | return key == Key && Modifiers == modifiers;
49 | }
50 |
51 | public override string ToString()
52 | {
53 | // not set
54 | if (Key == Key.Unknown)
55 | return string.Empty;
56 |
57 | StringBuilder sb = new StringBuilder();
58 |
59 | // control
60 | if ((Modifiers & KeyModifiers.Control) != 0)
61 | {
62 | sb.Append("Ctrl+");
63 | }
64 |
65 | // alt
66 | if ((Modifiers & KeyModifiers.Alt) != 0)
67 | {
68 | sb.Append("Alt+");
69 | }
70 |
71 | // shift
72 | if ((Modifiers & KeyModifiers.Shift) != 0)
73 | {
74 | sb.Append("Shift+");
75 | }
76 |
77 | // key
78 | sb.Append(Key.ToString());
79 |
80 | return sb.ToString();
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/source/Common/TextRow.cs:
--------------------------------------------------------------------------------
1 | namespace NanoUI.Common
2 | {
3 | ///
4 | /// TextRow.
5 | ///
6 | public struct TextRow
7 | {
8 | ///
9 | /// Row start in passed text
10 | ///
11 | public int StartPos;
12 |
13 | ///
14 | /// Text length in row
15 | ///
16 | public int TextLength;
17 |
18 | ///
19 | /// Logical width of the row
20 | ///
21 | public float Width;
22 |
23 | ///
24 | /// Actual least X-bound of the row. Logical with and bounds can differ
25 | /// because of kerning and some parts over extending
26 | ///
27 | public float MinX;
28 |
29 | ///
30 | /// Actual largest X-bound of the row. Logical with and bounds can differ
31 | /// because of kerning and some parts over extending.
32 | ///
33 | public float MaxX;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/source/Common/TextureDesc.cs:
--------------------------------------------------------------------------------
1 | namespace NanoUI.Common
2 | {
3 | ///
4 | /// Texture description is passed to renderer when creating textures.
5 | ///
6 | public struct TextureDesc
7 | {
8 | ///
9 | /// Width.
10 | ///
11 | public uint Width;
12 |
13 | ///
14 | /// Height.
15 | ///
16 | public uint Height;
17 |
18 | ///
19 | /// TextureFormat should be mapped to graphic engine's pixel format.
20 | ///
21 | public TextureFormat Format;
22 |
23 | ///
24 | /// TextureFlags. Optional flags to pass.
25 | ///
26 | public TextureFlags TextureFlags;
27 |
28 | ///
29 | /// Creates TextureDesc.
30 | ///
31 | /// Width
32 | /// Height
33 | /// TextureFormat
34 | /// TextureFlags
35 | public TextureDesc(uint width, uint height, TextureFormat format = TextureFormat.RGBA, TextureFlags flags = 0)
36 | {
37 | Width = width;
38 | Height = height;
39 | Format = format;
40 | TextureFlags = flags;
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/source/Common/Thickness.cs:
--------------------------------------------------------------------------------
1 | namespace NanoUI.Common
2 | {
3 | // note: this could be a Vector2, but for possible future use could be extended
4 | // (separate left/right & top/bottom values)
5 |
6 | ///
7 | /// Thickness is used as layouting hints (margins, paddings etc).
8 | ///
9 | public struct Thickness
10 | {
11 | ///
12 | /// Horizontal.
13 | ///
14 | public float Horizontal { get; set; }
15 |
16 | ///
17 | /// Vertical.
18 | ///
19 | public float Vertical { get; set; }
20 |
21 | ///
22 | /// Creates.
23 | ///
24 | /// Horizontal & vertical value
25 | public Thickness(float val)
26 | {
27 | Horizontal = Vertical = val;
28 | }
29 |
30 | ///
31 | /// Creates.
32 | ///
33 | /// Horizontal
34 | /// Vertical
35 | public Thickness(float horizontal, float vertical)
36 | {
37 | Horizontal = horizontal;
38 | Vertical = vertical;
39 | }
40 |
41 | ///
42 | /// Gets value by index
43 | ///
44 | /// Index
45 | /// Value
46 | public float this[int index]
47 | {
48 | get => index == 1? Vertical : Horizontal;
49 | set
50 | {
51 | if(index == 1)
52 | Vertical = value;
53 | else
54 | Horizontal = value;
55 | }
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/source/Components/Bars/UIMenubar.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 | using NanoUI.Nvg;
3 |
4 | namespace NanoUI.Components.Bars
5 | {
6 | // note: this doesn't pass OnKeyChar event to children, because widget needs to be in focuspath
7 |
8 | ///
9 | /// UIMenubar is only widget, that can receive OnKeyUpDown event while not in UIScreen's focus path.
10 | ///
11 | ///
12 | /// To get this OnKeyUpDown event parent of this (screen or window) must be in focus path (screen is allways).
13 | /// The main use case is to pass keyboard shortcuts to menu items.
14 | /// This means also that you can have multiple windows with menubars, but only the active/focused
15 | /// window gets event and passes it to this widget.
16 | ///
17 | public class UIMenubar : UIWidgetbar
18 | {
19 | ///
20 | public UIMenubar() { }
21 |
22 | ///
23 | public UIMenubar(UIWidget parent)
24 | : base(parent)
25 | {
26 | DisablePointerFocus = true;
27 | }
28 |
29 | #region Events
30 |
31 | ///
32 | public override bool OnKeyUpDown(Key key, bool down, KeyModifiers modifiers)
33 | {
34 | foreach (var child in Children.AsReadOnlySpan())
35 | {
36 | if (!child.Visible || child.Disabled)
37 | continue;
38 |
39 | if (child.OnKeyUpDown(key, down, modifiers))
40 | {
41 | return true;
42 | }
43 | }
44 |
45 | return base.OnKeyUpDown(key, down, modifiers);
46 | }
47 |
48 | #endregion
49 |
50 | #region Drawing
51 |
52 | ///
53 | public override void Draw(NvgContext ctx)
54 | {
55 | DrawBackgroundBrush(ctx);
56 |
57 | base.Draw(ctx);
58 |
59 | this.DrawBorder(ctx, false);
60 | }
61 |
62 | #endregion
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/source/Components/Bars/UIToolbar.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Nvg;
2 |
3 | namespace NanoUI.Components.Bars
4 | {
5 | ///
6 | /// UIToolbar.
7 | ///
8 | public class UIToolbar : UIWidgetbar
9 | {
10 | ///
11 | public UIToolbar() { }
12 |
13 | ///
14 | public UIToolbar(UIWidget parent)
15 | : base(parent)
16 | {
17 | DisablePointerFocus = true;
18 | }
19 |
20 | #region Drawing
21 |
22 | ///
23 | public override void Draw(NvgContext ctx)
24 | {
25 | DrawBackgroundBrush(ctx);
26 |
27 | base.Draw(ctx);
28 |
29 | this.DrawBorder(ctx, false);
30 | }
31 |
32 | #endregion
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/source/Components/Bars/UIWidgetbar.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 | using NanoUI.Layouts;
3 | using NanoUI.Nvg;
4 | using System.Numerics;
5 |
6 | namespace NanoUI.Components.Bars
7 | {
8 | // todo: statusbar (needs positioning info: top / bottom)
9 | // todo2: if also Scrollbar extends this, there should be also "right" (needs to refactor scrollbar logic!)
10 |
11 | ///
12 | /// UIWidgetbar is an abstract bar component, that provides some common functionalty.
13 | /// It could be used for example in UIWindow with other specified bars (menubar, toolbar, etc).
14 | ///
15 | ///
16 | /// Parent should do the positioning, since it knows what bars there exist.
17 | ///
18 | public abstract class UIWidgetbar : UIWidget
19 | {
20 | ///
21 | public UIWidgetbar()
22 | {
23 |
24 | }
25 |
26 | ///
27 | public UIWidgetbar(UIWidget parent)
28 | :base(parent)
29 | {
30 | // todo: configurable?
31 | ChildrenLayout = new StackLayout(Orientation.Horizontal, LayoutAlignment.Middle);
32 | ChildrenLayout.Spacing = new Vector2 (5, 0);
33 |
34 | ThemeType = GetType();
35 | }
36 |
37 | #region Layout
38 |
39 | ///
40 | public override void PerformLayout(NvgContext ctx)
41 | {
42 | base.PerformLayout(ctx);
43 |
44 | // stretch
45 | if(Parent != null)
46 | Size = new Vector2(Parent.Size.X, Size.Y);
47 | }
48 |
49 | #endregion
50 |
51 | #region Events
52 |
53 | ///
54 | public override void OnScreenResize(Vector2 size, NvgContext ctx)
55 | {
56 | // note: this should be unnecessary, since other parents should not call this function
57 | if(Parent is not UIScreen screen)
58 | return;
59 |
60 | Size = new Vector2(size.X, Size.Y);
61 |
62 | PerformLayout(ctx);
63 | }
64 |
65 | #endregion
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/source/Components/Buttons/UIToolButton.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 | using NanoUI.Nvg;
3 | using System.Numerics;
4 |
5 | namespace NanoUI.Components.Buttons
6 | {
7 | ///
8 | /// UIToolButton can be combined with button flags RadioButton & ToggleButton.
9 | ///
10 | /// There is no text by default.
11 | public class UIToolButton : UIButton
12 | {
13 | ///
14 | public UIToolButton()
15 | {
16 | // set defaults to theme impl - prevents circular reference
17 | Dimension = default;
18 | Flags = default;
19 |
20 | // no text!
21 | }
22 |
23 | ///
24 | public UIToolButton(UIWidget parent)
25 | : this(parent, -1)
26 | {
27 | }
28 |
29 | ///
30 | public UIToolButton(UIWidget parent, int icon)
31 | : base(parent, string.Empty, icon)
32 | {
33 | // no text!
34 | ThemeType = typeof(UIButton);
35 | }
36 |
37 | #region Properties
38 |
39 | uint? _dimension;
40 |
41 | ///
42 | /// Dimension
43 | ///
44 | public uint Dimension
45 | {
46 | get => _dimension?? GetTheme().ToolButton.Dimension;
47 | set => _dimension = value;
48 | }
49 |
50 | ButtonFlags? _flags;
51 |
52 | ///
53 | public override ButtonFlags Flags
54 | {
55 | get => _flags?? GetTheme().ToolButton.Flags;
56 | set => _flags = value;
57 | }
58 |
59 | #endregion
60 |
61 | #region Layout
62 |
63 | ///
64 | public override Vector2 PreferredSize(NvgContext ctx)
65 | {
66 | return Vector2.Max(MinSize, new Vector2(Dimension));
67 | }
68 |
69 | #endregion
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/source/Components/Dialogs/UIDialog.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 | using NanoUI.Nvg;
3 | using System.ComponentModel;
4 |
5 | namespace NanoUI.Components.Dialogs
6 | {
7 | ///
8 | /// UIDialog is a base class, that is registered & stored in UIScreen.
9 | /// Use Screen.GetDialog.
10 | ///
11 | public class UIDialog : UIWindow
12 | {
13 | ///
14 | /// Caller is used to set focus back to caller widget when dialog closes.
15 | ///
16 | protected UIWidget? _caller;
17 |
18 | ///
19 | public UIDialog()
20 | {
21 | // set defaults to theme impl - prevents circular reference
22 | _buttonPanelMargin = new();
23 | }
24 |
25 | ///
26 | protected UIDialog(UIScreen screen)
27 | : base(screen, string.Empty, ScrollbarType.NONE)
28 | {
29 | // init in screen creation, create titlebar with empty string
30 |
31 | Visible = false;
32 | Modal = true;
33 | //TitleAlign = TextHorizontalAlign.Center;
34 |
35 | ThemeType = typeof(UIDialog);
36 | }
37 |
38 | #region Properties
39 |
40 | Thickness? _buttonPanelMargin;
41 |
42 | ///
43 | /// ButtonPanelMargin.
44 | ///
45 | [Category(Globals.CATEGORY_LAYOUT)]
46 | public Thickness ButtonPanelMargin
47 | {
48 | get => _buttonPanelMargin?? GetTheme().Dialog.ButtonPanelMargin;
49 | set => _buttonPanelMargin = value;
50 | }
51 |
52 | #endregion
53 |
54 | #region Methods
55 |
56 | ///
57 | /// ReInit.
58 | ///
59 | protected void ReInit(NvgContext ctx)
60 | {
61 | // center
62 | Center();
63 |
64 | PerformLayout(ctx);
65 | RequestFocus();
66 | }
67 |
68 | ///
69 | /// Reset.
70 | /// Note: we use normally same dialog instances, that are stored in UIScreen.
71 | /// When you get dialog from screen, screen calls Reset(), so you can have clean state.
72 | ///
73 | public virtual void Reset()
74 | {
75 |
76 | }
77 |
78 | ///
79 | public override void Close()
80 | {
81 | // note: we override base since it disposes widget
82 |
83 | if (_caller != null)
84 | {
85 | _caller.RequestFocus();
86 | }
87 | else
88 | {
89 | // todo: get window!
90 | Screen?.RequestFocus();
91 | }
92 |
93 | Visible = false;
94 | }
95 |
96 | #endregion
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/source/Components/Docking/DockArea.cs:
--------------------------------------------------------------------------------
1 | namespace NanoUI.Components.Docking
2 | {
3 | ///
4 | /// DockArea. Values (int) are used as array indexes.
5 | ///
6 | public enum DockArea : int
7 | {
8 | Left = 0,
9 | Right = 1,
10 | Top = 2,
11 | Bottom = 3,
12 | Center = 4,
13 | NONE = -1
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/source/Components/Docking/DockHit.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 | using NanoUI.Nvg;
3 | using System.Numerics;
4 |
5 | namespace NanoUI.Components.Docking
6 | {
7 | ///
8 | /// DockHit.
9 | ///
10 | public struct DockHit
11 | {
12 | ///
13 | /// Hit areas (used also to check hit).
14 | ///
15 | public Rect Area;
16 |
17 | ///
18 | /// Hit areas' fills - visual clue where docking is happening.
19 | ///
20 | public Rect Fill;
21 |
22 | ///
23 | /// Overlay areas - visual clue where docking is happening.
24 | ///
25 | public Rect Overlay;
26 |
27 | ///
28 | /// Contains
29 | ///
30 | /// Position
31 | /// Success
32 | public bool Contains(Vector2 position) => Area.Contains(position);
33 |
34 | ///
35 | /// Draws hit area.
36 | ///
37 | /// NvgContext
38 | /// Corner radius
39 | /// Background color
40 | /// Brush
41 | public void DrawHitArea(NvgContext ctx, float cornerRadius, Color backgroundColor, BrushBase brush)
42 | {
43 | if (Area.Size == Vector2.Zero)
44 | return;
45 |
46 | // background
47 | ctx.BeginPath();
48 | ctx.RoundedRect(Area, cornerRadius);
49 | ctx.FillColor(backgroundColor);
50 | ctx.Fill();
51 |
52 | // fill
53 | if (Fill.Size != Vector2.Zero)
54 | {
55 | brush?.Draw(ctx,
56 | Fill.Position, Fill.Size, null);
57 | }
58 |
59 | // we draw border last since it overwrites background & fill
60 | ctx.BeginPath();
61 | ctx.RoundedRect(Area, cornerRadius);
62 | ctx.StrokeWidth(1);
63 | ctx.StrokeColor(Color.Black);
64 | ctx.Stroke();
65 | }
66 |
67 | ///
68 | /// Draws overlay.
69 | ///
70 | /// NvgContext
71 | /// Color
72 | public void DrawOverlay(NvgContext ctx, Color color)
73 | {
74 | ctx.BeginPath();
75 | ctx.Rect(Overlay);
76 | ctx.FillColor(color);
77 | ctx.Fill();
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/source/Components/Docking/DockTabWidget.cs:
--------------------------------------------------------------------------------
1 | namespace NanoUI.Components.Docking
2 | {
3 | // todo: we could have here also some spesific methods (remove from DockNode)
4 |
5 | ///
6 | /// DockTabWidget is an extension of normal tabwidget.
7 | /// So you can have different styling for dock tabs & normal tabwidget.
8 | ///
9 | public class DockTabWidget : UITabWidget
10 | {
11 | ///
12 | public DockTabWidget()
13 | : base()
14 | {
15 |
16 | }
17 |
18 | ///
19 | public DockTabWidget(DockNode parent)
20 | : base(parent)
21 | {
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/source/Components/Docking/DockTitlebar.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 | using NanoUI.Components.Bars;
3 | using System.Numerics;
4 |
5 | namespace NanoUI.Components.Docking
6 | {
7 | // todo: there should be easy mechanics to set title etc (probably context menu)
8 |
9 | ///
10 | /// DockTitlebar supports only dock nodes.
11 | ///
12 | public class DockTitlebar : UITitlebar
13 | {
14 | ///
15 | public DockTitlebar() { }
16 |
17 | // todo: dock node name
18 |
19 | ///
20 | public DockTitlebar(DockNode parent)
21 | :base(parent, "DockNode")
22 | {
23 | // todo: in properties
24 | BackgroundFocused = GetTheme().Docks.TitleBackgroundFocused;
25 | BackgroundUnfocused = GetTheme().Docks.TitleBackgroundUnfocused;
26 |
27 | string? fontType = GetTheme().Docks.TitleFontType;
28 | if (fontType != null)
29 | {
30 | FontType = fontType;
31 | }
32 |
33 | FontSize = GetTheme().Docks.TitleFontSize;
34 | ButtonSize = GetTheme().Docks.TitleButtonSize;
35 | }
36 |
37 | #region Events
38 |
39 | ///
40 | public override bool OnPointerUpDown(Vector2 p, PointerButton button, bool down)
41 | {
42 | // check first if titlebar button handle event
43 | if(base.OnPointerUpDown(p, button, down))
44 | {
45 | return true;
46 | }
47 |
48 | // we handle - pointer on label
49 | // note: we don't need to "clear" drag widget since UIScreen does it automatically when pointer UP
50 | if (down)
51 | {
52 | Screen?.SetDragWidget(this);
53 | }
54 |
55 | return true;
56 | }
57 |
58 | ///
59 | public override bool OnPointerDrag(Vector2 p, Vector2 rel)
60 | {
61 | // check if this is dragged outside title area
62 |
63 | if (!Contains(p))
64 | {
65 | // remove drag widget, so we can start detach process
66 | Screen?.SetDragWidget(null);
67 |
68 | // signal parent dock node that it should be detached
69 | if (Parent != null && Parent.OnDetach(this))
70 | {
71 |
72 | }
73 |
74 | return true;
75 | }
76 |
77 | return false;
78 | }
79 |
80 | #endregion
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/source/Components/Files/FileFolderInfo.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 |
3 | namespace NanoUI.Components.Files
4 | {
5 | // todo: here could be logic to create display text
6 |
7 | ///
8 | /// FileFolderInfo.
9 | ///
10 | public struct FileFolderInfo
11 | {
12 | ///
13 | /// Path
14 | ///
15 | public string Path;
16 |
17 | ///
18 | /// FileFolderType
19 | ///
20 | public FileFolderType FileFolderType;
21 |
22 | ///
23 | /// Constructor.
24 | ///
25 | /// Path
26 | /// FileFolderType
27 | public FileFolderInfo(string path, FileFolderType fileFolderType)
28 | {
29 | Path = path;
30 | FileFolderType = fileFolderType;
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/source/Components/Menus/UIContextMenu.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 | using NanoUI.Layouts;
3 | using System;
4 |
5 | namespace NanoUI.Components.Menus
6 | {
7 | // todo: context menu holds menubuttons, but these can't have shortcuts(?)
8 |
9 | ///
10 | /// UIContextMenu.
11 | ///
12 | public class UIContextMenu : UIPopup
13 | {
14 | ///
15 | /// Handles clicks & shortcut matches. This is called from the child menu item buttons,
16 | /// if they have ItemId specified.
17 | ///
18 | public Action? MenuItemSelected;
19 |
20 | UIWidget? _owner;
21 |
22 | ///
23 | public UIContextMenu() { }
24 |
25 | ///
26 | public UIContextMenu(UIWidget owner)
27 | : base(owner.Screen)
28 | {
29 | _owner = owner;
30 | owner.ContextMenu = this;
31 |
32 | ChildrenLayout = new StackLayout(Orientation.Vertical, LayoutAlignment.Minimum);
33 | AnchorSize = 0;
34 |
35 | ThemeType = typeof(UIContextMenu);
36 | }
37 |
38 | #region Events
39 |
40 | ///
41 | /// This is called from menu items,
42 | /// when they are clicked or shortcut matches.
43 | ///
44 | public virtual void OnMenuItemSelected(int menuItemId)
45 | {
46 | // closes this
47 | _owner?.RequestFocus();
48 |
49 | MenuItemSelected?.Invoke(menuItemId);
50 | }
51 |
52 | ///
53 | public override bool OnFocusChanged(bool focused)
54 | {
55 | // todo: this could be in base Popup?
56 |
57 | if (!Disabled)
58 | {
59 | // set values
60 | Focused = focused;
61 | Visible = focused;
62 |
63 | if (!focused)
64 | {
65 | // close child popups
66 | RecursiveCloseChildPopups(this);
67 |
68 | // set focus to owner
69 | //_owner.RequestFocus();
70 | // lost focus => propagate to owner
71 | _owner?.FindParentWindow()?.OnFocusChanged(false);
72 | }
73 | else if(Screen != null)
74 | {
75 | // bring window to front
76 | _owner?.FindParentWindow()?.MoveToLast();
77 |
78 | Position = Screen.PointerPosition;
79 | RequestFocus();
80 |
81 | // keep owner window focused (this parent is screen)
82 | _owner?.FindParentWindow()?.OnFocusChanged(true);
83 | }
84 |
85 | return true;
86 | }
87 |
88 | return base.OnFocusChanged(focused);
89 | }
90 |
91 | #endregion
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/source/Components/Menus/UIMenuSeparator.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Components.Simple;
2 | using NanoUI.Nvg;
3 | using System.Numerics;
4 |
5 | namespace NanoUI.Components.Menus
6 | {
7 | ///
8 | /// UIMenuSeparator.
9 | ///
10 | public class UIMenuSeparator : UISeparator
11 | {
12 | ///
13 | public UIMenuSeparator(UIWidget parent)
14 | :base(parent)
15 | {
16 | Height = 1;
17 | FixedSize = new Vector2(0, Height);
18 | }
19 |
20 | #region Layout
21 |
22 | ///
23 | public override void PerformLayout(NvgContext ctx)
24 | {
25 | base.PerformLayout(ctx);
26 |
27 | // stretch with parent
28 | if (Parent != null)
29 | Size = new Vector2(Parent.Size.X, Size.Y);
30 | }
31 |
32 | #endregion
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/source/Components/Menus/UIMenuSubmenu.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 | using NanoUI.Nvg;
3 | using System.Numerics;
4 |
5 | namespace NanoUI.Components.Menus
6 | {
7 | ///
8 | /// UIMenuSubmenu.
9 | /// Note: functions/actions are inherited from UIMenu, but theme from UIMenuItem.
10 | ///
11 | public class UIMenuSubmenu : UIMenu
12 | {
13 | ///
14 | public UIMenuSubmenu()
15 | {
16 |
17 | }
18 |
19 | ///
20 | public UIMenuSubmenu(UIWidget parent, string caption)
21 | : base(parent, caption)
22 | {
23 | Border = false;
24 |
25 | // popup
26 | Popup.RelativePosition = PopupPosition.RightTop;
27 |
28 | ThemeType = typeof(UIMenuItem);
29 | }
30 |
31 | #region Properties
32 |
33 | Thickness? _padding;
34 |
35 | ///
36 | public override Thickness Padding
37 | {
38 | get => _padding ?? GetTheme().MenuItem.Padding;
39 | set => _padding = value;
40 | }
41 |
42 | #endregion
43 |
44 | #region Layout
45 |
46 | ///
47 | public override void PerformLayout(NvgContext ctx)
48 | {
49 | Icon = GetTheme().Fonts.IconCaretRight;
50 |
51 | base.PerformLayout(ctx);
52 |
53 | // check if this is really in context menu
54 | var parent = Parent;
55 |
56 | while (parent != null)
57 | {
58 | // we must check for popups first, because their parent is Screen
59 | if (parent is UIPopup popup)
60 | {
61 | var popupButton = popup.GetParentButton();
62 |
63 | // check nested
64 | if (popupButton is UIMenuSubmenu menuButton && menuButton != null)
65 | {
66 | // change calculation starting with popup button
67 | parent = menuButton;
68 | }
69 | else if (popup is UIContextMenu contextMenu)
70 | {
71 | // we found ultimate parent - set fixed width same as in context menu
72 | FixedSize = new Vector2(contextMenu.FixedSize.X, 0);
73 | break;
74 | }
75 | }
76 |
77 | parent = parent.Parent;
78 | }
79 |
80 | // stretch with parent
81 | if(Parent != null)
82 | Size = new Vector2(Parent.Size.X, Size.Y);
83 | }
84 |
85 | #endregion
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/source/Components/Scrolling/IScrollable.cs:
--------------------------------------------------------------------------------
1 | using System.Numerics;
2 |
3 | namespace NanoUI.Components.Scrolling
4 | {
5 | ///
6 | /// IScrollable.
7 | /// Note: UIWindow & UIScrollpanel could be scrolled & popup does need to if its UIPopupButton is scrolled.
8 | ///
9 | public interface IScrollable
10 | {
11 | ///
12 | /// Scroll offset is negative or Vectro2.Zero
13 | ///
14 | Vector2 ScrollOffset { get; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/source/Components/Simple/UIFileIcon.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 | using NanoUI.Components.Files;
3 | using NanoUI.Nvg;
4 |
5 | namespace NanoUI.Components.Simple
6 | {
7 | ///
8 | /// UIFileIcon.
9 | /// Note: supports dynamic theming. If dynamic theming is not needed,
10 | /// use UIIcon instead of UIFileIcon with fixed Icon & IconColor (better performance).
11 | ///
12 | public class UIFileIcon : UIIcon
13 | {
14 | public UIFileIcon(FileFolderInfo fileFolderInfo)
15 | {
16 | FileFolderInfo = fileFolderInfo;
17 | }
18 |
19 | ///
20 | public UIFileIcon(UIWidget parent)
21 | : base(parent)
22 | {
23 |
24 | }
25 |
26 | #region Properties
27 |
28 | ///
29 | /// FileFolderInfo
30 | ///
31 | public FileFolderInfo FileFolderInfo { get; set; }
32 |
33 | #endregion
34 |
35 | #region Drawing
36 |
37 | ///
38 | public override void Draw(NvgContext ctx)
39 | {
40 | // set icon & icon color
41 | (int Icon, Color IconColor) iconSpec = GetTheme().GetFileIcon(FileFolderInfo);
42 |
43 | Icon = iconSpec.Icon;
44 | IconColor = iconSpec.IconColor;
45 |
46 | base.Draw(ctx);
47 | }
48 |
49 | #endregion
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/source/Components/Simple/UIFileIconText.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 | using NanoUI.Components.Files;
3 | using NanoUI.Nvg;
4 |
5 | namespace NanoUI.Components.Simple
6 | {
7 | ///
8 | /// UIFileIconText.
9 | /// Note: supports dynamic theming. If dynamic theming is not needed,
10 | /// use UIIcon instead of UIFileIcon with fixed Icon & IconColor (better performance).
11 | ///
12 | public class UIFileIconText : UIIconText
13 | {
14 | public UIFileIconText(FileFolderInfo fileFolderInfo, string displayName)
15 | {
16 | FileFolderInfo = fileFolderInfo;
17 | Text = displayName;
18 | }
19 |
20 | ///
21 | public UIFileIconText(UIWidget parent)
22 | : base(parent)
23 | {
24 |
25 | }
26 |
27 | #region Properties
28 |
29 | ///
30 | /// FileFolderInfo
31 | ///
32 | public FileFolderInfo FileFolderInfo { get; set; }
33 |
34 | #endregion
35 |
36 | #region Drawing
37 |
38 | ///
39 | public override void Draw(NvgContext ctx)
40 | {
41 | // set icon & icon color
42 | (int Icon, Color IconColor) iconSpec = GetTheme().GetFileIcon(FileFolderInfo);
43 |
44 | Icon = iconSpec.Icon;
45 | IconColor = iconSpec.IconColor;
46 |
47 | base.Draw(ctx);
48 | }
49 |
50 | #endregion
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/source/Components/Simple/UIIcon.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 | using NanoUI.Nvg;
3 | using System.Numerics;
4 | using System.Text.Json.Serialization;
5 |
6 | namespace NanoUI.Components.Simple
7 | {
8 | ///
9 | /// UIIcon.
10 | ///
11 | public class UIIcon : UIWidget
12 | {
13 | ///
14 | public UIIcon()
15 | {
16 |
17 | }
18 |
19 | public UIIcon(int icon)
20 | {
21 | Icon = icon;
22 | }
23 |
24 | ///
25 | public UIIcon(UIWidget parent)
26 | : base(parent)
27 | {
28 |
29 | }
30 |
31 | #region Properties
32 |
33 | ///
34 | /// Icon. -1 means no icon.
35 | ///
36 | public virtual int Icon { get; set; }
37 |
38 | float? _iconSize;
39 |
40 | ///
41 | /// IconSize
42 | ///
43 | public float IconSize
44 | {
45 | get => _iconSize?? GetTheme().Widget.FontSize;
46 | set => _iconSize = value;
47 | }
48 |
49 | // todo: in base Widget
50 | int? _fontIconsId;
51 |
52 | ///
53 | [JsonIgnore]
54 | public override int FontIconsId
55 | {
56 | get =>_fontIconsId?? GetTheme().Fonts.GetFontId(GetTheme().Fonts.GetDefaultIconType());
57 | set => _fontIconsId = value;
58 | }
59 |
60 | TextAlignment? _alignment;
61 |
62 | ///
63 | /// Text alignment
64 | ///
65 | public TextAlignment Alignment
66 | {
67 | get => _alignment ?? TextAlignment.Left | TextAlignment.Middle;
68 | set => _alignment = value;
69 | }
70 |
71 | // todo: should this be in Widget?
72 | Color? _iconColor;
73 |
74 | ///
75 | /// Icon color
76 | ///
77 | public virtual Color IconColor
78 | {
79 | get => _iconColor?? GetTheme().Widget.TextColor;
80 | set => _iconColor = value;
81 | }
82 |
83 | #endregion
84 |
85 | #region Drawing
86 |
87 | ///
88 | public override void Draw(NvgContext ctx)
89 | {
90 | if (Icon <= 0)
91 | return;
92 |
93 | ctx.FontSize(IconSize);
94 | ctx.FontFaceId(FontIconsId);
95 |
96 | Vector2 center = Position + Size * 0.5f;
97 |
98 | ctx.FillColor(IconColor);
99 |
100 | ctx.TextAlign(Alignment);
101 |
102 | ctx.Text(Position.X, center.Y, Icon);
103 | }
104 |
105 | #endregion
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/source/Components/Simple/UIImage.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 | using NanoUI.Nvg;
3 | using System.Numerics;
4 |
5 | namespace NanoUI.Components.Simple
6 | {
7 | ///
8 | /// UIImage.
9 | ///
10 | public class UIImage : UIWidget
11 | {
12 | // calculated texture size
13 | Vector2 _imgSize;
14 |
15 | public UIImage(int texture)
16 | {
17 | Texture = texture;
18 | }
19 |
20 | ///
21 | public UIImage(UIWidget parent)
22 | : base(parent)
23 | {
24 |
25 | }
26 |
27 | #region Properties
28 |
29 | int _texture;
30 |
31 | ///
32 | /// Texture id.
33 | ///
34 | public int Texture
35 | {
36 | get => _texture;
37 | set
38 | {
39 | _texture = value;
40 |
41 | if(_texture > Globals.INVALID)
42 | {
43 | // calculate image size
44 | NvgContext.Instance.GetTextureSize(Texture, out _imgSize);
45 | }
46 | }
47 | }
48 |
49 | ///
50 | /// Tint color
51 | ///
52 | public Color TintColor { get; set; }
53 |
54 | #endregion
55 |
56 | #region Drawing
57 |
58 | // todo: does this handle case when width != height
59 |
60 | ///
61 | public override void Draw(NvgContext ctx)
62 | {
63 | if (Texture <= Globals.INVALID)
64 | return;
65 |
66 |
67 | // note: Y is calculated dynamically from thumb size & image real size
68 | // todo: these calculations could be in PerformLayout?
69 | // todo2: make confugurable MathF.Min(thumbSize, Size.X)?
70 | float thumbSize = Size.X;
71 |
72 | float iw, ih, ix, iy;
73 |
74 | if (_imgSize.X < _imgSize.Y)
75 | {
76 | iw = thumbSize;
77 | ih = iw * _imgSize.Y / _imgSize.X;
78 | ix = 0;
79 | iy = -(ih - thumbSize) * 0.5f;
80 | }
81 | else
82 | {
83 | ih = thumbSize;
84 | iw = ih * _imgSize.X / _imgSize.Y;
85 | ix = -(iw - thumbSize) * 0.5f;
86 | iy = 0;
87 | }
88 |
89 | // draw texture
90 | Paint imgPaint = Paint.ImagePattern(
91 | Position.X + ix, Position.Y + iy, iw, ih, 0, Texture, TintColor);
92 |
93 | ctx.BeginPath();
94 | ctx.Rect(Position.X, Position.Y, thumbSize, thumbSize);
95 | ctx.FillPaint(imgPaint);
96 | ctx.Fill();
97 | }
98 |
99 | #endregion
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/source/Components/Simple/UISeparator.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 | using NanoUI.Nvg;
3 | using System.Numerics;
4 |
5 | namespace NanoUI.Components.Simple
6 | {
7 | ///
8 | /// UISeparator.
9 | ///
10 | public class UISeparator : UIWidget
11 | {
12 | public UISeparator(int height)
13 | {
14 | Height = height;
15 | }
16 |
17 | ///
18 | public UISeparator(UIWidget parent)
19 | : base(parent)
20 | {
21 |
22 | }
23 |
24 | #region Properties
25 |
26 | // todo: also orientation vertical & Height => Dimension?
27 | float? _height;
28 |
29 | ///
30 | /// Height
31 | ///
32 | public override float Height
33 | {
34 | get => _height?? 1f;
35 | set => _height = value;
36 | }
37 |
38 | // todo: configurable?
39 |
40 | Color? _color;
41 |
42 | ///
43 | /// Color. If not set makes this dimmer(currently TextColor * 0.7f).
44 | ///
45 | public Color Color
46 | {
47 | get => _color?? GetTheme().Widget.TextColor * 0.7f;
48 | set => _color = value;
49 | }
50 |
51 | ///
52 | /// Padding is set in view panel - when drawing.
53 | ///
54 | internal int Padding { get; set; }
55 |
56 | #endregion
57 |
58 | #region Drawing
59 |
60 | ///
61 | public override void Draw(NvgContext ctx)
62 | {
63 | ctx.BeginPath();
64 | ctx.StrokeWidth(Height);
65 |
66 | ctx.StrokeColor(Color);
67 |
68 | // todo : use column padding or this Padding?
69 | var center = Position + new Vector2(Padding, Size.Y / 2);
70 |
71 | ctx.MoveTo(center);
72 | ctx.LineTo(center + new Vector2(Size.X - 2 * Padding, 0));
73 |
74 | ctx.Stroke();
75 | }
76 |
77 | #endregion
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/source/Components/Simple/UIShortcut.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 | using NanoUI.Nvg;
3 |
4 | namespace NanoUI.Components.Simple
5 | {
6 | ///
7 | /// UIShortcut.
8 | ///
9 | public class UIShortcut : UIWidget
10 | {
11 | ///
12 | public UIShortcut()
13 | {
14 |
15 | }
16 |
17 | public UIShortcut(Shortcut shortcut)
18 | : this()
19 | {
20 | Shortcut = shortcut;
21 | }
22 |
23 | ///
24 | public UIShortcut(UIWidget parent)
25 | : base(parent)
26 | {
27 |
28 | }
29 |
30 | #region Properties
31 |
32 | float? _fontSize;
33 |
34 | ///
35 | public override float FontSize
36 | {
37 | get => _fontSize ?? GetTheme().Widget.FontSize;
38 | set => _fontSize = value;
39 | }
40 |
41 | TextAlignment? _alignment;
42 |
43 | ///
44 | /// Text alignment
45 | ///
46 | public TextAlignment Alignment
47 | {
48 | get => _alignment ?? TextAlignment.Left | TextAlignment.Middle;
49 | set => _alignment = value;
50 | }
51 |
52 | Color? _color;
53 |
54 | ///
55 | /// Color
56 | ///
57 | public virtual Color Color
58 | {
59 | get => _color ?? GetTheme().Widget.TextColor;
60 | set => _color = value;
61 | }
62 |
63 | ///
64 | /// Shortcut
65 | ///
66 | public Shortcut? Shortcut { get; set; }
67 |
68 | #endregion
69 |
70 | #region Drawing
71 |
72 | ///
73 | public override void Draw(NvgContext ctx)
74 | {
75 | if (!Shortcut.HasValue)
76 | return;
77 |
78 | ctx.FontSize(FontSize);
79 | ctx.FontFaceId(FontFaceId);
80 |
81 | ctx.TextAlign(Alignment);
82 | ctx.FillColor(Color);
83 |
84 | // note: top left
85 | ctx.Text(Position.X, Position.Y + Size.Y * 0.5f, Shortcut.Value.ToString());
86 | }
87 |
88 | #endregion
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/source/Components/Simple/UIText.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 | using NanoUI.Nvg;
3 | using System.Numerics;
4 |
5 | namespace NanoUI.Components.Simple
6 | {
7 | // todo: remove this - use UIlabel
8 |
9 | ///
10 | /// UIText.
11 | ///
12 | public class UIText : UIWidget
13 | {
14 | ///
15 | public UIText()
16 | {
17 |
18 | }
19 |
20 | ///
21 | public UIText(string text)
22 | : this()
23 | {
24 | Text = text;
25 | }
26 |
27 | public UIText(UIWidget parent)
28 | : base(parent)
29 | {
30 |
31 | }
32 |
33 | #region Properties
34 |
35 | ///
36 | /// Text
37 | ///
38 | public string? Text { get; set; }
39 |
40 | float? _fontSize;
41 |
42 | ///
43 | public override float FontSize
44 | {
45 | get => _fontSize?? GetTheme().Widget.FontSize;
46 | set => _fontSize = value;
47 | }
48 |
49 | float? _charSpacing;
50 |
51 | ///
52 | /// Char spacing is additional spacing (default is 0).
53 | ///
54 | public float CharSpacing
55 | {
56 | get => _charSpacing?? 0;
57 | set => _charSpacing = value;
58 | }
59 |
60 | ///
61 | /// LineHeight is proportional line height (default is 1).
62 | ///
63 | float? _lineHeight;
64 | public float LineHeight
65 | {
66 | get => _lineHeight ?? 1;
67 | set => _lineHeight = value;
68 | }
69 |
70 | TextAlignment? _alignment;
71 |
72 | ///
73 | /// Text alignment
74 | ///
75 | public TextAlignment Alignment
76 | {
77 | get => _alignment?? TextAlignment.Left | TextAlignment.Middle;
78 | set => _alignment = value;
79 | }
80 |
81 | Color? _textColor;
82 |
83 | ///
84 | public override Color TextColor
85 | {
86 | get => _textColor?? GetTheme().Widget.TextColor;
87 | set => _textColor = value;
88 | }
89 |
90 | #endregion
91 |
92 | #region Drawing
93 |
94 | // todo : calculate correct alignment
95 |
96 | ///
97 | public override void Draw(NvgContext ctx)
98 | {
99 | if (string.IsNullOrEmpty(Text))
100 | return;
101 |
102 | // todo: alignment etc
103 | Vector2 textPos = Position + new Vector2(0, Size.Y * 0.5f);
104 |
105 | ctx.FontSize(FontSize);
106 | ctx.FontFaceId(FontFaceId);
107 | ctx.TextCharSpacing(CharSpacing);
108 | ctx.TextLineHeight(LineHeight);
109 |
110 | // todo: align correctly
111 | ctx.TextAlign(Alignment);
112 | ctx.FillColor(TextColor);
113 |
114 | // draw
115 | ctx.Text(textPos, Text);
116 | }
117 |
118 | #endregion
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/source/Components/UIComboBox.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 | using NanoUI.Components.Simple;
3 | using NanoUI.Components.Views;
4 | using NanoUI.Components.Views.Items;
5 | using NanoUI.Nvg;
6 | using System;
7 |
8 | namespace NanoUI.Components
9 | {
10 | ///
11 | /// UIComboBox is just simple combo box with only 1 column (item text).
12 | ///
13 | public class UIComboBox : UIDropDownView
14 | {
15 | // these are used to calculate combo box popup min width
16 | const int ITEM_SAFETY_MARGIN = 18;
17 |
18 | string _longestCaption = string.Empty;
19 |
20 | ///
21 | public UIComboBox(UIWidget parent)
22 | : base(parent)
23 | {
24 |
25 | }
26 |
27 | #region Methods
28 |
29 | ///
30 | /// AddItem
31 | ///
32 | /// Caption
33 | /// Data that is passed when selected
34 | ///
35 | public UIViewItemWidget AddItem(string caption, T eventData)
36 | {
37 | // get the longest caption so we can calculate min width of the display column / popup
38 | if(_longestCaption.Length < caption.Length)
39 | {
40 | _longestCaption = caption;
41 | }
42 |
43 | UIWidget[] cells =
44 | [
45 | new UIText { Text = caption },
46 | ];
47 |
48 | return Add(new RowItem(cells, eventData));
49 | }
50 |
51 | #endregion
52 |
53 | #region Layout
54 |
55 | ///
56 | public override void PerformLayout(NvgContext ctx)
57 | {
58 | // calculate longest item width
59 | ctx.FontFaceId(FontFaceId);
60 | ctx.FontSize(FontSize);
61 | ctx.TextAlign(TextAlignment.Left | TextAlignment.Top);
62 | var longestItemWidth = ctx.TextBounds(0, 0, _longestCaption, out _);
63 |
64 | // there is only 1 column (combo item text)
65 | // get the max of width / longest item width
66 | Columns =
67 | [
68 | new ColumnDefinition((int)Math.Max((int)longestItemWidth +
69 | GetTheme().Scrollbars.ScrollbarDimension + ITEM_SAFETY_MARGIN, Size.X))
70 | ];
71 |
72 | base.PerformLayout(ctx);
73 | }
74 |
75 | #endregion
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/source/Components/UIEnumDropDown.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace NanoUI.Components
4 | {
5 | ///
6 | /// UIEnumDropDown is just simple enum combo box with only 1 column (enum text).
7 | ///
8 | public class UIEnumDropDown : UIComboBox where T : struct, Enum
9 | {
10 | ///
11 | public UIEnumDropDown(UIWidget parent)
12 | : base(parent)
13 | {
14 | foreach (T value in Enum.GetValues())
15 | {
16 | AddItem(value.ToString(), value);
17 | }
18 | }
19 |
20 | #region Methods
21 |
22 | ///
23 | public override void SetSelected(T @enum)
24 | {
25 | int index = 0;
26 |
27 | foreach (var item in Enum.GetValues())
28 | {
29 | if (item.Equals(@enum))
30 | {
31 | SelectedIndex = index;
32 | break;
33 | }
34 | index++;
35 | }
36 | }
37 |
38 | #endregion
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/source/Components/UIListBox.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 | using NanoUI.Components.Simple;
3 | using NanoUI.Components.Views;
4 | using NanoUI.Components.Views.Items;
5 | using NanoUI.Nvg;
6 |
7 | namespace NanoUI.Components
8 | {
9 | ///
10 | /// UIListBox is simple listbox, that displays strings & returns T when item selected.
11 | ///
12 | public class UIListBox : UIListView
13 | {
14 | ///
15 | public UIListBox(UIWidget parent)
16 | : base(parent)
17 | {
18 |
19 | }
20 |
21 | #region Methods
22 |
23 | ///
24 | /// Add item
25 | ///
26 | /// Caption
27 | /// Passed event data, when selected
28 | ///
29 | public UIViewItemWidget AddItem(string caption, T eventData)
30 | {
31 | UIWidget[] cells =
32 | [
33 | new UIText { Text = caption },
34 | ];
35 |
36 | return Add(new RowItem(cells, eventData));
37 | }
38 |
39 | #endregion
40 |
41 | #region Layout
42 |
43 | ///
44 | public override void PerformLayout(NvgContext ctx)
45 | {
46 | // there is only 1 column (list item text)
47 | ViewPanel.Columns =
48 | [
49 | new ColumnDefinition((int)Size.X)
50 | ];
51 |
52 | base.PerformLayout(ctx);
53 | }
54 |
55 | #endregion
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/source/Components/UIPanel.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Nvg;
2 |
3 | namespace NanoUI.Components
4 | {
5 | ///
6 | /// UIPanel is a simple container widget, that only draws background (if spesified) and children.
7 | ///
8 | public class UIPanel : UIWidget
9 | {
10 | ///
11 | public UIPanel(UIWidget parent)
12 | : base(parent)
13 | {
14 |
15 | }
16 |
17 | ///
18 | public override void Draw(NvgContext ctx)
19 | {
20 | // background
21 | DrawBackgroundBrush(ctx);
22 |
23 | // draw children
24 | base.Draw(ctx);
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/source/Components/UIProgressbar.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 | using NanoUI.Nvg;
3 | using System;
4 | using System.ComponentModel;
5 |
6 | namespace NanoUI.Components
7 | {
8 | // todo : Orientation
9 | // todo : draw progress text value into the center of widget
10 |
11 | ///
12 | /// UIProgressbar.
13 | ///
14 | public class UIProgressbar : UIWidget
15 | {
16 | ///
17 | public UIProgressbar()
18 | {
19 | // set defaults to theme impl - prevents circular reference
20 | ValueColor = default;
21 | }
22 |
23 | ///
24 | public UIProgressbar(UIWidget parent)
25 | : base(parent)
26 | {
27 | ThemeType = typeof(UIProgressbar);
28 | }
29 |
30 | #region Properties
31 |
32 | ///
33 | /// Value
34 | ///
35 | [Browsable(false)]
36 | public virtual float Value { get; set; }
37 |
38 | Color? _valueColor;
39 |
40 | ///
41 | /// Value color
42 | ///
43 | public Color ValueColor
44 | {
45 | get => _valueColor?? GetTheme().Progressbar.ValueColor;
46 | set => _valueColor = value;
47 | }
48 |
49 | #endregion
50 |
51 | #region Drawing
52 |
53 | ///
54 | public override void Draw(NvgContext ctx)
55 | {
56 | // background
57 | DrawBackgroundBrush(ctx);
58 |
59 | // todo : there should not be children but call base.Draw anyway
60 | base.Draw(ctx);
61 |
62 | // Progress
63 | float value = Math.Clamp(Value, 0.0f, 1.0f);
64 | int barPos = (int)Math.Round((Size.X - 2) * value);
65 |
66 | // todo : magical numbers
67 | var cornerRadius = CornerRadius.TopLeft;
68 |
69 | Paint paint = Paint.BoxGradient(
70 | Position.X, Position.Y,
71 | barPos + 1.5f, Size.Y - 1, cornerRadius, 4, // corner radius fixed was 3
72 | ValueColor, ValueColor);
73 |
74 | ctx.BeginPath();
75 | ctx.RoundedRectVarying(
76 | Position.X + 1, Position.Y + 1,
77 | barPos, Size.Y - 2, CornerRadius);
78 |
79 | ctx.FillPaint(paint);
80 | ctx.Fill();
81 |
82 | // border
83 | this.DrawBorder(ctx, true);
84 | }
85 |
86 | #endregion
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/source/Components/UISvgWidget.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Nvg;
2 | using System.Numerics;
3 |
4 | namespace NanoUI.Components
5 | {
6 | ///
7 | /// UISvgWidget.
8 | ///
9 | public class UISvgWidget : UIWidget
10 | {
11 | ///
12 | public UISvgWidget()
13 | {
14 |
15 | }
16 |
17 | ///
18 | public UISvgWidget(UIWidget parent)
19 | : base(parent)
20 | {
21 |
22 | }
23 |
24 | #region Properties
25 |
26 | int? svgId;
27 |
28 | ///
29 | /// Svg id
30 | ///
31 | public int? SvgId
32 | {
33 | get => svgId;
34 | set => svgId = value;
35 | }
36 |
37 | ///
38 | /// Shall we scale svg so it fits into widgets area. Default: true;
39 | ///
40 | public bool FitSvg { get; set; } = true;
41 |
42 | #endregion
43 |
44 | #region Drawing
45 |
46 | ///
47 | public override void Draw(NvgContext ctx)
48 | {
49 | // Background
50 | DrawBackgroundBrush(ctx);
51 |
52 | if (svgId != null)
53 | {
54 | ctx.SaveState();
55 |
56 | // move to widgets parent position
57 | ctx.Translate(Position);
58 |
59 | if(FitSvg && ctx.TryGetSvgSize(svgId.Value, out Vector2 svgSize))
60 | {
61 | // we must set scale so svg fits in this widget
62 | ctx.Scale(Size / svgSize);
63 | }
64 |
65 | ctx.DrawSvg(svgId.Value);
66 |
67 | ctx.RestoreState();
68 | }
69 |
70 | base.Draw(ctx);
71 | }
72 |
73 | #endregion
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/source/Components/Views/IViewItem.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace NanoUI.Components.Views
3 | {
4 | // todo: use guid's as id
5 |
6 | ///
7 | /// IViewItem.
8 | ///
9 | public interface IViewItem
10 | {
11 | ///
12 | /// Obligatory id in flat but mabdatory in hierarcial structures.
13 | ///
14 | string? Id { get; }
15 |
16 | ///
17 | /// ParentId is needed to place correctly into hierarcial structure.
18 | ///
19 | string? ParentId { get; }
20 |
21 | ///
22 | /// Widgets
23 | ///
24 | UIWidget[]? Widgets { get; set; }
25 |
26 | ///
27 | /// Event data
28 | ///
29 | T? EventData { get; set; }
30 |
31 | ///
32 | /// If row height is not defined, view item widget uses default row height from theme.
33 | ///
34 | int? RowHeight { get; set; }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/source/Components/Views/Items/FlowItem.cs:
--------------------------------------------------------------------------------
1 | namespace NanoUI.Components.Views.Items
2 | {
3 | // todo: use only 1 cell
4 | // note: items are just sligthly different, but they are in separate classes in order to force use
5 | // right ctor params & with correct view
6 | // todo: struct?
7 | // todo: use guid's as id
8 |
9 | ///
10 | /// FlowItem.
11 | ///
12 | public class FlowItem : IViewItem
13 | {
14 | ///
15 | /// Obligatory id in flat but mandatory in hierarcial structures.
16 | ///
17 | public string? Id { get; }
18 |
19 | ///
20 | /// ParentId is needed to place correctly into hierarcial structure.
21 | ///
22 | public string? ParentId { get; }
23 |
24 | ///
25 | /// Widgets
26 | ///
27 | public UIWidget[]? Widgets { get; set; }
28 |
29 | ///
30 | /// Event data
31 | ///
32 | public T? EventData { get; set; }
33 |
34 | ///
35 | /// If row height is not defined, view item widget uses default row height from theme.
36 | ///
37 | public int? RowHeight { get; set; }
38 |
39 | public FlowItem(T eventData)
40 | {
41 | EventData = eventData;
42 | }
43 |
44 | public FlowItem(UIWidget widget, T eventData)
45 | {
46 | Widgets = [widget];
47 | EventData = eventData;
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/source/Components/Views/Items/RowItem.cs:
--------------------------------------------------------------------------------
1 | namespace NanoUI.Components.Views.Items
2 | {
3 | // note: items are just sligthly different, but they are in separate classes in order to force use
4 | // right ctor params & with correct view
5 | // todo: struct?
6 | // todo: use guid's as id
7 |
8 | ///
9 | /// RowItem.
10 | ///
11 | public class RowItem : IViewItem
12 | {
13 | ///
14 | /// Obligatory id in flat but mandatory in hierarcial structures.
15 | ///
16 | public string? Id { get; }
17 |
18 | ///
19 | /// ParentId is needed to place correctly into hierarcial structure.
20 | ///
21 | public string? ParentId { get; }
22 |
23 | ///
24 | /// Widgets
25 | ///
26 | public UIWidget[]? Widgets { get; set; }
27 |
28 | ///
29 | /// Event data
30 | ///
31 | public T? EventData { get; set; }
32 |
33 | ///
34 | /// If row height is not defined, view item widget uses default row height from theme.
35 | ///
36 | public int? RowHeight { get; set; }
37 |
38 | // todo : check, cells are set in extension
39 |
40 | public RowItem(T eventData)
41 | {
42 | EventData = eventData;
43 | }
44 |
45 | public RowItem(UIWidget[] widgets, T eventData)
46 | {
47 | Widgets = widgets;
48 | EventData = eventData;
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/source/Components/Views/Items/TreeItem.cs:
--------------------------------------------------------------------------------
1 | namespace NanoUI.Components.Views.Items
2 | {
3 | // note: items are just sligthly different, but they are in separate classes in order to force use
4 | // right ctor params & with correct view
5 | // todo: struct?
6 | // todo: use guid's as id
7 |
8 | ///
9 | /// TreeItem.
10 | ///
11 | public class TreeItem : IViewItem
12 | {
13 | ///
14 | /// Obligatory id in flat but mandatory in hierarcial structures.
15 | ///
16 | public string? Id { get; internal set; }
17 |
18 | ///
19 | /// ParentId is needed to place correctly into hierarcial structure.
20 | ///
21 | public string? ParentId { get; internal set; }
22 |
23 | ///
24 | /// Widgets
25 | ///
26 | public UIWidget[]? Widgets { get; set; }
27 |
28 | ///
29 | /// Event data
30 | ///
31 | public T? EventData { get; set; }
32 |
33 | ///
34 | /// If row height is not defined, view item widget uses default row height from theme.
35 | ///
36 | public int? RowHeight { get; set; }
37 |
38 | ///
39 | /// Constructor. For hierarcial structures (treeview) - id & parentId are mandatory.
40 | ///
41 | public TreeItem(T eventData, string? id, string? parentId)
42 | {
43 | EventData = eventData;
44 | Id = id;
45 | ParentId = parentId;
46 | }
47 |
48 | ///
49 | /// Constructor. For hierarcial structures (treeview) - id & parentId are mandatory.
50 | ///
51 | public TreeItem(UIWidget[] widgets, T eventData, string? id, string? parentId)
52 | {
53 | Widgets = widgets;
54 | EventData = eventData;
55 | Id = id;
56 | ParentId = parentId;
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/source/Components/Views/UIFlowView.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 | using NanoUI.Layouts;
3 | using NanoUI.Components.Views.Items;
4 | using System.Numerics;
5 |
6 | namespace NanoUI.Components.Views
7 | {
8 | // todo : Show name under Texture/Icon (truncated/wrapped if not fits to thumbsize) - CUSTOM CELL?
9 | // todo : Show tooltip (description) under Texture/Icon if spesified?
10 |
11 | ///
12 | /// UIFlowView.
13 | ///
14 | public class UIFlowView : UIViewWidget
15 | {
16 | ///
17 | public UIFlowView()
18 | {
19 | // set defaults to theme impl - prevents circular reference
20 | // note: user can set default part size
21 | // PartSize = new Vector2(100, 100);
22 | }
23 |
24 | ///
25 | public UIFlowView(UIWidget parent)
26 | : base(parent)
27 | {
28 | // note: we create view panel in base
29 |
30 | // override default
31 | ViewPanel.ChildrenLayout = new FlowLayout(LayoutAlignment.Minimum) { Spacing = new Vector2(10) };
32 | ViewPanel.ViewSelectionMode = ViewSelectionMode.Cell;
33 | }
34 |
35 | #region Properties
36 |
37 | // todo: If user changes this, we must update panel widgets Fixed size & panel layout
38 | // todo: we don't store param here, since it produces sync problem, if user changes columns/rowheight directly
39 | Vector2 _partSize;
40 |
41 | ///
42 | /// PartSize is just a helper.
43 | ///
44 | /// Since Columns (ViewColumn[]) is not stored with theme (has owner widget).
45 | public Vector2 PartSize
46 | {
47 | get => _partSize;
48 | set
49 | {
50 | _partSize = value;
51 |
52 | ViewPanel.Columns = [new ColumnDefinition((int)_partSize.X)];
53 | ViewPanel.RowHeight = (int)_partSize.Y;
54 |
55 | // todo: sync all view panel widgets & perform layout if this is changed at runtime
56 | // (must sync also vscrollpanel)
57 | }
58 | }
59 |
60 | #endregion
61 |
62 | #region Methods
63 |
64 | ///
65 | /// Adds item.
66 | ///
67 | /// FlowItem
68 | /// UIViewItemWidget
69 | public UIViewItemWidget Add(FlowItem flowItem)
70 | {
71 | return new UIViewItemWidget(ViewPanel, flowItem)
72 | {
73 | StretchWidth = true,
74 | FixedSize = PartSize,
75 | CornerRadius = new CornerRadius(0)
76 | };
77 | }
78 |
79 | #endregion
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/source/Components/Views/UIListView.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Components.Views.Items;
2 |
3 | namespace NanoUI.Components.Views
4 | {
5 | ///
6 | /// UIListView.
7 | ///
8 | public class UIListView : UIViewWidget
9 | {
10 | ///
11 | public UIListView()
12 | {
13 | // set defaults to theme impl - prevents circular reference
14 | }
15 |
16 | ///
17 | public UIListView(UIWidget parent)
18 | :base(parent)
19 | {
20 | // note: we create view panel in base
21 | }
22 |
23 | #region Methods
24 |
25 | ///
26 | /// Adds item.
27 | /// Cells can have their own data OR row can have common data.
28 | ///
29 | /// RowItem
30 | /// widget so you can set common properties.
31 | public UIViewItemWidget Add(RowItem listItem)
32 | {
33 | return new UIViewItemWidget(ViewPanel, listItem) { StretchWidth = true };
34 | }
35 |
36 | #endregion
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/source/Components/Views/UITableView.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 | using NanoUI.Components.Views.Items;
3 |
4 | namespace NanoUI.Components.Views
5 | {
6 | // todo : draw column headers & provide sort by clicked column
7 |
8 | ///
9 | /// UITableView is a generic table view using cells.
10 | ///
11 | public class UITableView : UIViewWidget
12 | {
13 | ///
14 | public UITableView()
15 | {
16 | // set defaults to theme impl - prevents circular reference
17 | }
18 |
19 | ///
20 | public UITableView(UIWidget parent)
21 | :base(parent)
22 | {
23 | // note: we create view panel in base
24 |
25 | // override default
26 | ViewPanel.ViewSelectionMode = ViewSelectionMode.Cell;
27 | }
28 |
29 | #region Methods
30 |
31 | ///
32 | /// Adds item.
33 | ///
34 | /// RowItem
35 | /// UIViewItemWidget
36 | public UIViewItemWidget Add(RowItem viewItem)
37 | {
38 | return new UIViewItemWidget(ViewPanel, viewItem) { StretchWidth = true };
39 | }
40 |
41 | #endregion
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/source/Components/Views/UIViewItemWidget.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Components.Simple;
2 | using NanoUI.Nvg;
3 | using System.Numerics;
4 |
5 | namespace NanoUI.Components.Views
6 | {
7 | ///
8 | /// UIViewItemWidget. Most of the views / view panels use this as is
9 | /// (exception: UITreeItemWidget).
10 | ///
11 | public class UIViewItemWidget : UIWidget
12 | {
13 | ///
14 | public UIViewItemWidget(UIWidget parent, IViewItem viewRow)
15 | : base(parent)
16 | {
17 | // change/set item cells parent to this
18 | if(viewRow.Widgets != null)
19 | {
20 | foreach (var item in viewRow.Widgets)
21 | {
22 | item.CreateParented(this);
23 | }
24 | }
25 |
26 |
27 | // set params
28 | Name = viewRow.Id?? "No name";
29 | ParentId = viewRow.ParentId?? "";
30 | EventData = viewRow.EventData;
31 |
32 | // if row height not set - use default
33 | Size = new Vector2(Size.X, viewRow.RowHeight.HasValue ? viewRow.RowHeight.Value : GetTheme().ViewPanel.RowHeight);
34 |
35 | // todo : should these be in theme?
36 | // note: these are overridden if focused/pointerFocused (uses theme colors)
37 | //BackgroundMode = BackgroundMode.NONE;
38 | Border = false;
39 | }
40 |
41 | #region Properties
42 |
43 | ///
44 | /// StretchWidth determines if we sync width with parent width.
45 | /// Default: false.
46 | ///
47 | /// Only flow & menu view currently doesn't use parent strech.
48 | public bool StretchWidth { get; set; } = false;
49 |
50 | ///
51 | /// ParentId is needed to place correctly into hierarcial structure.
52 | ///
53 | public string ParentId { get; }
54 |
55 | ///
56 | /// EventData.
57 | ///
58 | public T? EventData { get; set; }
59 |
60 | ///
61 | /// IsSeparator.
62 | ///
63 | /// Special handling for separator (do not pointer click/focus etc).
64 | public bool IsSeparator
65 | {
66 | get => Children.Count == 1 && Children[0] is UISeparator;
67 | }
68 |
69 | #endregion
70 |
71 | #region Layout
72 |
73 | ///
74 | public override void PerformLayout(NvgContext ctx)
75 | {
76 | base.PerformLayout(ctx);
77 |
78 | if (Parent != null && StretchWidth)
79 | {
80 | Size = new Vector2(Parent.Size.X, Size.Y);
81 | }
82 | }
83 |
84 | #endregion
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/source/Fonts/Data/Font.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 |
3 | namespace NanoUI.Fonts.Data
4 | {
5 | internal struct Font
6 | {
7 | // needed to get glyphs & pass to font manager
8 | public int Id;
9 | // for search purposes
10 | public string Name;
11 | public float Ascender;
12 | public float Descender;
13 | public float LineHeight;
14 | public GlyphBaking FontBaking;
15 | }
16 | }
--------------------------------------------------------------------------------
/source/Fonts/Data/FontAtlas.cs:
--------------------------------------------------------------------------------
1 | namespace NanoUI.Fonts.Data
2 | {
3 | internal struct FontAtlas
4 | {
5 | public int Width;
6 | public int Height;
7 | }
8 | }
--------------------------------------------------------------------------------
/source/Fonts/Data/FontAtlasNode.cs:
--------------------------------------------------------------------------------
1 | namespace NanoUI.Fonts.Data
2 | {
3 | internal struct FontAtlasNode
4 | {
5 | public int X;
6 | public int Y;
7 | public int Width;
8 | }
9 | }
--------------------------------------------------------------------------------
/source/Fonts/Data/FontEnums.cs:
--------------------------------------------------------------------------------
1 | namespace NanoUI.Fonts.Data
2 | {
3 | internal enum CodepointType
4 | {
5 | Space,
6 | Newline,
7 | Char,
8 | CJKChar
9 | }
10 |
11 | internal enum FontGlyphBitmap
12 | {
13 | Optional = 1,
14 | Required = 2
15 | }
16 | }
--------------------------------------------------------------------------------
/source/Fonts/Data/FontState.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 |
3 | namespace NanoUI.Fonts.Data
4 | {
5 | // note: we can't use NvgState, since there is scaling applied in GetFontScale
6 | internal struct FontState
7 | {
8 | // this is just needed for glyphs
9 | public int FontId;
10 | public TextAlignment TextAlign;
11 | public float FontSize;
12 | public float CharSpacing;
13 | // this is a scale to convert font file's internal units to pixels
14 | public float PixelScale;
15 | public float Blur;
16 | public float Dilate;
17 | // there is different logic in some FontStash functions based on baking method
18 | public GlyphBaking GlyphBaking;
19 |
20 | // glyph shapes
21 | public Color? TextShapeOutline;
22 | public float TextShapeOutlineWidth;
23 | public Paint? TextShapeFill;
24 | }
25 | }
--------------------------------------------------------------------------------
/source/Fonts/Data/FontTextIter.cs:
--------------------------------------------------------------------------------
1 | namespace NanoUI.Fonts.Data
2 | {
3 | // note: we use same iterator whole time, so we must reset values
4 | internal struct FontTextIter
5 | {
6 | public float X, Y, NextX, NextY;
7 | public uint Codepoint;
8 | public int PrevGlyphIndex;
9 |
10 | // current pos (char) in string
11 | public int CurrentPos;
12 | // next char pos
13 | public int NextPos;
14 |
15 | public FontGlyphBitmap BitmapOption;
16 |
17 | public void Reset(float x, float y, FontGlyphBitmap bitmapOption)
18 | {
19 | X = NextX = x;
20 | Y = NextY = y;
21 | CurrentPos = NextPos = 0;
22 | Codepoint = 0;
23 | PrevGlyphIndex = -1;
24 | BitmapOption = bitmapOption;
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/source/Fonts/Data/Glyph.cs:
--------------------------------------------------------------------------------
1 | namespace NanoUI.Fonts.Data
2 | {
3 | internal struct Glyph
4 | {
5 | public uint Codepoint;
6 | // this is glyphIndex in Font
7 | public int FontGlyphIndex;
8 | // this is the font size, when glyph was originally created
9 | // note: if we use same glyph with all font sizes, we must calculate scale/advanceX based on this
10 | public float FontSize;
11 | public int X0, Y0, X1, Y1; // min, max
12 | public int OffX, OffY;
13 | public float AdvX;
14 | public int Blur;
15 | public int Dilate;
16 | }
17 | }
--------------------------------------------------------------------------------
/source/Fonts/Data/GlyphQuad.cs:
--------------------------------------------------------------------------------
1 | namespace NanoUI.Fonts.Data
2 | {
3 | // this is "area" that glyph occupies in atlas texture
4 | // - x0, y0, s0, t0 = MIN pos & uv
5 | // - x1, y1, s1, t1 = MAX pos & uv
6 | internal struct GlyphQuad
7 | {
8 | public float x0, y0, s0, t0;
9 | public float x1, y1, s1, t1;
10 | }
11 | }
--------------------------------------------------------------------------------
/source/Fonts/SafeTrueType/CharStringContext.cs:
--------------------------------------------------------------------------------
1 | using static SafeStbTrueTypeSharp.Common;
2 |
3 | namespace SafeStbTrueTypeSharp
4 | {
5 | // fixed nullable warnings
6 | internal class CharStringContext
7 | {
8 | public int bounds;
9 | public float first_x;
10 | public float first_y;
11 | public int max_x;
12 | public int max_y;
13 | public int min_x;
14 | public int min_y;
15 | public int num_vertices;
16 | public stbtt_vertex[]? pvertices; // fixed
17 | public int started;
18 | public float x;
19 | public float y;
20 |
21 | public void stbtt__track_vertex(int x, int y)
22 | {
23 | if (x > max_x || started == 0)
24 | max_x = x;
25 | if (y > max_y || started == 0)
26 | max_y = y;
27 | if (x < min_x || started == 0)
28 | min_x = x;
29 | if (y < min_y || started == 0)
30 | min_y = y;
31 | started = 1;
32 | }
33 |
34 | public void stbtt__csctx_v(byte type, int x, int y, int cx, int cy, int cx1, int cy1)
35 | {
36 | if (bounds != 0)
37 | {
38 | stbtt__track_vertex(x, y);
39 | if (type == STBTT_vcubic)
40 | {
41 | stbtt__track_vertex(cx, cy);
42 | stbtt__track_vertex(cx1, cy1);
43 | }
44 | }
45 | else
46 | {
47 | var v = new stbtt_vertex();
48 | stbtt_setvertex(ref v, type, x, y, cx, cy);
49 | pvertices![num_vertices] = v; // fixed
50 | pvertices[num_vertices].cx1 = (short)cx1;
51 | pvertices[num_vertices].cy1 = (short)cy1;
52 | }
53 |
54 | num_vertices++;
55 | }
56 |
57 | public void stbtt__csctx_close_shape()
58 | {
59 | if (first_x != x || first_y != y)
60 | stbtt__csctx_v(STBTT_vline, (int)first_x, (int)first_y, 0, 0, 0, 0);
61 | }
62 |
63 | public void stbtt__csctx_rmove_to(float dx, float dy)
64 | {
65 | stbtt__csctx_close_shape();
66 | first_x = x = x + dx;
67 | first_y = y = y + dy;
68 | stbtt__csctx_v(STBTT_vmove, (int)x, (int)y, 0, 0, 0, 0);
69 | }
70 |
71 | public void stbtt__csctx_rline_to(float dx, float dy)
72 | {
73 | x += dx;
74 | y += dy;
75 | stbtt__csctx_v(STBTT_vline, (int)x, (int)y, 0, 0, 0, 0);
76 | }
77 |
78 | public void stbtt__csctx_rccurve_to(float dx1, float dy1, float dx2, float dy2,
79 | float dx3, float dy3)
80 | {
81 | var cx1 = x + dx1;
82 | var cy1 = y + dy1;
83 | var cx2 = cx1 + dx2;
84 | var cy2 = cy1 + dy2;
85 | x = cx2 + dx3;
86 | y = cy2 + dy3;
87 | stbtt__csctx_v(STBTT_vcubic, (int)x, (int)y, (int)cx1, (int)cy1, (int)cx2, (int)cy2);
88 | }
89 | }
90 | }
--------------------------------------------------------------------------------
/source/Fonts/TrueType/StbTrueType.CharString.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | namespace StbTrueTypeSharp
4 | {
5 | unsafe partial class StbTrueType
6 | {
7 | public static void stbtt__csctx_close_shape(stbtt__csctx* ctx)
8 | {
9 | if (ctx->first_x != ctx->x || ctx->first_y != ctx->y)
10 | stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->first_x, (int)ctx->first_y, 0, 0, 0, 0);
11 | }
12 |
13 | public static void stbtt__csctx_rccurve_to(stbtt__csctx* ctx, float dx1, float dy1, float dx2, float dy2,
14 | float dx3, float dy3)
15 | {
16 | var cx1 = ctx->x + dx1;
17 | var cy1 = ctx->y + dy1;
18 | var cx2 = cx1 + dx2;
19 | var cy2 = cy1 + dy2;
20 | ctx->x = cx2 + dx3;
21 | ctx->y = cy2 + dy3;
22 | stbtt__csctx_v(ctx, STBTT_vcubic, (int)ctx->x, (int)ctx->y, (int)cx1, (int)cy1, (int)cx2, (int)cy2);
23 | }
24 |
25 | public static void stbtt__csctx_rline_to(stbtt__csctx* ctx, float dx, float dy)
26 | {
27 | ctx->x += dx;
28 | ctx->y += dy;
29 | stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0);
30 | }
31 |
32 | public static void stbtt__csctx_rmove_to(stbtt__csctx* ctx, float dx, float dy)
33 | {
34 | stbtt__csctx_close_shape(ctx);
35 | ctx->first_x = ctx->x = ctx->x + dx;
36 | ctx->first_y = ctx->y = ctx->y + dy;
37 | stbtt__csctx_v(ctx, STBTT_vmove, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0);
38 | }
39 |
40 | public static void stbtt__csctx_v(stbtt__csctx* c, byte type, int x, int y, int cx, int cy, int cx1, int cy1)
41 | {
42 | if (c->bounds != 0)
43 | {
44 | stbtt__track_vertex(c, x, y);
45 | if (type == STBTT_vcubic)
46 | {
47 | stbtt__track_vertex(c, cx, cy);
48 | stbtt__track_vertex(c, cx1, cy1);
49 | }
50 | }
51 | else
52 | {
53 | stbtt_setvertex(&c->pvertices[c->num_vertices], type, x, y, cx, cy);
54 | c->pvertices[c->num_vertices].cx1 = (short)cx1;
55 | c->pvertices[c->num_vertices].cy1 = (short)cy1;
56 | }
57 |
58 | c->num_vertices++;
59 | }
60 |
61 | public static void stbtt__track_vertex(stbtt__csctx* c, int x, int y)
62 | {
63 | if (x > c->max_x || c->started == 0)
64 | c->max_x = x;
65 | if (y > c->max_y || c->started == 0)
66 | c->max_y = y;
67 | if (x < c->min_x || c->started == 0)
68 | c->min_x = x;
69 | if (y < c->min_y || c->started == 0)
70 | c->min_y = y;
71 | c->started = 1;
72 | }
73 |
74 | [StructLayout(LayoutKind.Sequential)]
75 | public struct stbtt__csctx
76 | {
77 | public int bounds;
78 | public int started;
79 | public float first_x;
80 | public float first_y;
81 | public float x;
82 | public float y;
83 | public int min_x;
84 | public int max_x;
85 | public int min_y;
86 | public int max_y;
87 | public stbtt_vertex* pvertices;
88 | public int num_vertices;
89 | }
90 | }
91 | }
--------------------------------------------------------------------------------
/source/Fonts/TrueType/StbTrueType.Heap.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | namespace StbTrueTypeSharp
4 | {
5 | unsafe partial class StbTrueType
6 | {
7 | public static void* stbtt__hheap_alloc(stbtt__hheap* hh, ulong size, void* userdata)
8 | {
9 | if (hh->first_free != null)
10 | {
11 | var p = hh->first_free;
12 | hh->first_free = *(void**)p;
13 | return p;
14 | }
15 |
16 | if (hh->num_remaining_in_head_chunk == 0)
17 | {
18 | var count = size < 32 ? 2000 : size < 128 ? 800 : 100;
19 | var c = (stbtt__hheap_chunk*)CRuntime.malloc((ulong)sizeof(stbtt__hheap_chunk) +
20 | size * (ulong)count);
21 | if (c == null)
22 | return null;
23 | c->next = hh->head;
24 | hh->head = c;
25 | hh->num_remaining_in_head_chunk = count;
26 | }
27 |
28 | --hh->num_remaining_in_head_chunk;
29 | return (sbyte*)hh->head + sizeof(stbtt__hheap_chunk) + size * (ulong)hh->num_remaining_in_head_chunk;
30 | }
31 |
32 | public static void stbtt__hheap_cleanup(stbtt__hheap* hh, void* userdata)
33 | {
34 | var c = hh->head;
35 | while (c != null)
36 | {
37 | var n = c->next;
38 | CRuntime.free(c);
39 | c = n;
40 | }
41 | }
42 |
43 | public static void stbtt__hheap_free(stbtt__hheap* hh, void* p)
44 | {
45 | *(void**)p = hh->first_free;
46 | hh->first_free = p;
47 | }
48 |
49 | public static stbtt__active_edge* stbtt__new_active(stbtt__hheap* hh, stbtt__edge* e, int off_x,
50 | float start_point, void* userdata)
51 | {
52 | var z = (stbtt__active_edge*)stbtt__hheap_alloc(hh, (ulong)sizeof(stbtt__active_edge), userdata);
53 | var dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
54 | if (z == null)
55 | return z;
56 | z->fdx = dxdy;
57 | z->fdy = dxdy != 0.0f ? 1.0f / dxdy : 0.0f;
58 | z->fx = e->x0 + dxdy * (start_point - e->y0);
59 | z->fx -= off_x;
60 | z->direction = e->invert != 0 ? 1.0f : -1.0f;
61 | z->sy = e->y0;
62 | z->ey = e->y1;
63 | z->next = null;
64 | return z;
65 | }
66 |
67 | [StructLayout(LayoutKind.Sequential)]
68 | public struct stbtt__hheap
69 | {
70 | public stbtt__hheap_chunk* head;
71 | public void* first_free;
72 | public int num_remaining_in_head_chunk;
73 | }
74 |
75 | [StructLayout(LayoutKind.Sequential)]
76 | public struct stbtt__hheap_chunk
77 | {
78 | public stbtt__hheap_chunk* next;
79 | }
80 | }
81 | }
--------------------------------------------------------------------------------
/source/Fonts/TrueType/StbTrueType.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace StbTrueTypeSharp
5 | {
6 | internal static unsafe partial class StbTrueType
7 | {
8 | internal static bool usedOldRasterizer = false;
9 |
10 | public class stbtt_fontinfo : IDisposable
11 | {
12 | public stbtt__buf cff;
13 | public stbtt__buf charstrings;
14 | public byte* data = null;
15 | public stbtt__buf fdselect;
16 | public stbtt__buf fontdicts;
17 | public int fontstart;
18 | public int glyf;
19 | public int gpos;
20 | public stbtt__buf gsubrs;
21 | public int head;
22 | public int hhea;
23 | public int hmtx;
24 | public int index_map;
25 | public int indexToLocFormat;
26 | public bool isDataCopy;
27 | public int kern;
28 | public int loca;
29 | public int numGlyphs;
30 | public stbtt__buf subrs;
31 | public int svg;
32 | public void* userdata;
33 | public bool useOldRasterizer = false;
34 |
35 | public void Dispose()
36 | {
37 | Dispose(true);
38 | }
39 |
40 | ~stbtt_fontinfo()
41 | {
42 | Dispose(false);
43 | }
44 |
45 | protected virtual void Dispose(bool disposing)
46 | {
47 | if (isDataCopy && data != null)
48 | {
49 | CRuntime.free(data);
50 | data = null;
51 | }
52 | }
53 | }
54 |
55 | public static uint stbtt__find_table(byte* data, uint fontstart, string tag)
56 | {
57 | int num_tables = ttUSHORT(data + fontstart + 4);
58 | var tabledir = fontstart + 12;
59 | int i;
60 | for (i = 0; i < num_tables; ++i)
61 | {
62 | var loc = (uint)(tabledir + 16 * i);
63 | if ((data + loc + 0)[0] == tag[0] && (data + loc + 0)[1] == tag[1] &&
64 | (data + loc + 0)[2] == tag[2] && (data + loc + 0)[3] == tag[3])
65 | return ttULONG(data + loc + 8);
66 | }
67 |
68 | return 0;
69 | }
70 |
71 | public static bool stbtt_BakeFontBitmap(byte[] ttf, int offset, float pixel_height, byte[] pixels, int pw,
72 | int ph,
73 | int first_char, int num_chars, stbtt_bakedchar[] chardata)
74 | {
75 | fixed (byte* ttfPtr = ttf)
76 | {
77 | fixed (byte* pixelsPtr = pixels)
78 | {
79 | fixed (stbtt_bakedchar* chardataPtr = chardata)
80 | {
81 | var result = stbtt_BakeFontBitmap(ttfPtr, offset, pixel_height, pixelsPtr, pw, ph, first_char,
82 | num_chars,
83 | chardataPtr);
84 |
85 | return result != 0;
86 | }
87 | }
88 | }
89 | }
90 |
91 | ///
92 | /// Creates and initializes a font from ttf/otf/ttc data
93 | ///
94 | ///
95 | ///
96 | /// null if the data was invalid
97 | public static stbtt_fontinfo? CreateFont(byte[] data, int offset)
98 | {
99 | var dataCopy = (byte*)CRuntime.malloc(data.Length);
100 | Marshal.Copy(data, 0, new IntPtr(dataCopy), data.Length);
101 |
102 | var info = new stbtt_fontinfo
103 | {
104 | isDataCopy = true
105 | };
106 |
107 | if (stbtt_InitFont_internal(info, dataCopy, offset) == 0)
108 | {
109 | info.Dispose();
110 | return null;
111 | }
112 |
113 | return info;
114 | }
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/source/INvgRenderer.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 | using System;
3 | using System.Numerics;
4 |
5 | namespace NanoUI
6 | {
7 | ///
8 | /// NanoUI knows nothing about your graphics system.
9 | /// So you must have INvgRenderer implementation, that handles rendering to your
10 | /// graphics system.
11 | /// Note: You must send this implementation to NanoUI, when you init NvgContext.
12 | ///
13 | public interface INvgRenderer
14 | {
15 | ///
16 | /// Create a texture from the specified path with texture options (flags).
17 | ///
18 | /// Path
19 | /// Texture flags
20 | /// Texture id
21 | ///
22 | /// Path can be any kind of identification you like, since NanoUI passes it as-is.
23 | ///
24 | int CreateTexture(string path, TextureFlags textureFlags = 0);
25 |
26 | ///
27 | /// Create a texture from the texture description.
28 | ///
29 | /// Texture description
30 | /// Texture id
31 | int CreateTexture(TextureDesc description);
32 |
33 | ///
34 | /// Update a texture with data.
35 | ///
36 | /// Texture id
37 | /// Data
38 | /// Success
39 | /// Data is in 8-bit format when updating font texture.
40 | bool UpdateTexture(int texture, ReadOnlySpan data);
41 |
42 | ///
43 | /// Resize a texture according to texture description.
44 | ///
45 | /// Texture id
46 | /// Texture description
47 | /// Success
48 | ///
49 | /// You can copy data from the old texture to the new, but NanoUI is
50 | /// not demanding it when font texture is resized
51 | /// (NanoUI calls UpdateTexture command with all the new data after this).
52 | ///
53 | bool ResizeTexture(int texture, TextureDesc description);
54 |
55 | ///
56 | /// Delete a texture
57 | ///
58 | /// Texture id
59 | /// Success
60 | bool DeleteTexture(int texture);
61 |
62 | ///
63 | /// Get a texture size (width, height)
64 | ///
65 | /// Texture id
66 | /// Texture size
67 | /// Success
68 | bool GetTextureSize(int texture, out Vector2 size);
69 |
70 | ///
71 | /// Triggerred from NvgContext when EndFrame called.
72 | /// DrawCache is cleared after rendering is done.
73 | ///
74 | void Render();
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/source/Layouts/Layout.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Components;
2 | using NanoUI.Nvg;
3 | using System.Numerics;
4 |
5 | namespace NanoUI.Layouts
6 | {
7 | ///
8 | /// Layout is an abstract layout class, that all layout implementations should extend.
9 | ///
10 | public abstract class Layout
11 | {
12 | ///
13 | /// Spacing between widgets.
14 | ///
15 | /// Layouts my use spacing only in 1 dimension.
16 | public Vector2 Spacing { get; set; }
17 |
18 | ///
19 | /// Calculates parent widget's children preferred size with margins.
20 | ///
21 | /// NvgContext
22 | /// Parent
23 | /// Size
24 | public abstract Vector2 PreferredSize(NvgContext ctx, UIWidget parent);
25 |
26 | ///
27 | /// Sets widget's children positions and sizes & calls childs to perform layout,
28 | /// where you can tweak calculated values.
29 | ///
30 | /// NvgContext
31 | /// Parent
32 | /// Calls parent widget's GetLayoutArea method in order to get offset/topLeft & children area size.
33 | public abstract void PerformLayout(NvgContext ctx, UIWidget parent);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/source/NanoUI.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | Small, extendable and quite feature-rich C# UI and drawing library with no external dependencies, native libraries and no extra assets
6 | disable
7 | enable
8 | True
9 | README.md
10 | true
11 |
12 |
13 |
14 |
15 | 1.0.10
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/source/Nvg/Data/NvgBounds.cs:
--------------------------------------------------------------------------------
1 | using System.Numerics;
2 |
3 | namespace NanoUI.Nvg.Data
4 | {
5 | internal struct NvgBounds
6 | {
7 | public Vector2 Min;
8 | public Vector2 Max;
9 |
10 | public float X
11 | {
12 | get => Min.X;
13 | set => Min.X = value;
14 | }
15 |
16 | public float Y
17 | {
18 | get => Min.Y;
19 | set => Min.Y = value;
20 | }
21 |
22 | public float X2
23 | {
24 | get => Max.X;
25 | set => Max.X = value;
26 | }
27 |
28 | public float Y2
29 | {
30 | get => Max.Y;
31 | set => Max.Y = value;
32 | }
33 |
34 | public NvgBounds(Vector2 min, Vector2 max)
35 | {
36 | Min = min;
37 | Max = max;
38 | }
39 |
40 | public void Reset()
41 | {
42 | Min = new Vector2(1e6f);
43 | Max = new Vector2(-1e6f);
44 | }
45 | }
46 | }
--------------------------------------------------------------------------------
/source/Nvg/Data/NvgParams.cs:
--------------------------------------------------------------------------------
1 | namespace NanoUI.Nvg.Data
2 | {
3 | internal struct NvgParams
4 | {
5 | public float TessTol { get; private set; }
6 | public float DistTol { get; private set; }
7 | public float FringeWidth { get; private set; }
8 | public float DevicePxRatio { get; private set; }
9 |
10 | // nvg__setDevicePixelRatio
11 | public void SetDevicePixelRatio(float pixelRatio)
12 | {
13 | TessTol = 0.25f / pixelRatio;
14 | DistTol = 0.01f / pixelRatio;
15 | FringeWidth = 1.0f / pixelRatio;
16 | DevicePxRatio = pixelRatio;
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/source/Nvg/Data/NvgPath.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 |
3 | namespace NanoUI.Nvg.Data
4 | {
5 | internal struct NvgPath
6 | {
7 | public bool Closed;
8 | public uint BevelCount;
9 | public bool Convex;
10 | public Winding Winding;
11 | public NvgBounds Bounds;
12 |
13 | // structs params
14 | public int PointOffset;
15 | public int PointCount;
16 | public int FillCount;
17 | public int FillOffset;
18 | public int StrokeCount;
19 | public int StrokeOffset;
20 |
21 | // when adding path we must reset values
22 | public void Reset()
23 | {
24 | Closed = default;
25 | BevelCount = default;
26 | Convex = default;
27 | // default winding marks solid fill
28 | Winding = Winding.CounterClockwise;
29 |
30 | Bounds.Reset();
31 |
32 | // structs params
33 | PointOffset = default;
34 | PointCount = default;
35 | FillCount = default;
36 | FillOffset = default;
37 | StrokeCount = default;
38 | StrokeOffset = default;
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/source/Nvg/Data/NvgPathCommand.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 | using System.Numerics;
3 |
4 | namespace NanoUI.Nvg.Data
5 | {
6 | internal struct NvgPathCommand
7 | {
8 | public NvgPathCommandType CommandType;
9 | public Vector2 P0;
10 | public Vector2 P1;
11 | public Vector2 P2;
12 |
13 | public float TessTol;
14 | public Winding Winding;
15 | }
16 | }
--------------------------------------------------------------------------------
/source/Nvg/Data/NvgPathCommandType.cs:
--------------------------------------------------------------------------------
1 | namespace NanoUI.Nvg.Data
2 | {
3 | internal enum NvgPathCommandType
4 | {
5 | MoveTo,
6 | LineTo,
7 | BezierTo,
8 | Close,
9 | Winding,
10 | }
11 | }
--------------------------------------------------------------------------------
/source/Nvg/Data/NvgPoint.cs:
--------------------------------------------------------------------------------
1 | using System.Numerics;
2 |
3 | namespace NanoUI.Nvg.Data
4 | {
5 | internal struct NvgPoint
6 | {
7 | public Vector2 Position;
8 | public Vector2 Delta;
9 | public float Length;
10 | public Vector2 DeltaM;
11 | public NvgPointFlags Flags;
12 |
13 | public void Reset()
14 | {
15 | Position = Delta = DeltaM = Vector2.Zero;
16 | Length = 0;
17 | Flags = 0;// default;
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/source/Nvg/Data/NvgPointFlags.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace NanoUI.Nvg.Data
4 | {
5 | [Flags]
6 | internal enum NvgPointFlags
7 | {
8 | Corner = 1 << 0,
9 | Left = 1 << 1,
10 | Bevel = 1 << 2,
11 | InnerBevel = 1 << 3
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/source/Nvg/Data/NvgScissor.cs:
--------------------------------------------------------------------------------
1 | using System.Numerics;
2 |
3 | namespace NanoUI.Nvg.Data
4 | {
5 | internal struct NvgScissor
6 | {
7 | public Matrix3x2 Transform;
8 | public Vector2 Extent;
9 |
10 | public void Reset()
11 | {
12 | // todo: identity?
13 | Transform = default;
14 | Extent = new Vector2(-1.0f);
15 | }
16 | }
17 | }
--------------------------------------------------------------------------------
/source/Nvg/Data/NvgState.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 | using System.Numerics;
3 |
4 | namespace NanoUI.Nvg.Data
5 | {
6 | // todo: should some values be nullable?
7 | internal struct NvgState
8 | {
9 | public Paint Fill;
10 | public Paint Stroke;
11 | public float StrokeWidth;
12 | public float MiterLimit;
13 | public LineCap LineJoin;
14 | public LineCap LineCap;
15 | public float Alpha;
16 | public Matrix3x2 Transform;
17 | public NvgScissor Scissor;
18 | public float FontSize;
19 | // note: this is additional spacing (default is 0)
20 | public float TextCharSpacing;
21 | // note: this is proportional line height (default is 1)
22 | public float TextLineHeight;
23 | public TextAlignment TextAlign;
24 | public int FontId;
25 | public int TextBlur;
26 | public int TextDilate;
27 |
28 | // glyph shapes
29 | public Color? TextShapeOutline;
30 | public float TextShapeOutlineWidth;
31 | public Paint? TextShapeFill;
32 |
33 | public NvgState()
34 | {
35 | Reset();
36 | }
37 |
38 | public void Reset()
39 | {
40 | // init defaults
41 | Fill.Reset(Color.White);
42 | Stroke.Reset(Color.Black);
43 | StrokeWidth = 1.0f;
44 | MiterLimit = 10.0f;
45 | LineJoin = LineCap.Miter;
46 | LineCap = LineCap.Butt;
47 | Alpha = 1.0f;
48 | Transform = Matrix3x2.Identity;
49 | Scissor.Reset();
50 | FontSize = 16.0f;
51 | TextCharSpacing = 0.0f;
52 | TextLineHeight = 1.0f;
53 | TextAlign = TextAlignment.Left | TextAlignment.Baseline;
54 | FontId = 0;
55 | TextBlur = 0;
56 | TextDilate = 0;
57 | // glyph shapes
58 | TextShapeOutline = null;
59 | TextShapeOutlineWidth = 1;
60 | TextShapeFill = null;
61 | }
62 | }
63 | }
--------------------------------------------------------------------------------
/source/README.md:
--------------------------------------------------------------------------------
1 | Small, extendable and quite feature-rich C# UI & drawing library with no external dependencies, native libraries and no extra assets.
2 |
3 | More information and changelog in the source repository.
4 |
--------------------------------------------------------------------------------
/source/Rendering/Data/DrawCall.cs:
--------------------------------------------------------------------------------
1 | namespace NanoUI.Rendering.Data
2 | {
3 | // this is internal draw call info that is used to create draw command(s) for the user
4 | internal struct DrawCall
5 | {
6 | public DrawCallType Type;
7 |
8 | public int Uniform1;
9 | public int Uniform2;
10 |
11 | public int VertexOffset;
12 | public int VertexCount;
13 |
14 | public int FillStrokeCount;
15 | public int FillStrokeOffset;
16 |
17 | public int Texture;
18 | }
19 | }
--------------------------------------------------------------------------------
/source/Rendering/Data/DrawCommand.cs:
--------------------------------------------------------------------------------
1 | namespace NanoUI.Rendering.Data
2 | {
3 | ///
4 | /// Draw command to be used when rendering. Renderer should loop all draw commands &
5 | /// prepare graphics engine before drawing.
6 | ///
7 | public struct DrawCommand
8 | {
9 | ///
10 | /// DrawCommandType to select correct pipeline settings.
11 | ///
12 | public DrawCommandType DrawCommandType;
13 |
14 | ///
15 | /// DrawCallType can be used in rendering, if some special operation is needed (optional).
16 | ///
17 | public DrawCallType DrawCallType;
18 |
19 | ///
20 | /// Uniform index.
21 | ///
22 | public int UniformOffset;
23 |
24 | ///
25 | /// Texture id.
26 | ///
27 | public int Texture;
28 |
29 | ///
30 | /// Indices start index.
31 | ///
32 | public int IndexOffset;
33 |
34 | ///
35 | /// Indices count.
36 | ///
37 | public int IndexCount;
38 |
39 | ///
40 | /// Vertices start index.
41 | ///
42 | public int VertexOffset;
43 |
44 | ///
45 | /// Vertices count.
46 | ///
47 | ///
48 | /// You should not use VertexCount when drawing (use indexed drawing),
49 | /// since it will produce unspecified results.
50 | ///
51 | public int VertexCount;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/source/Rendering/Data/FillStrokeInfo.cs:
--------------------------------------------------------------------------------
1 | namespace NanoUI.Rendering.Data
2 | {
3 | internal struct FillStrokeInfo
4 | {
5 | public int FillOffset;
6 | public int FillCount;
7 |
8 | public int StrokeOffset;
9 | public int StrokeCount;
10 | }
11 | }
--------------------------------------------------------------------------------
/source/Rendering/Data/FragmentUniform.cs:
--------------------------------------------------------------------------------
1 | using System.Numerics;
2 |
3 | namespace NanoUI.Rendering.Data
4 | {
5 | ///
6 | /// Uniform used in fragment/pixel shader.
7 | /// Note: You shouldn't normally worry about this, since NanoUI sets values and
8 | /// your fragment/pixel shader uses them.
9 | ///
10 | public struct FragmentUniform
11 | {
12 | ///
13 | /// Scissor matrix.
14 | ///
15 | public Matrix4x4 ScissorMat;
16 |
17 | ///
18 | /// Paint matrix.
19 | ///
20 | public Matrix4x4 PaintMat;
21 |
22 | ///
23 | /// Inner color.
24 | ///
25 | public Vector4 InnerCol;
26 |
27 | ///
28 | /// Outer color.
29 | ///
30 | public Vector4 OuterCol;
31 |
32 | ///
33 | /// Scissor extent.
34 | ///
35 | public Vector2 ScissorExt;
36 |
37 | ///
38 | /// Scissor scale.
39 | ///
40 | public Vector2 ScissorScale;
41 |
42 | ///
43 | /// Extent.
44 | ///
45 | public Vector2 Extent;
46 |
47 | ///
48 | /// Radius.
49 | ///
50 | public float Radius;
51 |
52 | ///
53 | /// Feather.
54 | ///
55 | public float Feather;
56 |
57 | ///
58 | /// Action type.
59 | ///
60 | /// ActionType is actually int, but some HLSL shaders don't like ints.
61 | public float ActionType;
62 |
63 | ///
64 | /// Font size.
65 | ///
66 | public float FontSize;
67 |
68 | ///
69 | /// Reserved for future usage. Needed to set correct alignment.
70 | ///
71 | private float Unused1;
72 |
73 | ///
74 | /// Reserved for future usage. Needed to set correct alignment.
75 | ///
76 | private float Unused2;
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/source/Rendering/Data/Vertex.cs:
--------------------------------------------------------------------------------
1 | using System.Numerics;
2 |
3 | namespace NanoUI.Rendering.Data
4 | {
5 | ///
6 | /// Vertex to store into VertexBuffer.
7 | ///
8 | public struct Vertex
9 | {
10 | ///
11 | /// Size in bytes.
12 | ///
13 | public const byte SizeInBytes = 16;
14 |
15 | ///
16 | /// Position.
17 | ///
18 | public Vector2 Position;
19 |
20 | ///
21 | /// Texture coordinate.
22 | ///
23 | public Vector2 UV;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/source/Rendering/DrawEnums.cs:
--------------------------------------------------------------------------------
1 | namespace NanoUI.Rendering
2 | {
3 | ///
4 | /// (Optional) DrawCallType can be used in rendering,
5 | /// if some special operation is needed.
6 | ///
7 | public enum DrawCallType
8 | {
9 | Fill,
10 | ConvexFill,
11 | Stroke,
12 | Text
13 | }
14 |
15 | ///
16 | /// DrawCommandType should be used in rendering,
17 | /// when setting correct pipeline settings.
18 | ///
19 | public enum DrawCommandType
20 | {
21 | // TriangleFan --> TriangleList - indexed
22 | FillStencil,
23 |
24 | // TriangleStrip --> TriangleList - indexed
25 | Fill,
26 |
27 | // TriangleFan/TriangleStrip/TriangleList --> TriangleList - indexed
28 | // used by ConvexFill, Stroke, Text
29 | Triangles
30 | }
31 |
32 | ///
33 | /// DrawActionType is used in fragment/pixel shader to determine
34 | /// the correct action.
35 | ///
36 | public enum DrawActionType : int
37 | {
38 | FillGradient = 0,
39 | FillImage = 1,
40 | FillStencil = 2,
41 | Text = 3,
42 | // this allows to use normal & additional text effects in shader (outline, blur etc)
43 | TextSDF = 4
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/source/Serializers/NumericsArrayConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Numerics;
3 |
4 | namespace NanoUI.Serializers
5 | {
6 | ///
7 | /// NumericsArrayConverter is used when serializing/deserializing to/from JSON.
8 | ///
9 | public static class NumericsArrayConverter
10 | {
11 | // Vector2
12 | public static Vector2 ToVector2(this float[] arr)
13 | {
14 | if (arr == null || arr.Length != 2)
15 | throw new ArgumentException("Array length must be 2");
16 |
17 | return new Vector2(arr[0], arr[1]);
18 | }
19 |
20 | public static float[] ToArray(this Vector2 vec2)
21 | {
22 | return [ vec2.X, vec2.Y ];
23 | }
24 |
25 | // Vector3
26 | public static float[] ToArray(this Vector3 vec3)
27 | {
28 | return [ vec3.X, vec3.Y, vec3.Z ];
29 | }
30 | public static Vector3 ToVector3(this float[] arr)
31 | {
32 | if (arr == null || arr.Length != 3)
33 | throw new ArgumentException("Array length must be 3");
34 |
35 | return new Vector3(arr[0], arr[1], arr[2]);
36 | }
37 |
38 | // Vector4
39 | public static float[] ToArray(this Vector4 vec4)
40 | {
41 | return [ vec4.X, vec4.Y, vec4.Z, vec4.W ];
42 | }
43 |
44 | public static Vector4 ToVector4(this float[] arr)
45 | {
46 | if (arr == null || arr.Length != 4)
47 | throw new ArgumentException("Array length must be 4");
48 |
49 | return new Vector4(arr[0], arr[1], arr[2], arr[3]);
50 | }
51 |
52 | // Quaternion
53 | public static float[] ToArray(this Quaternion quaternion)
54 | {
55 | return [ quaternion.X, quaternion.Y, quaternion.Z, quaternion.W ];
56 | }
57 |
58 | public static Quaternion ToQuaternion(this float[] arr)
59 | {
60 | if (arr == null || arr.Length != 4)
61 | throw new ArgumentException("Array length must be 4");
62 |
63 | return new Quaternion(arr[0], arr[1], arr[2], arr[3]);
64 | }
65 |
66 | // Matrix3x2
67 | public static float[] ToArray(this Matrix3x2 mat)
68 | {
69 | return
70 | [
71 | mat.M11, mat.M12,
72 | mat.M21, mat.M22,
73 | mat.M31, mat.M32
74 | ];
75 | }
76 |
77 | // Matrix4x4
78 | public static float[] ToArray(this Matrix4x4 mat)
79 | {
80 | return
81 | [
82 | mat.M11, mat.M12, mat.M13, mat.M14,
83 | mat.M21, mat.M22, mat.M23, mat.M24,
84 | mat.M31, mat.M32, mat.M33, mat.M34,
85 | mat.M41, mat.M42, mat.M43, mat.M44,
86 | ];
87 | }
88 |
89 | // Plane
90 | public static float[] ToArray(this Plane value)
91 | {
92 | return [ value.Normal.X, value.Normal.Y, value.Normal.Z, value.D ];
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/source/Styles/BorderStyle.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 | namespace NanoUI.Styles
3 | {
4 | ///
5 | /// Global border style.
6 | ///
7 | public struct BorderStyle
8 | {
9 | ///
10 | /// Dark
11 | ///
12 | public Color Dark { get; set; }
13 |
14 | ///
15 | /// Light
16 | ///
17 | public Color Light { get; set; }
18 |
19 | ///
20 | /// Medium
21 | ///
22 | public Color Medium { get; set; }
23 |
24 | ///
25 | /// Pointer focus color.
26 | ///
27 | public Color PointerFocus { get; set; }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/source/Styles/CommonStyle.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 |
3 | namespace NanoUI.Styles
4 | {
5 | ///
6 | /// Global common style is used to set some widgets common properties
7 | /// in order to achieve some visual consistency.
8 | ///
9 | public struct CommonStyle
10 | {
11 | ///
12 | /// Accent color can be used to highlight some area.
13 | ///
14 | /// Not all widgets use this.
15 | public Color AccentColor { get; set; }
16 |
17 | ///
18 | /// Sunken background brush can be used to have some consistent, "sunken" look in widgets.
19 | ///
20 | public BrushBase? BackgroundSunken { get; set; }
21 |
22 | ///
23 | /// Disabled background brush.
24 | ///
25 | public BrushBase? BackgroundDisabled { get; set; }
26 |
27 | ///
28 | /// Invalid background brush is used to indicate invalid status
29 | /// (like invalid entry in UITextField).
30 | ///
31 | public BrushBase? BackgroundInvalid { get; set; }
32 |
33 | ///
34 | /// Background hover tint color.
35 | ///
36 | public Color? BackgroundHoverTint { get; set; }
37 |
38 | ///
39 | /// Frontend disabled color is used,
40 | /// when widget must draw widgets frontend (like text) disabled.
41 | ///
42 | public Color FrontendDisabledColor { get; set; }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/source/Styles/DockingStyle.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 | using System.Numerics;
3 |
4 | namespace NanoUI.Styles
5 | {
6 | ///
7 | /// Global docking style is only used in docking.
8 | ///
9 | public struct DockingStyle
10 | {
11 | ///
12 | /// Hit area corner radius.
13 | ///
14 | public float HitAreaCornerRadius { get; set; }
15 |
16 | ///
17 | /// Hit area background color.
18 | ///
19 | public Color HitAreaBackgroundColor { get; set; }
20 |
21 | ///
22 | /// Hit area fill brush is for hit area visualization (left, top, right, bottom, center).
23 | ///
24 | public BrushBase? HitAreaFillBrush { get; set; }
25 |
26 | ///
27 | /// Docking overlay area color to show, where docking is going to be performed.
28 | ///
29 | public Color OverlayColor { get; set; }
30 |
31 | ///
32 | /// Title background focused brush.
33 | ///
34 | public BrushBase? TitleBackgroundFocused { get; set; }
35 |
36 | ///
37 | /// Title background unfocused brush.
38 | ///
39 | public BrushBase? TitleBackgroundUnfocused { get; set; }
40 |
41 | ///
42 | /// Title font type.
43 | ///
44 | public string? TitleFontType { get; set; }
45 |
46 | ///
47 | /// Title font size.
48 | ///
49 | public float TitleFontSize { get; set; }
50 |
51 | ///
52 | /// Title button size.
53 | ///
54 | public Vector2 TitleButtonSize { get; set; }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/source/Styles/FilesStyle.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 | using System;
3 |
4 | namespace NanoUI.Styles
5 | {
6 | ///
7 | /// Global file style.
8 | ///
9 | public struct FilesStyle
10 | {
11 | ///
12 | /// Hard drive color.
13 | ///
14 | public Color HardDriveColor { get; set; }
15 |
16 | ///
17 | /// Folder color
18 | ///
19 | public Color FolderColor { get; set; }
20 |
21 | ///
22 | /// File color.
23 | ///
24 | public Color FileColor { get; set; }
25 |
26 | ///
27 | /// Column definitions for details (UIFileFolderDetails).
28 | ///
29 | public ColumnDefinition[] DetailsColumns { get; set; } = Array.Empty();
30 |
31 | ///
32 | /// Column definitions for dropdown (UIFileFolderDropdown).
33 | ///
34 | public ColumnDefinition[] DropdownColumns { get; set; } = Array.Empty();
35 |
36 | ///
37 | /// Column definitions for list (UIFileFolderList).
38 | ///
39 | public ColumnDefinition[] ListColumns { get; set; } = Array.Empty();
40 |
41 | ///
42 | /// Column definitions for tree (UIFileFolderTree).
43 | ///
44 | public ColumnDefinition[] TreeColumns { get; set; } = Array.Empty();
45 |
46 | public FilesStyle() { }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/source/Styles/PointerStyle.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 | using NanoUI.Nvg;
3 | using System.Numerics;
4 |
5 | namespace NanoUI.Styles
6 | {
7 | ///
8 | /// Global pointer style
9 | ///
10 | public struct PointerStyle
11 | {
12 | ///
13 | /// Default pointer type when no other specified or ResetPointerType called.
14 | ///
15 | public int PointerType { get; set; }
16 |
17 | ///
18 | /// Pointer marker color can be used to "mark" position in the display.
19 | ///
20 | /// Can be used in post draw phase.
21 | public Color MarkerColor { get; set; }
22 |
23 | ///
24 | /// Radius for pointer marker circle. Default: 14.
25 | ///
26 | public float MarkerRadius { get; set; } = 14f;
27 |
28 | ///
29 | /// Constructor.
30 | ///
31 | public PointerStyle() { }
32 |
33 | ///
34 | /// Draws pointer marker circle with color & radius to given position.
35 | ///
36 | /// NvgContext
37 | /// Circle center
38 | public void DrawMarker(NvgContext ctx, Vector2 position)
39 | {
40 | ctx.BeginPath();
41 | ctx.Circle(position, MarkerRadius);
42 | ctx.FillColor(MarkerColor);
43 | ctx.Fill();
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/source/Styles/ScrollbarStyle.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 |
3 | namespace NanoUI.Styles
4 | {
5 | ///
6 | /// Global scrollbar style.
7 | /// Note: UIScrollbar is not themable widget, so we must have global style.
8 | ///
9 | public struct ScrollbarStyle
10 | {
11 | ///
12 | /// Scrollbar dimension.
13 | ///
14 | public uint ScrollbarDimension { get; set; }
15 |
16 | ///
17 | /// Background enabled brush.
18 | ///
19 | public BrushBase? BackgroundEnabled { get; set; }
20 |
21 | ///
22 | /// Slider brush.
23 | ///
24 | public BrushBase? SliderBrush { get; set; }
25 |
26 | ///
27 | /// Slider hover tint color.
28 | ///
29 | public Color SliderHoverTint { get; set; }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/source/Styles/WindowStyle.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 |
3 | namespace NanoUI.Styles
4 | {
5 | ///
6 | /// Global window style has properties, that are same to all window instances.
7 | ///
8 | public struct WindowStyle
9 | {
10 | ///
11 | /// Border focused color.
12 | ///
13 | public Color BorderFocusedColor { get; set; }
14 |
15 | ///
16 | /// Border unfocused color.
17 | ///
18 | public Color BorderUnfocusedColor { get; set; }
19 |
20 | ///
21 | /// Border resizing color.
22 | ///
23 | public Color BorderResizingColor { get; set; }
24 |
25 | ///
26 | /// DragAreaWidth determines the area (border) width where we track if drag is happening.
27 | /// Default: 10,
28 | ///
29 | public uint DragAreaWidth { get; set; } = 10;
30 |
31 | ///
32 | /// Resizing triangle size in the UIWindows' bottom-right corner. Default: 25,
33 | ///
34 | public float ResizingTriangleSize { get; set; } = 25f;
35 |
36 | ///
37 | /// Constructor.
38 | ///
39 | public WindowStyle() { }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/source/Svg/Data/SvgGradientStop.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 |
3 | namespace NanoUI.Svg.Data
4 | {
5 | internal struct SvgGradientStop
6 | {
7 | // defines where the gradient stop is placed along the gradient vector.
8 | public float Offset;
9 | // defines the color of the gradient stop.
10 | public Color StopColor;
11 | // defines the opacity of the gradient stop.
12 | public float StopOpacity;
13 |
14 | public bool IsPercent;
15 | }
16 | }
--------------------------------------------------------------------------------
/source/Svg/Data/SvgLinearGradient.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 | using NanoUI.Nvg.Data;
3 | using System;
4 | using System.Numerics;
5 |
6 | namespace NanoUI.Svg.Data
7 | {
8 | // note: we treat all values as percentages
9 | internal struct SvgLinearGradient
10 | {
11 | // Defines a unique id for the element
12 | public string id;
13 | // The x position of the starting point of the vector gradient. Default is 0%
14 | public float x1;
15 | // The x position of the ending point of the vector gradient. Default is 100%
16 | public float x2;
17 | // The y position of the starting point of the vector gradient. Default is 0%
18 | public float y1;
19 | // y2 The y position of the ending point of the vector gradient. Default is 0%
20 | public float y2;
21 |
22 | // collect stops here
23 | public SvgGradientStop[] Stops;
24 |
25 | public bool TryGetPaint(NvgBounds bounds, out Paint paint)
26 | {
27 | // not valid values
28 | if (Stops == null || Stops.Length < 2 && string.IsNullOrEmpty(id))
29 | {
30 | paint = default;
31 | return false;
32 | }
33 |
34 | // convert to proportional values (range 0 .. 1)
35 | float sx = Math.Clamp(x1 / 100, 0, 1);
36 | float sy = Math.Clamp(y1 / 100, 0, 1);
37 | float ex = Math.Clamp(x2 / 100, 0, 1);
38 | float ey = Math.Clamp(y2 / 100, 0, 1);
39 |
40 | // convert to world space
41 | Vector2 start = bounds.Min + new Vector2(sx, sy) * (bounds.Max - bounds.Min);
42 | Vector2 end = bounds.Min + new Vector2(ex, ey) * (bounds.Max - bounds.Min);
43 |
44 | // get colors
45 | // start
46 | Color startColor = new Color(Stops[0].StopColor, Math.Clamp(Stops[0].StopOpacity, 0, 1));
47 | // we support only 2 stops - take last
48 | Color endColor = new Color(
49 | Stops[Stops.Length - 1].StopColor,
50 | Math.Clamp(Stops[Stops.Length - 1].StopOpacity, 0, 1));
51 |
52 | // create paint
53 | paint = Paint.LinearGradient(start, end, startColor, endColor);
54 |
55 | return true;
56 | }
57 | }
58 | }
--------------------------------------------------------------------------------
/source/Svg/Data/SvgPath.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Nvg.Data;
2 |
3 | namespace NanoUI.Svg.Data
4 | {
5 | // this is the result - it is drawn in own BeginPath() function
6 | internal struct SvgPath
7 | {
8 | // collected commands
9 | public NvgPathCommand[] Commands;
10 |
11 | // style info (fill, stroke etc)
12 | public SvgStyle Style;
13 |
14 | public NvgBounds Bounds;
15 |
16 | // transform already applied when commands created
17 | }
18 | }
--------------------------------------------------------------------------------
/source/Svg/Data/SvgRadialGradient.cs:
--------------------------------------------------------------------------------
1 | using NanoUI.Common;
2 | using NanoUI.Nvg.Data;
3 | using System;
4 | using System.Numerics;
5 |
6 | namespace NanoUI.Svg.Data
7 | {
8 | // note: we treat all values as percentages
9 |
10 | // todo: this is not entirely correct!
11 | internal struct SvgRadialGradient
12 | {
13 | // Defines a unique id for the element
14 | public string id;
15 | // The x position of the end circle of the radial gradient. Default is 50%
16 | public float cx;
17 | // The y position of the end circle of the radial gradient. Default is 50%
18 | public float cy;
19 | // The radius of the start circle of the radial gradient. Default is 0%
20 | //public float fr;
21 | // The x position of the start circle of the radial gradient. Default is 50%
22 | public float fx;
23 | // The y position of the start circle of the radial gradient. Default is 50%
24 | public float fy;
25 | // The radius of the end circle of the radial gradient. Default is 50%
26 | public float r;
27 |
28 | // collect stops here
29 | public SvgGradientStop[] Stops;
30 |
31 | public bool TryGetPaint(NvgBounds bounds, out Paint paint)
32 | {
33 | // not valid values
34 | if (Stops == null || Stops.Length < 2 && string.IsNullOrEmpty(id))
35 | {
36 | paint = default;
37 | return false;
38 | }
39 |
40 | // convert to proportional values
41 | float _cx = Math.Clamp(cx / 100, 0, 1);
42 | float _cy = Math.Clamp(cy / 100, 0, 1);
43 | //float _r1 = Math.Clamp(fx / 100, 0, 1);
44 | //float _r2 = Math.Clamp(fy / 100, 0, 1);
45 | float _r = Math.Clamp(r / 100, 0, 1);
46 |
47 | // support misplaced center
48 | Vector2 center = bounds.Min + (new Vector2(_cx, _cy) * (bounds.Max - bounds.Min));
49 |
50 | Vector2 rad = bounds.Min + new Vector2(_r) * (bounds.Max - bounds.Min);
51 | rad = new Vector2(_r) * (bounds.Max - bounds.Min);
52 |
53 | float inr = 0;
54 | float outr = rad.Y < rad.X? rad.Y : rad.X;
55 |
56 | Color innerColor = new Color(Stops[0].StopColor, Math.Clamp(Stops[0].StopOpacity, 0, 1));
57 | Color outerColor = new Color(
58 | Stops[Stops.Length - 1].StopColor,
59 | Math.Clamp(Stops[Stops.Length - 1].StopOpacity, 0, 1));
60 |
61 | // create paint
62 | paint = Paint.RadialGradient(center, inr, outr, innerColor, outerColor);
63 |
64 | return true;
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/source/Svg/Data/SvgShape.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Numerics;
3 |
4 | namespace NanoUI.Svg.Data
5 | {
6 | // collect here all params from