├── .forgejo └── workflows │ ├── docs.yaml │ └── github.yaml ├── .github ├── FUNDING.yml └── workflows │ └── d.yml ├── .gitignore ├── contributing.md ├── docs ├── .gitignore ├── README.md ├── docs │ ├── .vuepress │ │ └── config.yml │ ├── README.md │ └── guide │ │ ├── README.md │ │ └── some-feature.md ├── package-lock.json └── package.json ├── dub.json ├── dub.selections.json ├── icon.png ├── icon.svg ├── libraries ├── macos │ ├── libfreetype.a │ └── libraylib.a ├── readme.md ├── ubuntu │ ├── libfreetype.a │ └── libraylib.a └── windows │ ├── freetype.dll │ ├── freetype.lib │ ├── raylib.dll │ └── raylib.lib ├── license ├── logo.png ├── logo.svg ├── readme.md ├── resources ├── arrows-alpha ├── arrows.png ├── checkmark-alpha ├── checkmark.png ├── fluid-docs.css ├── hello-fluid.png ├── ruda-license.txt ├── ruda-regular.ttf └── theme.ddoc ├── source └── fluid │ ├── actions.d │ ├── arsd_image_chain.d │ ├── backend │ ├── headless.d │ ├── package.d │ └── raylib5.d │ ├── border.d │ ├── button.d │ ├── checkbox.d │ ├── children.d │ ├── clipboard_chain.d │ ├── code_input.d │ ├── default_theme.d │ ├── drag_slot.d │ ├── dub_template.d │ ├── field_slot.d │ ├── file_chain.d │ ├── file_input.d │ ├── focus_chain.d │ ├── frame.d │ ├── future │ ├── action.d │ ├── arena.d │ ├── branch_action.d │ ├── context.d │ ├── package.d │ ├── pipe.d │ ├── stack.d │ └── static_id.d │ ├── grid.d │ ├── hover_button.d │ ├── hover_chain.d │ ├── hover_transform.d │ ├── image_view.d │ ├── input.d │ ├── input_map_chain.d │ ├── io │ ├── action.d │ ├── canvas.d │ ├── clipboard.d │ ├── debug_signal.d │ ├── file.d │ ├── focus.d │ ├── hover.d │ ├── image_load.d │ ├── keyboard.d │ ├── mouse.d │ ├── overlay.d │ ├── package.d │ ├── preference.d │ └── time.d │ ├── label.d │ ├── map_frame.d │ ├── module_view.d │ ├── node.d │ ├── node_chain.d │ ├── number_input.d │ ├── onion_frame.d │ ├── overlay_chain.d │ ├── package.d │ ├── password_input.d │ ├── popup_button.d │ ├── popup_frame.d │ ├── preference_chain.d │ ├── progress_bar.d │ ├── radiobox.d │ ├── raylib_view.d │ ├── resolution_override.d │ ├── rope.d │ ├── scroll.d │ ├── scroll_frame.d │ ├── scroll_input.d │ ├── separator.d │ ├── size_lock.d │ ├── slider.d │ ├── slot.d │ ├── space.d │ ├── structs.d │ ├── style.d │ ├── switch_slot.d │ ├── test_space.d │ ├── text.d │ ├── text_input.d │ ├── theme.d │ ├── time_chain.d │ ├── time_machine.d │ ├── tree.d │ ├── typeface.d │ ├── types.d │ └── utils.d ├── tests ├── actions │ ├── branch_action.d │ ├── filters.d │ ├── find_focus_box_action.d │ ├── find_hovered_node_action.d │ ├── ordered_focus_action.d │ ├── scheduling.d │ ├── scroll_into_view_action.d │ ├── start_stop.d │ └── tree_action.d ├── io_upgrade.d ├── legacy │ ├── code_input.d │ ├── drag_slot.d │ ├── field_slot.d │ ├── grid_frame.d │ ├── image_view.d │ ├── label.d │ ├── map_frame.d │ ├── node.d │ ├── node_slot.d │ ├── number_input.d │ ├── onion_frame.d │ ├── package.d │ ├── popup_button.d │ ├── progress_bar.d │ ├── scroll_input.d │ ├── separator.d │ ├── size_lock.d │ ├── slider.d │ ├── space.d │ ├── switch_slot.d │ └── text_input.d ├── nodes │ ├── arsd_image_chain.d │ ├── checkbox.d │ ├── code_input.d │ ├── drag_slot.d │ ├── field_slot.d │ ├── file_chain.d │ ├── focus_chain.d │ ├── frame.d │ ├── grid.d │ ├── hover_chain.d │ ├── hover_transform.d │ ├── image_view.d │ ├── input_map_chain.d │ ├── input_node.d │ ├── label.d │ ├── map_frame.d │ ├── node.d │ ├── node_chain.d │ ├── node_slot.d │ ├── number_input.d │ ├── onion_frame.d │ ├── overlay_chain.d │ ├── password_input.d │ ├── popup_button.d │ ├── popup_frame.d │ ├── preference_chain.d │ ├── progress_bar.d │ ├── radiobox.d │ ├── resolution_override.d │ ├── scroll.d │ ├── scroll_input.d │ ├── separator.d │ ├── size_lock.d │ ├── slider.d │ ├── space.d │ ├── switch_slot.d │ ├── test_space.d │ ├── text_input.d │ └── time_machine.d ├── styles │ ├── children.d │ ├── theme.d │ └── tint.d └── text │ └── composite_texture.d ├── tools └── silly.d └── tour ├── buttons.d ├── drag_and_drop.d ├── dub.json ├── dub.selections.json ├── forms.d ├── frames.d ├── ibm-plex-mono-licence.txt ├── ibm-plex-mono.ttf ├── introduction.d ├── margins.d ├── module_view.d ├── package.d ├── popups.d ├── slots.d └── themes.d /.forgejo/workflows/docs.yaml: -------------------------------------------------------------------------------- 1 | name: Deploy documentation 2 | on: 3 | push: 4 | branches: 5 | - main 6 | - unstable 7 | release: 8 | types: 9 | - published 10 | 11 | jobs: 12 | build: 13 | name: Deploy documentation 14 | runs-on: ubuntu-20.04 15 | env: 16 | REF_NAME: ${{ github.event.release.tag_name || github.head_ref || github.ref_name }} 17 | steps: 18 | - uses: https://code.forgejo.org/actions/checkout@v4 19 | - name: Install D compiler 20 | uses: https://github.com/dlang-community/setup-dlang@v2 21 | with: 22 | compiler: dmd 23 | - name: Build the documentation 24 | shell: bash 25 | run: dub -b=docs 26 | - name: Update links 27 | shell: bash 28 | run: | 29 | sed -i 's:href="/docs/source/fluid:href="/docs/'$REF_NAME':g' docs/source/fluid/**.html 30 | - name: Install SSH key 31 | uses: https://github.com:/shimataro/ssh-key-action@v2 32 | with: 33 | key: ${{ secrets.DOCS_KEY }} 34 | known_hosts: ${{ secrets.KNOWN_HOSTS }} 35 | config: ${{ secrets.SSH_CONFIG }} 36 | - name: Upload documentation 37 | shell: bash 38 | run: | 39 | echo "Uploading to https://libfluid.org/docs/$REF_NAME" 40 | scp resources/ruda-regular.ttf libfluid.org:/srv/http/libfluid.org/resources/ 41 | scp resources/fluid-docs.css libfluid.org:/srv/http/libfluid.org/resources/ 42 | mv "docs/source/fluid" "docs/source/$REF_NAME" 43 | scp -r "docs/source/$REF_NAME" "libfluid.org:/srv/http/libfluid.org/docs/" 44 | echo "Documentation is now online at https://libfluid.org/docs/$REF_NAME" 45 | 46 | # Documentation must exist, and the "fluid" directory must be omitted 47 | wget --spider "https://libfluid.org/docs/$REF_NAME" 48 | wget --spider "https://libfluid.org/docs/$REF_NAME/package.html" 49 | wget --spider "https://libfluid.org/docs/$REF_NAME/label" 50 | wget --spider "https://libfluid.org/docs/$REF_NAME/label.html" 51 | ! wget --spider "https://libfluid.org/docs/$REF_NAME/fluid" 52 | ! wget --spider "https://libfluid.org/docs/$REF_NAME/fluid/package.html" 53 | -------------------------------------------------------------------------------- /.forgejo/workflows/github.yaml: -------------------------------------------------------------------------------- 1 | name: Verify test status 2 | on: [push] 3 | 4 | jobs: 5 | verify: 6 | name: Verify test status 7 | runs-on: ubuntu-20.04 8 | steps: 9 | - name: Get status 10 | uses: https://git.samerion.com/Actions/GithubStatus@main 11 | with: 12 | token: ${{ secrets.GH_TOKEN }} 13 | event: push 14 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | # github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: samerion # Replace with a single Patreon username 5 | # open_collective: # Replace with a single Open Collective username 6 | ko_fi: artha # Replace with a single Ko-fi username 7 | # tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | # community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | # liberapay: # Replace with a single Liberapay username 10 | # issuehunt: # Replace with a single IssueHunt username 11 | # lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 12 | # polar: # Replace with a single Polar username 13 | # buy_me_a_coffee: # Replace with a single Buy Me a Coffee username 14 | # thanks_dev: # Replace with a single thanks.dev username 15 | # custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 16 | -------------------------------------------------------------------------------- /.github/workflows/d.yml: -------------------------------------------------------------------------------- 1 | name: Run all tests 2 | on: [push] 3 | 4 | jobs: 5 | test: 6 | name: DUB tests 7 | strategy: 8 | fail-fast: false 9 | matrix: 10 | os: [ubuntu-latest, windows-latest, macOS-latest, macos-13] 11 | dc: [dmd, ldc, ldc-1.28.1] 12 | #dub: [dub, redub] 13 | #os: [ubuntu-latest, windows-latest] # DEBUG 14 | dub: [dub] # DEBUG 15 | exclude: 16 | - { os: macos-latest, dc: dmd } 17 | - { os: macos-13, dc: dmd } 18 | 19 | runs-on: ${{ matrix.os }} 20 | env: 21 | DUB: dub 22 | steps: 23 | - uses: actions/checkout@v4 24 | - name: Install D compiler 25 | uses: dlang-community/setup-dlang@v2 26 | with: 27 | compiler: ${{ matrix.dc }} 28 | 29 | - name: Install Redub 30 | if: matrix.dub == 'redub' 31 | shell: bash 32 | run: | 33 | dub fetch redub 34 | echo "DUB=dub run redub" >> "$GITHUB_ENV" 35 | 36 | - name: Test moduleView 37 | shell: bash 38 | run: $DUB test :module-view -d Fluid_BuildMessages 39 | if: matrix.dc != 'ldc-1.28.1' 40 | 41 | - name: Compile tour 42 | shell: bash 43 | run: $DUB build :tour 44 | if: matrix.dc != 'ldc-1.28.1' 45 | 46 | - name: Run tests 47 | shell: bash 48 | run: $DUB test 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .dub 2 | docs.json 3 | __dummy.html 4 | profilegc.log 5 | build/ 6 | *.exe 7 | *.o 8 | *.obj 9 | *.lst 10 | /tags 11 | .DS_Store 12 | *~ 13 | /docs/source 14 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | docs/.vuepress/dist 3 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Documentation with VuePress 2 | 3 | This directory contains a markdown-formatted documentation pages for the Fluid 4 | library, using the [VuePress](https://vuepress.vuejs.org/guide/) documentation 5 | system. 6 | 7 | ## Developing 8 | 9 | 1. Setup the project by running `npm install`. 10 | 2. Run a local dev instance that auto-reloads changes with `npm run docs:dev`. 11 | 3. Build the static site files with `npm run docs:build`. 12 | -------------------------------------------------------------------------------- /docs/docs/.vuepress/config.yml: -------------------------------------------------------------------------------- 1 | title: Fluid Docs 2 | description: Documentation pages for the Fluid graphics library. 3 | themeConfig: 4 | nav: 5 | - text: 'Home' 6 | link: '/' 7 | - text: 'Guide' 8 | link: '/guide/' 9 | sidebarDepth: 2 10 | sidebar: 11 | '/guide/': 12 | - '' 13 | - 'some-feature' 14 | lastUpdated: 'Last Updated' 15 | smoothScroll: true 16 | -------------------------------------------------------------------------------- /docs/docs/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | home: true 3 | heroImage: /image.png 4 | heroText: Title 5 | tagline: Subtitle 6 | actionText: Get Started → 7 | actionLink: /guide/ 8 | features: 9 | - title: Simplicity First 10 | details: Minimal setup with markdown-centered project structure helps you focus on writing. 11 | - title: Vue-Powered 12 | details: Enjoy the dev experience of Vue + webpack, use Vue components in markdown, and develop custom themes with Vue. 13 | - title: Performant 14 | details: VuePress generates pre-rendered static HTML for each page, and runs as an SPA once a page is loaded. 15 | footer: MIT Licensed | Copyright © 2018-present Evan You 16 | --- 17 | -------------------------------------------------------------------------------- /docs/docs/guide/README.md: -------------------------------------------------------------------------------- 1 | # Sample Page 2 | 3 | This is a sample page with some sample content! 4 | 5 | ```d 6 | import std.stdio; 7 | 8 | void main() { 9 | const user = "Bob"; 10 | writefln!"Hello, %s"(user); 11 | } 12 | ``` 13 | 14 | ## Sub-Heading 15 | 16 | More content here! 17 | -------------------------------------------------------------------------------- /docs/docs/guide/some-feature.md: -------------------------------------------------------------------------------- 1 | # Some Feature 2 | 3 | This is a sample page for some feature. 4 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docs", 3 | "version": "1.0.0", 4 | "description": "Documentation for the Fluid graphics library.", 5 | "main": "index.js", 6 | "scripts": { 7 | "docs:dev": "vuepress dev docs", 8 | "docs:build": "vuepress build docs" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "vuepress": "^1.9.10" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /dub.selections.json: -------------------------------------------------------------------------------- 1 | { 2 | "fileVersion": 1, 3 | "versions": { 4 | "arsd-official": "11.5.3", 5 | "bindbc-freetype": "1.1.1", 6 | "bindbc-loader": "1.1.5", 7 | "bolts": "1.3.1", 8 | "ddmp": "0.0.1-0.dev.3", 9 | "elemi": "1.2.3", 10 | "fluent-asserts": "0.13.3", 11 | "fluid-tree-sitter": "0.1.7", 12 | "libdparse": "0.23.2", 13 | "optional": "1.3.0", 14 | "stdx-allocator": "2.77.5" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Samerion/Fluid/6304cbbc4def3c336af5f5940fbabd64169b62f7/icon.png -------------------------------------------------------------------------------- /libraries/macos/libfreetype.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Samerion/Fluid/6304cbbc4def3c336af5f5940fbabd64169b62f7/libraries/macos/libfreetype.a -------------------------------------------------------------------------------- /libraries/macos/libraylib.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Samerion/Fluid/6304cbbc4def3c336af5f5940fbabd64169b62f7/libraries/macos/libraylib.a -------------------------------------------------------------------------------- /libraries/readme.md: -------------------------------------------------------------------------------- 1 | # Fluid dependency binaries 2 | 3 | Fluid relies on Freetype to perform text rendering. Freetype is a C library and thus will not be built by DUB. This 4 | directory provides raw, pre-built binaries of Freetype matching the version used by Fluid. Fluid will link against those 5 | *by default*. 6 | 7 | Moreover, to make the tour easier to run, Raylib binaries are provided just as well. 8 | 9 | Warning: Supplied Ubuntu libraries may not work on other distros, and will not work on older Ubuntu releases. 10 | -------------------------------------------------------------------------------- /libraries/ubuntu/libfreetype.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Samerion/Fluid/6304cbbc4def3c336af5f5940fbabd64169b62f7/libraries/ubuntu/libfreetype.a -------------------------------------------------------------------------------- /libraries/ubuntu/libraylib.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Samerion/Fluid/6304cbbc4def3c336af5f5940fbabd64169b62f7/libraries/ubuntu/libraylib.a -------------------------------------------------------------------------------- /libraries/windows/freetype.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Samerion/Fluid/6304cbbc4def3c336af5f5940fbabd64169b62f7/libraries/windows/freetype.dll -------------------------------------------------------------------------------- /libraries/windows/freetype.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Samerion/Fluid/6304cbbc4def3c336af5f5940fbabd64169b62f7/libraries/windows/freetype.lib -------------------------------------------------------------------------------- /libraries/windows/raylib.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Samerion/Fluid/6304cbbc4def3c336af5f5940fbabd64169b62f7/libraries/windows/raylib.dll -------------------------------------------------------------------------------- /libraries/windows/raylib.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Samerion/Fluid/6304cbbc4def3c336af5f5940fbabd64169b62f7/libraries/windows/raylib.lib -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Samerion/Fluid/6304cbbc4def3c336af5f5940fbabd64169b62f7/logo.png -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ![Hello World from Fluid!](./resources/hello-fluid.png) 2 | 3 | A flexible UI library for [the D programming language](https://dlang.org/). Minimal setup. Declarative. Non-intrusive. 4 | 5 | ```d 6 | auto root = vspace( 7 | .layout!"center", 8 | label(.layout!"center", "Hello World from"), 9 | imageView("./logo.png"), 10 | ); 11 | ``` 12 | 13 | Fluid comes with [Raylib 5][raylib] support. Integration is seamless: one or two calls do the job. 14 | 15 | ```d 16 | while (!WindowShouldClose) { 17 | 18 | BeginDrawing(); 19 | 20 | ClearBackground(color!"#fff"); 21 | root.draw(); 22 | 23 | EndDrawing(); 24 | 25 | } 26 | ``` 27 | 28 | [raylib]: https://www.raylib.com/ 29 | 30 | Fluid has a decent feature set at the moment and new features will still be added over time. Fluid is already mostly 31 | stable and ready for use, but is still likely to receive a few breaking changes before leaving its pre-release stage. 32 | 33 | **Support Fluid development on Patreon: https://www.patreon.com/samerion** 34 | 35 | * Straightforward, high-level API 36 | * Responsive layout 37 | * Extensible 38 | * Components easily combined together 39 | * Reliable mouse and keyboard input 40 | * Separate layout and styling 41 | * Scrolling support 42 | * Out-of-the-box Unicode support 43 | * Code editor node included 44 | * Full HiDPI support 45 | * Partial gamepad support 46 | 47 | ## Get Fluid 48 | 49 | For a quick start guide on Fluid, check out the tour: 50 | 51 | ``` 52 | dub run fluid:tour 53 | ``` 54 | 55 | Create a new [dub][dub] project based on Fluid: 56 | 57 | ``` 58 | dub init -t fluid 59 | ``` 60 | 61 | You can use [dub][dub] to include Fluid in your code: 62 | 63 | ``` 64 | dub add fluid 65 | dub add raylib-d 66 | dub run raylib-d:install 67 | ``` 68 | 69 | [dub]: https://code.dlang.org/ 70 | 71 | ## Contribute to Fluid 72 | 73 | Fluid welcomes contributions! You can review open issues and open pull requests to fix them. 74 | If you need help, you'll receive it. 75 | 76 | * [Open an issue](https://git.samerion.com/Samerion/Fluid/issues/new) 77 | * [Review current goals](https://git.samerion.com/Samerion/Fluid/milestones?state=open&q=0.7&fuzzy=) 78 | 79 | Read more about contributing to Fluid in our [contributing.md](contributing.md) file. 80 | -------------------------------------------------------------------------------- /resources/arrows-alpha: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Samerion/Fluid/6304cbbc4def3c336af5f5940fbabd64169b62f7/resources/arrows-alpha -------------------------------------------------------------------------------- /resources/arrows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Samerion/Fluid/6304cbbc4def3c336af5f5940fbabd64169b62f7/resources/arrows.png -------------------------------------------------------------------------------- /resources/checkmark-alpha: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Samerion/Fluid/6304cbbc4def3c336af5f5940fbabd64169b62f7/resources/checkmark-alpha -------------------------------------------------------------------------------- /resources/checkmark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Samerion/Fluid/6304cbbc4def3c336af5f5940fbabd64169b62f7/resources/checkmark.png -------------------------------------------------------------------------------- /resources/hello-fluid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Samerion/Fluid/6304cbbc4def3c336af5f5940fbabd64169b62f7/resources/hello-fluid.png -------------------------------------------------------------------------------- /resources/ruda-license.txt: -------------------------------------------------------------------------------- 1 | Copyright 2019 The Ruda Project Authors (https://github.com/marmonsalve/Ruda-new) 2 | 3 | This Font Software is licensed under the SIL Open Font License, Version 1.1. 4 | This license is copied below, and is also available with a FAQ at: 5 | http://scripts.sil.org/OFL 6 | 7 | 8 | ----------------------------------------------------------- 9 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 10 | ----------------------------------------------------------- 11 | 12 | PREAMBLE 13 | The goals of the Open Font License (OFL) are to stimulate worldwide 14 | development of collaborative font projects, to support the font creation 15 | efforts of academic and linguistic communities, and to provide a free and 16 | open framework in which fonts may be shared and improved in partnership 17 | with others. 18 | 19 | The OFL allows the licensed fonts to be used, studied, modified and 20 | redistributed freely as long as they are not sold by themselves. The 21 | fonts, including any derivative works, can be bundled, embedded, 22 | redistributed and/or sold with any software provided that any reserved 23 | names are not used by derivative works. The fonts and derivatives, 24 | however, cannot be released under any other type of license. The 25 | requirement for fonts to remain under this license does not apply 26 | to any document created using the fonts or their derivatives. 27 | 28 | DEFINITIONS 29 | "Font Software" refers to the set of files released by the Copyright 30 | Holder(s) under this license and clearly marked as such. This may 31 | include source files, build scripts and documentation. 32 | 33 | "Reserved Font Name" refers to any names specified as such after the 34 | copyright statement(s). 35 | 36 | "Original Version" refers to the collection of Font Software components as 37 | distributed by the Copyright Holder(s). 38 | 39 | "Modified Version" refers to any derivative made by adding to, deleting, 40 | or substituting -- in part or in whole -- any of the components of the 41 | Original Version, by changing formats or by porting the Font Software to a 42 | new environment. 43 | 44 | "Author" refers to any designer, engineer, programmer, technical 45 | writer or other person who contributed to the Font Software. 46 | 47 | PERMISSION & CONDITIONS 48 | Permission is hereby granted, free of charge, to any person obtaining 49 | a copy of the Font Software, to use, study, copy, merge, embed, modify, 50 | redistribute, and sell modified and unmodified copies of the Font 51 | Software, subject to the following conditions: 52 | 53 | 1) Neither the Font Software nor any of its individual components, 54 | in Original or Modified Versions, may be sold by itself. 55 | 56 | 2) Original or Modified Versions of the Font Software may be bundled, 57 | redistributed and/or sold with any software, provided that each copy 58 | contains the above copyright notice and this license. These can be 59 | included either as stand-alone text files, human-readable headers or 60 | in the appropriate machine-readable metadata fields within text or 61 | binary files as long as those fields can be easily viewed by the user. 62 | 63 | 3) No Modified Version of the Font Software may use the Reserved Font 64 | Name(s) unless explicit written permission is granted by the corresponding 65 | Copyright Holder. This restriction only applies to the primary font name as 66 | presented to the users. 67 | 68 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 69 | Software shall not be used to promote, endorse or advertise any 70 | Modified Version, except to acknowledge the contribution(s) of the 71 | Copyright Holder(s) and the Author(s) or with their explicit written 72 | permission. 73 | 74 | 5) The Font Software, modified or unmodified, in part or in whole, 75 | must be distributed entirely under this license, and must not be 76 | distributed under any other license. The requirement for fonts to 77 | remain under this license does not apply to any document created 78 | using the Font Software. 79 | 80 | TERMINATION 81 | This license becomes null and void if any of the above conditions are 82 | not met. 83 | 84 | DISCLAIMER 85 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 86 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 87 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 88 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 89 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 90 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 91 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 92 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 93 | OTHER DEALINGS IN THE FONT SOFTWARE. 94 | -------------------------------------------------------------------------------- /resources/ruda-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Samerion/Fluid/6304cbbc4def3c336af5f5940fbabd64169b62f7/resources/ruda-regular.ttf -------------------------------------------------------------------------------- /source/fluid/arsd_image_chain.d: -------------------------------------------------------------------------------- 1 | /// This module provides an image loading implementation based on `arsd-official:image-files`, as available on DUB. 2 | /// It will only be accessible if this package is loaded through DUB. 3 | module fluid.arsd_image_chain; 4 | 5 | version (Have_arsd_official_image_files): 6 | 7 | import arsd.image; 8 | 9 | import fluid.node; 10 | import fluid.types; 11 | import fluid.utils; 12 | import fluid.node_chain; 13 | 14 | import fluid.io.file; 15 | import fluid.io.image_load; 16 | 17 | @safe: 18 | 19 | alias arsdImageChain = nodeBuilder!ARSDImageChain; 20 | 21 | /// An implementation of the `ImageLoadIO` API based on the `arsd-official:image-files` package available on DUB. 22 | class ARSDImageChain : NodeChain, ImageLoadIO { 23 | 24 | mixin controlIO; 25 | 26 | this(Node node = null) { 27 | super(node); 28 | } 29 | 30 | override void beforeResize(Vector2) { 31 | startIO(); 32 | } 33 | 34 | override void afterResize(Vector2) { 35 | stopIO(); 36 | } 37 | 38 | Image loadImage(const(ubyte)[] data) @trusted { 39 | return loadImageFromMemory(data).toFluid(); 40 | } 41 | 42 | } 43 | 44 | /// Convert an ARSD image to a Fluid `Image`. 45 | /// Params: 46 | /// image = An ARSD instance of a `MemoryImage`. 47 | /// Returns: 48 | /// A Fluid `Image` struct. 49 | Image toFluid(MemoryImage image) @trusted { 50 | auto trueColorImage = image.getAsTrueColorImage(); 51 | return Image( 52 | cast(fluid.types.Color[]) trueColorImage.imageData.bytes, 53 | image.width, 54 | image.height 55 | ); 56 | } 57 | -------------------------------------------------------------------------------- /source/fluid/button.d: -------------------------------------------------------------------------------- 1 | /// A button can be clicked by the user to trigger an event. 2 | module fluid.button; 3 | 4 | @safe: 5 | 6 | /// [Button] is described with text. It can be constructed with the [button][button] node builder. 7 | @("Button reference example") 8 | unittest { 9 | run( 10 | button("Click me!", delegate { }), 11 | ); 12 | } 13 | 14 | /// Text is not enough? A [FrameButton] can mix content — for example, place an 15 | /// [ImageView][fluid.image_view] inside if you need an icon. Add text with [Label]. 16 | /// 17 | /// A FrameButton can be created with [vframeButton], to align content vertically — or with 18 | /// [hframeButton], for horizontal content. 19 | @("FrameButton reference example") 20 | unittest { 21 | import fluid.image_view; 22 | run( 23 | hframeButton( 24 | HitFilter.hitBranch, 25 | imageView("myicon.png"), 26 | label("Click me!"), 27 | delegate { } 28 | ), 29 | ); 30 | } 31 | 32 | import fluid.node; 33 | import fluid.frame; 34 | import fluid.input; 35 | import fluid.label; 36 | import fluid.utils; 37 | import fluid.style; 38 | import fluid.structs; 39 | import fluid.backend; 40 | 41 | /// A [node builder][nodeBuilder] to create a [Button] labelled with text. 42 | /// It takes a string for the label text, and a delegate describing the effect. 43 | alias button = nodeBuilder!Button; 44 | 45 | deprecated("Use vframeButton instead") 46 | alias frameButton = nodeBuilder!FrameButton; 47 | 48 | /// A [node builder][nodeBuilder] to create a [FrameButton]. The contents will be aligned 49 | /// horizontally (for `hframeButton`) or vertically (for `vframeButton`). Pass a delegate to 50 | /// describe the button's effects as the last argument. 51 | alias hframeButton = nodeBuilder!(FrameButton, (a) { 52 | a.isHorizontal = true; 53 | }); 54 | 55 | /// ditto 56 | alias vframeButton = nodeBuilder!FrameButton; 57 | 58 | /// A [ButtonImpl] based on a [Label]. It will display text. 59 | /// 60 | /// Note: 61 | /// In a future update, `Button` will be a dedicated subclass of `ButtonImpl!Node`. 62 | /// See [issue #298](https://git.samerion.com/Samerion/Fluid/issues/298). 63 | alias Button = ButtonImpl!Label; 64 | 65 | /// A [ButtonImpl] based on a [Frame]. 66 | alias FrameButton = ButtonImpl!Frame; 67 | 68 | /// A button can be pressed by the user to trigger an action. 69 | /// 70 | /// `ButtonImpl` is a template, and can be used with most other nodes. 71 | class ButtonImpl(T : Node = Label) : InputNode!T { 72 | 73 | mixin enableInputActions; 74 | 75 | /// A callback to run when the button is pressed. This is actually an alias for 76 | /// [InputNode.submitted][fluid.input.InputNode]. 77 | alias pressed = submitted; 78 | 79 | // Button status 80 | public { 81 | 82 | /// Set to true while the button is held down; can be used for styling. 83 | bool isPressed; 84 | 85 | } 86 | 87 | /// Create a new button. 88 | /// Params: 89 | /// sup = Parameters to pass to the parent node. 90 | /// Most commonly, this defines the button's visual content. 91 | /// For [Button] this will be the label text. 92 | /// pressed = Action to perform when the button is pressed. 93 | this(T...)(T sup, void delegate() @safe pressed) { 94 | 95 | super(sup); 96 | this.pressed = pressed; 97 | 98 | } 99 | 100 | protected override void drawImpl(Rectangle outer, Rectangle inner) { 101 | 102 | // Check if pressed 103 | isPressed = checkIsPressed; 104 | // TODO this should be *false* if key is held down, but wasn't pressed while in focus 105 | 106 | // Draw the button 107 | super.drawImpl(outer, inner); 108 | 109 | } 110 | 111 | /// Handle input by calling the [pressed][Button.pressed] delegate assigned to this 112 | /// button. 113 | /// 114 | /// This method is bound to the [press input action][FluidInputAction.press]. 115 | @(FluidInputAction.press) 116 | void press() @trusted { 117 | 118 | // Run the callback 119 | if (pressed) pressed(); 120 | 121 | } 122 | 123 | static if (is(typeof(text) : string)) 124 | override string toString() const { 125 | 126 | import std.format; 127 | return format!"button(%s)"(text); 128 | 129 | } 130 | 131 | } 132 | -------------------------------------------------------------------------------- /source/fluid/checkbox.d: -------------------------------------------------------------------------------- 1 | /// 2 | module fluid.checkbox; 3 | 4 | import fluid.node; 5 | import fluid.input; 6 | import fluid.utils; 7 | import fluid.style; 8 | import fluid.backend; 9 | import fluid.image_view; 10 | 11 | import fluid.io.canvas; 12 | 13 | @safe: 14 | 15 | /// A checkbox can be selected by the user to indicate a true or false state. 16 | alias checkbox = simpleConstructor!Checkbox; 17 | 18 | /// ditto 19 | class Checkbox : InputNode!Node { 20 | 21 | mixin enableInputActions; 22 | 23 | CanvasIO canvasIO; 24 | 25 | /// Additional features available for checkbox styling. 26 | static class Extra : typeof(super).Extra { 27 | 28 | /// Image to use for the checkmark. 29 | Image checkmark; 30 | 31 | this(Image checkmark) { 32 | this.checkmark = checkmark; 33 | } 34 | 35 | } 36 | 37 | // Button status 38 | public { 39 | 40 | /// Size of the checkbox. 41 | Vector2 size; 42 | 43 | } 44 | 45 | private { 46 | 47 | DrawableImage _markImage; 48 | bool _isChecked; 49 | 50 | } 51 | 52 | /// Create a new checkbox. 53 | /// Params: 54 | /// isChecked = Whether the checkbox should be checked or not. 55 | /// changed = Callback to run whenever the user changes the value. 56 | this(bool isChecked, void delegate() @safe changed = null) { 57 | 58 | this(changed); 59 | this._isChecked = isChecked; 60 | 61 | } 62 | 63 | /// ditto 64 | this(void delegate() @safe changed = null) { 65 | 66 | this.size = Vector2(10, 10); 67 | this.changed = changed; 68 | 69 | } 70 | 71 | /// If true, the box is checked. 72 | bool isChecked() const { 73 | return _isChecked; 74 | 75 | } 76 | 77 | /// ditto 78 | bool isChecked(bool value) { 79 | updateSize(); 80 | return _isChecked = value; 81 | } 82 | 83 | /// Get the currently used checkmark image. Requires `CanvasIO`, updated on resize. 84 | /// Returns: 85 | /// Active checkmark image. 86 | inout(Image) markImage() inout { 87 | return _markImage; 88 | } 89 | 90 | protected override void resizeImpl(Vector2 space) { 91 | 92 | use(canvasIO); 93 | 94 | if (canvasIO) { 95 | _markImage = getImage(pickStyle()); 96 | load(canvasIO, _markImage); 97 | } 98 | 99 | minSize = size; 100 | 101 | } 102 | 103 | protected override void drawImpl(Rectangle outer, Rectangle inner) { 104 | 105 | import std.algorithm : min; 106 | 107 | auto style = pickStyle(); 108 | 109 | style.drawBackground(io, canvasIO, outer); 110 | 111 | if (canvasIO) { 112 | 113 | const size = _markImage.size.fitInto(inner.size); 114 | const position = center(inner) - size/2; 115 | 116 | _markImage.draw(Rectangle(position.tupleof, size.tupleof)); 117 | 118 | } 119 | 120 | if (auto texture = getTexture(style)) { 121 | 122 | const size = texture.canvasSize.fitInto(inner.size); 123 | const position = center(inner) - size/2; 124 | 125 | texture.draw(Rectangle(position.tupleof, size.tupleof)); 126 | 127 | } 128 | 129 | } 130 | 131 | /// Get checkmark image used by this checkbox. 132 | protected Image getImage(Style style) { 133 | 134 | if (auto extra = cast(Extra) style.extra) { 135 | return extra.checkmark; 136 | } 137 | return Image.init; 138 | 139 | } 140 | 141 | /// Get checkmark texture used by this checkbox. 142 | protected TextureGC* getTexture(Style style) @trusted { 143 | 144 | auto extra = cast(Extra) style.extra; 145 | 146 | // No valid extra data, ignore 147 | if (!extra) return null; 148 | 149 | // Load the texture 150 | return extra.getTexture(io, extra.checkmark); 151 | 152 | } 153 | 154 | 155 | /// Toggle the checkbox. 156 | void toggle() { 157 | 158 | isChecked = !isChecked; 159 | if (changed) changed(); 160 | 161 | } 162 | 163 | /// ditto 164 | @(FluidInputAction.press) 165 | protected void press() { 166 | 167 | toggle(); 168 | 169 | } 170 | 171 | static if (is(typeof(text) : string)) 172 | override string toString() const { 173 | 174 | if (isChecked) 175 | return "checkbox(true)"; 176 | else 177 | return "checkbox()"; 178 | 179 | } 180 | 181 | } 182 | 183 | /// 184 | unittest { 185 | 186 | // Checkbox creates a toggleable button 187 | auto myCheckbox = checkbox(); 188 | 189 | assert(!myCheckbox.isChecked); 190 | 191 | } 192 | -------------------------------------------------------------------------------- /source/fluid/clipboard_chain.d: -------------------------------------------------------------------------------- 1 | /// Basic implementation of clipboard I/O without communicating with the system. Exchanges clipboard data 2 | /// only between nodes with access, and does not transfer them to other apps. 3 | module fluid.clipboard_chain; 4 | 5 | import fluid.node; 6 | import fluid.types; 7 | import fluid.utils; 8 | import fluid.node_chain; 9 | 10 | import fluid.io.clipboard; 11 | 12 | @safe: 13 | 14 | alias clipboardChain = nodeBuilder!ClipboardChain; 15 | 16 | /// Local clipboard provider. Makes it possible to copy and paste text between nodes in the same branch. 17 | /// 18 | /// `ClipboardChain` does not communicate with the system, so the clipboard will *not* be accessible to other apps. 19 | /// This makes this node suitable for testing. 20 | class ClipboardChain : NodeChain, ClipboardIO { 21 | 22 | mixin controlIO; 23 | 24 | private { 25 | string _value; 26 | } 27 | 28 | this(Node next = null) { 29 | super(next); 30 | } 31 | 32 | /// Returns: 33 | /// Current clipboard content. 34 | string value() const { 35 | return _value; 36 | } 37 | 38 | /// Replace the clipboard contents. 39 | /// Params: 40 | /// newValue = New clipboard content. 41 | /// Returns: 42 | /// Same text as passed into the function. 43 | string value(string newValue) { 44 | return _value = newValue; 45 | } 46 | 47 | override void beforeResize(Vector2) { 48 | startIO(); 49 | } 50 | 51 | override void afterResize(Vector2) { 52 | stopIO(); 53 | } 54 | 55 | override bool writeClipboard(string text) { 56 | _value = text; 57 | return true; 58 | } 59 | 60 | char[] readClipboard(return scope char[] buffer, ref int offset) nothrow { 61 | 62 | import std.algorithm : min; 63 | 64 | // Read the entire text, nothing remains to be read 65 | if (offset >= _value.length) return null; 66 | 67 | // Get remaining text 68 | const text = _value[offset .. $]; 69 | const length = min(text.length, buffer.length); 70 | 71 | offset += length; 72 | return buffer[0 .. length] = text[0 .. length]; 73 | 74 | } 75 | 76 | } 77 | 78 | /// 79 | @("Example of basic ClipboardChain usage compiles and works") 80 | unittest { 81 | 82 | import fluid; 83 | 84 | TextInput first, second; 85 | 86 | // Children of a ClipboardChain will share the same clipboard 87 | auto root = clipboardChain( 88 | vspace( 89 | first = textInput(), 90 | second = textInput(), 91 | ), 92 | ); 93 | root.draw(); 94 | 95 | // Text copied by the first input... 96 | first.value = "Hello!"; 97 | first.selectAll(); 98 | first.copy(); 99 | 100 | // ... can now be pasted into the other 101 | second.paste(); 102 | assert(second.value == "Hello!"); 103 | 104 | } 105 | -------------------------------------------------------------------------------- /source/fluid/dub_template.d: -------------------------------------------------------------------------------- 1 | /// This module provides a DUB template for `dub init -t fluid` 2 | module fluid.dub_template; 3 | 4 | import std.file; 5 | import std.string; 6 | import std.process; 7 | 8 | import std.stdio : writefln, stderr; 9 | 10 | 11 | version (Fluid_InitExec): 12 | 13 | 14 | void main() { 15 | 16 | const mainFile = q{ 17 | 18 | import fluid; 19 | import raylib; 20 | 21 | void main() { 22 | 23 | // Prepare the window 24 | SetConfigFlags(ConfigFlags.FLAG_WINDOW_RESIZABLE); 25 | SetTraceLogLevel(TraceLogLevel.LOG_WARNING); 26 | InitWindow(800, 600, "Hello, Fluid!"); 27 | SetTargetFPS(60); 28 | scope (exit) CloseWindow(); 29 | 30 | // Create UI 31 | auto ui = label("Hello, World!"); 32 | 33 | // Event loop 34 | while (!WindowShouldClose) { 35 | 36 | BeginDrawing(); 37 | scope (exit) EndDrawing(); 38 | 39 | ClearBackground(color("fff")); 40 | 41 | ui.draw(); 42 | 43 | } 44 | 45 | } 46 | 47 | }; 48 | 49 | const mainOutdent = mainFile 50 | .splitLines 51 | .outdent // Remove indent 52 | .join("\n") 53 | .strip; // Strip leading & trailing whitespace 54 | 55 | if ("source".exists) { 56 | 57 | stderr.writefln!"fluid: Directory 'source/' already exists, aborting."; 58 | return; 59 | 60 | } 61 | 62 | // Prepare the source 63 | mkdir("source"); 64 | write("source/main.d", mainOutdent); 65 | append(".gitignore", "*.so\n"); 66 | append(".gitignore", "*.so.*\n"); 67 | 68 | // Install raylib 69 | spawnShell("dub add raylib-d").wait; 70 | spawnShell("dub run raylib-d:install -y -n").wait; 71 | 72 | } 73 | -------------------------------------------------------------------------------- /source/fluid/field_slot.d: -------------------------------------------------------------------------------- 1 | /// 2 | module fluid.field_slot; 3 | 4 | import fluid.node; 5 | import fluid.utils; 6 | import fluid.input; 7 | import fluid.actions; 8 | import fluid.backend; 9 | 10 | import fluid.io.hover; 11 | import fluid.io.focus; 12 | 13 | @safe: 14 | 15 | 16 | /// A field slot is a node meant to hold an input node along with associated nodes, like labels. It's functionally 17 | /// equivalent to the [`