digitalmars.D.announce - Fluid 0.7.0 has been released!
- cookiewitch (191/191) Oct 03 After 9 months of development and 252 commits later, finally
- ryuukk_ (4/4) Oct 03 Congrats on the release
- Dennis (9/14) Oct 04 I tried `dub run fluid:showcase`, but it gives an error about a
- cookiewitch (3/18) Oct 05 `dub fluid:showcase` should issue a warning recommending `:tour`
- holyzantaclara (3/8) Oct 05 Congratulations ! I will definitely try this one ! Thank you so
- cookiewitch (4/13) Oct 05 Hm, for what it's worth it uses OpenGL at the moment, but
- WB (75/76) Oct 20 ...
- cookiewitch (5/34) Oct 20 Fluid requires DMD≥2.098.1 or LDC≥1.28.1. The tour requires a
- IchorDev (2/6) Oct 24 Is it going to be supported?
- cookiewitch (3/9) Oct 25 Can't say for sure, because I haven't used it myself, but it's a
- IchorDev (13/15) Oct 24 This project certainly seems promising, although I’m rather
- cookiewitch (15/30) Oct 25 Fluid nodes aren't just pointers to functions, so no. I think
- IchorDev (115/134) Oct 25 No problem! Only thing holding me from putting it on dub is that
- cookiewitch (10/41) Oct 25 Looking through Pango's documentation and code, [integrating it
- IchorDev (72/81) Oct 31 Sorry for my late reply! Anyway, here we go…
- cookiewitch (22/41) Nov 01 Thank you for dedicating your time to this, and for the very
- IchorDev (101/139) Nov 02 If the modified source is available then I don't think that's a
- cookiewitch (24/42) Nov 03 Inline styling of `Text` was just a dirty hack to have syntax
After 9 months of development and 252 commits later, finally 0.7.0 gets to see the sunlight! This is the biggest update to Fluid yet, almost twice as big as [0.6.0](https://git.samerion.com/Samerion/Fluid/releases/tag/v0.6.0), and also almost half the size of Fluid itself. In fact, so big, that I decided to delay some of the changes to a [separate future update](https://git.samerion.com/Samerion/Fluid/milestone/19); too big. **[Fluid is a general-purpose user interface library](https://git.samerion.com/Samerion/Fluid)**. It is D first, and comes with Raylib support. While largely a work in progress, and of pre-release quality, it's already mostly stable and ready for use. Start a new Fluid project [with DUB](https://fluid.dub.pm): ```shell dub fetch fluid dub init -t fluid myproject ``` Add Fluid to your existing project: ``` dub add fluid ``` Among other stuff, this update addresses feedback from community members. Folks reported a lot of issue with building this thing. Fluid now has CI coverage and should work just fine on all the three major platforms. Fluid's tour now also features an experimental, fully interactive "moduleView" chapter, which at the moment only works properly on Linux. In short term, I hope to improve Fluid's documentation and add a number of missing features, mostly nodes. In long term, I would like to work on animations and reactive programming. [Full changelog can be seen on the releases page](https://git.samerion.com/Samerion/Fluid/releases/tag/v0.7.0) Most importantly, 0.7.0 introduces a reworked theme system, one much more readable than the last: ```d import fluid.theme; // explicit import needed! auto theme = Theme( rule!Node( typeface = Style.loadTypeface("noto.ttf"), fontSize = 12.pt, textColor = color("#fff"), ), rule!Frame( ), ); ``` `when` rules can be used to alter the style based on any of the node's properties. Multiple `when` rules can be applied at the same time. ```d border = 1, when!"a.isHovered"( ), when!"a.isFocused"( borderStyle = colorBorder(color("#fff")), ), when!(a => a.text.isValidPassword)( ), ``` Rules can now also affect children nodes through `children`: ```d rule!PopupFrame( border = 1, children!Button( // style all buttons inside PopupFrames margin = 0, padding.sideX = 4, padding.sideY = 2, ) ), ``` For more advanced usecases, values can also be picked based on runtime values: ```d rule!Node( a => rule( backgroundColor = pickColor(a.score), ), ), ``` [This feature was covered on this year's DConf!](https://youtu.be/AzezZhvIyS4?t=21141) In the previous releases, `Layout` and `Theme` were taken directly as constructor arguments, which could be really confusing, and at the same time, limiting. Now, the `nodeBuilder` takes care of this automatically: ```d alias label = nodeBuilder!Label; class Label : Node { this(string text) { // ... } // ... } label( .layout!"fill", .myTheme, "Hello, World!" ), ``` More interestingly, it's now extensible — for example, `sizeLimit` can be used with `sizeLock` nodes: ```d sizeLock!label( .sizeLimitX = 400, .layout!"fill", .myTheme, "Hello, World!" ) ``` You can define your own node property by creating a struct with an `apply` method: ```d auto hidden(bool value = true) { static struct Hidden { bool value; void apply(Node node) { node.isHidden = value; } } return Hidden(value); } label( .hidden, "I'm invisible!" ), ``` Other node properties are now available: `.tags` (see below), `.ignoreMouse`, `.hidden` and `.disabled`. `simpleConstructor` remains alive as an alias to `nodeBuilder`. One can now define an enum marked ` NodeTag` to create *tags*. These are very similar to [CSS classes](https://developer.mozilla.org/en-US/docs/Web/HTML/Globa _attributes/class), making it possible to change how a node is styled in a consistent, predictable manner: ```d NodeTag enum Tag { heading, red, } vspace( myTheme, label( .tags!(Tag.heading), "This is a heading!" ), label( .tags!(Tag.red), "Red text!" ), label( .tags!(Tag.heading, Tag.red), "Red heading!" ), ); ``` Use tags in your theme by passing them into a `rule` argument: ```d rule!(Label, Tag.heading)( fontSize = 22.pt, ), rule!(Label, Tag.red)( textColor = color("#f00"), ). ``` TextInput now supports multiline input via `.multiline`, the caret can now be moved around, text can be selected, copied, pasted, and changes can be undone or redone with keyboard shortcuts. ```d textInput(); // single line lineInput(); // single line multilineInput(); // multiline textInput(.multiline); // multiline codeInput(); // code editor ``` This is a massive change under the hood. Fluid's text rendering is now a lot more performant, and can support rendering pages of text without slowdowns. Editing performance still needs some improvements. A code editor is now available with `CodeInput` with support for syntax highlighting and automatic indentation. Performance issues are especially visible with this one, but it is expected they will be fixed in coming releases. [Full changelog can be seen on the releases page](https://git.samerion.com/Samerion/Fluid/releases/tag/v0.7.0)
Oct 03
Congrats on the release You should include some example with some screenshots, it'll be great way to advertise both the library and D Your library has lot of potential
Oct 03
Nice! On Thursday, 3 October 2024 at 11:15:16 UTC, cookiewitch wrote:Start a new Fluid project [with DUB](https://fluid.dub.pm): ```shell dub fetch fluid dub init -t fluid myproject ```I tried `dub run fluid:showcase`, but it gives an error about a raylib import it can't resolve. ``` ../../.dub/packages/fluid/0.7.0/fluid/tour/package.d(173,12): Error: unable to read module `raylib` ``` `dub run fluid:tour` does work though.
Oct 04
On Friday, 4 October 2024 at 12:14:09 UTC, Dennis wrote:Nice! On Thursday, 3 October 2024 at 11:15:16 UTC, cookiewitch wrote:`dub fluid:showcase` should issue a warning recommending `:tour` now. I'm going to be honest, I didn't check if it still works. ^^Start a new Fluid project [with DUB](https://fluid.dub.pm): ```shell dub fetch fluid dub init -t fluid myproject ```I tried `dub run fluid:showcase`, but it gives an error about a raylib import it can't resolve. ``` ../../.dub/packages/fluid/0.7.0/fluid/tour/package.d(173,12): Error: unable to read module `raylib` ``` `dub run fluid:tour` does work though.
Oct 05
On Thursday, 3 October 2024 at 11:15:16 UTC, cookiewitch wrote:After 9 months of development and 252 commits later, finally 0.7.0 gets to see the sunlight! This is the biggest update to Fluid yet, almost twice as big as [0.6.0](https://git.samerion.com/Samerion/Fluid/releases/tag/v0.6.0), and also almost half the size of Fluid itself. In fact, so big, that I decided to delay some of the changes to a [separate future update](https://git.samerion.com/Samerion/Fluid/milestone/19); too big. [...]Congratulations ! I will definitely try this one ! Thank you so much, I was looking for an UI native library, good timing !
Oct 05
On Saturday, 5 October 2024 at 08:44:58 UTC, holyzantaclara wrote:On Thursday, 3 October 2024 at 11:15:16 UTC, cookiewitch wrote:Hm, for what it's worth it uses OpenGL at the moment, but integrating with OS-specific toolkits is something I plan to do. At least it's not a web browser!After 9 months of development and 252 commits later, finally 0.7.0 gets to see the sunlight! This is the biggest update to Fluid yet, almost twice as big as [0.6.0](https://git.samerion.com/Samerion/Fluid/releases/tag/v0.6.0), and also almost half the size of Fluid itself. In fact, so big, that I decided to delay some of the changes to a [separate future update](https://git.samerion.com/Samerion/Fluid/milestone/19); too big. [...]Congratulations ! I will definitely try this one ! Thank you so much, I was looking for an UI native library, good timing !
Oct 05
On Thursday, 3 October 2024 at 11:15:16 UTC, cookiewitch wrote:Start a new Fluid project [with DUB](https://fluid.dub.pm):... Kind of does not work out of the box: ``` user debian:~/k$ dub run fluid:tour Package 'fluid:tour' was not found locally but is available online: --- Description: A straightforward and easy to use GUI library. Version: 0.7.0 --- Do you want to fetch 'fluid:tour' now? [Y/n]: Y Fetching fluid:tour 0.7.0 Building package fluid:tour in /home/user/.dub/packages/fluid/0.7.0/fluid/tour/ Fetching raylib-d 5.0.1 (getting selected version) Fetching silly 1.1.1 (getting selected version) Fetching bindbc-freetype 1.1.1 (getting selected version) Fetching fluid-tree-sitter 0.1.7 (getting selected version) Fetching bindbc-loader 1.1.5 (getting selected version) Fetching libdparse 0.23.2 (getting selected version) Starting Performing "debug" build using /usr/bin/gdc for x86_64. Building bindbc-freetype 1.1.1: building configuration [staticBC] Building bindbc-loader 1.1.5: building configuration [noBC] Building fluid 0.7.0: building configuration [linux-dynamic] Building fluid-tree-sitter:tree-sitter 0.1.7: building configuration [default] gdc: error: unrecognized command-line option ‘-P-I/home/user/.dub/packages/fluid-tree-sitter/0.1.7/fluid-tree-sitter/external/tree-sitter/lib/include’ gdc: error: unrecognized command-line option ‘-P-I/home/user/.dub/packages/fluid-tree-sitter/0.1.7/fluid-tree-sitter/external/tree-sitter/lib/src’ Error /usr/bin/gdc failed with exit code 1. user debian:~/k$ ``` versions: ``` user debian:~/k$ dub --version DUB version 1.36.0-3+b1, built on Aug 1 2024 user debian:~/k$ gdc -v Using built-in specs. COLLECT_GCC=gdc COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-linux-gnu/14/lto-wrapper OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa OFFLOAD_TARGET_DEFAULT=1 Target: x86_64-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Debian 14.2.0-3' --with-bugurl=file:///usr/share/doc/gcc-14/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++,m2,rust --prefix=/usr --with-gcc-major-version-only --program-suffix=-14 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/libexec --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-libstdcxx-backtrace --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/reproducible-path/gcc-14-14.2.0/debian/tmp-nvptx/usr,amdgcn-amdhsa=/build/reproducible-path/gcc-14-14.2. /debian/tmp-gcn/usr --enable-offload-defaulted --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu --with-build-config=bootstrap-lto-lean --enable-link-serialization=2 Thread model: posix Supported LTO compression algorithms: zlib zstd gcc version 14.2.0 (Debian 14.2.0-3) user debian:~/k$ ```
Oct 20
On Sunday, 20 October 2024 at 21:59:49 UTC, WB wrote:On Thursday, 3 October 2024 at 11:15:16 UTC, cookiewitch wrote:Fluid requires DMD≥2.098.1 or LDC≥1.28.1. The tour requires a newer compiler than that (meanining Fluid itself might still work) but I did not pinpoint the exact version. GDC is not supported.Start a new Fluid project [with DUB](https://fluid.dub.pm):... Kind of does not work out of the box: ``` user debian:~/k$ dub run fluid:tour [...] Building fluid-tree-sitter:tree-sitter 0.1.7: building configuration [default] gdc: error: unrecognized command-line option ‘-P-I/home/user/.dub/packages/fluid-tree-sitter/0.1.7/fluid-tree-sitter/external/tree-sitter/lib/include’ gdc: error: unrecognized command-line option ‘-P-I/home/user/.dub/packages/fluid-tree-sitter/0.1.7/fluid-tree-sitter/external/tree-sitter/lib/src’ Error /usr/bin/gdc failed with exit code 1. user debian:~/k$ ``` versions: ``` user debian:~/k$ dub --version DUB version 1.36.0-3+b1, built on Aug 1 2024 user debian:~/k$ gdc -v Using built-in specs. COLLECT_GCC=gdc [...] gcc version 14.2.0 (Debian 14.2.0-3) user debian:~/k$ ```
Oct 20
On Monday, 21 October 2024 at 02:31:19 UTC, cookiewitch wrote:Fluid requires DMD≥2.098.1 or LDC≥1.28.1. The tour requires a newer compiler than that (meanining Fluid itself might still work) but I did not pinpoint the exact version. GDC is not supported.Is it going to be supported?
Oct 24
On Thursday, 24 October 2024 at 11:26:14 UTC, IchorDev wrote:On Monday, 21 October 2024 at 02:31:19 UTC, cookiewitch wrote:Can't say for sure, because I haven't used it myself, but it's a matter of adding it to CI and doing some fix-ups where needed.Fluid requires DMD≥2.098.1 or LDC≥1.28.1. The tour requires a newer compiler than that (meanining Fluid itself might still work) but I did not pinpoint the exact version. GDC is not supported.Is it going to be supported?
Oct 25
On Thursday, 3 October 2024 at 11:15:16 UTC, cookiewitch wrote:After 9 months of development and 252 commits later, finally 0.7.0 gets to see the sunlight!This project certainly seems promising, although I’m rather worried about how many classes there are with almost no data—so many allocations for what could just be a struct with function pointers, no? That’s how FreeType does ‘inheritance’ in pure C. Anyway, at this stage, how difficult is it to make a custom Fluid backend? (e.g. SDL2 for input or a different renderer) Also does this project have proper text layout support? I noticed there’s a dependency on FreeType; but FreeType doesn’t do layout, only rendering. I’m about to release [BindBC-Pango](https://github.com/BindBC/bindbc-pango) if you need a text layout engine. They’re absolutely imperative for acceptable internationalisation support.
Oct 24
On Thursday, 24 October 2024 at 12:02:00 UTC, IchorDev wrote:On Thursday, 3 October 2024 at 11:15:16 UTC, cookiewitch wrote:Fluid nodes aren't just pointers to functions, so no. I think switching to struct based code would intensely increase Fluid's complexity, both for me and anyone trying to start using it. I don't think it's worth it.After 9 months of development and 252 commits later, finally 0.7.0 gets to see the sunlight!This project certainly seems promising, although I’m rather worried about how many classes there are with almost no data—so many allocations for what could just be a struct with function pointers, no? That’s how FreeType does ‘inheritance’ in pure C.Anyway, at this stage, how difficult is it to make a custom Fluid backend? (e.g. SDL2 for input or a different renderer)The backend API still isn't very polished. It's not difficult, but it takes some time to prepare. I also regret choosing a Raylib-like API rather than an event-based on. I want to change that in a later update, probably 0.8.0 or 0.9.0.Also does this project have proper text layout support? I noticed there’s a dependency on FreeType; but FreeType doesn’t do layout, only rendering. I’m about to release [BindBC-Pango](https://github.com/BindBC/bindbc-pango) if you need a text layout engine. They’re absolutely imperative for acceptable internationalisation support.That is true, Fluid can only do the basic left-to-right text layout right now. To be frank, it isn't even able to center or right align text. So far I've opted for Freetype, because I'm more familiar with APIs of its kind and I wanted to save some of my time, but it might be about time I tried Pango. Thank you for your work on the bindings, I'll check them out!
Oct 25
On Friday, 25 October 2024 at 09:44:18 UTC, cookiewitch wrote:On Thursday, 24 October 2024 at 12:02:00 UTC, IchorDev wrote:I will check in again once that's done. :)Anyway, at this stage, how difficult is it to make a custom Fluid backend? (e.g. SDL2 for input or a different renderer)The backend API still isn't very polished. It's not difficult, but it takes some time to prepare. I also regret choosing a Raylib-like API rather than an event-based on. I want to change that in a later update, probably 0.8.0 or 0.9.0.No problem! Only thing holding me from putting it on dub is that its dependency BindBC-GLib has no README yet. BindBC-Pango comes with an example that should adequately demonstrate the basics of how to make use of it with FreeType's renderer. If you want to make your own renderer, I've translated enough of GObject's macros into string mixin generators that you can sub-class Pango's base render class like you would in C without any extra hassle: ```d FT_Face[PangoFont*] faces; ///A simplified version of `pango_ft2_font_get_face` from PangoFT, which is not a public method. FT_Face pango_ft2_font_get_face(PangoFont* font) nothrow{ assert(font); if(auto face = font in faces) return *face; FcPattern* pattern = pango_fc_font_get_pattern(cast(PangoFcFont*)font); FT_Error err; char* filename; if(FcPatternGetString(pattern, FC_FILE, 0, &filename) != FcResultMatch){ //ERROR! } int id; if(FcPatternGetInteger(pattern, FC_INDEX, 0, &id) != FcResultMatch){ //ERROR! } FT_Face face; err = FT_New_Face(ftLib, filename, id, &face); if(err){ //ERROR! } double size; if(FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &size) != FcResultMatch){ //ERROR! } err = FT_Set_Char_Size( face, cast(FT_F26Dot6)(size * (1<<6)), cast(FT_F26Dot6)(size * (1<<6)), 0, 0, ); if(err){ //ERROR! } faces[font] = face; return face; } struct PangoCustomRenderer{ PangoRenderer parentInstance; //custom class instance data goes here } struct PangoCustomRendererClass{ PangoRendererClass parentClass; } mixin(G_DEFINE_TYPE("PangoCustomRenderer", "pango_Custom_renderer", "PANGO_TYPE_RENDERER")); extern(C) nothrow{ void pango_Custom_renderer_init(PangoCustomRenderer* self){ //per-instance initialisation } void pango_Custom_renderer_class_init(PangoCustomRendererClass* self){ auto rendererClass = &self.parentClass; //also written as `cast(PangoRendererClass*)` rendererClass.drawGlyph = &pangoCustomRendererDrawGlyph; //override drawGlyph } struct DrawState{ FT_Vector pos; } ///Move the pen position int moveTo(const(FT_Vector)* to, void* user) => 0; ///Draw a line int lineTo(const(FT_Vector)* to, void* user) => 0; ///Draw a quadratic bézier int conicTo(const(FT_Vector)* ctrl, const(FT_Vector)* to, void* user) => 0; ///Draw a cubic bézier int cubicTo(const(FT_Vector)* ctrl1, const(FT_Vector)* ctrl2, const(FT_Vector)* to, void* user) => 0; void pangoCustomRendererDrawGlyph(PangoRenderer* pangoRenderer, PangoFont* font, PangoGlyph glyph, double x, double y){ if(FT_Face face = pango_ft2_font_get_face(font)){ FT_Load_Glyph(face, glyph, 0); //NOTE: glyph outline direction may be reversed immutable fns = FT_Outline_Funcs( &moveTo, &lineTo, &conicTo, &cubicTo, 0, 0, ); auto state = DrawState(); FT_Outline_Decompose(&face.glyph.outline, &fns, &state); } } } //using the class: auto pangoRenderer = cast(PangoRenderer*)g_object_new(pango_Custom_renderer_get_type(), null); //... pango_renderer_draw_layout(pangoRenderer, layout, 0,0); ```Also does this project have proper text layout support? I noticed there’s a dependency on FreeType; but FreeType doesn’t do layout, only rendering. I’m about to release [BindBC-Pango](https://github.com/BindBC/bindbc-pango) if you need a text layout engine. They’re absolutely imperative for acceptable internationalisation support.That is true, Fluid can only do the basic left-to-right text layout right now. To be frank, it isn't even able to center or right align text. So far I've opted for Freetype, because I'm more familiar with APIs of its kind and I wanted to save some of my time, but it might be about time I tried Pango. Thank you for your work on the bindings, I'll check them out!
Oct 25
On Friday, 25 October 2024 at 12:21:14 UTC, IchorDev wrote:On Friday, 25 October 2024 at 09:44:18 UTC, cookiewitch wrote:Looking through Pango's documentation and code, [integrating it with Fluid might be tricky](https://git.samerion.com/Samerion/Fluid/issues/197). This topic is also complex and there are things I don't understand about Pango's approach that I can't find an explanation of. This is probably something I'll have to spend a lot of time on to get a proper grasp of. I'd really appreciate it if there were some other, more comprehensive learning resources. Do you know any?On Thursday, 24 October 2024 at 12:02:00 UTC, IchorDev wrote:I will check in again once that's done. :)Anyway, at this stage, how difficult is it to make a custom Fluid backend? (e.g. SDL2 for input or a different renderer)The backend API still isn't very polished. It's not difficult, but it takes some time to prepare. I also regret choosing a Raylib-like API rather than an event-based on. I want to change that in a later update, probably 0.8.0 or 0.9.0.No problem! Only thing holding me from putting it on dub is that its dependency BindBC-GLib has no README yet. BindBC-Pango comes with an example that should adequately demonstrate the basics of how to make use of it with FreeType's renderer. If you want to make your own renderer, I've translated enough of GObject's macros into string mixin generators that you can sub-class Pango's base render class like you would in C without any extra hassle [...]Also does this project have proper text layout support? I noticed there’s a dependency on FreeType; but FreeType doesn’t do layout, only rendering. I’m about to release [BindBC-Pango](https://github.com/BindBC/bindbc-pango) if you need a text layout engine. They’re absolutely imperative for acceptable internationalisation support.That is true, Fluid can only do the basic left-to-right text layout right now. To be frank, it isn't even able to center or right align text. So far I've opted for Freetype, because I'm more familiar with APIs of its kind and I wanted to save some of my time, but it might be about time I tried Pango. Thank you for your work on the bindings, I'll check them out!
Oct 25
On Friday, 25 October 2024 at 12:49:36 UTC, cookiewitch wrote:Looking through Pango's documentation and code, [integrating it with Fluid might be tricky](https://git.samerion.com/Samerion/Fluid/issues/197). This topic is also complex and there are things I don't understand about Pango's approach that I can't find an explanation of. This is probably something I'll have to spend a lot of time on to get a proper grasp of. I'd really appreciate it if there were some other, more comprehensive learning resources. Do you know any?Sorry for my late reply! Anyway, here we go… I was able to figure out how to use it for *static* text pretty easily from just the official docs. I found it best to look at what you want at the end (e.g. rendering the text), find how you do that, and then work backwards from there. This might not help you that much, but here's a step-by-step outline on getting started using Pango, with links to the relevant documentation, which provide a decent amount of insight into what each class is/does. This boils down to [about 20 lines of code from my example](https://github.com/BindBC/bindbc-pango/blob/master/example/source/app.d#L54). - First you need a [`PangoFontMap`](https://docs.gtk.org/Pango/class.FontMap.html). You can, for instance, get a `PangoFontMap` implemented using FreeType with `pango_ft2_font_map_new`. - Then, create a [`PangoContext`](https://docs.gtk.org/Pango/class.Context.html) from the `PangoFontMap`. - Create a [`PangoFontDescription`](https://docs.gtk.org/Pango/struct.F ntDescription.html) (e.g. using `pango_font_description_new`) and use whichever setter functions on it to provide info about what font you want it to use, how large it should be, et cetera. Pango automatically uses fallback fonts when needed, which is why you don't *just* give it which font to use. This way, when users write glyphs that are not included in your preferred font, the overall appearance of the text can remain more-or-less consistent. In my example I only set the size of a `PangoFontDescription`, so Pango will basically default to using the system's preferred default fonts. - Set the `PangoContext`'s `PangoFontDescription` to the one you just created/populated. - Create a [`PangoLayout`](https://docs.gtk.org/Pango/class.Layout.html) from the `PangoContext`. This layout object handles a lot of things for you that you can mostly otherwise do yourself with components of the Pango library like . - You can set the layout's contents with: - an unformatted string: [`pango_layout_set_text`](https://docs.gtk.org/Pango/method.Layout.set_text.html) - a string formatted with [Pango Markup](https://docs.gtk.org/Pango/pango_markup.html): [`pango_layout_set_markup`](https://docs.gtk.org/Pango/method.Layout.set_markup.html) - a string specially-formatted by your own code: `pango_layout_set_text` and [`pango_layout_set_attributes`](https://docs.gtk.org/Pango/method.Layout.set_attributes.html) From there, you'd mostly be interacting with the layout. A few things to note: - Pango uses reference counting for basically everything, so make sure to read up on how you're supposed to `unref` objects you've created so that they get deallocated. Often this is done with `g_object_unref` instead of a function from Pango. - The API & API reference use the term 'character' confusingly. Mostly it seems to refer to code-points, but occasionally I believe it is used to refer to individual bytes (i.e. code-units). I really don't think the stock `PangoLayout` implementation provides a way to make using ropes work in a fast manner without just capitulating and using strings. However, you could re-implement **most** (but not all) of `PangoLayout`'s layout functionality from functions that Pango exposes. [This page should give you an idea](https://docs.gtk.org/Pango/pango_rendering.html). Pango is far from perfect, and in some ways using it is an inherent compromise between what you want, and what's possible using libraries out there today. Even TextKit is [not without its problems](https://atadistance.net/2021/07/13/apple-text-layout-architecture-evolution-textkit-reboot/). There is one way around all of this, which is building a new text layout engine… Some consideration should be given to where to start. For instance, one could build up from HarfBuzz. However, HarfBuzz is another GLib-based FSF C library, just like Pango, so perhaps this would just shift the compromises further down the line. Say we want *no* compromises; then we have to do everything 100% in D. Certainly neither of these options are trivial, and it would be a fool's errand to embark upon them alone. Having a full D text layout engine is a pet dream of mine of course, so if you're interested in contributing to a project like that then I might be able to dedicate some of my spare time to it.
Oct 31
On Thursday, 31 October 2024 at 13:08:55 UTC, IchorDev wrote:On Friday, 25 October 2024 at 12:49:36 UTC, cookiewitch wrote:Thank you for dedicating your time to this, and for the very elaborate response! Reimplementing PangoLayout does sound like an option, but as far as I've seen, Pango operates on strings all the way through. I suppose it is possible to assemble parts of the rope into a string on the stack, and only operate on a single part at once, but I don't think this is going to be very bug-proof. Alternatively, Fluid's text engine does distinguish between static and dynamic text with an "edit mode" flag, so it could be possible to apply Pango on stringified static text, but that's never going to be enough. Oh, and also, since Pango is LGPLv2 licensed, I think a port of `PangoLayout` could run into licensing problems the way D programs are usually built \[with DUB\].[...] I'd really appreciate it if there were some other, more comprehensive learning resources. Do you know any?Sorry for my late reply! Anyway, here we go… [...] Some consideration should be given to where to start. For instance, one could build up from HarfBuzz. However, HarfBuzz is another GLib-based FSF C library, just like Pango, so perhaps this would just shift the compromises further down the line. Say we want *no* compromises; then we have to do everything 100% in D. Certainly neither of these options are trivial, and it would be a fool's errand to embark upon them alone.Having a full D text layout engine is a pet dream of mine of course, so if you're interested in contributing to a project like that then I might be able to dedicate some of my spare time to it.I've been thinking about this last week and I'm under the impression this is what is going to happen anyway. For what it's worth, I'm currently working on another large PR which upscales Fluid's text engine, splitting it into a separate `fluid.text` package and optimizing it on the way through. It is mostly standalone, so if you find it appropriate, I could create a new Git & DUB repository for it once I'm done. I would like to have your input on it.
Nov 01
On Friday, 1 November 2024 at 12:14:25 UTC, cookiewitch wrote:On Thursday, 31 October 2024 at 13:08:55 UTC, IchorDev wrote:Compromises!Sorry for my late reply! Anyway, here we go… [...] Some consideration should be given to where to start. For instance, one could build up from HarfBuzz. However, HarfBuzz is another GLib-based FSF C library, just like Pango, so perhaps this would just shift the compromises further down the line. Say we want *no* compromises; then we have to do everything 100% in D. Certainly neither of these options are trivial, and it would be a fool's errand to embark upon them alone.Thank you for dedicating your time to this, and for the very elaborate response! Reimplementing PangoLayout does sound like an option, but as far as I've seen, Pango operates on strings all the way through. I suppose it is possible to assemble parts of the rope into a string on the stack, and only operate on a single part at once, but I don't think this is going to be very bug-proof. Alternatively, Fluid's text engine does distinguish between static and dynamic text with an "edit mode" flag, so it could be possible to apply Pango on stringified static text, but that's never going to be enough.Oh, and also, since Pango is LGPLv2 licensed, I think a port of `PangoLayout` could run into licensing problems the way D programs are usually built \[with DUB\].If the modified source is available then I don't think that's a problem?Sure, that sounds like a great idea! Here are my thoughts about what could be changed based on how `fluid.text` is currently set up: - `StyledText` *only* stores its strings as ropes, making it less ideal for static text, and not very flexible (e.g. can't use a custom type with fast insertion). Ideally there'd be a layout option for static text that uses finite forward ranges of `const(char)` internally for static text, and also one that uses a mutable string templated interface internally for user-editable text. - `StyledText` only performs rendering to a texture, preventing it from working with renderers that use modern text rendering techniques, and not giving the user any control over the rendering pipeline. Any kind of rendering functionality should be separated out, and `StyledText` should provide a renderer-agnostic way to get all of the necessary information for rendering (e.g. each font glyph ID, its transformation, and style) as a forward range interface or similar. - Different methods of cutting off overflowing text should be provided, like placing ellipses at the end of the visible text. - You will probably want to use FontConfig (see: BindBC-FontConfig) by default (but ideally with an option for a custom implementation) to figure out what fonts each system prefers as fallbacks. And same story with using FreeType by default to load & process font data. - `TextStyleSlice` uses a palette right now, which is pointlessly limited to 256 different items. It might be worth attempting to use a `SumType` containing each individual styling option, since then the defaults don't have to be re-specified with 1 exception every time someone uses **bold** or *italic*. Otherwise, `TextStyleSlice` should probably use a `size_t` for style indices. Also, things like colour that do not affect text layout should not be part of the `Style` used when making layouts in the first place. A user's renderer can worry about that. - The `Typeface` interface expects implementations to have way too much state. - Everything that goes into text-shaping should be accessible in isolation so that people who need to perform more fine-grained tasks can use them. For example, the bi-directional algorithm. - The styling needs to be known when generating a layout, and it might be desirable for the layout to be lazily re-computed. So all in all, a bit like this example: ```d alias LayoutStyle = SumType!( FontFace, Padding, TextDirection, Alignment, Justify, /+et cetera+/ ); struct LayoutStyleRange{ size_t from, to; Style style; } struct Caret{ Vec2!float pos; float height; } mixin template SharedTextLayoutStuff(Text){ Text text; RedBlackTree!(LayoutStyleRange, ".from", true) styleRanges; //styles are sorted by `.from` for efficiency uint textSerialNumber; //to see if text was updated ///calculates the layout. Called when `textSerialNumber` is no longer current by anything that uses the layout (e.g. getRenderData) void calculate(); ///gets data used for rendering the glyphs SomeForwardRange!GlyphRenderData getRenderData(); //more functions... ///the position & height of a caret at a certain string index Caret getCaret(size_t ind) const; ///the string index of a caret at a certain visual position size_t getIndex(Vec2!float pos) const; } ///rarely changes, uses string-like forward ranges struct TextLayout(Text) if(IsSomeFiniteCharRange!InternalText){ mixin SharedTextLayoutStuff!(InternalText); //static-specific stuff } ///changes with random insertion and deletion, uses an abstract interface struct DynamicTextLayout(Text) if( isDynamicLayoutText!Text //`Text` needs at least: //a forward range interface (empty, popFront, front) //opIndex //opIndexAssign with overloads for slicing //insertion & deletion //a number that is incremented every time it is updated ){ mixin SharedTextLayoutStuff!(Text); //dynamic-specific stuff } ```Having a full D text layout engine is a pet dream of mine of course, so if you're interested in contributing to a project like that then I might be able to dedicate some of my spare time to it.I've been thinking about this last week and I'm under the impression this is what is going to happen anyway. For what it's worth, I'm currently working on another large PR which upscales Fluid's text engine, splitting it into a separate `fluid.text` package and optimizing it on the way through. It is mostly standalone, so if you find it appropriate, I could create a new Git & DUB repository for it once I'm done. I would like to have your input on it.
Nov 02
On Saturday, 2 November 2024 at 17:33:19 UTC, IchorDev wrote:[...] Sure, that sounds like a great idea! Here are my thoughts about what could be changed based on how `fluid.text` is currently set up: [...] - `TextStyleSlice` uses a palette right now, which is pointlessly limited to 256 different items. It might be worth attempting to use a `SumType` containing each individual styling option, since then the defaults don't have to be re-specified with 1 exception every time someone uses **bold** or *italic*. Otherwise, `TextStyleSlice` should probably use a `size_t` for style indices. Also, things like colour that do not affect text layout should not be part of the `Style` used when making layouts in the first place. A user's renderer can worry about that.Inline styling of `Text` was just a dirty hack to have syntax highlighting working instead of offering a proper, full solution, so it's far from being the final design. Some of my concerns: * How would you approach coloring text from the user's perspective? * What about handling text mixed with other content (like images, icons, UI components), something akin to CSS `display: inline-block`?- The `Typeface` interface expects implementations to have way too much state.`Typeface` is something I'm not very happy about either.So all in all, a bit like this example: [...]Looks good to me. Having a separate structure for static and dynamic text is reasonable, and as you've seen Fluid currently only distinguishes between this at runtime. I'd opt for a regular struct instead of mixin, though. I think it's worth noting that I also care about maintaining performance for large files (100K–10MB), which is what I'm attempting to fix on the [text-input-ranges](https://git.samerion.com/Samerion/Fluid/src/branc /text-input-ranges) branch, but I'm still struggling. Fluid will only draw the text that is visible on the screen (which is handled by `CompositeTexture`). I've introduced a `TextRulerCache` structure which maps characters (by index) to position in text in a way that also preserves layout data, so a piece of text can be edited without recalculating the layout for the rest of it. I'm not very proud of it, it's apparently very fragile, so I'm curious what is your idea of handling this, too.
Nov 03