├── .github
└── workflows
│ └── build.yml
├── .gitignore
├── LICENSE
├── README.md
├── config.nims
├── docs
├── banner.png
├── minimal.png
├── minimalHTML.png
└── uiExampleIce.png
├── examples
├── areas
│ ├── README.md
│ ├── areas.nim
│ └── screenshot.png
├── config.nims
├── demo
│ ├── README.md
│ ├── data
│ │ ├── IBMPlexSans-Bold.ttf
│ │ ├── IBMPlexSans-Regular.ttf
│ │ ├── arrow.flippy
│ │ ├── arrow.png
│ │ ├── arrow.slate
│ │ ├── arrow@2x.png
│ │ ├── img1.png
│ │ ├── img2.png
│ │ ├── img3.png
│ │ ├── img4.png
│ │ ├── img5.png
│ │ ├── img6.png
│ │ ├── img7.png
│ │ ├── img8.png
│ │ └── img9.png
│ ├── demo.nim
│ └── screenshot.png
├── gradaui
│ ├── data
│ │ ├── MaterialIcons-Regular.ttf
│ │ ├── Montserrat-Bold.ttf
│ │ ├── Montserrat-Regular.ttf
│ │ └── shell.html
│ ├── gradaui.data
│ ├── gradaui.html
│ ├── gradaui.nim
│ ├── gradaui.nims
│ └── gradaui.wasm
├── hn
│ ├── data
│ │ └── IBMPlexSans-Regular.ttf
│ ├── hn.nim
│ └── hn.nims
├── minimal
│ ├── minimal.nim
│ └── screenshot.png
├── padofcode
│ ├── data
│ │ └── Inconsolata-Regular.ttf
│ ├── padofcode.nim
│ └── screenshot.png
└── padoftext
│ ├── data
│ └── IBMPlexSans-Regular.ttf
│ ├── padoftext.nim
│ └── screenshot.png
├── fidget.nimble
├── figma_plugin
├── code.ts
├── figma.d.ts
├── figma.nim
├── manifest.json
└── tsconfig.json
├── src
├── fidget.nim
├── fidget
│ ├── _cairo.nim
│ ├── _flippy.nim
│ ├── common.nim
│ ├── dom2.nim
│ ├── html
│ │ └── ajax.nim
│ ├── htmlbackend.nim
│ ├── input.nim
│ ├── internal.nim
│ ├── nullbackend.nim
│ ├── opengl
│ │ ├── base.nim
│ │ ├── buffers.nim
│ │ ├── context.nim
│ │ ├── formatflippy.nim
│ │ ├── glsl
│ │ │ ├── 410
│ │ │ │ ├── atlas.frag
│ │ │ │ ├── atlas.vert
│ │ │ │ └── mask.frag
│ │ │ ├── atlas.frag
│ │ │ ├── atlas.vert
│ │ │ ├── emscripten
│ │ │ │ ├── atlas.frag
│ │ │ │ ├── atlas.vert
│ │ │ │ └── mask.frag
│ │ │ └── mask.frag
│ │ ├── perf.nim
│ │ ├── shaders.nim
│ │ └── textures.nim
│ └── openglbackend.nim
└── shell_minimal.html
└── tests
├── _old
├── IBMPlexSans-Regular.svg
├── IBMPlexSans-Regular.ttf
├── Inconsolata.otf
├── Inconsolata.svg
├── Ubuntu.svg
├── Ubuntu.ttf
├── build_android.sh
├── build_ios.sh
└── todo
│ ├── README.md
│ ├── data
│ ├── IBMPlexSans-Bold.ttf
│ ├── IBMPlexSans-Regular.ttf
│ ├── arrow.png
│ ├── arrow.slate
│ ├── arrow@2x.png
│ ├── icon.png
│ └── icon@2x.png
│ └── todo.nim
├── autolayoutcomplex
├── autolayoutcomplex.nim
└── screenshot.png
├── autolayouthorizontal
├── autolayouthorizontal.nim
└── screenshot.png
├── autolayouttext
├── autolayouttext.nim
├── data
│ └── Ubuntu.ttf
└── screenshot.png
├── autolayoutvertical
├── autolayoutvertical.nim
└── screenshot.png
├── bars
├── README.md
├── bars.nim
└── screenshot.png
├── bluestar.flippy
├── bluestar.png
├── centercentertext
├── centercentertext.nim
├── data
│ └── IBMPlexSans-Regular.ttf
└── screenshot.png
├── config.nims
├── constraints
├── constraints.nim
└── screenshot.png
├── constrantscenteroffset
├── constrantscenteroffset.nim
└── screenshot.png
├── context_test.nim
├── cursorstyle
├── cursorstyle.nim
└── screenshot.png
├── exportorder
├── exportorder.nim
└── screenshot.png
├── fontmetrics
├── data
│ ├── Changa-Bold.ttf
│ ├── IBMPlexSans-Regular.ttf
│ ├── Jura-Regular.ttf
│ ├── Lato-Regular.ttf
│ ├── SourceSansPro-Regular.ttf
│ ├── Ubuntu.ttf
│ └── silver.ttf
├── fontmetrics.nim
└── screenshot.png
├── hovers
├── README.md
├── hovers.nim
└── screenshot.png
├── httpget
├── data
│ └── IBMPlexSans-Regular.ttf
├── httpget.nim
└── httpget.nims
├── image_basic.png
├── image_masking.png
├── image_scale.png
├── imagegen
├── data
│ └── generated.png
└── imagegen.nim
├── images
├── data
│ ├── img1.png
│ ├── img2.png
│ ├── img3.png
│ ├── img4.png
│ ├── img5.png
│ ├── img6.png
│ ├── img7.png
│ ├── img8.png
│ └── img9.png
├── images.nim
└── screenshot.png
├── imagestatic
└── imagestatic.nim
├── inputsandoutputs
├── data
│ └── Ubuntu.ttf
├── inputsandoutputs.nim
└── screenshot.png
├── inputtest
├── data
│ └── IBMPlexSans-Regular.ttf
├── inputtest.nim
└── screenshot.png
├── inputtoggle
├── data
│ └── IBMPlexSans-Regular.ttf
├── inputtoggle.nim
└── screenshot.png
├── masking.png
├── masks
├── data
│ └── IBMPlexSans-Regular.ttf
├── masks.nim
└── screenshot.png
├── multi_masking.png
├── multi_masking_pop.png
├── opengltester.nim
├── orangeHex.flippy
├── orangeHex.png
├── pixelscaling
├── data
│ └── Ubuntu.ttf
├── pixelscaling.nim
└── screenshot.png
├── pluginexport
├── data
│ ├── testBg.png
│ └── testLogo.png
├── figmatests.nim
├── pluginexport.nim
└── screenshot.png
├── rounded.png
├── run.nim
├── scale.png
├── setwindowbounds
└── setwindowbounds.nim
├── sprite_basic.png
├── test.nim
├── textalign
├── README.md
├── data
│ └── IBMPlexSans-Regular.ttf
├── screenshot.png
└── textalign.nim
├── textalignexpand
├── data
│ └── Ubuntu.ttf
├── screenshot.png
└── textalignexpand.nim
├── textalignfixed
├── data
│ └── Ubuntu.ttf
├── screenshot.png
└── textalignfixed.nim
├── textandinputs
├── README.md
├── data
│ └── IBMPlexSans-Regular.ttf
├── screenshot.png
└── textandinputs.nim
├── textswitcher
└── textswicher.nim
├── translate.png
├── winFrame.flippy
├── winFrame.png
├── winFrameMask.flippy
└── winFrameMask.png
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Run tests
2 | on: [push, pull_request]
3 | jobs:
4 | build:
5 | runs-on: ubuntu-latest
6 |
7 | steps:
8 | - uses: actions/checkout@v1
9 |
10 | - name: Cache choosenim
11 | id: cache-choosenim
12 | uses: actions/cache@v1
13 | with:
14 | path: ~/.choosenim
15 | key: ${{ runner.os }}-choosenim-stable
16 |
17 | - name: Cache nimble
18 | id: cache-nimble
19 | uses: actions/cache@v1
20 | with:
21 | path: ~/.nimble
22 | key: ${{ runner.os }}-nimble-stable
23 |
24 | - uses: jiro4989/setup-nim-action@v1
25 |
26 | - name: Install GUI
27 | run: |
28 | sudo apt update
29 | sudo apt install -y build-essential libalut-dev libasound2-dev libc6-dev libgl1-mesa-dev libglu1-mesa-dev libxcursor-dev libxi-dev libxinerama-dev libxrandr-dev libxxf86vm-dev mesa-utils pkg-config xorg-dev xvfb
30 | - run: nimble install -y
31 | - run: nim c -r tests/run.nim --compile --native --js
32 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # ignore files with no extention:
2 | *
3 | !*/
4 | !*.*
5 |
6 | # normal ignores:
7 | .*
8 | *.exe
9 | *.js
10 | nimcache
11 | cairo
12 | *.dylib
13 | *.dll
14 | ios_bars
15 | android_bars
16 | tmp
17 | node_modules
18 | package-lock.json
19 | *.flippy
20 | wasm
21 | *.html
22 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT
2 |
3 | Copyright 2020 Andre von Houck
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | 👏 👏 👏 Check out video about the library: [Fidget: Let's rethink UI development with Nim (NimConf 2020)](https://www.youtube.com/watch?v=IB8Yt2dqZbo) 👏 👏 👏
4 |
5 | ⚠️ WARNING: This library is still in heavy development. ⚠️
6 |
7 | # Fidget - A cross platform UI library for nim
8 |
9 | `nimble install fidget`
10 |
11 | 
12 |
13 | [API reference](https://nimdocs.com/treeform/fidget)
14 |
15 | ## About
16 |
17 | Fidget aims to provide performant natively compiled cross platform UIs for any platform - Web with HTML5, Windows, macOS, Linux, iOS and Android with OpenGL.
18 |
19 | Fidget leverages [Figma](https://www.figma.com/) - an app that is taking the design world by storm. It does this by providing a [Figma Plugin](figma_plugin/code.ts) to export directly to fidget code! No more counting stupid pixels, no more CSS puzzles. Want to change some spaces? Change it in Figma and export.
20 |
21 | Fidget uses plain nim-procs, nim-templates, if-statements and for-loops. As well as providing only minimal primitives found in [Figma](https://www.figma.com/).
22 |
23 | ## Example:
24 |
25 |
26 |
27 |
28 |
29 |
30 | Design done by Kate von Houck. Available for hire.
31 |
32 |
33 | See code here: [examples/demo/demo.nim](examples/demo/demo.nim)
34 |
35 | ## Minimal Sample:
36 |
37 | ```nim
38 | import fidget, vmath
39 |
40 | proc drawMain() =
41 | frame "main":
42 | box 0, 0, 620, 140
43 | for i in 0 .. 4:
44 | group "block":
45 | box 20+i*120, 20, 100, 100
46 | fill "#2B9FEA"
47 |
48 | windowFrame = vec2(620, 140)
49 | startFidget(drawMain)
50 | ```
51 |
52 |
53 |
54 |
55 |
56 |
57 | See code here: [examples/minimal/minimal.nim](examples/minimal/minimal.nim)
58 |
59 |
60 | # Backends
61 |
62 | Fidget has several backends that are planned:
63 | * HTML (best supported)
64 | * Windows (next best support)
65 | * Mac (less support)
66 | * Linux (less support)
67 | * iOS (proof of concept only)
68 | * Android (proof of concept only)
69 |
70 | # Philosophy - Minimalism
71 |
72 | * Mimic how [Figma](https://www.figma.com/) (Amazing UI/UX app) does it.
73 | * Everything is a Node.
74 | * There are Group, Rectangle, Image and Text Nodes.
75 | * Nodes are positions relative to the parent
76 | * Nodes have minimal set of properties that match Figma.
77 | * Resizing is done same way as Fimga's [Constraints](https://www.youtube.com/watch?v=rRQAQ1d9q9w).
78 | * Layout is done same way as Figma's [Auto Layout](https://www.youtube.com/watch?v=NrKX46DzkGQ).
79 |
80 | The main idea of fidget is to use standard imperative nim paradigms like nim-procs, nim-for-loops, nim-ifs, nim-templates instead of say providing a custom language, XML templates, HTML, Jinja templates, CSS ...
81 |
82 | Instead of creating CSS classes you just create a nim proc or a nim template with the things you want and reuse that. Instead of having some sort of list controller you just use a for loop to position your list elements.
83 |
84 | There are very little UI layout primitives just align left, center, right, both, or scale for the X axis and top, center, bottom, both, or scale for the Y axis. There is none of margin, padding, float, absolute, relative, border box, flex, recycle view controllers, stack layout, constraints ...
85 |
86 | If you want to do something fancy just do a little math. Many times a simple math formula is smaller, simpler, and easier to figure out then layout puzzles.
87 |
88 | # Why Nim?
89 |
90 | Nim is a great languages because it’s easy on the eyes like Python, but typed and is performant as C. It can also compile to JavaScript, C, C++, ObjC. Nim is a great language for UI design because it has advanced templates and macros can make a really good DSL (domain specific language) - that makes writing UIs straightforward, intuitive and crossplatform.
91 |
92 | # Imperative UI Style
93 |
94 | I like imperative style of programming. This is a style you probably learned to program at the start, but was forced to abandon with more complex and ill fitting object oriented style. Imperative style to me means when you are only using functions, if-statements and for-loops. Imperative style to me means simple data structures of structs, lists and tables. Simple functions that read from top to bottom with as few branches as possible.
95 |
96 | Each UI frame is drawn completely from start to finish all in the code you control. Use of callbacks is discouraged. Think liner, think simple. After any event by the user, data or timer, the UI is redrawn. The UI is redrawn in an efficient way as to allow this. With HTML a modification cache is used to ensure only a minimal amount of DOM changes are needed. With OpenGL you redraw the whole screen using as few state transitions and batching everything into a texture atlas and single global vertex buffer.
97 |
98 |
99 | ## How to run the examples:
100 |
101 |
102 | ```sh
103 | git clone https://github.com/treeform/fidget
104 | cd fidget
105 | nimble install
106 | cd examples/minimal
107 | nim c -r minimal
108 | ```
109 |
110 | ### Native examples for Windows, macOS, and Linux:
111 |
112 | First `cd` to each folder then compile and run.
113 |
114 | ```sh
115 | nim c -r bars.nim
116 | nim c -r hovers.nim
117 | nim c -r inputs.nim
118 | nim c -r padoftext.nim
119 | nim c -r padofcode.nim
120 | nim c -r basic.nim
121 | ```
122 |
123 | ### Runs the same examples as HTML:
124 |
125 | First `cd` to each folder then run `js` compile command then open the `.html` file in a browser.
126 |
127 | ```sh
128 | nim js bars.nim
129 | nim js hovers.nim
130 | nim js inputs.nim
131 | nim js padoftext.nim
132 | nim js padofcode.nim
133 | nim js basic.nim
134 | ```
135 |
136 | ## Run all tests and save a screenshot
137 |
138 | ```sh
139 | nim c -r tests/run --compile --native --testOneFrame
140 | ```
141 |
142 | ## Figma Plug
143 |
144 | To compile the figma plug run TypeScript in the figma_plugin folder.
145 |
146 | ```sh
147 | tsc
148 | ```
149 |
150 | Then go to figma and add a development plugin from this folder.
151 |
--------------------------------------------------------------------------------
/config.nims:
--------------------------------------------------------------------------------
1 | switch("styleCheck", "hint")
2 |
3 | if defined(emscripten):
4 | # This path will only run if -d:emscripten is passed to nim.
5 |
6 | --nimcache:tmp # Store intermediate files close by in the ./tmp dir.
7 |
8 | --os:linux # Emscripten pretends to be linux.
9 | --cpu:i386 # Emscripten is 32bits.
10 | --cc:clang # Emscripten is very close to clang, so we ill replace it.
11 | --clang.exe:emcc.bat # Replace C
12 | --clang.linkerexe:emcc.bat # Replace C linker
13 | --clang.cpp.exe:emcc.bat # Replace C++
14 | --clang.cpp.linkerexe:emcc.bat # Replace C++ linker.
15 | --listCmd # List what commands we are running so that we can debug them.
16 |
17 | --gc:arc # GC:arc is friendlier with crazy platforms.
18 | --exceptions:goto # Goto exceptions are friendlier with crazy platforms.
19 |
20 | --d:noSignalHandler
21 |
22 | # Pass this to Emscripten linker to generate html file scaffold for us.
23 | # switch("passL", "-o wasm.html")
24 | # #switch("--preload-file data")
25 | # switch("--shell-file src/shell_minimal.html")
26 |
--------------------------------------------------------------------------------
/docs/banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/docs/banner.png
--------------------------------------------------------------------------------
/docs/minimal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/docs/minimal.png
--------------------------------------------------------------------------------
/docs/minimalHTML.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/docs/minimalHTML.png
--------------------------------------------------------------------------------
/docs/uiExampleIce.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/docs/uiExampleIce.png
--------------------------------------------------------------------------------
/examples/areas/README.md:
--------------------------------------------------------------------------------
1 | # Example for code + output pad simmilar to iPython, Mathematica or beta.observablehq.com.
2 |
--------------------------------------------------------------------------------
/examples/areas/areas.nim:
--------------------------------------------------------------------------------
1 | import fidget
2 |
3 | type
4 | Area = ref object
5 | title: string
6 | label: string
7 | queryCode: string
8 | expanded: bool
9 | heightOuput: int
10 | heightCode: int
11 | editing: bool
12 |
13 | var
14 | areas = newSeq[Area]()
15 | editingArea: Area
16 |
17 | areas.add Area(
18 | queryCode: "1+1",
19 | heightCode: 200,
20 | heightOuput: 200
21 | )
22 |
23 | areas.add Area(
24 | queryCode: "1*3*32",
25 | expanded: false,
26 | heightCode: 200,
27 | heightOuput: 100
28 | )
29 |
30 | areas.add Area(
31 | queryCode: "one three two",
32 | label: "text",
33 | heightCode: 200,
34 | heightOuput: 300
35 | )
36 |
37 | proc drawMain() =
38 | var totalPageHeight = 120
39 | for area in areas:
40 | totalPageHeight += area.heightOuput
41 | if area.expanded:
42 | totalPageHeight += area.heightCode
43 |
44 | totalPageHeight = max(totalPageHeight, root.box.h.int)
45 | let width = 1000
46 |
47 | frame "main":
48 | box 0, 0, root.box.w, totalPageHeight
49 | fill "#F7F7F9"
50 |
51 | group "center":
52 | box (int(parent.box.w) - width) / 2, 0, width, totalPageHeight
53 | fill "#FFFFFF"
54 |
55 | var atY = 60
56 |
57 | for i, area in areas.mpairs:
58 | group "area":
59 |
60 | var height = area.heightOuput
61 | if area.expanded:
62 | height += area.heightCode
63 |
64 | box 0, atY, root.box.w, height
65 |
66 | rectangle "codeExpander":
67 | box -26, 0, 16, 16
68 | fill "#AEB5C0"
69 |
70 | onHover:
71 | fill "#FF4400"
72 |
73 | onClick:
74 | area.expanded = not area.expanded
75 | mouse.consume()
76 |
77 | rectangle "reRun":
78 | box width + 10, 0, 16, 16
79 | fill "#AEB5C0"
80 | onHover:
81 | fill "#FF4400"
82 |
83 | onClick:
84 | mouse.consume()
85 |
86 | var innerAtY = 0
87 | if area.expanded:
88 | group "codeEditor":
89 | box 0, 0, width, area.heightCode
90 | innerAtY += area.heightCode
91 | rectangle "codeBg":
92 | box 0, 0, width, area.heightCode
93 | if editingArea == area:
94 | fill "#e0e0f0"
95 | else:
96 | fill "#edeff3"
97 |
98 | group "codeText":
99 | box 20, 20, width-40, area.heightCode-40
100 | fill "#000000"
101 | characters area.queryCode
102 |
103 | onClick:
104 | editingArea = area
105 | mouse.consume()
106 |
107 | onClickOutside:
108 | if editingArea == area:
109 | editingArea = nil
110 |
111 | group "resultsOutput":
112 | box 0, innerAtY, width, area.heightOuput
113 | fill "#FFFFFF"
114 |
115 | innerAtY += area.heightOuput
116 |
117 | atY += innerAtY
118 |
119 | startFidget(drawMain)
120 |
--------------------------------------------------------------------------------
/examples/areas/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/examples/areas/screenshot.png
--------------------------------------------------------------------------------
/examples/config.nims:
--------------------------------------------------------------------------------
1 | --path:"../src"
2 |
--------------------------------------------------------------------------------
/examples/demo/README.md:
--------------------------------------------------------------------------------
1 | # Demo - shows off some of the basic controls.
2 |
3 | Frame, button, text, checkbox, radio button, dropdown
4 |
--------------------------------------------------------------------------------
/examples/demo/data/IBMPlexSans-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/examples/demo/data/IBMPlexSans-Bold.ttf
--------------------------------------------------------------------------------
/examples/demo/data/IBMPlexSans-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/examples/demo/data/IBMPlexSans-Regular.ttf
--------------------------------------------------------------------------------
/examples/demo/data/arrow.flippy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/examples/demo/data/arrow.flippy
--------------------------------------------------------------------------------
/examples/demo/data/arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/examples/demo/data/arrow.png
--------------------------------------------------------------------------------
/examples/demo/data/arrow.slate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/examples/demo/data/arrow.slate
--------------------------------------------------------------------------------
/examples/demo/data/arrow@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/examples/demo/data/arrow@2x.png
--------------------------------------------------------------------------------
/examples/demo/data/img1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/examples/demo/data/img1.png
--------------------------------------------------------------------------------
/examples/demo/data/img2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/examples/demo/data/img2.png
--------------------------------------------------------------------------------
/examples/demo/data/img3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/examples/demo/data/img3.png
--------------------------------------------------------------------------------
/examples/demo/data/img4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/examples/demo/data/img4.png
--------------------------------------------------------------------------------
/examples/demo/data/img5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/examples/demo/data/img5.png
--------------------------------------------------------------------------------
/examples/demo/data/img6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/examples/demo/data/img6.png
--------------------------------------------------------------------------------
/examples/demo/data/img7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/examples/demo/data/img7.png
--------------------------------------------------------------------------------
/examples/demo/data/img8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/examples/demo/data/img8.png
--------------------------------------------------------------------------------
/examples/demo/data/img9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/examples/demo/data/img9.png
--------------------------------------------------------------------------------
/examples/demo/demo.nim:
--------------------------------------------------------------------------------
1 | ## A bunch of nice looking controls.
2 |
3 | import fidget
4 |
5 | loadFont("IBM Plex Sans", "IBMPlexSans-Regular.ttf")
6 | loadFont("IBM Plex Sans Bold", "IBMPlexSans-Bold.ttf")
7 |
8 | var
9 | textInputVar = ""
10 | checkBoxValue: bool
11 | radioBoxValue: bool
12 | selectedTab = "Controls"
13 | selectedButton = @["This"]
14 | pipDrag = false
15 | pipPos = 89
16 | progress = 20.0
17 | dropDownOpen = false
18 |
19 | proc basicText() =
20 | frame "autoLayoutText":
21 | box 130, 0, root.box.w - 130, 491
22 | fill "#ffffff"
23 | layout lmVertical
24 | counterAxisSizingMode csFixed
25 | horizontalPadding 30
26 | verticalPadding 30
27 | itemSpacing 10
28 | text "p2":
29 | box 30, 361, 326, 100
30 | fill "#000000"
31 | font "IBM Plex Sans", 14, 400, 20, hLeft, vTop
32 | characters "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
33 | textAutoResize tsHeight
34 | layoutAlign laStretch
35 | text "title2":
36 | box 30, 319, 326, 32
37 | fill "#000000"
38 | font "IBM Plex Sans", 20, 400, 32, hLeft, vTop
39 | characters "Lorem Ipsum"
40 | textAutoResize tsHeight
41 | layoutAlign laStretch
42 | text "imgCaption":
43 | box 30, 289, 326, 20
44 | fill "#9c9c9c"
45 | font "IBM Plex Sans", 14, 400, 20, hCenter, vTop
46 | characters "Lorem ipsum dolor sit ame"
47 | textAutoResize tsHeight
48 | layoutAlign laStretch
49 | rectangle "imgPlaceholder":
50 | box 125.5, 182, 135, 97
51 | fill "#5C8F9C"
52 | layoutAlign laCenter
53 | text "p1":
54 | box 30, 72, 326, 100
55 | fill "#000000"
56 | font "IBM Plex Sans", 14, 400, 20, hLeft, vTop
57 | characters "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
58 | textAutoResize tsHeight
59 | layoutAlign laStretch
60 | text "title1":
61 | box 30, 30, 326, 32
62 | fill "#000000"
63 | font "IBM Plex Sans", 20, 400, 32, hLeft, vTop
64 | characters "Lorem Ipsum"
65 | textAutoResize tsHeight
66 | layoutAlign laStretch
67 |
68 | proc basicControls() =
69 |
70 | group "dropdown":
71 | box 260, 115, 100, 20
72 | fill "#72bdd0"
73 | cornerRadius 5
74 | strokeWeight 1
75 | onHover:
76 | fill "#5C8F9C"
77 | onClick:
78 | dropDownOpen = not dropDownOpen
79 | instance "arrow":
80 | box 80, 0, 20, 20
81 | if dropDownOpen:
82 | rotation -90
83 | image "arrow.png"
84 | text "text":
85 | box 0, 0, 80, 20
86 | fill "#ffffff"
87 | strokeWeight 1
88 | font "IBM Plex Sans", 12, 200, 0, hCenter, vCenter
89 | characters "Dropdown"
90 |
91 | if dropDownOpen:
92 | frame "dropDown":
93 | box 0, 30, 100, 100
94 | fill "#ffffff"
95 | cornerRadius 5
96 | layout lmVertical
97 | counterAxisSizingMode csAuto
98 | horizontalPadding 0
99 | verticalPadding 0
100 | itemSpacing 0
101 | clipContent true
102 | for buttonName in reverse(@["Nim", "UI", "in", "100%", "Nim"]):
103 | group "button":
104 | box 0, 80, 100, 20
105 | layoutAlign laCenter
106 | fill "#72bdd0"
107 | onHover:
108 | fill "#5C8F9C"
109 | onClick:
110 | dropDownOpen = false
111 | text "text":
112 | box 0, 0, 100, 20
113 | fill "#ffffff"
114 | font "IBM Plex Sans", 12, 400, 0, hCenter, vCenter
115 | characters buttonName
116 |
117 | group "progress":
118 | box 260, 149, 250, 12
119 | fill "#ffffff"
120 | stroke "#70bdcf"
121 | cornerRadius 5
122 | strokeWeight 1
123 | rectangle "fill":
124 | progress = selectedButton.len / 5 * 100
125 | box 2, 2, int((parent.box.w - 4) * (progress/100)), 8
126 | fill "#9fe7f8"
127 | cornerRadius 5
128 |
129 | group "checkbox":
130 | box 152, 85, 91, 20
131 | onClick:
132 | checkBoxValue = not checkBoxValue
133 | rectangle "square":
134 | box 0, 2, 16, 16
135 |
136 | if checkBoxValue:
137 | fill "#9FE7F8"
138 | else:
139 | fill "#ffffff"
140 | stroke "#70bdcf"
141 | cornerRadius 5
142 | strokeWeight 1
143 | text "text":
144 | box 21, 0, 70, 20
145 |
146 | fill "#46607e"
147 | strokeWeight 1
148 | font "IBM Plex Sans", 12, 200, 0, hLeft, vCenter
149 | characters "Checkbox"
150 |
151 | group "radiobox":
152 | box 152, 115, 91, 20
153 | onClick:
154 | radioBoxValue = not radioBoxValue
155 | rectangle "circle":
156 | box 0, 2, 16, 16
157 | if radioBoxValue:
158 | fill "#9FE7F8"
159 | else:
160 | fill "#ffffff"
161 | stroke "#72bdd0"
162 | cornerRadius 8
163 | strokeWeight 1
164 | text "text":
165 | box 21, 0, 70, 20
166 | fill "#46607e"
167 | strokeWeight 1
168 | font "IBM Plex Sans", 12, 200, 0, hLeft, vCenter
169 | characters "Radiobox"
170 |
171 | group "slider":
172 | box 260, 90, 250, 10
173 | onClick:
174 | pipDrag = true
175 | if pipDrag:
176 | pipPos = int(mouse.pos.x - current.screenBox.x)
177 | pipPos = clamp(pipPos, 0, 240)
178 | pipDrag = buttonDown[MOUSE_LEFT]
179 | rectangle "pip":
180 | box pipPos, 0, 10, 10
181 | fill "#72bdd0"
182 | cornerRadius 5
183 | rectangle "fill":
184 | box 0, 3, pipPos, 4
185 | fill "#70bdcf"
186 | cornerRadius 2
187 | strokeWeight 1
188 | rectangle "bg":
189 | box 0, 3, 250, 4
190 | fill "#c2e3eb"
191 | cornerRadius 2
192 | strokeWeight 1
193 |
194 | frame "segmentedControl":
195 | box 260, 55, 250, 20
196 | fill "#72bdd0"
197 | cornerRadius 5
198 | layout lmHorizontal
199 | counterAxisSizingMode csAuto
200 | horizontalPadding 0
201 | verticalPadding 0
202 | itemSpacing 0
203 | for buttonName in reverse(@["This", "is", "a", "segmented", "button"]):
204 | group "Button":
205 | box 0, 0, buttonName.len * 9 + 10, 20
206 | layoutAlign laCenter
207 | if buttonName in selectedButton:
208 | fill "#ffffff", 0.5
209 | onHover:
210 | fill "#5C8F9C"
211 | onClick:
212 | if buttonName in selectedButton:
213 | selectedButton.del(selectedButton.find(buttonName))
214 | else:
215 | selectedButton.add(buttonName)
216 | text "text":
217 | box 0, 0, buttonName.len * 9 + 10, 20
218 | fill "#ffffff"
219 | font "IBM Plex Sans", 12, 400, 0, hCenter, vCenter
220 | characters buttonName
221 | rectangle "separator":
222 | box 0, 0, 1, 20
223 | fill "#ffffff", 0.5
224 |
225 | group "button":
226 | box 150, 55, 90, 20
227 | cornerRadius 5
228 | fill "#72bdd0"
229 | onHover:
230 | fill "#5C8F9C"
231 | onDown:
232 | fill "#3E656F"
233 | text "text":
234 | box 0, 0, 90, 20
235 | fill "#ffffff"
236 | font "IBM Plex Sans", 12, 200, 0, hCenter, vCenter
237 | characters "Button"
238 |
239 | group "input":
240 | box 260, 15, 250, 30
241 | text "text":
242 | box 9, 8, 232, 15
243 | fill "#46607e"
244 | strokeWeight 1
245 | font "IBM Plex Sans", 12, 200, 0, hLeft, vCenter
246 | binding textInputVar
247 | text "textPlaceholder":
248 | box 9, 8, 232, 15
249 | fill "#46607e", 0.5
250 | strokeWeight 1
251 | font "IBM Plex Sans", 12, 200, 0, hLeft, vCenter
252 | if textInputVar == "":
253 | characters "Start typing here"
254 | rectangle "bg":
255 | box 0, 0, 250, 30
256 | stroke "#72bdd0"
257 | cornerRadius 5
258 | strokeWeight 1
259 |
260 | group "label":
261 | box 150, 15, 100, 30
262 | text "Text field:":
263 | box 0, 0, 100, 30
264 | fill "#46607e"
265 | strokeWeight 1
266 | font "IBM Plex Sans", 12, 200, 0, hLeft, vCenter
267 | characters "Text field:"
268 |
269 | proc basicImage() =
270 | frame "images":
271 | box 130, 0, 400, 400
272 | fill "#ffffff"
273 | group "img1":
274 | box 260, 260, 100, 100
275 | image "img1.png"
276 | group "img2":
277 | box 260, 150, 100, 100
278 | image "img2.png"
279 | group "img3":
280 | box 260, 40, 100, 100
281 | image "img3.png"
282 | group "img4":
283 | box 150, 260, 100, 100
284 | image "img4.png"
285 | group "img5":
286 | box 150, 150, 100, 100
287 | image "img5.png"
288 | group "img6":
289 | box 150, 40, 100, 100
290 | image "img6.png"
291 | group "img7":
292 | box 40, 260, 100, 100
293 | image "img7.png"
294 | group "img8":
295 | box 40, 150, 100, 100
296 | image "img8.png"
297 | group "img9":
298 | box 40, 40, 100, 100
299 | image "img9.png"
300 |
301 | proc basicConstraints() =
302 | frame "constraints":
303 | # Got to specify orgBox for constraints to work.
304 | orgBox 0, 0, 400, 400
305 | # Then grow the normal box.
306 | box 130, 0, root.box.w - 130, root.box.h
307 | # Constraints will work on the difference between orgBox and box.
308 | fill "#ffffff"
309 | rectangle "Center":
310 | box 150, 150, 100, 100
311 | constraints cCenter, cCenter
312 | fill "#FFFFFF", 0.50
313 | rectangle "Scale":
314 | box 100, 100, 200, 200
315 | constraints cScale, cScale
316 | fill "#FFFFFF", 0.25
317 | rectangle "LRTB":
318 | box 40, 40, 320, 320
319 | constraints cStretch, cStretch
320 | fill "#70BDCF"
321 | rectangle "TR":
322 | box 360, 20, 20, 20
323 | constraints cMax, cMin
324 | fill "#70BDCF"
325 | rectangle "TL":
326 | box 20, 20, 20, 20
327 | constraints cMin, cMin
328 | fill "#70BDCF"
329 | rectangle "BR":
330 | box 360, 360, 20, 20
331 | constraints cMax, cMax
332 | fill "#70BDCF"
333 | rectangle "BL":
334 | box 20, 360, 20, 20
335 | constraints cMin, cMax
336 | fill "#70BDCF"
337 |
338 | proc drawMain() =
339 | setTitle("Fidget Example")
340 |
341 | component "iceUI":
342 | orgBox 0, 0, 530, 185
343 | box root.box
344 | fill "#ffffff"
345 |
346 | group "shadow":
347 | orgBox 0, 0, 530, 3
348 | box 0, 0, root.box.w, 3
349 | rectangle "l1":
350 | box 0, 0, 530, 1
351 | constraints cStretch, cMin
352 | fill "#000000", 0.10
353 | rectangle "l2":
354 | box 0, 1, 530, 1
355 | constraints cStretch, cMin
356 | fill "#000000", 0.07
357 | rectangle "l3":
358 | box 0, 2, 530, 1
359 | constraints cStretch, cMin
360 | fill "#000000", 0.03
361 |
362 | frame "verticalTabs":
363 | box 0, 15, 130, 120
364 | layout lmVertical
365 | counterAxisSizingMode csAuto
366 | horizontalPadding 0
367 | verticalPadding 0
368 | itemSpacing 0
369 |
370 | for tabName in ["Constraints", "Image", "Text", "Controls"]:
371 | group "tab":
372 | box 0, 0, 130, 30
373 | layoutAlign laCenter
374 | onHover:
375 | fill "#70bdcf", 0.5
376 | if selectedTab == tabName:
377 | fill "#70bdcf"
378 | onClick:
379 | selectedTab = tabName
380 | text "text":
381 | box 25, 0, 105, 30
382 | if selectedTab == tabName:
383 | fill "#ffffff"
384 | else:
385 | fill "#46607e"
386 | font "IBM Plex Sans", 12, 400, 12, hLeft, vCenter
387 | characters tabName
388 |
389 | rectangle "bg":
390 | box 0, 0, 130, 185
391 | constraints cMin, cStretch
392 | fill "#e5f7fe"
393 |
394 | case selectedTab:
395 | of "Controls":
396 | basicControls()
397 | of "Text":
398 | basicText()
399 | of "Image":
400 | basicImage()
401 | of "Constraints":
402 | basicConstraints()
403 |
404 | startFidget(drawMain, w = 530, h = 300)
405 |
--------------------------------------------------------------------------------
/examples/demo/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/examples/demo/screenshot.png
--------------------------------------------------------------------------------
/examples/gradaui/data/MaterialIcons-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/examples/gradaui/data/MaterialIcons-Regular.ttf
--------------------------------------------------------------------------------
/examples/gradaui/data/Montserrat-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/examples/gradaui/data/Montserrat-Bold.ttf
--------------------------------------------------------------------------------
/examples/gradaui/data/Montserrat-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/examples/gradaui/data/Montserrat-Regular.ttf
--------------------------------------------------------------------------------
/examples/gradaui/data/shell.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Emscripten-Generated Code
7 |
21 |
22 |
23 |
24 |
25 |
26 |
92 | {{{ SCRIPT }}}
93 |
94 |
95 |
--------------------------------------------------------------------------------
/examples/gradaui/gradaui.data:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/examples/gradaui/gradaui.data
--------------------------------------------------------------------------------
/examples/gradaui/gradaui.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Emscripten-Generated Code
7 |
21 |
22 |
23 |
24 |
25 |
26 |
92 |
93 |
94 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/examples/gradaui/gradaui.nims:
--------------------------------------------------------------------------------
1 | if defined(emscripten):
2 | # This path will only run if -d:emscripten is passed to nim.
3 |
4 | --nimcache:tmp # Store intermediate files close by in the ./tmp dir.
5 |
6 | --os:linux # Emscripten pretends to be linux.
7 | --cpu:i386 # Emscripten is 32bits.
8 | --cc:clang # Emscripten is very close to clang, so we ill replace it.
9 | --clang.exe:emcc.bat # Replace C
10 | --clang.linkerexe:emcc.bat # Replace C linker
11 | --clang.cpp.exe:emcc.bat # Replace C++
12 | --clang.cpp.linkerexe:emcc.bat # Replace C++ linker.
13 | --listCmd # List what commands we are running so that we can debug them.
14 |
15 | --d:useMalloc # regular malloc is friendlier with crazy platforms.
16 | --gc:arc # GC:arc is friendlier with crazy platforms.
17 | --exceptions:goto # Goto exceptions are friendlier with crazy platforms.
18 |
19 | --d:noSignalHandler
20 |
21 | # Pass this to Emscripten linker to generate html file scaffold for us.
22 | switch("passL", "-o gradaui.html -s ALLOW_MEMORY_GROWTH=1 --preload-file data --shell-file data/shell.html")
23 |
--------------------------------------------------------------------------------
/examples/gradaui/gradaui.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/examples/gradaui/gradaui.wasm
--------------------------------------------------------------------------------
/examples/hn/data/IBMPlexSans-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/examples/hn/data/IBMPlexSans-Regular.ttf
--------------------------------------------------------------------------------
/examples/hn/hn.nim:
--------------------------------------------------------------------------------
1 | ## Simple Haker News clone based on httpGet.
2 |
3 | import fidget, json, strformat, uri
4 |
5 | loadFont("IBM Plex Sans", "IBMPlexSans-Regular.ttf")
6 |
7 | setTitle("Hacker News")
8 |
9 | proc header() =
10 | component "header":
11 | box 0, 0, 596, 50
12 | fill "#f56400"
13 | layoutAlign laStretch
14 | group "logo":
15 | box 3, 3, 44, 44
16 | text "Y":
17 | box 2, 2, 40, 40
18 | fill "#ffffff"
19 | font "IBM Plex Sans", 30, 400, 0, hCenter, vCenter
20 | characters "Y"
21 | rectangle "border":
22 | box 0, 0, 44, 44
23 | stroke "#ffffff"
24 | strokeWeight 2
25 | text "title":
26 | box 58, 0, 178, 50
27 | fill "#ffffff"
28 | font "IBM Plex Sans", 30, 400, 0, hLeft, vCenter
29 | characters "Hacker News"
30 |
31 | proc news(id: string) =
32 | var call = httpGet(&"https://hacker-news.firebaseio.com/v0/item/{id}.json")
33 | if call.status != Ready:
34 | return
35 |
36 | frame "news":
37 | box 0, 50, 596, 50
38 | fill "#f6f6ef"
39 | layoutAlign laStretch
40 | frame "firstLine":
41 | box 11, 7, 485, 18
42 | layout lmHorizontal
43 | counterAxisSizingMode csFixed
44 | horizontalPadding 0
45 | verticalPadding 0
46 | itemSpacing 9
47 | text "domain":
48 | box 389, 0, 96, 18
49 | fill "#000000", 0.5
50 | font "IBM Plex Sans", 14, 400, 0, hLeft, vTop
51 | if "url" in call.json:
52 | let uri = parseUri(call.json["url"].getStr())
53 | characters "(" & uri.hostname & ")"
54 | textAutoResize tsWidthAndHeight
55 | layoutAlign laCenter
56 | text "title":
57 | box 18, 0, 362, 18
58 | fill "#000000"
59 | font "IBM Plex Sans", 14, 400, 0, hLeft, vTop
60 | characters call.json["title"].getStr()
61 | textAutoResize tsWidthAndHeight
62 | layoutAlign laCenter
63 | text "score":
64 | box 0, 0, 9, 18
65 | fill "#828282"
66 | font "IBM Plex Sans", 14, 700, 0, hLeft, vTop
67 | characters $call.json["score"].getInt()
68 | textAutoResize tsWidthAndHeight
69 | layoutAlign laCenter
70 | frame "secondLine":
71 | box 10, 26, 392, 18
72 | layout lmHorizontal
73 | counterAxisSizingMode csFixed
74 | horizontalPadding 0
75 | verticalPadding 0
76 | itemSpacing 4
77 | text "comments":
78 | box 305, 0, 87, 18
79 | fill "#000000", 0.5
80 | font "IBM Plex Sans", 14, 400, 0, hLeft, vTop
81 | if "descendants" in call.json:
82 | characters $call.json["descendants"].getInt() & " comments"
83 | textAutoResize tsWidthAndHeight
84 | layoutAlign laCenter
85 | text "bar":
86 | box 296, 0, 5, 18
87 | fill "#000000", 0.5
88 | font "IBM Plex Sans", 14, 400, 0, hLeft, vTop
89 | characters "|"
90 | textAutoResize tsWidthAndHeight
91 | layoutAlign laCenter
92 | text "hide":
93 | box 264, 0, 28, 18
94 | fill "#000000", 0.5
95 | font "IBM Plex Sans", 14, 400, 0, hLeft, vTop
96 | characters "hide"
97 | textAutoResize tsWidthAndHeight
98 | layoutAlign laCenter
99 | text "bar":
100 | box 255, 0, 5, 18
101 | fill "#000000", 0.5
102 | font "IBM Plex Sans", 14, 400, 0, hLeft, vTop
103 | characters "|"
104 | textAutoResize tsWidthAndHeight
105 | layoutAlign laCenter
106 | text "flag":
107 | box 227, 0, 24, 18
108 | fill "#000000", 0.5
109 | font "IBM Plex Sans", 14, 400, 0, hLeft, vTop
110 | characters "flag"
111 | textAutoResize tsWidthAndHeight
112 | layoutAlign laCenter
113 | text "bar":
114 | box 218, 0, 5, 18
115 | fill "#000000", 0.5
116 | font "IBM Plex Sans", 14, 400, 0, hLeft, vTop
117 | characters "|"
118 | textAutoResize tsWidthAndHeight
119 | layoutAlign laCenter
120 | text "points":
121 | box 0, 0, 214, 18
122 | fill "#000000", 0.5
123 | font "IBM Plex Sans", 14, 400, 0, hLeft, vTop
124 | characters "by " & call.json["by"].getStr()
125 | textAutoResize tsWidthAndHeight
126 | layoutAlign laCenter
127 |
128 | proc drawMain() =
129 | frame "Page":
130 | box 0, 0, parent.box.w, parent.box.h
131 | orgBox 0, 0, 696, 639
132 | fill "#ffffff"
133 | frame "main":
134 | box 50, 0, 596, 450
135 | constraints cStretch, cMin
136 | layout lmVertical
137 | counterAxisSizingMode csFixed
138 | horizontalPadding 0
139 | verticalPadding 0
140 | itemSpacing 0
141 |
142 | var call = httpGet("https://hacker-news.firebaseio.com/v0/topstories.json")
143 | if call.status == Ready:
144 | var i = 0
145 | for id in call.json:
146 | news($id.getInt())
147 | if i > 15:
148 | break
149 | inc i
150 | header()
151 | rectangle "bg":
152 | box 50, 0, 596, 639
153 | constraints cStretch, cStretch
154 | fill "#f6f6ef"
155 |
156 | startFidget(drawMain, w = 800, h = 800)
157 |
--------------------------------------------------------------------------------
/examples/hn/hn.nims:
--------------------------------------------------------------------------------
1 | --d:ssl
2 |
--------------------------------------------------------------------------------
/examples/minimal/minimal.nim:
--------------------------------------------------------------------------------
1 | ## This minimal example shows 5 blue squares.
2 |
3 | import fidget
4 |
5 | proc drawMain() =
6 | frame "main":
7 | box 0, 0, 620, 140
8 | for i in 0 .. 4:
9 | group "block":
10 | box 20 + i * 120, 20, 100, 100
11 | fill "#2B9FEA"
12 |
13 | startFidget(drawMain, w = 620, h = 140)
14 |
--------------------------------------------------------------------------------
/examples/minimal/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/examples/minimal/screenshot.png
--------------------------------------------------------------------------------
/examples/padofcode/data/Inconsolata-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/examples/padofcode/data/Inconsolata-Regular.ttf
--------------------------------------------------------------------------------
/examples/padofcode/padofcode.nim:
--------------------------------------------------------------------------------
1 | ## Shows code pad with monospace font.
2 |
3 | import fidget
4 |
5 | loadFont("Inconsolata", "Inconsolata-Regular.ttf")
6 |
7 | setTitle("Pad of Code")
8 |
9 | var
10 | textValue = """
11 | -- sql query
12 | SELECT foo
13 | FROM bar
14 | WHERE a = 234 and b = "nothing"
15 | """
16 |
17 | proc drawMain() =
18 |
19 | frame "main":
20 | box 0, 0, parent.box.w-20, parent.box.h
21 | font "Inconsolata", 16.0, 400.0, 20, hLeft, vTop
22 | fill "#F7F7F9"
23 |
24 | text "codebox":
25 | box 0, 0, parent.box.w, parent.box.h
26 | fill "#000000"
27 | multiline true
28 | binding textValue
29 |
30 | startFidget(drawMain)
31 |
--------------------------------------------------------------------------------
/examples/padofcode/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/examples/padofcode/screenshot.png
--------------------------------------------------------------------------------
/examples/padoftext/data/IBMPlexSans-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/examples/padoftext/data/IBMPlexSans-Regular.ttf
--------------------------------------------------------------------------------
/examples/padoftext/padoftext.nim:
--------------------------------------------------------------------------------
1 | ## Shows a text pad like program.
2 |
3 | import fidget
4 |
5 | loadFont("IBM Plex Sans Regular", "IBMPlexSans-Regular.ttf")
6 |
7 | setTitle("Pad of Text")
8 |
9 | var
10 | textValue = """
11 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut volutpat mi tortor, quis congue elit bibendum vitae. Pellentesque risus velit, tempor vel arcu pellentesque, lacinia ultrices felis. Aliquam erat volutpat. Nulla sodales odio ac turpis fermentum, quis pulvinar erat efficitur. Ut molestie consectetur odio vitae interdum. Etiam dui odio, porta in volutpat in, facilisis at erat. Etiam sed augue eget risus tincidunt sagittis sit amet nec justo. Donec ac auctor massa. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.
12 |
13 | Aenean rhoncus odio eu neque viverra auctor. Nullam commodo, elit nec efficitur finibus, orci tellus pharetra risus, at ultrices urna purus sed odio. Donec volutpat semper arcu, et rutrum mauris malesuada eu. Quisque dignissim, diam sed efficitur facilisis, lorem velit sagittis mauris, ut hendrerit diam ex a lorem. Duis iaculis nunc sem, sed vehicula urna consectetur ut. Morbi bibendum eros at dictum laoreet. Curabitur lacus diam, iaculis bibendum venenatis tempus, laoreet id velit. Sed laoreet dapibus efficitur. Integer sollicitudin mauris sed lacinia finibus.
14 |
15 | Duis eget tellus lacus. Sed eu sapien sed dolor placerat volutpat eget lacinia augue. Nulla arcu mauris, sodales eu nisl id, hendrerit imperdiet leo. Nulla varius metus dignissim sollicitudin fermentum. Phasellus non augue sollicitudin orci dignissim ullamcorper ac sed urna. In finibus metus sit amet erat volutpat, laoreet pellentesque lorem pulvinar. Vivamus non magna a enim ultricies cursus. Integer vitae nibh gravida, lacinia libero non, tristique nisi. Nullam vitae ultricies urna. Etiam vel mauris lectus. Quisque mattis luctus velit, eu mattis dolor mattis ut. Donec dapibus turpis sem, vitae tempus diam porta eget.
16 |
17 | Vivamus mattis congue faucibus. Nullam venenatis ipsum sed lacus pharetra pharetra. In urna dui, mollis sit amet consectetur quis, pellentesque non ante. Phasellus congue dui ac arcu interdum imperdiet. Praesent id egestas magna, quis tincidunt odio. Nunc ac diam a ipsum tempus posuere. Praesent egestas lobortis est, sed lacinia elit ullamcorper vel.
18 |
19 | Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Mauris mi magna, blandit non pharetra id, convallis in ex. Curabitur ut odio arcu. Praesent nec maximus lectus, eu varius massa. Quisque nec libero a turpis laoreet placerat a a felis. Vivamus dignissim augue vitae accumsan facilisis. Nunc at imperdiet risus. Aliquam elementum, purus id rhoncus eleifend, mauris nisl scelerisque nisl, vitae aliquam nulla enim ac metus.
20 | """
21 |
22 | proc drawMain() =
23 |
24 | group "pad":
25 | box 100, 100, parent.box.w - 200, parent.box.h - 200
26 | font "IBM Plex Sans Regular", 20.0, 400.0, 25, hLeft, vTop
27 | fill "#F7F7F9"
28 | clipContent true
29 |
30 | text "input":
31 | box 0, 0, parent.box.w, parent.box.h
32 | fill "#000000"
33 | multiline true
34 | binding textValue
35 |
36 | startFidget(drawMain)
37 |
--------------------------------------------------------------------------------
/examples/padoftext/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/examples/padoftext/screenshot.png
--------------------------------------------------------------------------------
/fidget.nimble:
--------------------------------------------------------------------------------
1 | # Package
2 |
3 | version = "0.7.10"
4 | author = "Andre von Houck"
5 | description = "Fidget - UI Library"
6 | license = "MIT"
7 | srcDir = "src"
8 |
9 | # Dependencies
10 |
11 | requires "nim >= 1.4.0"
12 | requires "typography >= 0.7.14"
13 | requires "print >= 0.1.0"
14 | requires "opengl >= 1.2.3"
15 | requires "html5_canvas >= 1.3"
16 | requires "staticglfw >= 4.1.2"
17 | requires "cligen >= 1.0.0"
18 | requires "supersnappy >= 1.0.0"
19 |
--------------------------------------------------------------------------------
/figma_plugin/code.ts:
--------------------------------------------------------------------------------
1 | function q(str) {
2 | return JSON.stringify(str);
3 | }
4 | function titleCase(str) {
5 | str = str.toLowerCase().split(' ');
6 | for (var i = 0; i < str.length; i++) {
7 | str[i] = str[i].charAt(0).toUpperCase() + str[i].slice(1);
8 | }
9 | return str.join(' ');
10 | }
11 | function toHtmlColor(color) {
12 | return "#" +
13 | ("0" + (Math.floor(color.r * 255.5)).toString(16)).slice(-2) +
14 | ("0" + (Math.floor(color.g * 255.5)).toString(16)).slice(-2) +
15 | ("0" + (Math.floor(color.b * 255.5)).toString(16)).slice(-2);
16 | }
17 | let fontStyleMapping = {
18 | Thin: 100,
19 | ThinItalic: 100,
20 | ExtraLight: 200,
21 | ExtraLightItalic: 200,
22 | Light: 300,
23 | LightItalic: 300,
24 | Regular: 400,
25 | RegularItalic: 400,
26 | Medium: 500,
27 | MediumItalic: 500,
28 | SemiBold: 600,
29 | SemiBoldItalic: 600,
30 | Bold: 700,
31 | BoldItalic: 700,
32 | ExtraBold: 800,
33 | ExtraBoldItalic: 800,
34 | Black: 900,
35 | BlackItalic: 900,
36 | };
37 | var text = "";
38 | var indent = 0;
39 | var at = { x: 0, y: 0 };
40 | var atStack = [];
41 | function ind() {
42 | return " ".repeat(indent);
43 | }
44 | function visitFill(fill) {
45 | // text += ind() + `fill color(${fill.color.r}, ${fill.color.g}, ${fill.color.b}, ${fill.opacity})\n`
46 | if (fill.color != undefined) {
47 | if (fill.opacity != 1) {
48 | text += ind() + `fill ${JSON.stringify(toHtmlColor(fill.color))}, ${fill.opacity}\n`;
49 | }
50 | else {
51 | text += ind() + `fill ${JSON.stringify(toHtmlColor(fill.color))}\n`;
52 | }
53 | }
54 | }
55 | function visitStroke(fill) {
56 | // text += ind() + `fill color(${fill.color.r}, ${fill.color.g}, ${fill.color.b}, ${fill.opacity})\n`
57 | if (fill.color != undefined) {
58 | if (fill.opacity != 1) {
59 | text += ind() + `stroke ${JSON.stringify(toHtmlColor(fill.color))}, ${fill.opacity}\n`;
60 | }
61 | else {
62 | text += ind() + `stroke ${JSON.stringify(toHtmlColor(fill.color))}\n`;
63 | }
64 | }
65 | }
66 | function visitEffect(effect) {
67 | // text += ind() + JSON.stringify(effect) + "\n"
68 | if (effect.type == "DROP_SHADOW" && effect.visible) {
69 | text += ind() + `dropShadow ${effect.radius}, ${effect.offset.x}, ${effect.offset.y}, ${JSON.stringify(toHtmlColor(effect.color))}, ${effect.color.a}\n`;
70 | }
71 | else if (effect.type == "INNER_SHADOW" && effect.visible) {
72 | text += ind() + `innerShadow ${effect.radius}, ${effect.offset.x}, ${effect.offset.y}, ${JSON.stringify(toHtmlColor(effect.color))}, ${effect.color.a}\n`;
73 | }
74 | }
75 | function visit(node) {
76 | if (!node.visible) {
77 | return;
78 | }
79 | if (node.name.includes('.ignore')) {
80 | return;
81 | }
82 | text += ind() + node.type.toLowerCase() + " \"" + node.name + "\":\n";
83 | indent += 1;
84 | //text += ind() + `# relativeTransform ${node.relativeTransform}\n`
85 | //text += ind() + `# ${node.x} ${node.y}\n`
86 | text += ind() + `box ${node.x - at.x}, ${node.y - at.y}, ${node.width}, ${node.height}\n`;
87 | if (node.constraints) {
88 | if (node.constraints.horizontal != "MIN" || node.constraints.vertical != "MIN") {
89 | text += ind() + `constraints c${titleCase(node.constraints.horizontal)}, c${titleCase(node.constraints.vertical)}\n`;
90 | }
91 | }
92 | if (node.type == "INSTANCE") {
93 | text += ind() + `image ${q(node.name + ".png")}\n`;
94 | indent -= 1;
95 | return;
96 | }
97 | if (node.exportSettings.length > 0) {
98 | // text += ind() + `exportSettings ${JSON.stringify(node.exportSettings)}\n`
99 | text += ind() + `image ${q(node.name + ".png")}\n`;
100 | indent -= 1;
101 | return;
102 | }
103 |
104 | if (node.fills != undefined && node.fills != figma.mixed) {
105 | for (let fill of node.fills) {
106 | visitFill(fill);
107 | }
108 | }
109 |
110 | if (node.strokes != undefined && node.strokes != figma.mixed) {
111 | for (let stroke of node.strokes) {
112 | visitStroke(stroke);
113 | }
114 | }
115 | if (node.cornerRadius != undefined && node.cornerRadius != figma.mixed) {
116 | if (node.cornerRadius != 0) {
117 | text += ind() + `cornerRadius ${node.cornerRadius}\n`;
118 | }
119 | }
120 | if (node.strokeWeight != undefined) {
121 | if (node.strokeWeight != 0 && node.strokes.length != 0) {
122 | text += ind() + `strokeWeight ${node.strokeWeight}\n`;
123 | }
124 | }
125 | if (node.effects != undefined) {
126 | for (let effect of node.effects) {
127 | visitEffect(effect);
128 | }
129 | }
130 | if (node.type == "TEXT") {
131 | let fontFamily = JSON.stringify(node.fontName.family);
132 | var lineHeight = 0;
133 | if (node.lineHeight.unit == "PIXELS") {
134 | lineHeight = node.lineHeight.value;
135 | }
136 | let fontWeight = fontStyleMapping[node.fontName.style];
137 | var h = "hCenter";
138 | if (node.textAlignHorizontal == "LEFT")
139 | h = "hLeft";
140 | if (node.textAlignHorizontal == "RIGHT")
141 | h = "hRight";
142 | var v = "vCenter";
143 | if (node.textAlignVertical == "TOP")
144 | v = "vTop";
145 | if (node.textAlignVertical == "BOTTOM")
146 | v = "vBottom";
147 | text += ind() + `font ${fontFamily}, ${node.fontSize}, ${fontWeight}, ${lineHeight}, ${h}, ${v}\n`;
148 | text += ind() + "characters " + JSON.stringify(node.characters) + "\n";
149 | if (node.textAutoResize != "NONE") {
150 | text += ind() + `textAutoResize ts${titleCase(node.textAutoResize)}\n`
151 | }
152 | }
153 |
154 | if (node.layoutMode == "VERTICAL" || node.layoutMode == "HORIZONTAL") {
155 | text += ind() + `layout lm${titleCase(node.layoutMode)}\n`;
156 | text += ind() + `counterAxisSizingMode cs${titleCase(node.counterAxisSizingMode)}\n`;
157 | text += ind() + `horizontalPadding ${node.horizontalPadding}\n`;
158 | text += ind() + `verticalPadding ${node.verticalPadding}\n`;
159 | text += ind() + `itemSpacing ${node.itemSpacing}\n`;
160 | }
161 |
162 | if (node.layoutAlign && node.layoutAlign != "MIN") {
163 | text += ind() + `layoutAlign la${titleCase(node.layoutAlign)}\n`;
164 | }
165 |
166 | if (node.children) {
167 | if (node.type == "GROUP") {
168 | atStack.push({ x: at.x, y: at.y });
169 | at.x = node.x;
170 | at.y = node.y;
171 | }
172 | node.children.slice().reverse().forEach(visit);
173 | if (node.type == "GROUP") {
174 | at = atStack.pop();
175 | }
176 | }
177 | indent -= 1;
178 | }
179 | for (const node of figma.currentPage.selection) {
180 | indent = 0;
181 | visit(node);
182 | text += "\n";
183 | }
184 | if (text.trim().length == 0) {
185 | text = `# Please select a node to generate fidget code for the node.
186 |
187 | # Here is want an empty fidget app looks like:
188 | import fidget
189 |
190 | proc drawMain() =
191 | # Fidget code goes here.
192 | discard
193 |
194 | startFidget(drawMain)
195 | `
196 |
197 | }
198 | figma.showUI(`
199 | ${text}
200 | `, { width: 500, height: 600 });
201 |
--------------------------------------------------------------------------------
/figma_plugin/figma.nim:
--------------------------------------------------------------------------------
1 | import chroma, vmath
2 |
3 | type
4 |
5 | FontName* = object
6 | family*: string
7 | style*: string
8 |
9 | TextCase* = enum
10 | tcOriginal
11 | tcUpper
12 | tcLower
13 | tcTitle
14 |
15 | TextDecoration* = enum
16 | tdNone
17 | tdUnderline
18 | tdStrikeThrough
19 |
20 | ArcData* = object
21 | startingAngle*: float32
22 | endingAngle*: float32
23 | innerRadius*: float32
24 |
25 | BlendMode* = enum
26 | bmPassThrough
27 | bmNormal
28 | bmDarken
29 | bmMultiply
30 | bmLinearBurn
31 | bmColorBurn
32 | bmLighten
33 | bmScreen
34 | bmLinearDodge
35 | bmColorDodge
36 | bmOverlay
37 | bmSoftLight
38 | bmHardLight
39 | bmDifference
40 | bmExclusion
41 | bmHue
42 | bmSaturation
43 | bmColor
44 | bmLuminosity
45 |
46 | ShadowEffectKind* = enum
47 | seDropShadow
48 | seInnerShadow
49 |
50 | ShadowEffect* = object
51 | kind*: ShadowEffectKind
52 | color*: ColorRGBA
53 | offset*: Vec2
54 | radius: float32
55 | visible: bool
56 | blendMode: BlendMode
57 |
58 | BlurEffectKind* = enum
59 | beLayerBlur
60 | beBackgroundBlur
61 |
62 | BlurEffect* = object
63 | kind*: BlurEffectKind
64 | radius*: float32
65 | visible*: bool
66 |
67 | Effect* = ShadowEffect | BlurEffect
68 |
69 | ConstraintKind* = enum
70 | cMin
71 | cCenter
72 | cMax
73 | cStretch
74 | cScale
75 |
76 | Constraints* = object
77 | horizontal*: ConstraintKind
78 | vertical*: ConstraintKind
79 |
80 | SolidPaint* = object
81 | visible*: bool
82 | color*: ColorRGBA
83 | opacity*: float32
84 | blendMode*: BlendMode
85 |
86 | ColorStop* = object
87 | position*: float32
88 | color*: ColorRGBA
89 |
90 | GradientPaintKind* = enum
91 | GradientLinear
92 | GradientRadial
93 | GradientAngular
94 | GradientDiamond
95 |
96 | GradientPaint* = object
97 | kind*: GradientPaintKind
98 | gradientTransform*: Mat3
99 | gradientStops*: seq[ColorStop]
100 |
101 | visible*: bool
102 | opacity*: float32
103 | blendMode*: BlendMode
104 |
105 | ImageFilters* = object
106 | exposure*: float32
107 | contrast*: float32
108 | saturation*: float32
109 | temperature*: float32
110 | tint*: float32
111 | highlights*: float32
112 | shadows*: float32
113 |
114 | ImageScaleMode* = enum
115 | msFill
116 | msFit
117 | msCrop
118 | msTile
119 |
120 | ImagePaint* = object
121 | scaleMode: ImageScaleMode
122 | imageHash: string
123 | imageTransform: Mat3
124 | scalingFactor: float32
125 | filters: ImageFilters
126 |
127 | visible*: bool
128 | opacity*: float32
129 | blendMode*: BlendMode
130 |
131 | Paint* = SolidPaint | GradientPaint | ImagePaint
132 |
133 | WindingRule* = enum
134 | wrNonZero
135 | wrEvenOdd
136 |
137 | StrokeCap* = enum
138 | scNone
139 | scRound
140 | scSquare
141 | scArrowLines
142 | scArrowEquilateral
143 |
144 | StrokeJoin* = enum
145 | sjMiter
146 | sjBevel
147 | sjRound
148 |
149 | HandleMirroring* = enum
150 | hmNone
151 | hmAngle
152 | hmAngleAndLength
153 |
154 | VectorVertex* = object
155 | pos*: Vec2
156 | strokeCap*: StrokeCap
157 | strokeJoin*: StrokeJoin
158 | cornerRadius*: float32
159 | handleMirroring*: HandleMirroring
160 |
--------------------------------------------------------------------------------
/figma_plugin/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Fidget Export",
3 | "api": "1.0.0",
4 | "main": "code.js",
5 | "id": "945866846468157120",
6 | "editorType": ["figma"]
7 | }
8 |
--------------------------------------------------------------------------------
/figma_plugin/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es6"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/src/fidget/_cairo.nim:
--------------------------------------------------------------------------------
1 | ## Cairo backend uses Cairo and glfw3 libarires to provide graphics and input
2 |
3 | import chroma, common, glfw3 as glfw, math, opengl, os, print, quickcairo,
4 | random, times, unicode, vmath
5 |
6 | when defined(Windows):
7 | import windows
8 | proc GetWin32Window*(window: glfw.Window): pointer {.cdecl,
9 | importc: "glfwGetWin32Window", dynlib: "glfw3.dll".}
10 | else:
11 | const GlfwLib = "libglfw.so.3"
12 |
13 | var
14 | surface: Surface
15 | ctx: quickcairo.Context
16 | frameCount = 0
17 | window: glfw.Window
18 | dpi*: float = 1.0
19 | windowFrame: Box
20 | viewPort: Box
21 |
22 | proc setSource(ctx: quickcairo.Context, color: Color) =
23 | ctx.setSource(
24 | color.r,
25 | color.g,
26 | color.b,
27 | color.a
28 | )
29 |
30 | proc rectangle(ctx: quickcairo.Context, box: Box) =
31 | ctx.rectangle(
32 | floor box.x,
33 | floor box.y,
34 | floor box.w,
35 | floor box.h
36 | )
37 |
38 | proc draw*(group: Group) =
39 | ## Redraws the whole screen
40 | if group.fill.a > 0:
41 |
42 | if group.kind == "text":
43 | if group.text.len > 0 or (group.editableText and group.placeholder.len > 0):
44 | var text = group.text
45 | if group.editableText:
46 |
47 | if group.text.len == 0 and group.placeholder.len > 0:
48 | text = group.placeholder
49 |
50 | if mouse.click and mouse.pos.inside(current.screenBox):
51 | echo "gain focus"
52 | keyboard.inputFocusId = group.id
53 | keyboard.input = group.text
54 | mouse.use()
55 |
56 | if mouse.click and not mouse.pos.inside(current.screenBox):
57 | echo "loose focus"
58 | if keyboard.inputFocusId == group.id:
59 | keyboard.inputFocusId = ""
60 |
61 | ctx.selectFontFace(group.textStyle.fontFamily, FONT_SLANT.normal,
62 | FONT_WEIGHT.normal)
63 | ctx.setFontSize(group.textStyle.fontSize)
64 | ctx.setSource(group.fill)
65 | var extents = TextExtents()
66 | ctx.textExtents(text, extents)
67 |
68 | var fontExtents = FontExtents()
69 | ctx.fontExtents(fontExtents)
70 | let capHeight = fontExtents.ascent - fontExtents.descent
71 | print fontExtents
72 | var x, y: float
73 |
74 | case group.textStyle.textAlignHorizontal:
75 | of -1:
76 | x = group.screenBox.x
77 | of 0:
78 | x = group.screenBox.x + group.screenBox.w/2 - float(extents.width)/2
79 | of 1:
80 | x = group.screenBox.x + group.screenBox.w - extents.width
81 | else:
82 | x = 0
83 | case group.textStyle.textAlignVertical:
84 | of -1:
85 | y = group.screenBox.y + fontExtents.ascent
86 | of 0:
87 | y = group.screenBox.y + group.screenBox.h/2 + float(capHeight)/2
88 | of 1:
89 | y = group.screenBox.y + group.screenBox.h - fontExtents.descent
90 | else:
91 | y = 0
92 | ctx.moveTo(x, y)
93 | ctx.showText(text)
94 |
95 | ctx.rectangle(Box(x: x, y: y, w: 4, h: 4))
96 | ctx.setSource(color(1, 0, 0, 1))
97 | ctx.stroke()
98 |
99 | else:
100 | ctx.rectangle(group.screenBox)
101 | ctx.setSource(group.fill)
102 | ctx.fill()
103 |
104 | proc redraw*() =
105 | ## Request the screen to be redrawn next
106 | if not requestedFrame:
107 | requestedFrame = true
108 |
109 | proc openBrowser*(url: string) =
110 | ## Opens a URL in a browser
111 | discard
112 |
113 | proc goto*(url: string) =
114 | ## Goes to a new URL, inserts it into history so that back button works
115 | discard
116 |
117 | proc display() =
118 | ## Called every frame by main while loop
119 | setupRoot()
120 |
121 | root.box.x = float 0
122 | root.box.y = float 0
123 | root.box.w = windowFrame.w
124 | root.box.h = windowFrame.h
125 |
126 | scrollBox.x = float 0
127 | scrollBox.y = float 0
128 | scrollBox.w = root.box.w
129 | scrollBox.h = root.box.h
130 |
131 | ctx.rectangle(root.box)
132 | ctx.setSource(color(1, 1, 1, 1))
133 | ctx.fill()
134 |
135 | drawMain()
136 |
137 | # update texture with new pixels from surface
138 | let
139 | dataPtr = surface.imageSurfaceGetData()
140 | w = surface.width
141 | h = surface.height
142 |
143 | when defined(windows):
144 | # draw image serface onto window
145 | var hwnd = cast[HWND](GetWin32Window(window))
146 | var dc = GetDC(hwnd)
147 | var info = BITMAPINFO()
148 | info.bmiHeader.biBitCount = 32
149 | info.bmiHeader.biWidth = int32 w
150 | info.bmiHeader.biHeight = int32 h
151 | info.bmiHeader.biPlanes = 1
152 | info.bmiHeader.biSize = DWORD sizeof(BITMAPINFOHEADER)
153 | info.bmiHeader.biSizeImage = int32(w * h * 4)
154 | info.bmiHeader.biCompression = BI_RGB
155 | discard StretchDIBits(dc, 0, int32 h - 1, int32 w, int32 -h, 0, 0, int32 w,
156 | int32 h, dataPtr, info, DIB_RGB_COLORS, SRCCOPY)
157 | discard ReleaseDC(hwnd, dc)
158 | else:
159 | # openGL way
160 | glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GLsizei w, GLsizei h, GL_BGRA,
161 | GL_UNSIGNED_BYTE, dataPtr)
162 | # draw a quad over the whole screen
163 | glClear(GL_COLOR_BUFFER_BIT)
164 | glBegin(GL_QUADS)
165 | glTexCoord2d(0.0, 0.0)
166 | glVertex2d(-1.0, +1.0)
167 | glTexCoord2d(viewPort.w/float(w), 0.0)
168 | glVertex2d(+1.0, +1.0)
169 | glTexCoord2d(viewPort.w/float(w), viewPort.h/float(h))
170 | glVertex2d(+1.0, -1.0)
171 | glTexCoord2d(0.0, viewPort.h/float(h))
172 | glVertex2d(-1.0, -1.0)
173 | glEnd()
174 | glfw.SwapBuffers(window)
175 |
176 | keyboard.use()
177 | mouse.use()
178 |
179 | inc frameCount
180 |
181 | proc closestPowerOf2(v: int): int =
182 | ## returns closets power of 2 ... 2,4,8,16... that is higher then v
183 | result = 2
184 | while true:
185 | if v < result:
186 | return
187 | result *= 2
188 |
189 | proc resize() =
190 | var cwidth, cheight: cint
191 | GetWindowSize(window, addr cwidth, addr cheight)
192 | windowFrame.w = float(cwidth)
193 | windowFrame.h = float(cheight)
194 |
195 | GetFramebufferSize(window, addr cwidth, addr cheight)
196 | viewPort.w = float(cwidth)
197 | viewPort.h = float(cheight)
198 | dpi = viewPort.w / windowFrame.w
199 |
200 | when defined(windows):
201 | discard
202 | else:
203 | glViewport(0, 0, cwidth, cheight)
204 |
205 | var
206 | w = closestPowerOf2(int viewPort.w)
207 | h = closestPowerOf2(int viewPort.h)
208 | if surface == nil or w > surface.width or h > surface.height:
209 | # need to resize and re inint everything
210 | surface = imageSurfaceCreate(FORMAT.rgb24, w, h)
211 | ctx = surface.newContext()
212 |
213 | # allocate a texture and bind it
214 | var dataPtr = surface.imageSurfaceGetData()
215 | when defined(windows):
216 | discard
217 | else:
218 | glTexImage2D(GL_TEXTURE_2D, 0, 3, GLsizei w, GLsizei h, 0, GL_BGRA,
219 | GL_UNSIGNED_BYTE, dataPtr)
220 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
221 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
222 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
223 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
224 | glEnable(GL_TEXTURE_2D)
225 |
226 | proc onResize(handle: glfw.Window, w, h: int32) {.cdecl.} =
227 | resize()
228 | display()
229 |
230 | proc onMouseButton(window: glfw.Window, button: cint, action: cint,
231 | modifiers: cint) {.cdecl.} =
232 | if action == 0:
233 | mouse.down = false
234 | mouse.click = false
235 | else:
236 | mouse.click = true
237 | mouse.down = true
238 | # let button = button + 1
239 | # if button < buttonDown.len:
240 | # if buttonDown[button] == false and setKey == true:
241 | # buttonPress[button] = true
242 | # buttonDown[button] = setKey
243 | redraw()
244 |
245 | proc onMouseMove(window: glfw.Window, x: cdouble, y: cdouble) {.cdecl.} =
246 | # this does not fire when mouse is not in the window
247 | mouse.pos = vec2(x, y) * dpi
248 | redraw()
249 |
250 | proc `title=`*(win: common.Window, title: string) =
251 | if win.innerTitle != title:
252 | win.innerTitle = title
253 | window.SetWindowTitle(title)
254 |
255 | proc `title`*(win: common.Window): string =
256 | win.innerTitle
257 |
258 | proc startFidget*(draw: proc()) =
259 | ## Starts cairo backend.
260 | drawMain = draw
261 | if glfw.Init() == 0:
262 | quit("Failed to Initialize GLFW")
263 | window = glfw.CreateWindow(1000, 800, "Fidget glfw/cairo backend window.",
264 | nil, nil)
265 | glfw.MakeContextCurrent(window)
266 |
267 | when defined(windows):
268 | discard
269 | else:
270 | loadExtensions()
271 |
272 | glfw.PollEvents()
273 | resize()
274 |
275 | discard SetCursorPosCallback(window, onMouseMove)
276 | discard SetMouseButtonCallback(window, onMouseButton)
277 | discard SetFramebufferSizeCallback(window, onResize)
278 | proc onCharCallback(window: glfw.Window, character: cuint) {.cdecl.} =
279 | keyboard.state = common.Press
280 | keyboard.keyString = $Rune(character)
281 | echo "keyboard.keyString", repr(keyboard.keyString)
282 | keyboard.input.add keyboard.keyString
283 | echo keyboard.input
284 | redraw()
285 | discard SetCharCallback(window, onCharCallback)
286 |
287 | proc onKeyCallback(
288 | window: glfw.Window,
289 | key: cint,
290 | scancode: cint,
291 | action: cint,
292 | modifiers: cint
293 | ) {.cdecl.} =
294 | echo "keyboard.key ", key, " action ", action
295 | #keyboard.input.add keyboard.keyString
296 | #echo keyboard.input
297 | if keyboard.inputFocusId != "" and action != 0:
298 | if key == KEY_BACKSPACE:
299 | keyboard.state = common.Press
300 | keyboard.keyString = ""
301 | if keyboard.input.len > 0:
302 | keyboard.input.setLen(keyboard.input.len - 1)
303 | redraw()
304 | discard SetKeyCallback(window, onKeyCallback)
305 |
306 | requestedFrame = true
307 |
308 | while glfw.WindowShouldClose(window) == 0:
309 | glfw.PollEvents()
310 |
311 | if requestedFrame:
312 | requestedFrame = false
313 | display()
314 | else:
315 | sleep(1)
316 |
317 | # reset one off events
318 | mouse.click = false
319 |
--------------------------------------------------------------------------------
/src/fidget/_flippy.nim:
--------------------------------------------------------------------------------
1 | ## Flippy backend uses Flippy and glfw3 libarires to provide graphics and input
2 |
3 | import chroma, common, flippy, glfw3 as glfw, math, opengl, os, print, tables,
4 | times, typography, unicode, vmath
5 |
6 | const GlfwLib = "libglfw.so.3"
7 |
8 | var
9 | ctx: flippy.Image
10 | frameCount = 0
11 | window: glfw.Window
12 | dpi*: float = 1.0
13 | windowFrame: Box
14 | viewPort: Box
15 |
16 | # readFontSvg("examples/Ubuntu.svg")
17 | #var font = readFontTtf("examples/IBMPlexSans-Regular.ttf")
18 | # font.size = 40
19 | # font.lineHeight = 20
20 |
21 | proc hAlignNum(num: int): HAlignMode =
22 | case num:
23 | of -1: Left
24 | of 0: Center
25 | of 1: Right
26 | else: Left
27 |
28 | proc vAlignNum(num: int): VAlignMode =
29 | case num:
30 | of -1: Top
31 | of 0: Middle
32 | of 1: Bottom
33 | else: Top
34 |
35 | proc drawText(group: Group) =
36 | if group.textStyle.fontFamily notin fonts:
37 | quit "font not found: " & group.textStyle.fontFamily
38 | var font = fonts[group.textStyle.fontFamily]
39 | font.size = group.textStyle.fontSize
40 | font.lineHeight = group.textStyle.lineHeight
41 | let fontHeight = font.ascent - font.descent
42 | let scale = font.size / fontHeight
43 | let editing = keyboard.inputFocusId == group.id
44 | let cursorWidth = floor(min(1, font.size/12.0))
45 |
46 | if editing:
47 | group.text = keyboard.input
48 |
49 | let layout = font.typeset(
50 | group.text,
51 | pos = group.screenBox.xy,
52 | size = group.screenBox.wh,
53 | hAlignNum(group.textStyle.textAlignHorizontal),
54 | vAlignNum(group.textStyle.textAlignVertical)
55 | )
56 |
57 | # draw layout boxes
58 | for pos in layout:
59 | var font = pos.font
60 | # if pos.character == "\n":
61 | # #print pos.selectRect, pos.index
62 | # ctx.strokeRect(pos.selectRect, rgba(0,0,255,255))
63 | # let baseLine = pos.selectRect.y + font.ascent * scale
64 | # ctx.line(
65 | # vec2(pos.selectRect.x, baseLine),
66 | # vec2(pos.selectRect.x + pos.selectRect.w, baseLine),
67 | # rgba(0,0,255,255)
68 | # )
69 |
70 | if pos.character in font.glyphs:
71 | var glyph = font.glyphs[pos.character]
72 | var glyphOffset: Vec2
73 | let img = font.getGlyphImage(
74 | glyph,
75 | glyphOffset,
76 | subPixelShift = pos.subPixelShift
77 | )
78 | let r = rect(
79 | pos.rect.xy + glyphOffset,
80 | vec2(float img.width, float img.height)
81 | )
82 | #ctx.strokeRect(r, rgba(255,0,0,255))
83 | ctx.blitWithMask(
84 | img,
85 | rect(
86 | 0, 0,
87 | float img.width, float img.height
88 | ),
89 | rect(
90 | pos.rect.x + glyphOffset.x, pos.rect.y + glyphOffset.y,
91 | float img.width, float img.height
92 | ),
93 | group.fill.rgba
94 | )
95 |
96 | if editing and keyboard.textCursor == pos.index:
97 | # draw text cursor at glyph pos
98 | ctx.fillRect(rect(
99 | pos.selectRect.x,
100 | pos.selectRect.y,
101 | cursorWidth,
102 | font.size
103 | ), group.fill.rgba)
104 |
105 | # draw text cursor if there is not character
106 | if editing and keyboard.input.len == 0:
107 | ctx.fillRect(rect(
108 | group.screenBox.x,
109 | group.screenBox.y,
110 | cursorWidth,
111 | font.size
112 | ), group.fill.rgba)
113 | # draw text cursor at the last character
114 | elif editing and keyboard.input.len == keyboard.textCursor:
115 | let pos = layout[^1]
116 | if pos.character != "\n":
117 | ctx.fillRect(rect(
118 | pos.selectRect.x + pos.selectRect.w,
119 | pos.selectRect.y,
120 | cursorWidth,
121 | font.size
122 | ), group.fill.rgba)
123 | else:
124 | ctx.fillRect(rect(
125 | group.screenBox.x,
126 | pos.selectRect.y + font.lineHeight,
127 | cursorWidth,
128 | font.size
129 | ), group.fill.rgba)
130 |
131 | if group.text.len > 0 or (group.editableText and group.placeholder.len > 0):
132 | var text = group.text
133 | if group.editableText:
134 |
135 | if group.text.len == 0 and group.placeholder.len > 0:
136 | text = group.placeholder
137 |
138 | if mouse.click and mouse.pos.inside(current.screenBox):
139 | echo "gain focus"
140 | keyboard.inputFocusId = group.id
141 | keyboard.input = group.text
142 | keyboard.textCursor = keyboard.input.len
143 |
144 | let pos = layout.pickGlyphAt(mouse.pos)
145 | if pos.character != "":
146 | keyboard.textCursor = pos.index
147 |
148 | mouse.use()
149 |
150 | if mouse.click and not mouse.pos.inside(current.screenBox):
151 | echo "loose focus"
152 | if keyboard.inputFocusId == group.id:
153 | keyboard.inputFocusId = ""
154 |
155 | var imageCache = newTable[string, flippy.Image]()
156 |
157 | proc draw*(group: Group) =
158 | ## Draw a single group
159 |
160 | if group.fill.a > 0:
161 | if group.kind == "text":
162 | drawText(group)
163 | else:
164 | if group.imageName == "":
165 | ctx.fillRect(rect(
166 | group.screenBox.x, group.screenBox.y,
167 | group.screenBox.w, group.screenBox.h
168 | ), group.fill.rgba)
169 |
170 | if group.imageName != "":
171 | if group.imageName notin imageCache:
172 | echo "load ", group.imageName
173 | imageCache[group.imageName] = loadImage("data/" & group.imageName & ".png")
174 | let image = imageCache[group.imageName]
175 | #ctx.blitWithAlpha(image, translate(vec3(group.screenBox.x, group.screenBox.y, 0)))
176 | ctx.blitWithAlpha(
177 | image,
178 | translate(vec3(group.screenBox.x, group.screenBox.y, 0))
179 | )
180 |
181 | proc redraw*() =
182 | ## Request the screen to be redrawn next
183 | if not requestedFrame:
184 | requestedFrame = true
185 |
186 | proc openBrowser*(url: string) =
187 | ## Opens a URL in a browser
188 | discard
189 |
190 | proc goto*(url: string) =
191 | ## Goes to a new URL, inserts it into history so that back button works
192 | discard
193 |
194 | proc display() =
195 | ## Called every frame by main while loop
196 | setupRoot()
197 |
198 | root.box.x = float 0
199 | root.box.y = float 0
200 | root.box.w = windowFrame.w
201 | root.box.h = windowFrame.h
202 |
203 | scrollBox.x = float 0
204 | scrollBox.y = float 0
205 | scrollBox.w = root.box.w
206 | scrollBox.h = root.box.h
207 |
208 | ctx.fill(color(1, 1, 1, 1).rgba)
209 |
210 | drawMain()
211 |
212 | # update texture with new pixels from ctx
213 | let
214 | dataPtr = addr ctx.data[0]
215 | w = ctx.width
216 | h = ctx.height
217 |
218 | # openGL way
219 | glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GLsizei w, GLsizei h, GL_RGBA,
220 | GL_UNSIGNED_BYTE, dataPtr)
221 | # draw a quad over the whole screen
222 | glClear(GL_COLOR_BUFFER_BIT)
223 | glBegin(GL_QUADS)
224 | glTexCoord2d(0.0, 0.0)
225 | glVertex2d(-1.0, +1.0)
226 | glTexCoord2d(viewPort.w/float(w), 0.0)
227 | glVertex2d(+1.0, +1.0)
228 | glTexCoord2d(viewPort.w/float(w), viewPort.h/float(h))
229 | glVertex2d(+1.0, -1.0)
230 | glTexCoord2d(0.0, viewPort.h/float(h))
231 | glVertex2d(-1.0, -1.0)
232 | glEnd()
233 | glfw.SwapBuffers(window)
234 |
235 | keyboard.use()
236 | mouse.use()
237 |
238 | inc frameCount
239 |
240 | proc closestPowerOf2(v: int): int =
241 | ## returns closets power of 2 ... 2,4,8,16... that is higher then v
242 | result = 2
243 | while true:
244 | if v < result:
245 | return
246 | result *= 2
247 |
248 | proc resize() =
249 | var cwidth, cheight: cint
250 | GetWindowSize(window, addr cwidth, addr cheight)
251 | windowFrame.w = float(cwidth)
252 | windowFrame.h = float(cheight)
253 |
254 | GetFramebufferSize(window, addr cwidth, addr cheight)
255 | viewPort.w = float(cwidth)
256 | viewPort.h = float(cheight)
257 | dpi = viewPort.w / windowFrame.w
258 |
259 | glViewport(0, 0, cwidth, cheight)
260 |
261 | var
262 | w = closestPowerOf2(int viewPort.w)
263 | h = closestPowerOf2(int viewPort.h)
264 | if ctx == nil or w > ctx.width or h > ctx.height:
265 | # need to resize and re inint everything
266 | ctx = newImage(w, h, 4)
267 |
268 | # allocate a texture and bind it
269 | var dataPtr = addr ctx.data[0]
270 | glTexImage2D(GL_TEXTURE_2D, 0, 3, GLsizei w, GLsizei h, 0, GL_RGBA,
271 | GL_UNSIGNED_BYTE, dataPtr)
272 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
273 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
274 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
275 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
276 | glEnable(GL_TEXTURE_2D)
277 |
278 | proc onResize(handle: glfw.Window, w, h: int32) {.cdecl.} =
279 | resize()
280 | display()
281 |
282 | proc onMouseButton(
283 | window: glfw.Window,
284 | button, action, modifiers: cint
285 | ) {.cdecl.} =
286 | if action == 0:
287 | mouse.down = false
288 | mouse.click = false
289 | else:
290 | mouse.click = true
291 | mouse.down = true
292 | # let button = button + 1
293 | # if button < buttonDown.len:
294 | # if buttonDown[button] == false and setKey == true:
295 | # buttonPress[button] = true
296 | # buttonDown[button] = setKey
297 | redraw()
298 |
299 | proc onMouseMove(window: glfw.Window, x, y: cdouble) {.cdecl.} =
300 | # this does not fire when mouse is not in the window
301 | mouse.pos = vec2(x, y) * dpi
302 | redraw()
303 |
304 | proc `title=`*(win: common.Window, title: string) =
305 | if win.innerTitle != title:
306 | win.innerTitle = title
307 | window.SetWindowTitle(title)
308 |
309 | proc `title`*(win: common.Window): string =
310 | win.innerTitle
311 |
312 | proc startFidget*(draw: proc()) =
313 | ## Starts the flippy backend.
314 | drawMain = draw
315 | if glfw.Init() == 0:
316 | quit("Failed to Initialize GLFW")
317 | window = glfw.CreateWindow(
318 | 1000,
319 | 800,
320 | "Fidget glfw/cairo backend window.",
321 | nil,
322 | nil
323 | )
324 | glfw.MakeContextCurrent(window)
325 |
326 | loadExtensions()
327 |
328 | glfw.PollEvents()
329 | resize()
330 |
331 | discard SetCursorPosCallback(window, onMouseMove)
332 | discard SetMouseButtonCallback(window, onMouseButton)
333 | discard SetFramebufferSizeCallback(window, onResize)
334 | proc onCharCallback(window: glfw.Window, character: cuint) {.cdecl.} =
335 | keyboard.state = common.Press
336 | keyboard.keyString = $Rune(character)
337 |
338 | if keyboard.inputFocusId != "":
339 | keyboard.input[keyboard.textCursor.. 0.uint8:
32 | sumR += int rgba.r
33 | sumG += int rgba.g
34 | sumB += int rgba.b
35 | count += 1
36 | use image.unsafe[x * 2 + 0, y * 2 + 0]
37 | use image.unsafe[x * 2 + 1, y * 2 + 0]
38 | use image.unsafe[x * 2 + 1, y * 2 + 1]
39 | use image.unsafe[x * 2 + 0, y * 2 + 1]
40 | if count > 0:
41 | var rgba: ColorRGBA
42 | rgba.r = uint8(sumR div count)
43 | rgba.g = uint8(sumG div count)
44 | rgba.b = uint8(sumB div count)
45 | rgba.a = 255
46 | result.unsafe[x, y] = rgba
47 |
48 | # scale image down in layers, only using opaque pixels
49 | var
50 | layers: seq[Image]
51 | min = image.minifyBy2Alpha()
52 | while min.width >= 2 and min.height >= 2:
53 | layers.add min
54 | min = min.minifyBy2Alpha()
55 |
56 | # walk over all transparent pixels, going up layers to find best colors
57 | for y in 0 ..< image.height:
58 | for x in 0 ..< image.width:
59 | var rgba = image.unsafe[x, y]
60 | if rgba.a == 0:
61 | var
62 | xs = x
63 | ys = y
64 | for l in layers:
65 | xs = min(xs div 2, l.width - 1)
66 | ys = min(ys div 2, l.height - 1)
67 | rgba = l.unsafe[xs, ys]
68 | if rgba.a > 0.uint8:
69 | break
70 | rgba.a = 0
71 | image.unsafe[x, y] = rgba
72 |
73 | proc save*(flippy: Flippy, filePath: string) =
74 | ## Flippy is a special file format that is fast to load and save with mip maps.
75 | var f = newFileStream(filePath, fmWrite)
76 | defer: f.close()
77 |
78 | f.write("flip")
79 | f.write(version.uint32)
80 | for mip in flippy.mipmaps:
81 | # TODO Talk to Ryan about format data compression.
82 | var s = newStringStream()
83 | for c in mip.data:
84 | s.write(c.color.rgba())
85 | s.setPosition(0)
86 | var stringData = s.readAll()
87 | var zipped = compress(stringData)
88 | #var zipped = compress(mip.data)
89 |
90 | f.write("mip!")
91 | f.write(mip.width.uint32)
92 | f.write(mip.height.uint32)
93 | f.write(len(zipped).uint32)
94 | f.writeData(zipped[0].addr, len(zipped))
95 |
96 | proc pngToFlippy*(pngPath, flippyPath: string) =
97 | var
98 | image = readImage(pngPath)
99 | flippy = Flippy()
100 | image.alphaBleed()
101 | var mip = image
102 | while true:
103 | flippy.mipmaps.add mip
104 | if mip.width == 1 or mip.height == 1:
105 | break
106 | mip = mip.minifyBy2()
107 | flippy.save(flippyPath)
108 |
109 | proc loadFlippy*(filePath: string): Flippy =
110 | ## Flippy is a special file format that is fast to load and save with mip maps.
111 | var f = newFileStream(filePath, fmRead)
112 | defer: f.close()
113 |
114 | if f.readStr(4) != "flip":
115 | raise newException(IOError, &"Invalid Flippy header {filePath}.")
116 |
117 | if f.readUint32() != version:
118 | raise newException(IOError, &"Invalid Flippy version {filePath}.")
119 |
120 | while not f.atEnd():
121 | if f.readStr(4) != "mip!":
122 | raise newException(IOError, &"Invalid Flippy sub header {filePath}.")
123 |
124 | var mip = Image()
125 | mip.width = int f.readUint32()
126 | mip.height = int f.readUint32()
127 | let zippedLen = f.readUint32().int
128 | var zipped = newSeq[uint8](zippedLen)
129 | let read = f.readData(zipped[0].addr, zippedLen)
130 | if read != zippedLen:
131 | raise newException(IOError, "Flippy read error.")
132 |
133 | # TODO: Talk to ryan about compression
134 | var unzipped = uncompress(zipped)
135 | var s = newStringStream(cast[string](unzipped))
136 | mip.data = newSeq[ColorRGBX](mip.width * mip.height)
137 | for c in mip.data.mitems:
138 | var rgba: ColorRGBA
139 | s.read(rgba)
140 | c = rgba
141 | #mip.data = uncompress(zipped)
142 |
143 | result.mipmaps.add(mip)
144 |
145 | proc outlineBorder*(image: Image, borderPx: int): Image =
146 | ## Adds n pixel border around alpha parts of the image.
147 | result = newImage(
148 | image.width + borderPx * 2,
149 | image.height + borderPx * 3,
150 | )
151 | for y in 0 ..< result.height:
152 | for x in 0 ..< result.width:
153 | var filled = false
154 | for bx in -borderPx .. borderPx:
155 | for by in -borderPx .. borderPx:
156 | var rgba = image[x + bx - borderPx, y - by - borderPx]
157 | if rgba.a > 0.uint8:
158 | filled = true
159 | break
160 | if filled:
161 | break
162 | if filled:
163 | result.unsafe[x, y] = rgba(255, 255, 255, 255)
164 |
--------------------------------------------------------------------------------
/src/fidget/opengl/glsl/410/atlas.frag:
--------------------------------------------------------------------------------
1 | #version 410
2 |
3 | in vec2 pos;
4 | in vec2 uv;
5 | in vec4 color;
6 |
7 | uniform vec2 windowFrame;
8 | uniform sampler2D atlasTex;
9 | uniform sampler2D maskTex;
10 |
11 | out vec4 fragColor;
12 |
13 | void main() {
14 | fragColor = texture(atlasTex, uv).rgba * color;
15 | vec2 normalizedPos = vec2(pos.x / windowFrame.x, 1 - pos.y / windowFrame.y);
16 | fragColor.a *= texture(maskTex, normalizedPos).r;
17 | }
18 |
--------------------------------------------------------------------------------
/src/fidget/opengl/glsl/410/atlas.vert:
--------------------------------------------------------------------------------
1 | #version 410
2 |
3 | in vec2 vertexPos;
4 | in vec2 vertexUv;
5 | in vec4 vertexColor;
6 |
7 | uniform mat4 proj;
8 |
9 | out vec2 pos;
10 | out vec2 uv;
11 | out vec4 color;
12 |
13 | void main() {
14 | pos = vertexPos;
15 | uv = vertexUv;
16 | color = vertexColor;
17 | gl_Position = proj * vec4(vertexPos, 0.0, 1.0);
18 | }
19 |
--------------------------------------------------------------------------------
/src/fidget/opengl/glsl/410/mask.frag:
--------------------------------------------------------------------------------
1 | #version 410
2 |
3 | in vec2 pos;
4 | in vec2 uv;
5 | in vec4 color;
6 |
7 | uniform vec2 windowFrame;
8 | uniform sampler2D atlasTex;
9 | uniform sampler2D maskTex;
10 |
11 | out vec4 fragColor;
12 |
13 | void main() {
14 | fragColor = vec4((texture(atlasTex, uv).rgba * color).a);
15 | vec2 normalizedPos = vec2(pos.x / windowFrame.x, 1 - pos.y / windowFrame.y);
16 | fragColor.a *= texture(maskTex, normalizedPos).r;
17 | }
18 |
--------------------------------------------------------------------------------
/src/fidget/opengl/glsl/atlas.frag:
--------------------------------------------------------------------------------
1 | #version 330
2 |
3 | in vec2 pos;
4 | in vec2 uv;
5 | in vec4 color;
6 |
7 | uniform vec2 windowFrame;
8 | uniform sampler2D atlasTex;
9 | uniform sampler2D maskTex;
10 |
11 | out vec4 fragColor;
12 |
13 | void main() {
14 | fragColor = texture(atlasTex, uv).rgba * color;
15 | vec2 normalizedPos = vec2(pos.x / windowFrame.x, 1 - pos.y / windowFrame.y);
16 | fragColor.a *= texture(maskTex, normalizedPos).r;
17 | }
18 |
--------------------------------------------------------------------------------
/src/fidget/opengl/glsl/atlas.vert:
--------------------------------------------------------------------------------
1 | #version 330
2 |
3 | in vec2 vertexPos;
4 | in vec2 vertexUv;
5 | in vec4 vertexColor;
6 |
7 | uniform mat4 proj;
8 |
9 | out vec2 pos;
10 | out vec2 uv;
11 | out vec4 color;
12 |
13 | void main() {
14 | pos = vertexPos;
15 | uv = vertexUv;
16 | color = vertexColor;
17 | gl_Position = proj * vec4(vertexPos, 0.0, 1.0);
18 | }
19 |
--------------------------------------------------------------------------------
/src/fidget/opengl/glsl/emscripten/atlas.frag:
--------------------------------------------------------------------------------
1 | #version 100
2 |
3 | precision highp float;
4 |
5 | varying vec2 pos;
6 | varying vec2 uv;
7 | varying vec4 color;
8 |
9 | uniform vec2 windowFrame;
10 | uniform sampler2D atlasTex;
11 | uniform sampler2D maskTex;
12 |
13 | void main() {
14 | gl_FragColor = texture2D(atlasTex, uv).rgba * color;
15 | vec2 normalizedPos = vec2(pos.x / windowFrame.x, 1.0 - pos.y / windowFrame.y);
16 | gl_FragColor.a *= texture2D(maskTex, normalizedPos).r;
17 | }
18 |
--------------------------------------------------------------------------------
/src/fidget/opengl/glsl/emscripten/atlas.vert:
--------------------------------------------------------------------------------
1 | #version 100
2 |
3 | precision highp float;
4 |
5 | attribute vec2 vertexPos;
6 | attribute vec2 vertexUv;
7 | attribute vec4 vertexColor;
8 |
9 | uniform mat4 proj;
10 |
11 | varying vec2 pos;
12 | varying vec2 uv;
13 | varying vec4 color;
14 |
15 | void main() {
16 | pos = vertexPos;
17 | uv = vertexUv;
18 | color = vertexColor;
19 | gl_Position = proj * vec4(vertexPos, 0.0, 1.0);
20 | }
21 |
--------------------------------------------------------------------------------
/src/fidget/opengl/glsl/emscripten/mask.frag:
--------------------------------------------------------------------------------
1 | #version 100
2 |
3 | precision highp float;
4 |
5 | varying vec2 pos;
6 | varying vec2 uv;
7 | varying vec4 color;
8 |
9 | uniform vec2 windowFrame;
10 | uniform sampler2D atlasTex;
11 | uniform sampler2D maskTex;
12 |
13 | void main() {
14 | gl_FragColor = vec4((texture2D(atlasTex, uv).rgba * color).a);
15 | vec2 normalizedPos = vec2(pos.x / windowFrame.x, 1.0 - pos.y / windowFrame.y);
16 | gl_FragColor .a *= texture2D(maskTex, normalizedPos).r;
17 | }
18 |
--------------------------------------------------------------------------------
/src/fidget/opengl/glsl/mask.frag:
--------------------------------------------------------------------------------
1 | #version 330
2 |
3 | in vec2 pos;
4 | in vec2 uv;
5 | in vec4 color;
6 |
7 | uniform vec2 windowFrame;
8 | uniform sampler2D atlasTex;
9 | uniform sampler2D maskTex;
10 |
11 | out vec4 fragColor;
12 |
13 | void main() {
14 | fragColor = vec4((texture(atlasTex, uv).rgba * color).a);
15 | vec2 normalizedPos = vec2(pos.x / windowFrame.x, 1 - pos.y / windowFrame.y);
16 | fragColor.a *= texture(maskTex, normalizedPos).r;
17 | }
18 |
--------------------------------------------------------------------------------
/src/fidget/opengl/perf.nim:
--------------------------------------------------------------------------------
1 | import math, std/monotimes, strformat, strutils, times
2 |
3 | when defined(nimTypeNames):
4 | import tables
5 |
6 | type
7 | EntryKind = enum
8 | Begin, End, Mark
9 |
10 | PerfEntry* = object
11 | tag: string
12 | ticks: int64
13 | kind: EntryKind
14 |
15 | TimeSeries* = ref object
16 | ## Helps you time stuff over multiple frames.
17 | at: Natural
18 | data: seq[float64]
19 |
20 | var
21 | perfEnabled* = true
22 | defaultBuffer: seq[PerfEntry]
23 |
24 | proc getTicks*(): int64 =
25 | getMonoTime().ticks
26 |
27 | proc addEntry(tag: string, kind: EntryKind, buffer: var seq[PerfEntry]) =
28 | var entry = PerfEntry()
29 | entry.tag = tag
30 | entry.ticks = getTicks()
31 | entry.kind = kind
32 |
33 | buffer.add(entry)
34 |
35 | template perfMark*(tag: string, buffer: var seq[PerfEntry] = defaultBuffer) =
36 | if perfEnabled:
37 | addEntry(tag, Mark, buffer)
38 |
39 | template perf*(tag: string, buffer: var seq[PerfEntry], body: untyped) =
40 | ## Logs the performance of the body block.
41 | if perfEnabled:
42 | addEntry(tag, Begin, buffer)
43 | body
44 | addEntry(tag, End, buffer)
45 | else:
46 | body
47 |
48 | template perf*(tag: string, body: untyped) =
49 | ## Logs the performance of the body block.
50 | if perfEnabled:
51 | perf(tag, defaultBuffer, body)
52 | else:
53 | body
54 |
55 | template timeIt*(tag: string, body: untyped) =
56 | ## Quick template to time an operation.
57 | var buffer: seq[PerfEntry]
58 | perf tag, buffer, body
59 |
60 | if len(buffer) > 0:
61 | let
62 | start = buffer[0].ticks
63 | finish = buffer[^1].ticks
64 | # Convert from nanoseconds to floating point seconds
65 | delta = float64(finish - start) / 1000000000.0
66 | echo tag, ": ", delta, "s"
67 | else:
68 | echo tag, " not timed, perf disabled"
69 |
70 | func `$`*(buffer: seq[PerfEntry]): string =
71 | if len(buffer) == 0:
72 | return
73 |
74 | var
75 | lines: seq[string]
76 | indent = ""
77 | prevTicks = buffer[0].ticks
78 |
79 | for i, entry in buffer:
80 | # Convert from nanoseconds to floating point seconds
81 | let delta = float64(entry.ticks - prevTicks) / 1000000000.0
82 | prevTicks = entry.ticks
83 |
84 | case entry.kind:
85 | of Begin:
86 | lines.add(&"{delta:>8.6f} {indent}{entry.tag} [")
87 | indent.add(" ")
88 | of End:
89 | indent = indent[0 .. ^3]
90 | lines.add(&"{delta:>8.6f} {indent}]")
91 | of Mark:
92 | lines.add(&"{delta:>8.6f}{indent} {entry.tag}")
93 |
94 | result = lines.join("\n")
95 |
96 | proc perfDump*(buffer: seq[PerfEntry] = defaultBuffer) =
97 | if perfEnabled:
98 | echo $defaultBuffer
99 | defaultBuffer.setLen(0)
100 |
101 | func newTimeSeries*(max: Natural = 1000): TimeSeries =
102 | result = TimeSeries()
103 | result.data = newSeq[float64](max)
104 |
105 | proc addTime*(timeSeries: var TimeSeries) =
106 | ## Add current time to time series.
107 | if timeSeries.at >= len(timeSeries.data):
108 | timeSeries.at = 0
109 | timeSeries.data[timeSeries.at] = epochTime()
110 | inc timeSeries.at
111 |
112 | proc num*(timeSeries: TimeSeries, inLastSeconds: float32 = 1.0): int =
113 | ## Get number of things in last N seconds.
114 | ## Example: get number of frames in the last second - fps.
115 | var startTime = epochTime()
116 | for f in timeSeries.data:
117 | if startTime - inLastSeconds < f:
118 | inc result
119 |
120 | proc avg*(timeSeries: TimeSeries, inLastSeconds: float32 = 1.0): float32 =
121 | ## Average over last N seconds.
122 | ## Example: 1/fps or average frame time.
123 | return inLastSeconds / float32(timeSeries.num(inLastSeconds))
124 |
125 | func byteFmt*(bytes: int): string =
126 | ## Formats computer sizes in B, KB, MB, GB etc...
127 | if bytes < 0:
128 | result.add "-"
129 | let
130 | sizes = @["B", "KB", "MB", "GB", "TB"]
131 | bytes = abs(bytes)
132 | if bytes < 1024:
133 | result.add $bytes & "B"
134 | else:
135 | var i = floor(log(float bytes, 10) / log(float 1024, 10))
136 | var scaled = float(bytes) / pow(float 1024, i)
137 | result.add &"{scaled:0.2f}{sizes[int i]}"
138 |
139 | assert byteFmt(12) == "12B"
140 | assert byteFmt(1000) == "1000B"
141 | assert byteFmt(1024) == "1.00KB"
142 | assert byteFmt(1200) == "1.17KB"
143 | assert byteFmt(1200_000) == "1.14MB"
144 | assert byteFmt(1200_000_000) == "1.12GB"
145 | assert byteFmt(-12) == "-12B"
146 | assert byteFmt(-1000) == "-1000B"
147 |
148 | when defined(nimTypeNames):
149 | import sequtils, algorithm
150 | type CountSize = object
151 | name: string
152 | count: int
153 | sizes: int
154 | diffCount: int
155 | diffSizes: int
156 | dead: bool
157 | var prevDump = newTable[string, CountSize]()
158 | func dumpHeapDiff*(top = 10): string =
159 | ## Takes a diff of the heap and prints out top 10 memory growers.
160 | # Example output:
161 | # HEAP total:276.95MB occupied:115.34MB free:148.76MB
162 | # [Heap] # 171765( -964) 68.97MB( -137.28KB) string
163 | # [Heap] # 1( 0) 40.00MB( 0B) seq[SelectorKey[asyncdispatch.AsyncData]]
164 | # [Heap] # 2889( -107) 1.58MB( -5.90KB) seq[string]
165 | # [Heap] # 2872( 0) 493.62KB( 0B) LyticTable
166 | # [Heap] # 2616( 0) 306.56KB( 0B) Field
167 | # [Heap] # 1( 0) 285.25KB( 0B) seq[DstChange]
168 | # [Heap] # 1( 0) 256.03KB( 0B) OrderedKeyValuePairSeq[system.string, lytic.LyticTable]
169 | # [Heap] # 1( 0) 128.03KB( 0B) OrderedKeyValuePairSeq[system.string, lytic.Field]
170 | # [Heap] # 2( -12) 8.00KB( -48.00KB) AsyncSocket
171 | # [Heap] # 33( -270) 2.32KB( -18.98KB) Future[system.void]
172 | # [Heap] # 6( -22) 5.25KB( -14.00KB) KeyValuePairSeq[system.string, seq[string]]
173 |
174 | result.add &"HEAP total:{byteFmt(getTotalMem())}"
175 | result.add &" occupied:{byteFmt(getOccupiedMem())}"
176 | result.add &" free:{byteFmt(getFreeMem())}\n"
177 | for v in prevDump.mvalues:
178 | v.dead = true
179 | for it in dumpHeapInstances():
180 | let name = $it.name
181 | if name notin prevDump:
182 | prevDump[name] = CountSize(
183 | name: name,
184 | count: it.count,
185 | sizes: it.sizes,
186 | diffCount: it.count,
187 | diffSizes: it.sizes
188 | )
189 | else:
190 | var prev = prevDump[name]
191 | prev.diffCount = it.count - prev.count
192 | prev.diffSizes = it.sizes - prev.sizes
193 | prev.count = it.count
194 | prev.sizes = it.sizes
195 | prev.dead = false
196 | prevDump[name] = prev
197 | for it in prevDump.mvalues:
198 | if it.dead:
199 | it.diffCount = -it.count
200 | it.diffSizes = -it.sizes
201 | it.count = 0
202 | it.sizes = 0
203 | # sort
204 | var arr = toSeq(prevDump.values())
205 | arr.sort func(a, b: CountSize): int =
206 | abs(b.sizes) + abs(b.diffSizes) - abs(a.sizes) - abs(a.diffSizes)
207 | for it in arr[0 .. min(len(arr)-1, top)]:
208 | result.add &"[Heap] #{it.count:>10}({it.diffCount:>10})"
209 | result.add &" {byteFmt(it.sizes):>10}({byteFmt(it.diffSizes):>10})"
210 | result.add &" {it.name}\n"
211 | else:
212 | func dumpHeapDiff*(top = 10): string =
213 | return "dumpHeapDiff disabled"
214 |
--------------------------------------------------------------------------------
/src/fidget/opengl/textures.nim:
--------------------------------------------------------------------------------
1 | import buffers, pixie, opengl
2 |
3 | type
4 | MinFilter* = enum
5 | minDefault,
6 | minNearest = GL_NEAREST,
7 | minLinear = GL_LINEAR,
8 | minNearestMipmapNearest = GL_NEAREST_MIPMAP_NEAREST,
9 | minLinearMipmapNearest = GL_LINEAR_MIPMAP_NEAREST,
10 | minNearestMipmapLinear = GL_NEAREST_MIPMAP_LINEAR,
11 | minLinearMipmapLinear = GL_LINEAR_MIPMAP_LINEAR
12 |
13 | MagFilter* = enum
14 | magDefault,
15 | magNearest = GL_NEAREST,
16 | magLinear = GL_LINEAR
17 |
18 | Wrap* = enum
19 | wDefault,
20 | wRepeat = GL_REPEAT,
21 | wClampToEdge = GL_CLAMP_TO_EDGE,
22 | wMirroredRepeat = GL_MIRRORED_REPEAT
23 |
24 | Texture* = object
25 | width*, height*: int32
26 | componentType*, format*, internalFormat*: GLenum
27 | minFilter*: MinFilter
28 | magFilter*: MagFilter
29 | wrapS*, wrapT*: Wrap
30 | genMipmap*: bool
31 | textureId*: GLuint
32 |
33 | proc bindTextureBufferData*(
34 | texture: ptr Texture, buffer: ptr Buffer, data: pointer
35 | ) =
36 | bindBufferData(buffer, data)
37 |
38 | if texture.textureId == 0:
39 | glGenTextures(1, texture.textureId.addr)
40 |
41 | glBindTexture(GL_TEXTURE_BUFFER, texture.textureId)
42 | glTexBuffer(
43 | GL_TEXTURE_BUFFER,
44 | texture.internalFormat,
45 | buffer.bufferId
46 | )
47 |
48 | proc bindTextureData*(texture: ptr Texture, data: pointer) =
49 | if texture.textureId == 0:
50 | glGenTextures(1, texture.textureId.addr)
51 |
52 | glBindTexture(GL_TEXTURE_2D, texture.textureId)
53 | glTexImage2D(
54 | target = GL_TEXTURE_2D,
55 | level = 0,
56 | internalFormat = texture.internalFormat.GLint,
57 | width = texture.width,
58 | height = texture.height,
59 | border = 0,
60 | format = texture.format,
61 | `type` = texture.componentType,
62 | pixels = data
63 | )
64 |
65 | if texture.magFilter != magDefault:
66 | glTexParameteri(
67 | GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, texture.magFilter.GLint
68 | )
69 | if texture.minFilter != minDefault:
70 | glTexParameteri(
71 | GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, texture.minFilter.GLint
72 | )
73 | if texture.wrapS != wDefault:
74 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, texture.wrapS.GLint)
75 | if texture.wrapT != wDefault:
76 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, texture.wrapT.GLint)
77 |
78 | if texture.genMipmap:
79 | glGenerateMipmap(GL_TEXTURE_2D)
80 |
81 | func getFormat(image: Image): GLenum =
82 | result = GL_RGBA
83 |
84 | proc initTexture*(image: Image): Texture =
85 | result.width = image.width.GLint
86 | result.height = image.height.GLint
87 | result.componentType = GL_UNSIGNED_BYTE
88 | result.format = image.getFormat()
89 | result.internalFormat = GL_RGBA8
90 | result.genMipmap = true
91 | result.minFilter = minLinearMipmapLinear
92 | result.magFilter = magLinear
93 | var data = newSeq[ColorRGBA](image.width * image.height)
94 | for i in 0 ..< data.len:
95 | data[i] = image.data[i]
96 | bindTextureData(result.addr, data[0].addr)
97 |
98 | proc updateSubImage*(texture: Texture, x, y: int, image: Image, level: int) =
99 | ## Update a small part of a texture image.
100 | var data = newSeq[ColorRGBA](image.width * image.height)
101 | for i in 0 ..< data.len:
102 | data[i] = image.data[i]
103 | glBindTexture(GL_TEXTURE_2D, texture.textureId)
104 | glTexSubImage2D(
105 | GL_TEXTURE_2D,
106 | level = level.GLint,
107 | xoffset = x.GLint,
108 | yoffset = y.GLint,
109 | width = image.width.GLint,
110 | height = image.height.GLint,
111 | format = image.getFormat(),
112 | `type` = GL_UNSIGNED_BYTE,
113 | pixels = data[0].addr
114 | )
115 |
116 | proc updateSubImage*(texture: Texture, x, y: int, image: Image) =
117 | ## Update a small part of texture with a new image.
118 | var
119 | x = x
120 | y = y
121 | image = image
122 | level = 0
123 |
124 | while image.width > 1 and image.height > 1:
125 | texture.updateSubImage(x, y, image, level)
126 | image = image.minifyBy2()
127 | x = x div 2
128 | y = y div 2
129 | inc(level)
130 |
--------------------------------------------------------------------------------
/src/shell_minimal.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Emscripten-Generated Code
7 |
21 |
22 |
23 |
24 |
25 |
26 |
92 | {{{ SCRIPT }}}
93 |
94 |
95 |
--------------------------------------------------------------------------------
/tests/_old/IBMPlexSans-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/_old/IBMPlexSans-Regular.ttf
--------------------------------------------------------------------------------
/tests/_old/Inconsolata.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/_old/Inconsolata.otf
--------------------------------------------------------------------------------
/tests/_old/Ubuntu.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/_old/Ubuntu.ttf
--------------------------------------------------------------------------------
/tests/_old/build_android.sh:
--------------------------------------------------------------------------------
1 | # force a build clean every time
2 | rm ~/.cache/nim/bars_d/*
3 | rm android_bars/app/src/main/cpp/*
4 |
5 | /p/Nim/bin/nim c -f --cpu:arm --os:android -c -d:androidNDK --noMain:on bars.nim
6 |
7 | cp android_bars/CMakeLists.txt android_bars/app/src/main/cpp/
8 |
9 | cp ~/.cache/nim/bars_d/*.c android_bars/app/src/main/cpp/
10 |
11 | cp /p/Nim/lib/nimbase.h android_bars/app/src/main/cpp/
12 | cp /p/glfm/glfm/src/file_compat.h android_bars/app/src/main/cpp/
13 | cp /p/glfm/glfm/include/glfm.h android_bars/app/src/main/cpp/
14 | cp /p/glfm/glfm/src/glfm_platform.h android_bars/app/src/main/cpp/
15 | cp /p/glfm/glfm/src/glfm_platform_android.c android_bars/app/src/main/cpp/
16 |
17 | cp -r assets/* android_bars/app/src/main/assets
18 |
19 | cp ~/.nimble/pkgs/stb_image-2.3/stb_image/*.c android_bars/app/src/main/cpp/
20 | cp ~/.nimble/pkgs/stb_image-2.3/stb_image/*.h android_bars/app/src/main/cpp/
21 |
--------------------------------------------------------------------------------
/tests/_old/build_ios.sh:
--------------------------------------------------------------------------------
1 | # force a build clean every time
2 | rm ~/.cache/nim/bars_d/*
3 | rm ios_bars/src/*
4 |
5 | # build it for iOS
6 | /p/Nim/bin/nim c -f --os:ios -d:macosx -c --noMain:on --gc:none bars.nim
7 |
8 | # copy all support files into the ios project
9 | cp ~/.cache/nim/bars_d/*.c ios_bars/src/
10 | cp /p/Nim/lib/nimbase.h ios_bars/src/
11 | cp /p/glfm/glfm/src/file_compat.h ios_bars/src/
12 | cp /p/glfm/glfm/include/glfm.h ios_bars/src/
13 | cp /p/glfm/glfm/src/glfm_platform.h ios_bars/src/
14 | cp /p/glfm/glfm/src/glfm_platform_ios.m ios_bars/src/
15 | cp -r assets/* ios_bars/
16 |
17 | cp ~/.nimble/pkgs/stb_image-2.3/stb_image/*.c ios_bars/src/
18 | cp ~/.nimble/pkgs/stb_image-2.3/stb_image/*.h ios_bars/src/
19 |
--------------------------------------------------------------------------------
/tests/_old/todo/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | https://medium.com/javascript-in-plain-english/i-created-the-exact-same-app-in-react-and-vue-part-2-angular-39b1aa289878
5 |
--------------------------------------------------------------------------------
/tests/_old/todo/data/IBMPlexSans-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/_old/todo/data/IBMPlexSans-Bold.ttf
--------------------------------------------------------------------------------
/tests/_old/todo/data/IBMPlexSans-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/_old/todo/data/IBMPlexSans-Regular.ttf
--------------------------------------------------------------------------------
/tests/_old/todo/data/arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/_old/todo/data/arrow.png
--------------------------------------------------------------------------------
/tests/_old/todo/data/arrow.slate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/_old/todo/data/arrow.slate
--------------------------------------------------------------------------------
/tests/_old/todo/data/arrow@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/_old/todo/data/arrow@2x.png
--------------------------------------------------------------------------------
/tests/_old/todo/data/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/_old/todo/data/icon.png
--------------------------------------------------------------------------------
/tests/_old/todo/data/icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/_old/todo/data/icon@2x.png
--------------------------------------------------------------------------------
/tests/_old/todo/todo.nim:
--------------------------------------------------------------------------------
1 | ## An example of how to implement a todo program based on:
2 | ## https://medium.com/javascript-in-plain-english/i-created-the-exact-same-app-in-react-and-vue-part-2-angular-39b1aa289878
3 |
4 | import fidget
5 |
6 | loadFont("IBM Plex Sans Regular", "IBMPlexSans-Regular.ttf")
7 | loadFont("IBM Plex Sans Bold", "IBMPlexSans-Bold.ttf")
8 |
9 | var todoItems: seq[string]
10 | var newItem: string
11 |
12 | todoItems = @["clean the house", "get milk"]
13 |
14 | proc drawMain() =
15 | setTitle("Fidget Example")
16 |
17 | frame "todoApp":
18 | box 0, 0, 473, 798
19 | constraints cMin, cMin
20 | fill "#ffffff"
21 | rectangle "bg":
22 | box 0, 0, 946, 1596
23 | constraints cMin, cMin
24 | fill "#dff6fe"
25 | cornerRadius 0
26 |
27 | frame "mainFrame":
28 | box 46, 132, 382, 535
29 | constraints cMin, cMin
30 | rectangle "bg":
31 | box 0, 0, 382, 535
32 | constraints cMin, cMin
33 | fill "#f6f6f6"
34 | stroke "#ffffff"
35 | cornerRadius 0
36 | strokeWeight 2
37 | text "title":
38 | box 94, 114, 211, 42
39 | constraints cMin, cMin
40 | fill "#000000"
41 | font "IBM Plex Sans Regular", 32, 200, 0, hLeft, vCenter
42 | characters "FIDGET TO DO"
43 |
44 | var y = 193
45 | var deleteIndex = -1
46 | for i, todoItem in todoItems:
47 | group "todoItem":
48 | box 30, y, 309, 44
49 | group "removeButton":
50 | box 281, 6, 28, 31
51 | rectangle "bg":
52 | box 0, 0, 28, 31
53 | # constraints cScale, cScale
54 | fill "#fd7476"
55 | cornerRadius 10
56 | text "minusText":
57 | box 0, 0, 28, 31
58 | # constraints cScale, cScale
59 | fill "#ffffff"
60 | font "IBM Plex Sans Regular", 22, 200, 0, hCenter, vCenter
61 | characters "-"
62 | onClick:
63 | deleteIndex = i
64 |
65 | rectangle "textBg":
66 | box 0, 0, 261, 44
67 | # constraints cScale, cScale
68 | fill "#ffffff"
69 | stroke "#d3d3d3"
70 | cornerRadius 0
71 | strokeWeight 2
72 | text "text":
73 | box 0, 0, 261, 44
74 | # constraints cScale, cScale
75 | fill "#000000"
76 | font "IBM Plex Sans Regular", 16, 200, 0, hCenter, vCenter
77 | characters todoItem
78 | y += 75
79 |
80 | if deleteIndex > -1:
81 | todoItems.delete(deleteIndex)
82 |
83 | group "addItem":
84 | box 30, y, 309, 44
85 | group "addButton":
86 | box 281, 6, 28, 31
87 | rectangle "Rectangle 25":
88 | box 0, 0, 28, 31
89 | constraints cMin, cMin
90 | fill "#79fd7a"
91 | cornerRadius 10
92 | text "+":
93 | box 0, 0, 28, 31
94 | constraints cMin, cMin
95 | fill "#ffffff"
96 | font "IBM Plex Sans Regular", 22, 200, 0, hCenter, vCenter
97 | characters "+"
98 |
99 | onClick:
100 | todoItems.add newItem
101 | newItem = ""
102 |
103 | rectangle "bg":
104 | box 0, 0, 261, 44
105 | constraints cMin, cMin
106 | fill "#ffffff"
107 | stroke "#d3d3d3"
108 | cornerRadius 0
109 | strokeWeight 2
110 | text "addText":
111 | box 0, 0, 261, 44
112 | # constraints cScale, cScale
113 | fill "#000000", 0.20000000298023224
114 | font "IBM Plex Sans Regular", 16, 200, 0, hCenter, vCenter
115 | #placeholder "add new item..."
116 | binding newItem
117 |
118 | startFidget(drawMain)
119 |
--------------------------------------------------------------------------------
/tests/autolayoutcomplex/autolayoutcomplex.nim:
--------------------------------------------------------------------------------
1 | import fidget
2 |
3 | setTitle("Auto Layout Complex")
4 |
5 | proc drawMain() =
6 | frame "autoLayoutComplex":
7 | box 0, 0, 400, 400
8 | fill "#ffffff"
9 | frame "autoFrame":
10 | box 0, 0, 300, 400
11 | fill "#cee5fb"
12 | layout lmVertical
13 | counterAxisSizingMode csAuto
14 | horizontalPadding 10
15 | verticalPadding 10
16 | itemSpacing 10
17 | rectangle "area1":
18 | box 10, 326, 75, 64
19 | fill "#90caff"
20 | rectangle "area2":
21 | box 35, 277, 101, 39
22 | fill "#379fff"
23 | layoutAlign laMax
24 | rectangle "area3":
25 | box 10, 203, 126, 64
26 | fill "#007ff4"
27 | layoutAlign laStretch
28 | rectangle "area4":
29 | box 10, 156, 40, 37
30 | fill "#0074df"
31 | rectangle "area6":
32 | box 34.5, 96, 77, 50
33 | fill "#005fb7"
34 | layoutAlign laCenter
35 | rectangle "area5":
36 | box 10, 56, 126, 30
37 | fill "#0062bd"
38 | layoutAlign laMax
39 | rectangle "area7":
40 | box 47.5, 10, 51, 36
41 | fill "#00407b"
42 | layoutAlign laCenter
43 |
44 | startFidget(drawMain, w = 400, h = 400)
45 |
--------------------------------------------------------------------------------
/tests/autolayoutcomplex/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/autolayoutcomplex/screenshot.png
--------------------------------------------------------------------------------
/tests/autolayouthorizontal/autolayouthorizontal.nim:
--------------------------------------------------------------------------------
1 | import fidget, random
2 |
3 | setTitle("Auto Layout Horizontal")
4 |
5 | var widths: seq[int]
6 | for i in 0 ..< 7:
7 | widths.add(27)
8 |
9 | proc drawMain() =
10 | frame "autoLayoutHorizontal":
11 | box 0, 0, 400, 400
12 | fill "#ffffff"
13 | fill "#ffffff"
14 | frame "autoFrame":
15 | box 58, 178, 284, 44
16 | fill "#cee5fb"
17 | fill "#cee5fb"
18 | layout lmHorizontal
19 | counterAxisSizingMode csAuto
20 | horizontalPadding 7
21 | verticalPadding 7
22 | itemSpacing 10
23 | rectangle "area1":
24 | box 247, 7, widths[0], 30
25 | fill "#90caff"
26 | rectangle "area2":
27 | box 207, 7, widths[1], 30
28 | fill "#379fff"
29 | rectangle "area3":
30 | box 167, 7, widths[2], 30
31 | fill "#007ff4"
32 | rectangle "area4":
33 | box 127, 7, widths[3], 30
34 | fill "#0074df"
35 | rectangle "area6":
36 | box 87, 7, widths[4], 30
37 | fill "#005fb7"
38 | rectangle "area5":
39 | box 47, 7, widths[5], 30
40 | fill "#0062bd"
41 | rectangle "area7":
42 | box 7, 7, widths[6], 30
43 | fill "#00407b"
44 |
45 | for i in 0 ..< 7:
46 | widths[i] = max(widths[i] + rand(-1 .. 2), 10)
47 |
48 | startFidget(drawMain, w = 400, h = 400)
49 |
--------------------------------------------------------------------------------
/tests/autolayouthorizontal/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/autolayouthorizontal/screenshot.png
--------------------------------------------------------------------------------
/tests/autolayouttext/autolayouttext.nim:
--------------------------------------------------------------------------------
1 | import fidget
2 |
3 | loadFont("Ubuntu", "Ubuntu.ttf")
4 | setTitle("Auto Layout Text")
5 |
6 | proc drawMain() =
7 | frame "autoLayoutText":
8 | box 0, 0, parent.box.w, 491
9 | fill "#ffffff"
10 | layout lmVertical
11 | counterAxisSizingMode csFixed
12 | horizontalPadding 30
13 | verticalPadding 30
14 | itemSpacing 10
15 | text "p2":
16 | box 30, 361, 326, 100
17 | fill "#000000"
18 | font "Ubuntu", 14, 400, 20, hLeft, vTop
19 | characters "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
20 | textAutoResize tsHeight
21 | layoutAlign laStretch
22 | text "title2":
23 | box 30, 319, 326, 32
24 | fill "#000000"
25 | font "Ubuntu", 20, 400, 32, hLeft, vTop
26 | characters "Lorem Ipsum"
27 | textAutoResize tsHeight
28 | layoutAlign laStretch
29 | text "imgCaption":
30 | box 30, 289, 326, 20
31 | fill "#9c9c9c"
32 | font "Ubuntu", 14, 400, 20, hCenter, vTop
33 | characters "Lorem ipsum dolor sit ame"
34 | textAutoResize tsHeight
35 | layoutAlign laStretch
36 | rectangle "imgPlaceholder":
37 | box 125.5, 182, 135, 97
38 | fill "#88dc60"
39 | layoutAlign laCenter
40 | text "p1":
41 | box 30, 72, 326, 100
42 | fill "#000000"
43 | font "Ubuntu", 14, 400, 20, hLeft, vTop
44 | characters "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
45 | textAutoResize tsHeight
46 | layoutAlign laStretch
47 | text "title1":
48 | box 30, 30, 326, 32
49 | fill "#000000"
50 | font "Ubuntu", 20, 400, 32, hLeft, vTop
51 | characters "Lorem Ipsum"
52 | textAutoResize tsHeight
53 | layoutAlign laStretch
54 |
55 | startFidget(drawMain, w = 400, h = 400)
56 |
--------------------------------------------------------------------------------
/tests/autolayouttext/data/Ubuntu.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/autolayouttext/data/Ubuntu.ttf
--------------------------------------------------------------------------------
/tests/autolayouttext/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/autolayouttext/screenshot.png
--------------------------------------------------------------------------------
/tests/autolayoutvertical/autolayoutvertical.nim:
--------------------------------------------------------------------------------
1 | import fidget, random
2 |
3 | setTitle("Auto Layout Vertical")
4 |
5 | var heights: seq[int]
6 | for i in 0 ..< 7:
7 | heights.add(27)
8 |
9 | proc drawMain() =
10 | frame "autoLayout":
11 | box 0, 0, 400, 400
12 | fill "#ffffff"
13 | frame "autoFrame":
14 | box 100, 75, 200, 249
15 | layout lmVertical
16 | counterAxisSizingMode csAuto
17 | horizontalPadding 0
18 | verticalPadding 0
19 | itemSpacing 10
20 | rectangle "area1":
21 | box 0, 222, 200, heights[0]
22 | fill "#90caff"
23 | rectangle "area2":
24 | box 0, 185, 200, heights[1]
25 | fill "#379fff"
26 | rectangle "area3":
27 | box 0, 148, 200, heights[2]
28 | fill "#007ff4"
29 | rectangle "area4":
30 | box 0, 111, 200, heights[3]
31 | fill "#0074df"
32 | rectangle "area5":
33 | box 0, 74, 200, heights[4]
34 | fill "#0062bd"
35 | rectangle "area6":
36 | box 0, 37, 200, heights[5]
37 | fill "#005fb7"
38 | rectangle "area7":
39 | box 0, 0, 200, heights[6]
40 | fill "#00407b"
41 |
42 | for i in 0 ..< 7:
43 | heights[i] = max(heights[i] + rand(-1 .. 2), 10)
44 |
45 | startFidget(drawMain, w = 400, h = 400)
46 |
--------------------------------------------------------------------------------
/tests/autolayoutvertical/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/autolayoutvertical/screenshot.png
--------------------------------------------------------------------------------
/tests/bars/README.md:
--------------------------------------------------------------------------------
1 | # Bars - Simple example that shows 1000s of bars
2 |
3 | Each bar has an add and subtract buttons on left and right.
4 | Thousands of bars can exist because only the bars on screens are drawn and processed.
5 |
--------------------------------------------------------------------------------
/tests/bars/bars.nim:
--------------------------------------------------------------------------------
1 | import bumpy, fidget, math, random
2 |
3 | # Create an array of 30 bars.
4 | var bars = newSeq[float](30)
5 | for i, bar in bars:
6 | bars[i] = rand(1.0)
7 |
8 | proc drawMain() =
9 | # Set the window title.
10 | setTitle("Fidget Bars Example")
11 |
12 | # Use simple math to layout things.
13 | let h = bars.len * 60 + 20
14 | let barW = root.box.w - 100
15 |
16 | frame "main":
17 | box 0, 0, int root.box.w, max(int root.box.h, h)
18 | fill "#F7F7F9"
19 |
20 | group "center":
21 | box 50, 0, barW, float max(int root.box.h, h)
22 | fill "#FFFFFF"
23 |
24 | # Draw a list of bars using a simple for loop.
25 | for i, bar in bars.mpairs:
26 | group "bar":
27 | box 20, 20 + 60 * i, barW, 60
28 |
29 | # If current box is not on screen, don't draw children.
30 | if current.screenBox.overlaps(scrollBox):
31 |
32 | # Draw the decrement button to make the bar go down.
33 | rectangle "dec":
34 | box 0, 0, 40, 40
35 | fill "#AEB5C0"
36 | onHover:
37 | fill "#FF4400"
38 | onClick:
39 | bar -= 0.1
40 | if bar < 0.0: bar = 0.0
41 |
42 | # Draw the increment button to make the bar go up.
43 | rectangle "inc":
44 | box barW-80, 0, 40, 40
45 | fill "#AEB5C0"
46 | onHover:
47 | fill "#FF4400"
48 | onClick:
49 | bar += 0.1
50 | if bar > 1.0: bar = 1.0
51 |
52 | # Draw the bar itself.
53 | group "bar":
54 | box 60, 0, barW - 80*2, 40
55 | fill "#F7F7F9"
56 | rectangle "barFg":
57 | box 0, 0, (barW - 80*2) * float(bar), 40
58 | fill "#46D15F"
59 |
60 | startFidget(drawMain)
61 |
--------------------------------------------------------------------------------
/tests/bars/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/bars/screenshot.png
--------------------------------------------------------------------------------
/tests/bluestar.flippy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/bluestar.flippy
--------------------------------------------------------------------------------
/tests/bluestar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/bluestar.png
--------------------------------------------------------------------------------
/tests/centercentertext/centercentertext.nim:
--------------------------------------------------------------------------------
1 | ## Shows a text pad like program.
2 |
3 | import fidget
4 |
5 | loadFont("IBM Plex Sans", "IBMPlexSans-Regular.ttf")
6 |
7 | setTitle("cCenter and vCenter text")
8 |
9 | proc drawMain() =
10 |
11 | frame "phoneLike":
12 | box 0, 0, parent.box.w, parent.box.h
13 | orgBox 0, 0, 375, 667
14 |
15 | fill "#ffffff"
16 |
17 | text "Some Test X":
18 | box 55, 81, 266, 62
19 | constraints cCenter, cCenter
20 | fill "#000000"
21 | font "IBM Plex Sans", 48, 400, 48, hLeft, vCenter
22 | characters "Some Test X"
23 | textAutoResize tsWidthAndHeight
24 |
25 | rectangle "box":
26 | box 55, 81, 266, 62
27 | constraints cCenter, cCenter
28 | fill "#ff7b7b"
29 |
30 | startFidget(drawMain, w = 375, h = 667)
31 |
--------------------------------------------------------------------------------
/tests/centercentertext/data/IBMPlexSans-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/centercentertext/data/IBMPlexSans-Regular.ttf
--------------------------------------------------------------------------------
/tests/centercentertext/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/centercentertext/screenshot.png
--------------------------------------------------------------------------------
/tests/config.nims:
--------------------------------------------------------------------------------
1 | --path:"../src"
2 |
--------------------------------------------------------------------------------
/tests/constraints/constraints.nim:
--------------------------------------------------------------------------------
1 | import fidget
2 |
3 | setTitle("Constraints")
4 |
5 | proc drawMain() =
6 | frame "constraints":
7 | # Got to specify orgBox for constraints to work.
8 | orgBox 0, 0, 400, 400
9 | # Then grow the normal box.
10 | box root.box
11 | # Constraints will work on the difference between orgBox and box.
12 | fill "#ffffff"
13 | rectangle "Center":
14 | box 150, 150, 100, 100
15 | constraints cCenter, cCenter
16 | fill "#f8c5a8"
17 | rectangle "Scale":
18 | box 100, 100, 200, 200
19 | constraints cScale, cScale
20 | fill "#ffac7d"
21 | rectangle "LRTB":
22 | box 40, 40, 320, 320
23 | constraints cStretch, cStretch
24 | fill "#ff8846"
25 | rectangle "TR":
26 | box 360, 20, 20, 20
27 | constraints cMax, cMin
28 | fill "#ff5b00"
29 | rectangle "TL":
30 | box 20, 20, 20, 20
31 | constraints cMin, cMin
32 | fill "#ff5b00"
33 | rectangle "BR":
34 | box 360, 360, 20, 20
35 | constraints cMax, cMax
36 | fill "#ff5b00"
37 | rectangle "BL":
38 | box 20, 360, 20, 20
39 | constraints cMin, cMax
40 | fill "#ff5b00"
41 |
42 | startFidget(drawMain, w = 400, h = 400)
43 |
--------------------------------------------------------------------------------
/tests/constraints/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/constraints/screenshot.png
--------------------------------------------------------------------------------
/tests/constrantscenteroffset/constrantscenteroffset.nim:
--------------------------------------------------------------------------------
1 | import fidget
2 |
3 | setTitle("Constraints Center Offset")
4 |
5 | proc drawMain() =
6 | frame "constraints":
7 | orgBox 0, 0, 500, 500
8 | box 0, 0, parent.box.w, parent.box.h
9 | fill "#ffffff"
10 | rectangle "Rectangle 5":
11 | box 300, 100, 100, 100
12 | constraints cCenter, cCenter
13 | fill "#d8fbbd"
14 | rectangle "Rectangle 4":
15 | box 300, 300, 100, 100
16 | constraints cCenter, cCenter
17 | fill "#ff7b7b"
18 | rectangle "Rectangle 3":
19 | box 100, 300, 100, 100
20 | constraints cCenter, cCenter
21 | fill "#ffb48a"
22 | rectangle "Rectangle 2":
23 | box 100, 100, 100, 100
24 | constraints cCenter, cCenter
25 | fill "#abf1e5"
26 |
27 | startFidget(drawMain, w = 500, h = 500)
28 |
--------------------------------------------------------------------------------
/tests/constrantscenteroffset/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/constrantscenteroffset/screenshot.png
--------------------------------------------------------------------------------
/tests/context_test.nim:
--------------------------------------------------------------------------------
1 | import chroma, fidget, fidget/common, fidget/opengl/base, fidget/opengl/context,
2 | flippy, os, osproc, vmath
3 |
4 | setCurrentDir(getCurrentDir() / "tests")
5 |
6 | var
7 | loaded: bool
8 | ctx: Context
9 |
10 | var tests: seq[proc()]
11 |
12 | tests.add(proc() =
13 | ctx.beginFrame(vec2(100, 100))
14 | ctx.drawImage("bluestar.png")
15 | ctx.drawImage("bluestar.png", size = vec2(20, 20))
16 | ctx.endFrame()
17 |
18 | takeScreenshot(rect(0, 0, 100, 100)).save("image_basic.png")
19 | )
20 |
21 | tests.add(proc() =
22 | ctx.beginFrame(vec2(100, 100))
23 | ctx.drawImage("bluestar.png", scale = 0.5)
24 | ctx.endFrame()
25 |
26 | takeScreenshot(rect(0, 0, 100, 100)).save("image_scale.png")
27 | )
28 |
29 | tests.add(proc() =
30 | ctx.beginFrame(vec2(100, 100))
31 | ctx.drawSprite("bluestar.png", vec2(50, 50))
32 | ctx.endFrame()
33 |
34 | takeScreenshot(rect(0, 0, 100, 100)).save("sprite_basic.png")
35 | )
36 |
37 | tests.add(proc() =
38 | ctx.beginFrame(vec2(100, 100))
39 | ctx.translate(vec2(25, 25))
40 | ctx.fillRect(rect(0, 0, 50, 50), color(0, 1, 0, 1))
41 | ctx.endFrame()
42 |
43 | takeScreenshot(rect(0, 0, 100, 100)).save("translate.png")
44 | )
45 |
46 | tests.add(proc() =
47 | ctx.beginFrame(vec2(100, 100))
48 | ctx.scale(2)
49 | ctx.fillRect(rect(0, 0, 50, 50), color(1, 1, 0, 1))
50 | ctx.endFrame()
51 |
52 | takeScreenshot(rect(0, 0, 100, 100)).save("scale.png")
53 | )
54 |
55 | tests.add(proc() =
56 | ctx.beginFrame(vec2(100, 100))
57 | ctx.fillRoundedRect(rect(25, 25, 50, 50), color(1, 0, 0, 1), 5)
58 | ctx.strokeRoundedRect(rect(10, 10, 80, 80), color(0.5, 0.5, 0.5, 1), 2, 10)
59 | ctx.endFrame()
60 |
61 | takeScreenshot(rect(0, 0, 100, 100)).save("rounded.png")
62 | )
63 |
64 | tests.add(proc() =
65 | ctx.beginFrame(vec2(501, 281))
66 |
67 | ctx.drawImage("winFrame.png")
68 | ctx.beginMask()
69 | ctx.drawImage("winFrameMask.png")
70 | ctx.endMask()
71 | for x in 0 .. 5:
72 | for y in 0 .. 3:
73 | ctx.drawImage(
74 | "bluestar.png", pos = vec2(x.float32 * 100, y.float32 * 100))
75 | ctx.popMask()
76 | ctx.endFrame()
77 |
78 | takeScreenshot(rect(0, 0, 501, 281)).save("masking.png")
79 | )
80 |
81 | tests.add(proc() =
82 | ctx.beginFrame(vec2(501, 281))
83 |
84 | ctx.drawImage("winFrame.png")
85 | ctx.beginMask()
86 | ctx.drawImage("winFrameMask.png")
87 | ctx.endMask()
88 |
89 | ctx.drawImage("winFrame.png", pos = vec2(60, 60))
90 | ctx.beginMask()
91 | ctx.drawImage("winFrameMask.png", pos = vec2(60, 60))
92 | ctx.endMask()
93 |
94 | ctx.drawImage("winFrame.png", pos = vec2(120, 120))
95 | ctx.beginMask()
96 | ctx.drawImage("winFrameMask.png", pos = vec2(120, 120))
97 | ctx.endMask()
98 |
99 | for x in 0 .. 5:
100 | for y in 0 .. 3:
101 | ctx.drawImage(
102 | "bluestar.png", pos = vec2(x.float32 * 100, y.float32 * 100))
103 |
104 | ctx.popMask()
105 | ctx.popMask()
106 | ctx.popMask()
107 |
108 | ctx.endFrame()
109 |
110 | takeScreenshot(rect(0, 0, 501, 281)).save("multi_masking.png")
111 | )
112 |
113 | tests.add(proc() =
114 | ctx.beginFrame(vec2(501, 281))
115 |
116 | ctx.drawImage("winFrame.png")
117 | ctx.beginMask()
118 | ctx.drawImage("winFrameMask.png")
119 | ctx.endMask()
120 |
121 | for x in 0 .. 5:
122 | for y in 0 .. 3:
123 | ctx.drawImage(
124 | "orangeHex.png", pos = vec2(x.float32 * 100, y.float32 * 100))
125 |
126 | ctx.popMask()
127 |
128 | for x in 0 .. 5:
129 | for y in 0 .. 3:
130 | ctx.drawImage(
131 | "bluestar.png", pos = vec2(x.float32 * 100, y.float32 * 100))
132 |
133 | ctx.endFrame()
134 |
135 | takeScreenshot(rect(0, 0, 501, 281)).save("multi_masking_pop.png")
136 | )
137 |
138 | tests.add(proc() =
139 | var passed: bool
140 | try:
141 | ctx.beginFrame(vec2(100, 100))
142 | ctx.beginFrame(vec2(100, 100))
143 | except:
144 | passed = true
145 | ctx.endFrame()
146 |
147 | if not passed:
148 | quit("Calling beginFrame before endFrame didn't fail as expected")
149 | )
150 |
151 | tests.add(proc() =
152 | try:
153 | ctx.endFrame()
154 | quit("Calling endFrame before beginFrame didn't fail as expected")
155 | except:
156 | discard
157 | )
158 |
159 | tests.add(proc() =
160 | var passed: bool
161 | try:
162 | ctx.beginMask()
163 | except:
164 | passed = true
165 |
166 | if not passed:
167 | quit("Calling beginMask before beginFrame didn't fail as expected")
168 | )
169 |
170 | tests.add(proc() =
171 | var passed: bool
172 | try:
173 | ctx.beginFrame(vec2(100, 100))
174 | ctx.beginMask()
175 | ctx.beginMask()
176 | except:
177 | passed = true
178 | ctx.endMask()
179 | ctx.popMask()
180 | ctx.endFrame()
181 |
182 | if not passed:
183 | quit("Calling beginMask before endMask didn't fail as expected")
184 | )
185 |
186 | tests.add(proc() =
187 | try:
188 | ctx.endMask()
189 | quit("Calling endMask before beginMask didn't fail as expected")
190 | except:
191 | discard
192 | )
193 |
194 | tests.add(proc() =
195 | try:
196 | ctx.clearMask()
197 | quit("Calling clearMask before beginFrame didn't fail as expected")
198 | except:
199 | discard
200 | )
201 |
202 | var i: int
203 | proc draw() =
204 | if not loaded:
205 | loaded = true
206 | ctx = newContext()
207 |
208 | ctx.clearTransform()
209 | tests[i]()
210 | inc(i)
211 |
212 | if i == len(tests):
213 | base.running = false
214 |
215 | startFidget(draw, mainLoopMode = RepaintOnFrame)
216 |
217 | let (outp, _) = execCmdEx("git diff tests/*.png")
218 | if len(outp) != 0:
219 | echo outp
220 | quit("Output does not match")
221 |
--------------------------------------------------------------------------------
/tests/cursorstyle/cursorstyle.nim:
--------------------------------------------------------------------------------
1 | ## Test the mouse cursor changing when you hover over an element.
2 |
3 | import fidget
4 |
5 | proc drawMain() =
6 | rectangle "example":
7 | box 100, 100, 100, 100
8 | fill "#FF0000"
9 | onHover:
10 | fill "#00FF00"
11 | mouse.cursorStyle = Pointer
12 |
13 | startFidget(drawMain, w = 400, h = 400)
14 |
--------------------------------------------------------------------------------
/tests/cursorstyle/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/cursorstyle/screenshot.png
--------------------------------------------------------------------------------
/tests/exportorder/exportorder.nim:
--------------------------------------------------------------------------------
1 |
2 | import fidget
3 |
4 | setTitle("Export Order")
5 |
6 | proc drawMain() =
7 | frame "export_order":
8 | box 0, 0, 400, 400
9 | constraints cMin, cMin
10 | fill "#ffffff"
11 | rectangle "rect1":
12 | ## This is the top rectangle
13 | box 250, 250, 100, 100
14 | fill "#f9e0d2"
15 | rectangle "rect2":
16 | box 200, 200, 100, 100
17 | fill "#f8c5a8"
18 | rectangle "rect3":
19 | box 150, 150, 100, 100
20 | fill "#ffac7d"
21 | rectangle "rect4":
22 | box 100, 100, 100, 100
23 | fill "#ff8846"
24 | rectangle "rect5":
25 | ## This is the bottom rectangle
26 | box 50, 50, 100, 100
27 | fill "#ff5b00"
28 |
29 | startFidget(drawMain, w = 400, h = 400)
30 |
--------------------------------------------------------------------------------
/tests/exportorder/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/exportorder/screenshot.png
--------------------------------------------------------------------------------
/tests/fontmetrics/data/Changa-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/fontmetrics/data/Changa-Bold.ttf
--------------------------------------------------------------------------------
/tests/fontmetrics/data/IBMPlexSans-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/fontmetrics/data/IBMPlexSans-Regular.ttf
--------------------------------------------------------------------------------
/tests/fontmetrics/data/Jura-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/fontmetrics/data/Jura-Regular.ttf
--------------------------------------------------------------------------------
/tests/fontmetrics/data/Lato-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/fontmetrics/data/Lato-Regular.ttf
--------------------------------------------------------------------------------
/tests/fontmetrics/data/SourceSansPro-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/fontmetrics/data/SourceSansPro-Regular.ttf
--------------------------------------------------------------------------------
/tests/fontmetrics/data/Ubuntu.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/fontmetrics/data/Ubuntu.ttf
--------------------------------------------------------------------------------
/tests/fontmetrics/data/silver.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/fontmetrics/data/silver.ttf
--------------------------------------------------------------------------------
/tests/fontmetrics/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/fontmetrics/screenshot.png
--------------------------------------------------------------------------------
/tests/hovers/README.md:
--------------------------------------------------------------------------------
1 | # Bars - Simple example that shows 1000s of bars
2 |
3 | Each bar has an add and subtract buttons on left and right.
4 | Thousands of bars can exist because only the bars on screens are drawn and processed.
5 |
--------------------------------------------------------------------------------
/tests/hovers/hovers.nim:
--------------------------------------------------------------------------------
1 | import fidget, math, random
2 |
3 | var bars = newSeq[int](10)
4 | for i, bar in bars:
5 | bars[i] = rand(40)
6 |
7 | proc drawMain() =
8 |
9 | setTitle("Hovers Example")
10 |
11 | popupActive = true
12 |
13 | let h = bars.len * 60 + 20
14 | frame "main":
15 | box 0, 0, int root.box.w, max(int root.box.h, h)
16 |
17 | inPopup = true
18 | group "center":
19 | box 150, 150, 100, 100
20 | fill "#00FF00"
21 |
22 | onHover:
23 | fill "#FF0000"
24 | inPopup = false
25 |
26 | group "center":
27 | box 100, 100, 100, 100
28 | fill "#0000FF"
29 |
30 | onHover:
31 | fill "#FF0000"
32 |
33 | startFidget(drawMain)
34 |
--------------------------------------------------------------------------------
/tests/hovers/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/hovers/screenshot.png
--------------------------------------------------------------------------------
/tests/httpget/data/IBMPlexSans-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/httpget/data/IBMPlexSans-Regular.ttf
--------------------------------------------------------------------------------
/tests/httpget/httpget.nim:
--------------------------------------------------------------------------------
1 | import fidget, json
2 |
3 | loadFont("IBM Plex Sans Regular", "IBMPlexSans-Regular.ttf")
4 |
5 | setTitle("What is my IP?")
6 |
7 | proc drawMain() =
8 |
9 | text "text":
10 | box 0, 0, 300, 100
11 | font "IBM Plex Sans Regular", 26.0, 400.0, 26, hCenter, vCenter
12 |
13 | # Do an HTTP call.
14 | var call = httpGet("https://api.ipify.org/?format=json")
15 | if call.status == Ready:
16 | fill "#000000"
17 | characters call.json["ip"].getStr()
18 | elif call.status == Error:
19 | fill "#FF0000"
20 | characters "Error!"
21 | else:
22 | fill "#808080"
23 | characters "Loading..."
24 |
25 | startFidget(drawMain, w = 300, h = 100)
26 |
--------------------------------------------------------------------------------
/tests/httpget/httpget.nims:
--------------------------------------------------------------------------------
1 | --d:ssl
2 |
--------------------------------------------------------------------------------
/tests/image_basic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/image_basic.png
--------------------------------------------------------------------------------
/tests/image_masking.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/image_masking.png
--------------------------------------------------------------------------------
/tests/image_scale.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/image_scale.png
--------------------------------------------------------------------------------
/tests/imagegen/data/generated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/imagegen/data/generated.png
--------------------------------------------------------------------------------
/tests/imagegen/imagegen.nim:
--------------------------------------------------------------------------------
1 | import chroma, fidget, flippy
2 |
3 | # Generate an image - color palette.
4 | var f = newImage(600, 300, 4)
5 | for x in 0 ..< f.width:
6 | for y in 0 ..< f.height:
7 | f.putRgba(x, y, hsl(
8 | x.float/f.width.float*360,
9 | y.float/f.height.float*100,
10 | 50
11 | ).color.rgba)
12 | f.save("data/generated.png")
13 |
14 | # Display the generated image in a window.
15 | setTitle("Image viewer")
16 | proc drawMain() =
17 | group "image":
18 | box 0, 0, f.width, f.height
19 | image "generated.png"
20 | startFidget(drawMain, w = f.width, h = f.height)
21 |
--------------------------------------------------------------------------------
/tests/images/data/img1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/images/data/img1.png
--------------------------------------------------------------------------------
/tests/images/data/img2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/images/data/img2.png
--------------------------------------------------------------------------------
/tests/images/data/img3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/images/data/img3.png
--------------------------------------------------------------------------------
/tests/images/data/img4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/images/data/img4.png
--------------------------------------------------------------------------------
/tests/images/data/img5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/images/data/img5.png
--------------------------------------------------------------------------------
/tests/images/data/img6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/images/data/img6.png
--------------------------------------------------------------------------------
/tests/images/data/img7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/images/data/img7.png
--------------------------------------------------------------------------------
/tests/images/data/img8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/images/data/img8.png
--------------------------------------------------------------------------------
/tests/images/data/img9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/images/data/img9.png
--------------------------------------------------------------------------------
/tests/images/images.nim:
--------------------------------------------------------------------------------
1 | import fidget
2 |
3 | setTitle("Images")
4 |
5 | # Photo from: https://unsplash.com/photos/64ldgzW158M
6 | # by Kyle Mackie @macrz
7 |
8 | proc drawMain() =
9 | frame "images":
10 | box 0, 0, 400, 400
11 | fill "#ffffff"
12 | group "img1":
13 | box 260, 260, 100, 100
14 | image "img1.png"
15 | group "img2":
16 | box 260, 150, 100, 100
17 | image "img2.png"
18 | group "img3":
19 | box 260, 40, 100, 100
20 | image "img3.png"
21 | group "img4":
22 | box 150, 260, 100, 100
23 | image "img4.png"
24 | group "img5":
25 | box 150, 150, 100, 100
26 | image "img5.png"
27 | group "img6":
28 | box 150, 40, 100, 100
29 | image "img6.png"
30 | group "img7":
31 | box 40, 260, 100, 100
32 | image "img7.png"
33 | group "img8":
34 | box 40, 150, 100, 100
35 | image "img8.png"
36 | group "img9":
37 | box 40, 40, 100, 100
38 | image "img9.png"
39 |
40 | startFidget(drawMain, w = 400, h = 400)
41 |
--------------------------------------------------------------------------------
/tests/images/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/images/screenshot.png
--------------------------------------------------------------------------------
/tests/imagestatic/imagestatic.nim:
--------------------------------------------------------------------------------
1 | import chroma, fidget, fidget/opengl/base, fidget/opengl/context, flippy,
2 | hashes, random, tables
3 |
4 | # Generate an image.
5 | var f = newImage(600, 300, 4)
6 |
7 | # Display the generated image in a window.
8 | setTitle("Image static viewer.")
9 | proc drawMain() =
10 |
11 | # Generate new static.
12 | for x in 0 ..< f.width:
13 | for y in 0 ..< f.height:
14 | let v = rand(0..255).uint8
15 | f.putRgba(x, y, rgba(v, v, v, 255))
16 |
17 | # Put or update the static.
18 | if hash("static") notin ctx.entries:
19 | ctx.putImage("static", f)
20 | else:
21 | ctx.updateImage("static", f)
22 |
23 | ctx.drawImage("static")
24 |
25 | startFidget(drawMain, w = f.width, h = f.height, mainLoopMode = RepaintOnFrame)
26 |
--------------------------------------------------------------------------------
/tests/inputsandoutputs/data/Ubuntu.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/inputsandoutputs/data/Ubuntu.ttf
--------------------------------------------------------------------------------
/tests/inputsandoutputs/inputsandoutputs.nim:
--------------------------------------------------------------------------------
1 | import fidget
2 |
3 | loadFont("Ubuntu", "Ubuntu.ttf")
4 | setTitle("Inputs and Outputs")
5 |
6 | var data = @[
7 | @["Fidget", "Fidget", "Fidget"],
8 | @["Fidget", "Fidget", "Fidget"],
9 | @["Fidget", "Fidget", "Fidget"],
10 | ]
11 |
12 | proc drawMain() =
13 |
14 | frame "inputsAndOutputs":
15 | box 0, 0, 800, 400
16 | fill "#ffffff"
17 | layout lmHorizontal
18 | counterAxisSizingMode csAuto
19 | horizontalPadding 40
20 | verticalPadding 40
21 | itemSpacing 80
22 | group "outputs":
23 | box 440, 40, 320, 320
24 | layoutAlign laCenter
25 | text "output":
26 | box 220, 220, 100, 100
27 | fill "#000000"
28 | font "Ubuntu", 20, 400, 32, hRight, vBottom
29 | characters data[0][0]
30 | text "output":
31 | box 220, 110, 100, 100
32 | fill "#000000"
33 | font "Ubuntu", 20, 400, 32, hRight, vCenter
34 | characters data[1][0]
35 | text "output":
36 | box 220, 0, 100, 100
37 | fill "#000000"
38 | font "Ubuntu", 20, 400, 32, hRight, vTop
39 | characters data[2][0]
40 | text "output":
41 | box 110, 220, 100, 100
42 | fill "#000000"
43 | font "Ubuntu", 20, 400, 32, hCenter, vBottom
44 | characters data[0][1]
45 | text "output":
46 | box 110, 110, 100, 100
47 | fill "#000000"
48 | font "Ubuntu", 20, 400, 32, hCenter, vCenter
49 | characters data[1][1]
50 | text "output":
51 | box 110, 0, 100, 100
52 | fill "#000000"
53 | font "Ubuntu", 20, 400, 32, hCenter, vTop
54 | characters data[2][1]
55 | text "output":
56 | box 0, 220, 100, 100
57 | fill "#000000"
58 | font "Ubuntu", 20, 400, 32, hLeft, vBottom
59 | characters data[0][2]
60 | text "output":
61 | box 0, 110, 100, 100
62 | fill "#000000"
63 | font "Ubuntu", 20, 400, 32, hLeft, vCenter
64 | characters data[1][2]
65 | text "output":
66 | box 0, 0, 100, 100
67 | fill "#000000"
68 | font "Ubuntu", 20, 400, 32, hLeft, vTop
69 | characters data[2][2]
70 | rectangle "bg":
71 | box 220, 220, 100, 100
72 | fill "#bdd3e8"
73 | rectangle "bg":
74 | box 220, 110, 100, 100
75 | fill "#bdd3e8"
76 | rectangle "bg":
77 | box 220, 0, 100, 100
78 | fill "#bdd3e8"
79 | rectangle "bg":
80 | box 110, 220, 100, 100
81 | fill "#bdd3e8"
82 | rectangle "bg":
83 | box 110, 110, 100, 100
84 | fill "#bdd3e8"
85 | rectangle "bg":
86 | box 110, 0, 100, 100
87 | fill "#bdd3e8"
88 | rectangle "bg":
89 | box 0, 220, 100, 100
90 | fill "#bdd3e8"
91 | rectangle "bg":
92 | box 0, 110, 100, 100
93 | fill "#bdd3e8"
94 | rectangle "bg":
95 | box 0, 0, 100, 100
96 | fill "#bdd3e8"
97 | group "inputs":
98 | box 40, 40, 320, 320
99 | layoutAlign laCenter
100 | text "input":
101 | box 220, 220, 100, 100
102 | fill "#000000"
103 | font "Ubuntu", 20, 400, 32, hRight, vBottom
104 | binding data[0][0]
105 | text "input":
106 | box 220, 110, 100, 100
107 | fill "#000000"
108 | font "Ubuntu", 20, 400, 32, hRight, vCenter
109 | binding data[1][0]
110 | text "input":
111 | box 220, 0, 100, 100
112 | fill "#000000"
113 | font "Ubuntu", 20, 400, 32, hRight, vTop
114 | binding data[2][0]
115 | text "input":
116 | box 110, 220, 100, 100
117 | fill "#000000"
118 | font "Ubuntu", 20, 400, 32, hCenter, vBottom
119 | binding data[0][1]
120 | text "input":
121 | box 110, 110, 100, 100
122 | fill "#000000"
123 | font "Ubuntu", 20, 400, 32, hCenter, vCenter
124 | binding data[1][1]
125 | text "input":
126 | box 110, 0, 100, 100
127 | fill "#000000"
128 | font "Ubuntu", 20, 400, 32, hCenter, vTop
129 | binding data[2][1]
130 | text "input":
131 | box 0, 220, 100, 100
132 | fill "#000000"
133 | font "Ubuntu", 20, 400, 32, hLeft, vBottom
134 | binding data[0][2]
135 | text "input":
136 | box 0, 110, 100, 100
137 | fill "#000000"
138 | font "Ubuntu", 20, 400, 32, hLeft, vCenter
139 | binding data[1][2]
140 | text "input":
141 | box 0, 0, 100, 100
142 | fill "#000000"
143 | font "Ubuntu", 20, 400, 32, hLeft, vTop
144 | binding data[2][2]
145 | rectangle "bg":
146 | box 220, 220, 100, 100
147 | fill "#abf1e5"
148 | rectangle "bg":
149 | box 220, 110, 100, 100
150 | fill "#abf1e5"
151 | rectangle "bg":
152 | box 220, 0, 100, 100
153 | fill "#abf1e5"
154 | rectangle "bg":
155 | box 110, 220, 100, 100
156 | fill "#abf1e5"
157 | rectangle "bg":
158 | box 110, 110, 100, 100
159 | fill "#abf1e5"
160 | rectangle "bg":
161 | box 110, 0, 100, 100
162 | fill "#abf1e5"
163 | rectangle "bg":
164 | box 0, 220, 100, 100
165 | fill "#abf1e5"
166 | rectangle "bg":
167 | box 0, 110, 100, 100
168 | fill "#abf1e5"
169 | rectangle "bg":
170 | box 0, 0, 100, 100
171 | fill "#abf1e5"
172 |
173 | startFidget(
174 | drawMain,
175 | w = 800,
176 | h = 400,
177 | )
178 |
--------------------------------------------------------------------------------
/tests/inputsandoutputs/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/inputsandoutputs/screenshot.png
--------------------------------------------------------------------------------
/tests/inputtest/data/IBMPlexSans-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/inputtest/data/IBMPlexSans-Regular.ttf
--------------------------------------------------------------------------------
/tests/inputtest/inputtest.nim:
--------------------------------------------------------------------------------
1 | import fidget, math, random
2 |
3 | loadFont("IBM Plex Sans Regular", "IBMPlexSans-Regular.ttf")
4 |
5 | var bars = newSeq[int](10)
6 | for i, bar in bars:
7 | bars[i] = rand(40)
8 |
9 | var
10 | singleLineValue: string
11 | multiLineValue: string
12 |
13 | proc drawMain() =
14 | setTitle("Input Test")
15 |
16 | let h = 1000
17 | frame "main":
18 | font "IBM Plex Sans Regular", 14.0, 400.0, 20, hLeft, vCenter
19 |
20 | box 0, 0, int root.box.w, max(int root.box.h, h)
21 |
22 | group "singleLineBox":
23 | box 300, 0, 400, 40
24 | fill "#F8F8F8"
25 | clipContent true
26 |
27 | text "text":
28 | box 0, 0, 400, 40
29 | fill "#000000"
30 | textAlign hLeft, vTop
31 | binding singleLineValue
32 | onFocus:
33 | echo "onFocus singleLineBox"
34 | onUnFocus:
35 | echo "onUnFocus singleLineBox"
36 |
37 | text "placeHolder":
38 | box 0, 0, 400, 40
39 | fill "#888888"
40 | textAlign hLeft, vTop
41 | selectable false
42 | if singleLineValue == "":
43 | characters "This is an single line box."
44 | else:
45 | characters ""
46 | onFocus:
47 | echo "onFocus ", current.id
48 | onUnFocus:
49 | echo "onUnFocus ", current.id
50 |
51 | group "multiLineBox":
52 | box 300, 60, 400, 100
53 | fill "#F8F8F8"
54 | clipContent true
55 |
56 | text "text":
57 | box 0, 0, 400, 100
58 | fill "#000000"
59 | textAlign hLeft, vTop
60 | multiline true
61 | #placeholder "This is a text area"
62 | binding multiLineValue
63 | onFocus:
64 | echo "onFocus multiLineBox"
65 | onUnFocus:
66 | echo "onUnFocus multiLineBox"
67 |
68 | text "placeHolder":
69 | box 0, 0, 400, 100
70 | fill "#888888"
71 | textAlign hLeft, vTop
72 | selectable false
73 | if multiLineValue == "":
74 | characters "This is an multi line box."
75 | else:
76 | characters ""
77 | onFocus:
78 | echo "onFocus ", current.id
79 | onUnFocus:
80 | echo "onUnFocus ", current.id
81 |
82 | text "singleLineOut":
83 | box 300, 300, 400, 40
84 | fill "#000000"
85 | textAlign hLeft, vTop
86 | characters singleLineValue
87 | group "bg4":
88 | box 300, 300, 400, 40
89 | fill "#F8E8E8"
90 |
91 | text "multiLineOut":
92 | box 300, 360, 400, 100
93 | fill "#000000"
94 | textAlign hLeft, vTop
95 | multiline true
96 | characters multiLineValue
97 | group "bg5":
98 | box 300, 360, 400, 100
99 | fill "#F8E8E8"
100 |
101 | text "inputFocusIdPath":
102 | box 300, 480, 400, 40
103 | fill "#000000"
104 | textAlign hLeft, vTop
105 | if keyboard.focusNode != nil:
106 | characters keyboard.focusNode.id
107 | else:
108 | characters "nil"
109 | group "bg6":
110 | box 300, 480, 400, 40
111 | fill "#F8E8E8"
112 |
113 | text "prevInputFocusIdPath":
114 | box 300, 560, 400, 40
115 | fill "#000000"
116 | textAlign hLeft, vTop
117 | if keyboard.onUnFocusNode != nil:
118 | characters keyboard.onUnFocusNode.id
119 | else:
120 | characters "nil"
121 | group "bg7":
122 | box 300, 560, 400, 40
123 | fill "#F8E8E8"
124 |
125 | text "button1":
126 | box 300, 620, 100, 20
127 | fill "#000000"
128 | textAlign hLeft, vTop
129 | multiline true
130 | characters "Press me"
131 | group "bg8":
132 | box 300, 620, 100, 20
133 | fill "#F8E8E8"
134 | onHover:
135 | fill "#FF0000"
136 | onClick:
137 | echo "pressed!"
138 |
139 | group "bg1":
140 | box 0, 0, 200, 500
141 | fill "#F8F8F8"
142 | var y: int
143 | for buttonIdx in 0 ..< buttonDown.len:
144 | let button = Button(buttonIdx)
145 | if buttonDown[button]:
146 | text "text-" & $button:
147 | box 10, y*20, 150, 20
148 | fill "#000000"
149 | echo $button
150 | characters $button
151 |
152 | group "group-" & $button:
153 | box 150, y*20, 20, 20
154 | fill "#FF0000"
155 |
156 | inc y
157 |
158 | startFidget(drawMain)
159 |
--------------------------------------------------------------------------------
/tests/inputtest/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/inputtest/screenshot.png
--------------------------------------------------------------------------------
/tests/inputtoggle/data/IBMPlexSans-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/inputtoggle/data/IBMPlexSans-Regular.ttf
--------------------------------------------------------------------------------
/tests/inputtoggle/inputtoggle.nim:
--------------------------------------------------------------------------------
1 | import fidget
2 |
3 | var
4 | textValue: string
5 | beEdit = false
6 |
7 | loadFont("IBM Plex Sans Regular", "IBMPlexSans-Regular.ttf")
8 |
9 | setTitle("Inputs Example")
10 |
11 | proc drawMain() =
12 | frame "main":
13 | box 100, 100, 500, 30
14 | fill "#F7F7F9"
15 |
16 | text "input":
17 | box 0, 0, 500, 30
18 | fill "#000000"
19 | font "IBM Plex Sans Regular", 16.0, 400.0, 30, hLeft, vCenter
20 | if beEdit:
21 | #placeholder "[Enabled, type here]"
22 | binding textValue
23 | else:
24 | characters "[Please enabled]"
25 |
26 | group "button":
27 | box 100, 20, 160, 30
28 | fill "#46D15F"
29 |
30 | text "text":
31 | box 10, 0, parent.box.w, parent.box.h
32 | fill "#FFFFFF"
33 | font "IBM Plex Sans Regular", 16.0, 400.0, 30, hLeft, vCenter
34 | characters "Switch to input:" & $beEdit
35 |
36 | onHover:
37 | mouse.cursorStyle = Pointer
38 |
39 | onClick:
40 | beEdit = not beEdit
41 |
42 | echo "textValue is ", repr(textValue), " s ", keyboard.state
43 |
44 | startFidget(drawMain)
45 |
--------------------------------------------------------------------------------
/tests/inputtoggle/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/inputtoggle/screenshot.png
--------------------------------------------------------------------------------
/tests/masking.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/masking.png
--------------------------------------------------------------------------------
/tests/masks/data/IBMPlexSans-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/masks/data/IBMPlexSans-Regular.ttf
--------------------------------------------------------------------------------
/tests/masks/masks.nim:
--------------------------------------------------------------------------------
1 | import fidget, math
2 |
3 | loadFont("IBM Plex Sans Regular", "IBMPlexSans-Regular.ttf")
4 |
5 | var clip = true
6 |
7 | proc drawMain() =
8 |
9 | font "IBM Plex Sans Regular", 12, 200, 16, hLeft, vTop
10 |
11 | frame "main":
12 | box 0, 0, int root.box.w, root.box.h
13 |
14 | text "noClipped":
15 | box 100, 80, 100, 20
16 | fill "#FF0000"
17 | textAlign hLeft, vTop
18 | characters "Not clipped"
19 |
20 | group "parent":
21 | box 100, 100, 100, 100
22 | fill "#0000FF"
23 |
24 | group "child":
25 | box 50, 50, 100, 100
26 | fill "#00FF00"
27 |
28 | text "childText":
29 | box 50, 50, 100, 100
30 | fill "#0000FF"
31 | textAlign hLeft, vTop
32 | characters "Some text here"
33 |
34 | text "noClipped":
35 | box 500, 80, 100, 20
36 | fill "#FF0000"
37 | textAlign hLeft, vTop
38 | characters "Clipped " & $clip
39 | onClick:
40 | clip = not clip
41 |
42 | group "clippedParent":
43 | clipContent clip
44 | box 500, 100, 100, 100
45 | fill "#0000FF"
46 |
47 | group "clippedChild":
48 | box 50, 50, 100, 100
49 | fill "#00FF00"
50 |
51 | text "childText":
52 | box 50, 50, 100, 100
53 | fill "#0000FF"
54 | textAlign hLeft, vTop
55 | characters "Some text here"
56 |
57 | startFidget(drawMain)
58 |
--------------------------------------------------------------------------------
/tests/masks/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/masks/screenshot.png
--------------------------------------------------------------------------------
/tests/multi_masking.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/multi_masking.png
--------------------------------------------------------------------------------
/tests/multi_masking_pop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/multi_masking_pop.png
--------------------------------------------------------------------------------
/tests/opengltester.nim:
--------------------------------------------------------------------------------
1 | import staticglfw, opengl
2 |
3 | if init() == 0:
4 | quit("Failed to intialize GLFW.")
5 |
6 | for openglVersion in [
7 | (1, 0),
8 | (1, 1),
9 | (1, 2),
10 | (1, 3),
11 | (1, 4),
12 | (1, 5),
13 | (2, 0),
14 | (2, 1),
15 | (3, 0),
16 | (3, 1),
17 | (3, 2),
18 | (3, 3),
19 | (4, 0),
20 | (4, 1),
21 | (4, 2),
22 | (4, 3),
23 | (4, 4),
24 | (4, 5),
25 | (4, 6),
26 | ]:
27 |
28 | windowHint(OPENGL_FORWARD_COMPAT, GL_TRUE.cint)
29 | windowHint(OPENGL_PROFILE, OPENGL_CORE_PROFILE)
30 | windowHint(CONTEXT_VERSION_MAJOR, openglVersion[0].cint)
31 | windowHint(CONTEXT_VERSION_MINOR, openglVersion[1].cint)
32 |
33 | windowHint(VISIBLE, GL_FALSE.cint)
34 |
35 | let window = createWindow(100, 100, "Test", nil, nil)
36 | if window.isNil:
37 | echo "ERROR: ", openglVersion
38 | else:
39 | echo "SUCCESS: ", openglVersion
40 |
41 | destroyWindow(window)
42 |
--------------------------------------------------------------------------------
/tests/orangeHex.flippy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/orangeHex.flippy
--------------------------------------------------------------------------------
/tests/orangeHex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/orangeHex.png
--------------------------------------------------------------------------------
/tests/pixelscaling/data/Ubuntu.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/pixelscaling/data/Ubuntu.ttf
--------------------------------------------------------------------------------
/tests/pixelscaling/pixelscaling.nim:
--------------------------------------------------------------------------------
1 | import fidget
2 |
3 | loadFont("Ubuntu", "Ubuntu.ttf")
4 | setTitle("Auto Layout Text")
5 |
6 | proc drawMain() =
7 | frame "pixelScaling":
8 | box 0, 0, root.box.w, 341
9 | fill "#ffffff"
10 | layout lmVertical
11 | counterAxisSizingMode csFixed
12 | horizontalPadding 5
13 | verticalPadding 5
14 | itemSpacing 10
15 | text "p2":
16 | box 5, 276, 190, 60
17 | fill "#000000"
18 | font "Ubuntu", 14, 400, 20, hLeft, vTop
19 | characters "The design stays low resolution though. But it displays all upscale!"
20 | textAutoResize tsHeight
21 | layoutAlign laStretch
22 | text "title2":
23 | box 5, 234, 190, 32
24 | fill "#000000"
25 | font "Ubuntu", 20, 400, 32, hLeft, vTop
26 | characters "Lorem Ipsum"
27 | textAutoResize tsHeight
28 | layoutAlign laStretch
29 | text "imgCaption":
30 | box 5, 204, 190, 20
31 | fill "#9c9c9c"
32 | font "Ubuntu", 14, 400, 20, hCenter, vTop
33 | characters "Lorem ipsum dolor sit ame"
34 | textAutoResize tsHeight
35 | layoutAlign laStretch
36 | rectangle "imgPlaceholder":
37 | box 32.5, 97, 135, 97
38 | fill "#88dc60"
39 | onHover:
40 | fill "#FF0000"
41 | layoutAlign laCenter
42 | text "p1":
43 | box 5, 47, 190, 40
44 | fill "#000000"
45 | font "Ubuntu", 14, 400, 20, hLeft, vTop
46 | characters "Everything scales to x1, x2, x3 to match pixel game asthenic."
47 | textAutoResize tsHeight
48 | layoutAlign laStretch
49 | text "title1":
50 | box 5, 5, 190, 32
51 | fill "#000000"
52 | font "Ubuntu", 20, 400, 32, hLeft, vTop
53 | characters "Pixel Scale"
54 | textAutoResize tsHeight
55 | layoutAlign laStretch
56 |
57 | when defined(js):
58 | echo "JS backend does not support pixel scaling"
59 | startFidget(drawMain)
60 | else:
61 | startFidget(
62 | drawMain,
63 | w = 600,
64 | h = 341*3,
65 | pixelate = true,
66 | pixelScale = 3.0
67 | )
68 |
--------------------------------------------------------------------------------
/tests/pixelscaling/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/pixelscaling/screenshot.png
--------------------------------------------------------------------------------
/tests/pluginexport/data/testBg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/pluginexport/data/testBg.png
--------------------------------------------------------------------------------
/tests/pluginexport/data/testLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/pluginexport/data/testLogo.png
--------------------------------------------------------------------------------
/tests/pluginexport/figmatests.nim:
--------------------------------------------------------------------------------
1 | import fidget
2 |
3 | proc frameTest1Square_root*() =
4 | frame "test1Square_root": # 1:2
5 | box 0, 0, root.box.w, root.box.h # ROOT ROOT
6 | fill color(1.000, 1.000, 1.000, 1.000)
7 |
8 | rectangle "Rectangle": # 1:3
9 | box 100, 100, 300, 300
10 | fill "#65F8DE"
11 |
12 | proc frameTest2StretchySquare_root*() =
13 | frame "test2StretchySquare_root": # 1:4
14 | box 0, 0, root.box.w, root.box.h # ROOT ROOT
15 | fill color(1.000, 1.000, 1.000, 1.000)
16 |
17 | rectangle "Rectangle": # 1:5
18 | box 100, 100, parent.box.w - 200, parent.box.h - 200 # TOP_BOTTOM LEFT_RIGHT
19 | fill "#65F8B2"
20 |
21 | proc frameTest3CenterSquare_root*() =
22 | frame "test3CenterSquare_root": # 1:6
23 | box 0, 0, root.box.w, root.box.h # ROOT ROOT
24 | fill color(1.000, 1.000, 1.000, 1.000)
25 |
26 | rectangle "Rectangle": # 1:7
27 | box parent.box.w/2 - 150, parent.box.h/2 - 150, 300, 300 # CENTER CENTER
28 | fill "#68F865"
29 |
30 | proc frameTest4MultiSquare_root*() =
31 | frame "test4MultiSquare_root": # 1:9
32 | box 0, 0, root.box.w, root.box.h # ROOT ROOT
33 | fill color(1.000, 1.000, 1.000, 1.000)
34 |
35 | rectangle "Rectangle": # 1:10
36 | box 100, 100, parent.box.w - 200, parent.box.h - 200 # TOP_BOTTOM LEFT_RIGHT
37 | fill "#65F8DE"
38 |
39 | rectangle "Rectangle": # 1:11
40 | box 200, 200, parent.box.w - 400, parent.box.h - 400 # TOP_BOTTOM LEFT_RIGHT
41 | fill "#65BAF8"
42 |
43 | rectangle "Rectangle 2": # 1:12
44 | box 75, 75, 50, 50
45 | fill "#F88865"
46 |
47 | rectangle "Rectangle 2.1": # 1:13
48 | box parent.box.w - 125, 75, 50, 50 # TOP RIGHT
49 | fill "#F88865"
50 |
51 | rectangle "Rectangle 2.2": # 1:14
52 | box parent.box.w - 125, parent.box.h - 125, 50, 50 # BOTTOM RIGHT
53 | fill "#F88865"
54 |
55 | rectangle "Rectangle 2.3": # 1:15
56 | box 75, parent.box.h - 125, 50, 50 # BOTTOM LEFT
57 | fill "#F88865"
58 |
59 | proc frameTest5DoubleStretch_root*() =
60 | frame "test5DoubleStretch_root": # 1:16
61 | box 0, 0, root.box.w, root.box.h # ROOT ROOT
62 | fill color(1.000, 1.000, 1.000, 1.000)
63 |
64 | rectangle "Rectangle 2": # 1:19
65 | box 100, 100, 50, parent.box.h - 300 # TOP_BOTTOM LEFT
66 | fill "#F88865"
67 |
68 | rectangle "Rectangle 2.1": # 1:20
69 | box 200, 100, parent.box.w - 300, 50 # TOP LEFT_RIGHT
70 | fill "#F88865"
71 |
72 | rectangle "Rectangle 2.2": # 1:21
73 | box parent.box.w - 144, 200, 44, parent.box.h - 300 # TOP_BOTTOM RIGHT
74 | fill "#F88865"
75 |
76 | rectangle "Rectangle 2.3": # 1:22
77 | box 100, parent.box.h - 150, parent.box.w - 300, 50 # BOTTOM LEFT_RIGHT
78 | fill "#F88865"
79 |
80 | rectangle "Rectangle 3": # 1:23
81 | box 0, 0, 100, 100
82 | fill "#ECECEC"
83 |
84 | rectangle "Rectangle 3.1": # 1:24
85 | box 0, parent.box.h - 100, 100, 100 # BOTTOM LEFT
86 | fill "#ECECEC"
87 |
88 | rectangle "Rectangle 3.2": # 1:25
89 | box parent.box.w - 95, parent.box.h - 100, 100, 100 # BOTTOM RIGHT
90 | fill "#ECECEC"
91 |
92 | rectangle "Rectangle 3.3": # 1:26
93 | box parent.box.w - 100, 0, 100, 100 # TOP RIGHT
94 | fill "#ECECEC"
95 |
96 | proc frameTest6TextBasic_root*() =
97 | frame "test6TextBasic_root": # 8:2
98 | box 0, 0, root.box.w, root.box.h # ROOT ROOT
99 | fill color(1.000, 1.000, 1.000, 1.000)
100 |
101 | rectangle "Rectangle": # 8:6
102 | box 108, 64, 283, 86
103 | fill "#F2F2F2"
104 |
105 | rectangle "Rectangle 2": # 8:7
106 | box 108, 134, 283, 16
107 | fill "#E3E3E3"
108 |
109 | rectangle "Rectangle 2.1": # 8:8
110 | box 108, 64, 283, 18
111 | fill "#E3E3E3"
112 |
113 | text "Test Text": # 8:5
114 | box 108, 64, 283, 86
115 | fill "#000000"
116 | font "Helvetica Neue", 72.0, 400.0, 81, hLeft, vTop
117 | characters "Test Text"
118 |
119 | rectangle "Rectangle": # 8:9
120 | box 108, 173, 197, 60
121 | fill "#F2F2F2"
122 |
123 | rectangle "Rectangle 2.2": # 8:10
124 | box 108, 221, 197, 12
125 | fill "#E3E3E3"
126 |
127 | rectangle "Rectangle 2.3": # 8:11
128 | box 108, 173, 197, 12
129 | fill "#E3E3E3"
130 |
131 | text "Test Text": # 8:12
132 | box 108, 173, 197, 60
133 | fill "#000000"
134 | font "Helvetica Neue", 50.0, 400.0, 55, hLeft, vTop
135 | characters "Test Text"
136 |
137 | rectangle "Rectangle": # 8:25
138 | box 108, 256, 79, 24
139 | fill "#F2F2F2"
140 |
141 | rectangle "Rectangle 2.4": # 8:26
142 | box 108, 275, 79, 5
143 | fill "#E3E3E3"
144 |
145 | rectangle "Rectangle 2.5": # 8:27
146 | box 108, 256, 79, 4
147 | fill "#E3E3E3"
148 |
149 | text "Test Text": # 8:28
150 | box 108, 256, 79, 24
151 | fill "#000000"
152 | font "Helvetica Neue", 20.0, 400.0, 20, hLeft, vTop
153 | characters "Test Text"
154 |
155 | proc frameTest7TextAlign_root*() =
156 | frame "test7TextAlign_root": # 8:29
157 | box 0, 0, root.box.w, root.box.h # ROOT ROOT
158 | fill color(1.000, 1.000, 1.000, 1.000)
159 |
160 | rectangle "Rectangle": # 8:42
161 | box 100, 100, 300, 300
162 | fill "#F2F2F2"
163 |
164 | text "right top": # 8:43
165 | box 100, 100, 300, 300
166 | fill "#000000"
167 | font "Helvetica Neue", 14.0, 400.0, 13, hLeft, vTop
168 | characters "right top"
169 |
170 | text "center top": # 8:45
171 | box 100, 100, 300, 300
172 | fill "#000000"
173 | font "Helvetica Neue", 14.0, 400.0, 13, hCenter, vTop
174 | characters "center top"
175 |
176 | text "left top": # 8:44
177 | box 100, 100, 300, 300
178 | fill "#000000"
179 | font "Helvetica Neue", 14.0, 400.0, 13, hRight, vTop
180 | characters "left top"
181 |
182 | text "right center": # 8:46
183 | box 100, 100, 300, 300
184 | fill "#000000"
185 | font "Helvetica Neue", 14.0, 400.0, 13, hLeft, vCenter
186 | characters "right center"
187 |
188 | text "center": # 8:47
189 | box 100, 100, 300, 300
190 | fill "#000000"
191 | font "Helvetica Neue", 14.0, 400.0, 13, hCenter, vCenter
192 | characters "center"
193 |
194 | text "left center": # 8:48
195 | box 100, 100, 300, 300
196 | fill "#000000"
197 | font "Helvetica Neue", 14.0, 400.0, 13, hRight, vCenter
198 | characters "left center"
199 |
200 | text "right bottom": # 8:49
201 | box 100, 100, 300, 300
202 | fill "#000000"
203 | font "Helvetica Neue", 14.0, 400.0, 13, hLeft, vBottom
204 | characters "right bottom"
205 |
206 | text "center bottom": # 8:50
207 | box 100, 100, 300, 300
208 | fill "#000000"
209 | font "Helvetica Neue", 14.0, 400.0, 13, hCenter, vBottom
210 | characters "center bottom"
211 |
212 | text "left bottom": # 8:51
213 | box 100, 100, 300, 300
214 | fill "#000000"
215 | font "Helvetica Neue", 14.0, 400.0, 13, hRight, vBottom
216 | characters "left bottom"
217 |
218 | proc frameTest8TextInput_root*() =
219 | frame "test8TextInput_root": # 8:52
220 | box 0, 0, root.box.w, root.box.h # ROOT ROOT
221 | fill color(1.000, 1.000, 1.000, 1.000)
222 |
223 | rectangle "Rectangle": # 8:53
224 | box 100, 190, 300, 60
225 | fill "#F2F2F2"
226 |
227 | text "enter your name:": # 8:58
228 | box 100, 171, 114, 19
229 | fill "#000000"
230 | font "Helvetica Neue", 14.0, 400.0, 13, hLeft, vTop
231 | characters "enter your name:"
232 |
233 | text "Name": # 8:63
234 | box 116, 190, 274, 60
235 | fill "#000000"
236 | font "Helvetica Neue", 28.0, 400.0, 29, hLeft, vCenter
237 | characters "Name"
238 |
239 | rectangle "Rectangle 2": # 8:64
240 | box 220, 60, 60, 60
241 | fill "#F88865"
242 |
243 | proc frameTest10Rotations_root*() =
244 | frame "test10Rotations_root": # 9:8
245 | box 0, 0, root.box.w, root.box.h # ROOT ROOT
246 | fill color(1.000, 1.000, 1.000, 1.000)
247 |
248 | rectangle "Rectangle": # 9:13
249 | rotation 45.00000098057549
250 | box 8, 291, 200, 200
251 | fill "#C4C4C4", 0.450
252 |
253 | rectangle "Rectangle": # 9:14
254 | rotation 15.00000300355992
255 | box 98, 201, 200, 200
256 | fill "#C4C4C4", 0.150
257 |
258 | rectangle "Rectangle": # 9:15
259 | rotation 30.00000178116811
260 | box 50, 250, 200, 200
261 | fill "#C4C4C4", 0.300
262 |
263 | proc frameTest9Images_root*() =
264 | frame "test9Images_root": # 8:65
265 | box 0, 0, root.box.w, root.box.h # ROOT ROOT
266 | fill color(1.000, 1.000, 1.000, 1.000)
267 |
268 | component "wrapper": # 9:7
269 | box parent.box.w/2 - 400, 0, 800, 1217 # TOP CENTER
270 |
271 | rectangle "testBg": # 9:0
272 | box parent.box.w/2 - 400, 0, 800, 1217 # TOP CENTER
273 | image "testBg"
274 |
275 | text "All that is gold does not glitter, Not all those who wander are lost; The old that is strong does not wither, Deep roots are not reached by the frost. From the ashes, a fire shall be woken, A light from the shadows shall spring; Renewed shall be blade that was broken, The crownless again shall be king.": # 9:1
276 | box parent.box.w/2 - 185, 224, 369, 262 # TOP CENTER
277 | fill "#000000", 0.700
278 | font "Helvetica Neue", 20.0, 400.0, 20, hCenter, vCenter
279 | characters "All that is gold does not glitter,\nNot all those who wander are lost;\nThe old that is strong does not wither,\nDeep roots are not reached by the frost.\nFrom the ashes, a fire shall be woken,\nA light from the shadows shall spring;\nRenewed shall be blade that was broken,\nThe crownless again shall be king."
280 |
281 | group "testLogo": # 9:6
282 | box 341, 52, 117, 117
283 | image "testLogo"
284 |
--------------------------------------------------------------------------------
/tests/pluginexport/pluginexport.nim:
--------------------------------------------------------------------------------
1 | import fidget, figmatests
2 |
3 | var screen = 0
4 |
5 | proc drawMain() =
6 | frame "main":
7 | onKey:
8 | if keyboard.keyString == " ":
9 | inc screen
10 | case screen:
11 | of 0: frameTest1Square_root()
12 | of 1: frameTest2StretchySquare_root()
13 | of 2: frameTest3CenterSquare_root()
14 | of 3: frameTest4MultiSquare_root()
15 | of 4: frameTest5DoubleStretch_root()
16 | of 5: frameTest6TextBasic_root()
17 | of 6: frameTest7TextAlign_root()
18 | of 7: frameTest8TextInput_root()
19 | of 8: frameTest9Images_root()
20 | of 9: frameTest10Rotations_root()
21 | else:
22 | screen = 0
23 | frameTest1Square_root()
24 |
25 | echo "Press space bar to advance to next scene."
26 |
27 | startFidget(drawMain)
28 |
--------------------------------------------------------------------------------
/tests/pluginexport/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/pluginexport/screenshot.png
--------------------------------------------------------------------------------
/tests/rounded.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/rounded.png
--------------------------------------------------------------------------------
/tests/run.nim:
--------------------------------------------------------------------------------
1 | import cligen, os, strformat, osproc
2 |
3 | let projectDir = getCurrentDir()
4 |
5 | var runList: seq[string]
6 |
7 | proc compileNative() =
8 | for folder in runList:
9 | let file = folder.lastPathPart
10 | let cmd = &"nim c --hints:off --verbosity:0 {folder}/{file}.nim"
11 | echo cmd
12 | if execShellCmd(cmd) != 0:
13 | quit "[error] " & folder
14 | else:
15 | echo "[ok] " & folder
16 |
17 | proc compileTestOneFrame() =
18 | for folder in runList:
19 | setCurrentDir(folder)
20 | let file = folder.lastPathPart
21 | let cmd = &"nim c -r --hints:off --verbosity:0 -d:testOneFrame {file}.nim"
22 | echo cmd
23 | if execShellCmd(cmd) != 0:
24 | quit "[error] " & folder
25 | else:
26 | echo "[ok] " & folder
27 | setCurrentDir(projectDir)
28 |
29 | proc runNative() =
30 | for folder in runList:
31 | setCurrentDir(folder)
32 | let exeUrl = folder.lastPathPart
33 | when defined(windows):
34 | if execShellCmd(exeUrl & ".exe") != 0:
35 | quit "[error] Starting " & exeUrl & ".exe"
36 | elif defined(linux):
37 | if execShellCmd("xvfb-run " & getCurrentDir() & "/" & exeUrl) != 0:
38 | quit "[error] Starting " & getCurrentDir() & "/" & exeUrl
39 | else:
40 | if execShellCmd("./" & exeUrl) != 0:
41 | quit "[error] Starting " & exeUrl
42 | setCurrentDir(projectDir)
43 |
44 | proc compileJS() =
45 | for folder in runList:
46 | let file = folder.lastPathPart
47 | let cmd = &"nim js --hints:off --verbosity:0 {folder}/{file}.nim"
48 | echo cmd
49 | if execShellCmd(cmd) != 0:
50 | quit "[error] " & folder
51 | else:
52 | echo "[ok] " & folder
53 | # write html file
54 | let(dir, name, _) = folder.splitFile
55 | let indexPath = &"{dir}/{name}/{name}.html"
56 | writeFile(indexPath, &"""""")
57 |
58 | proc runJS() =
59 | for folder in runList:
60 | let file = folder.lastPathPart
61 | var exeDir = os.getAppDir().parentDir
62 | let fileUrl = &"file:///{exeDir}/{folder}/{file}.html"
63 | when defined(windows):
64 | if execShellCmd(&"start chrome {fileUrl}") != 0:
65 | quit "[error] Starting Chrome: " & fileUrl
66 | else:
67 | if execShellCmd(&"open {fileUrl}") != 0:
68 | quit "[error] Starting Chrome: " & fileUrl
69 |
70 | proc compileWasm() =
71 | for folder in runList:
72 | let file = folder.lastPathPart
73 | if not existsDir(folder / "wasm"):
74 | createDir(folder / "wasm")
75 | echo folder / "data"
76 | let inner =
77 | if existsDir(folder / "data"):
78 | echo "using data folder"
79 | &"-o {folder}/wasm/{file}.html --preload-file {folder}/data@data/ --shell-file src/shell_minimal.html -s ALLOW_MEMORY_GROWTH=1"
80 | else:
81 | &"-o {folder}/wasm/{file}.html --shell-file src/shell_minimal.html -s ALLOW_MEMORY_GROWTH=1"
82 | let cmd = &"nim c -d:emscripten --gc:arc --hints:off --verbosity:0 --passL:\"{inner}\" {folder}/{file}.nim"
83 | echo cmd
84 | if execShellCmd(cmd) != 0:
85 | quit "[error] " & folder
86 |
87 | proc runWasm() =
88 | for folder in runList:
89 | let file = folder.lastPathPart
90 | var exeDir = os.getAppDir().parentDir
91 | let fileUrl = &"http://localhost:1337/{folder}/wasm/{file}.html"
92 | when defined(windows):
93 | if execShellCmd(&"start chrome {fileUrl}") != 0:
94 | quit "[error] Starting Chrome: " & fileUrl
95 | else:
96 | if execShellCmd(&"open {fileUrl}") != 0:
97 | quit "[error] Starting Chrome: " & fileUrl
98 |
99 | proc runClean() =
100 | for folder in runList:
101 | if existsDir(folder / "wasm"):
102 | removeDir(folder / "wasm")
103 | let file = folder.lastPathPart
104 | if existsFile(folder / file & ".html"):
105 | removeFile(folder / file & ".html")
106 | if existsFile(folder / file & ".js"):
107 | removeFile(folder / file & ".js")
108 | if existsFile(folder / file & ".exe"):
109 | removeFile(folder / file & ".exe")
110 |
111 | proc main(
112 | compile: bool = false,
113 | native: bool = false,
114 | js: bool = false,
115 | run: bool = false,
116 | wasm: bool = false,
117 | clean: bool = false,
118 | testOneFrame: bool = false,
119 | ) =
120 |
121 | # if not wasm:
122 | # runList.add "tests/httpget"
123 | # runList.add "examples/hn"
124 |
125 | # if not js:
126 | # runList.add "tests/imagegen"
127 | # runList.add "tests/imagestatic"
128 |
129 | runList.add "tests/centercentertext"
130 | runList.add "tests/constrantscenteroffset"
131 | runList.add "tests/autolayouttext"
132 | runList.add "tests/autolayoutcomplex"
133 | runList.add "tests/autolayouthorizontal"
134 | runList.add "tests/autolayoutvertical"
135 | runList.add "tests/bars"
136 | runList.add "tests/constraints"
137 | runList.add "tests/exportorder"
138 | runList.add "tests/fontmetrics"
139 | runList.add "tests/hovers"
140 | runList.add "tests/images"
141 | runList.add "tests/inputtoggle"
142 | runList.add "tests/inputsandoutputs"
143 | runList.add "tests/inputtest"
144 | runList.add "tests/masks"
145 | runList.add "tests/pixelscaling"
146 | runList.add "tests/pluginexport"
147 | runList.add "tests/textalign"
148 | runList.add "tests/textalignexpand"
149 | runList.add "tests/textalignfixed"
150 | runList.add "tests/textandinputs"
151 | runList.add "tests/cursorstyle"
152 |
153 | runList.add "examples/areas"
154 | runList.add "examples/demo"
155 | runList.add "examples/minimal"
156 | runList.add "examples/padofcode"
157 | runList.add "examples/padoftext"
158 |
159 | if not(compile or native or js or run or wasm or clean):
160 | echo "Usage:"
161 | echo " run --compile --native --js --run"
162 |
163 | if compile and native:
164 | if testOneFrame:
165 | compileTestOneFrame()
166 | else:
167 | compileNative()
168 | if run and native:
169 | runNative()
170 | if compile and js:
171 | compileJS()
172 | if run and js:
173 | runJS()
174 | if compile and wasm:
175 | compileWasm()
176 | if run and wasm:
177 | runWasm()
178 | if clean:
179 | runClean()
180 |
181 | if testOneFrame:
182 | let (outp, _) = execCmdEx("git diff *.png")
183 | if len(outp) != 0:
184 | echo outp
185 | quit("Output does not match")
186 |
187 | dispatch(main)
188 |
--------------------------------------------------------------------------------
/tests/scale.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/scale.png
--------------------------------------------------------------------------------
/tests/setwindowbounds/setwindowbounds.nim:
--------------------------------------------------------------------------------
1 | ## This shows how to set window bounds, so that window can't be resized smaller
2 | ## or larger by the user.
3 | ## Note: setWindowBounds does not work in JS mode.
4 |
5 | import fidget, vmath
6 |
7 | proc loadMain() =
8 | setWindowBounds(vec2(200, 200), vec2(300, 300))
9 |
10 | proc drawMain() =
11 | frame "main":
12 | box 0, 0, 620, 140
13 | for i in 0 .. 4:
14 | group "block":
15 | box 20 + i * 120, 20, 100, 100
16 | fill "#2B9FEA"
17 |
18 | startFidget(draw=drawMain, load=loadMain, w = 300, h = 300)
19 |
--------------------------------------------------------------------------------
/tests/sprite_basic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/sprite_basic.png
--------------------------------------------------------------------------------
/tests/test.nim:
--------------------------------------------------------------------------------
1 | import fidget
2 |
--------------------------------------------------------------------------------
/tests/textalign/README.md:
--------------------------------------------------------------------------------
1 | # Fonts - shows off diferent typograhy and layout features
2 |
--------------------------------------------------------------------------------
/tests/textalign/data/IBMPlexSans-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/textalign/data/IBMPlexSans-Regular.ttf
--------------------------------------------------------------------------------
/tests/textalign/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/textalign/screenshot.png
--------------------------------------------------------------------------------
/tests/textalign/textalign.nim:
--------------------------------------------------------------------------------
1 | import fidget, math, strformat
2 |
3 | var
4 | fontS = 14.0
5 | lineH = 14.0
6 |
7 | setTitle("Fidget Fonts Example")
8 | loadFont("IBM Plex Sans Regular", "IBMPlexSans-Regular.ttf")
9 |
10 | proc drawMain() =
11 |
12 | font "IBM Plex Sans Regular", 12, 200, 16, hLeft, vTop
13 |
14 | let h = 1000
15 | frame "main":
16 |
17 | # onKeyDown:
18 | # if keyboard.keyCode == 39:
19 | # fontS += 1.0
20 | # if keyboard.keyCode == 37:
21 | # fontS -= 1.0
22 |
23 | # if keyboard.keyCode == 86:
24 | # lineH += 1.0
25 | # if keyboard.keyCode == 67:
26 | # lineH -= 1.0
27 | # print fontS, keyboard.keyCode
28 |
29 | box 0, 0, int root.box.w, max(int root.box.h, h)
30 |
31 | text "t":
32 | box 10, 10, 600, 50
33 | fill "#46D15F"
34 | fontSize 50
35 | characters "Text Align"
36 |
37 | group "box2":
38 | box 100, 100, 300, 300
39 | #fill "#AEB5C0"
40 | fontSize fontS
41 | lineHeight lineH
42 |
43 | text "tl":
44 | box 0, 0, 300, 300
45 | fill "#AEB5C0"
46 | textAlign hLeft, vTop
47 | characters "TL"
48 |
49 | text "tr":
50 | box 0, 0, 300, 300
51 | fill "#AEB5C0"
52 | textAlign hRight, vTop
53 | characters "TR"
54 |
55 | text "tc":
56 | box 0, 0, 300, 300
57 | fill "#AEB5C0"
58 | textAlign hCenter, vTop
59 | characters "TC"
60 |
61 | text "cl":
62 | box 0, 0, 300, 300
63 | fill "#AEB5C0"
64 | textAlign hLeft, vCenter
65 | characters "CL"
66 |
67 | text "cr":
68 | box 0, 0, 300, 300
69 | fill "#AEB5C0"
70 | textAlign hRight, vCenter
71 | characters "CR"
72 |
73 | text "c":
74 | box 0, 0, 300, 300
75 | fill "#AEB5C0"
76 | textAlign hCenter, vCenter
77 | characters "C"
78 |
79 | text "bl":
80 | box 0, 0, 300, 300
81 | fill "#AEB5C0"
82 | textAlign hLeft, vBottom
83 | characters "BL"
84 |
85 | text "br":
86 | box 0, 0, 300, 300
87 | fill "#AEB5C0"
88 | textAlign hRight, vBottom
89 | characters "BR"
90 |
91 | text "bc":
92 | box 0, 0, 300, 300
93 | fill "#AEB5C0"
94 | textAlign hCenter, vBottom
95 | characters "BC"
96 |
97 | group "box2":
98 | box 100, 500, 10000, 100
99 | text "bc":
100 | box 0, 0, 10000, 100
101 | fontSize fontS
102 | lineHeight lineH
103 | fill "#AEB5C0"
104 | textAlign hLeft, vTop
105 | characters &"fontSize {fontS} lineHeight {lineH}"
106 |
107 | group "box2":
108 | box 100, 650, 10000, 100
109 | text "bc":
110 | box 0, 0, 10000, 100
111 | fontSize fontS
112 | lineHeight lineH
113 | fill "#AEB5C0"
114 | textAlign hLeft, vCenter
115 | characters &"fontSize {fontS} lineHeight {lineH}"
116 |
117 | group "box2":
118 | box 100, 800, 10000, 100
119 | text "bc":
120 | box 0, 0, 10000, 100
121 | fontSize fontS
122 | lineHeight lineH
123 | fill "#AEB5C0"
124 | textAlign hLeft, vBottom
125 | characters &"fontSize {fontS} lineHeight {lineH}"
126 |
127 | startFidget(drawMain)
128 |
--------------------------------------------------------------------------------
/tests/textalignexpand/data/Ubuntu.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/textalignexpand/data/Ubuntu.ttf
--------------------------------------------------------------------------------
/tests/textalignexpand/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/textalignexpand/screenshot.png
--------------------------------------------------------------------------------
/tests/textalignexpand/textalignexpand.nim:
--------------------------------------------------------------------------------
1 | import fidget
2 |
3 | loadFont("Ubuntu", "Ubuntu.ttf")
4 | setTitle("Text Align Expand")
5 |
6 | proc drawMain() =
7 | frame "textAlignExpand":
8 | box 0, 0, 400, 400
9 | fill "#ffffff"
10 | text "Fidget1":
11 | box 301, 328, 59, 32
12 | fill "#000000"
13 | font "Ubuntu", 20, 400, 32, hRight, vBottom
14 | characters "Fidget"
15 | text "Fidget2":
16 | box 301, 184, 59, 32
17 | fill "#000000"
18 | font "Ubuntu", 20, 400, 32, hRight, vCenter
19 | characters "Fidget"
20 | text "Fidget3":
21 | box 301, 40, 59, 32
22 | fill "#000000"
23 | font "Ubuntu", 20, 400, 32, hRight, vTop
24 | characters "Fidget"
25 | text "Fidget4":
26 | box 171, 328, 59, 32
27 | fill "#000000"
28 | font "Ubuntu", 20, 400, 32, hCenter, vBottom
29 | characters "Fidget"
30 | text "Fidget5":
31 | box 171, 184, 59, 32
32 | fill "#000000"
33 | font "Ubuntu", 20, 400, 32, hCenter, vCenter
34 | characters "Fidget"
35 | text "Fidget6":
36 | box 171, 40, 59, 32
37 | fill "#000000"
38 | font "Ubuntu", 20, 400, 32, hCenter, vTop
39 | characters "Fidget"
40 | text "Fidget7":
41 | box 40, 328, 59, 32
42 | fill "#000000"
43 | font "Ubuntu", 20, 400, 32, hLeft, vBottom
44 | characters "Fidget"
45 | text "Fidget8":
46 | box 40, 184, 59, 32
47 | fill "#000000"
48 | font "Ubuntu", 20, 400, 32, hLeft, vCenter
49 | characters "Fidget"
50 | text "Fidget9":
51 | box 41, 40, 59, 32
52 | fill "#000000"
53 | font "Ubuntu", 20, 400, 32, hLeft, vTop
54 | characters "Fidget"
55 | rectangle "Center":
56 | box 301, 328, 59, 32
57 | fill "#d8fbbd"
58 | rectangle "Center":
59 | box 301, 184, 59, 32
60 | fill "#d8fbbd"
61 | rectangle "Center":
62 | box 301, 40, 59, 32
63 | fill "#d8fbbd"
64 | rectangle "Center":
65 | box 171, 328, 59, 32
66 | fill "#d8fbbd"
67 | rectangle "Center":
68 | box 171, 184, 59, 32
69 | fill "#d8fbbd"
70 | rectangle "Center":
71 | box 171, 40, 59, 32
72 | fill "#d8fbbd"
73 | rectangle "Center":
74 | box 40, 328, 59, 32
75 | fill "#d8fbbd"
76 | rectangle "Center":
77 | box 40, 184, 59, 32
78 | fill "#d8fbbd"
79 | rectangle "Center":
80 | box 40, 40, 59, 32
81 | fill "#d8fbbd"
82 | rectangle "Center":
83 | box 260, 260, 100, 100
84 | fill "#f0fce7"
85 | rectangle "Center":
86 | box 260, 150, 100, 100
87 | fill "#f0fce7"
88 | rectangle "Center":
89 | box 260, 40, 100, 100
90 | fill "#f0fce7"
91 | rectangle "Center":
92 | box 150, 260, 100, 100
93 | fill "#f0fce7"
94 | rectangle "Center":
95 | box 150, 150, 100, 100
96 | fill "#f0fce7"
97 | rectangle "Center":
98 | box 150, 40, 100, 100
99 | fill "#f0fce7"
100 | rectangle "Center":
101 | box 40, 260, 100, 100
102 | fill "#f0fce7"
103 | rectangle "Center":
104 | box 40, 150, 100, 100
105 | fill "#f0fce7"
106 | rectangle "Center":
107 | box 40, 40, 100, 100
108 | fill "#f0fce7"
109 |
110 | startFidget(drawMain, w = 400, h = 400)
111 |
--------------------------------------------------------------------------------
/tests/textalignfixed/data/Ubuntu.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/textalignfixed/data/Ubuntu.ttf
--------------------------------------------------------------------------------
/tests/textalignfixed/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/textalignfixed/screenshot.png
--------------------------------------------------------------------------------
/tests/textalignfixed/textalignfixed.nim:
--------------------------------------------------------------------------------
1 |
2 | import fidget
3 |
4 | loadFont("Ubuntu", "Ubuntu.ttf")
5 | setTitle("Text Align Fixed")
6 |
7 | proc drawMain() =
8 | frame "textAlignFixed":
9 | box 0, 0, 400, 400
10 | fill "#ffffff"
11 | text "Fidget1":
12 | box 260, 260, 100, 100
13 | fill "#000000"
14 | font "Ubuntu", 20, 400, 32, hRight, vBottom
15 | characters "Fidget"
16 | text "Fidget2":
17 | box 260, 150, 100, 100
18 | fill "#000000"
19 | font "Ubuntu", 20, 400, 32, hRight, vCenter
20 | characters "Fidget"
21 | text "Fidget3":
22 | box 260, 40, 100, 100
23 | fill "#000000"
24 | font "Ubuntu", 20, 400, 32, hRight, vTop
25 | characters "Fidget"
26 | text "Fidget4":
27 | box 150, 260, 100, 100
28 | fill "#000000"
29 | font "Ubuntu", 20, 400, 32, hCenter, vBottom
30 | characters "Fidget"
31 | text "Fidget5":
32 | box 150, 150, 100, 100
33 | fill "#000000"
34 | font "Ubuntu", 20, 400, 32, hCenter, vCenter
35 | characters "Fidget"
36 | text "Fidget6":
37 | box 150, 40, 100, 100
38 | fill "#000000"
39 | font "Ubuntu", 20, 400, 32, hCenter, vTop
40 | characters "Fidget"
41 | text "Fidget7":
42 | box 40, 260, 100, 100
43 | fill "#000000"
44 | font "Ubuntu", 20, 400, 32, hLeft, vBottom
45 | characters "Fidget"
46 | text "Fidget8":
47 | box 40, 150, 100, 100
48 | fill "#000000"
49 | font "Ubuntu", 20, 400, 32, hLeft, vCenter
50 | characters "Fidget"
51 | text "Fidget9":
52 | box 40, 40, 100, 100
53 | fill "#000000"
54 | font "Ubuntu", 20, 400, 32, hLeft, vTop
55 | characters "Fidget"
56 | rectangle "Center":
57 | box 260, 260, 100, 100
58 | fill "#f8c5a8"
59 | rectangle "Center":
60 | box 260, 150, 100, 100
61 | fill "#f8c5a8"
62 | rectangle "Center":
63 | box 260, 40, 100, 100
64 | fill "#f8c5a8"
65 | rectangle "Center":
66 | box 150, 260, 100, 100
67 | fill "#f8c5a8"
68 | rectangle "Center":
69 | box 150, 150, 100, 100
70 | fill "#f8c5a8"
71 | rectangle "Center":
72 | box 150, 40, 100, 100
73 | fill "#f8c5a8"
74 | rectangle "Center":
75 | box 40, 260, 100, 100
76 | fill "#f8c5a8"
77 | rectangle "Center":
78 | box 40, 150, 100, 100
79 | fill "#f8c5a8"
80 | rectangle "Center":
81 | box 40, 40, 100, 100
82 | fill "#f8c5a8"
83 |
84 | startFidget(drawMain, w = 400, h = 400)
85 |
--------------------------------------------------------------------------------
/tests/textandinputs/README.md:
--------------------------------------------------------------------------------
1 | # Text and Inputs - Large number of chaning text and inputs
2 |
3 | This tests a bug with rewriting large number of text and inputs.
4 |
--------------------------------------------------------------------------------
/tests/textandinputs/data/IBMPlexSans-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/textandinputs/data/IBMPlexSans-Regular.ttf
--------------------------------------------------------------------------------
/tests/textandinputs/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/textandinputs/screenshot.png
--------------------------------------------------------------------------------
/tests/textandinputs/textandinputs.nim:
--------------------------------------------------------------------------------
1 | import fidget
2 |
3 | loadFont("IBM Plex Sans Regular", "IBMPlexSans-Regular.ttf")
4 |
5 | proc drawMain() =
6 | # Set the window title.
7 | setTitle("Fidget Text And Inputs Example")
8 |
9 | font "IBM Plex Sans Regular", 16.0, 400.0, 15, hLeft, vTop
10 |
11 | var i = 0
12 | for y in 0 ..< 100:
13 | for x in 0 ..< 100:
14 | if float(x) * 200.0 < root.box.w:
15 | if x mod 4 == 0:
16 | group "group-" & $i:
17 | box x*200, y*40, 200, 40
18 | fill "#FF0000"
19 | inc i
20 | elif x mod 4 == 1:
21 | text "text-" & $i:
22 | box x*200, y*40, 200, 40
23 | fill "#00FF00"
24 | editableText false
25 | characters "the text is " & $i
26 | inc i
27 | elif x mod 4 == 2:
28 | text "input-" & $i:
29 | box x*200, y*40, 200, 40
30 | fill "#0000FF"
31 | editableText true
32 | characters "the input is " & $i
33 | inc i
34 | else:
35 | text "textarea-" & $i:
36 | box x*200, y*40, 200, 40
37 | fill "#FF00FF"
38 | editableText true
39 | multiline true
40 | characters "the textarea is " & $i
41 | inc i
42 |
43 | startFidget(drawMain)
44 |
--------------------------------------------------------------------------------
/tests/textswitcher/textswicher.nim:
--------------------------------------------------------------------------------
1 | import fidget
2 |
3 | var showText = true
4 | var inputVar = ""
5 |
6 | proc drawMain() =
7 |
8 | if showText:
9 | text "foo1":
10 | box 100, 100, 100, 100
11 | fill "#2c3e50"
12 | binding inputVar
13 | text "foo2":
14 | box 100, 100, 100, 100
15 | fill "#95a5a6"
16 | if inputVar == "":
17 | characters "type here"
18 | else:
19 | group "foo1":
20 | box 100, 100, 100, 100
21 | strokeWeight 2
22 | stroke "#ecf0f1"
23 | cornerRadius 10
24 | fill "#7f8c8d"
25 |
26 | if buttonPress[ESCAPE]:
27 | showText = not showText
28 | echo "is text ", showText
29 |
30 | startFidget(drawMain)
31 |
--------------------------------------------------------------------------------
/tests/translate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/translate.png
--------------------------------------------------------------------------------
/tests/winFrame.flippy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/winFrame.flippy
--------------------------------------------------------------------------------
/tests/winFrame.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/winFrame.png
--------------------------------------------------------------------------------
/tests/winFrameMask.flippy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/winFrameMask.flippy
--------------------------------------------------------------------------------
/tests/winFrameMask.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/treeform/fidget/ccbf6169686ce99c02d09c66e59a905de793d554/tests/winFrameMask.png
--------------------------------------------------------------------------------