glyphon icon indicating copy to clipboard operation
glyphon copied to clipboard

Center Text

Open DasLixou opened this issue 1 year ago • 20 comments

How would I center the text in for example the middle of my window?

I currently do

let x = self.size.width / 2;
        let y = self.size.height / 2;

        self.text_renderer
            .prepare(
                &self.device,
                &self.queue,
                &mut self.font_system,
                &mut self.atlas,
                Resolution {
                    width: self.size.width,
                    height: self.size.height,
                },
                [TextArea {
                    buffer: &self.buffer,
                    left: x as f32,
                    top: y as f32,
                    scale: 1.0,
                    bounds: TextBounds {
                        left: x as i32,
                        top: y as i32,
                        right: self.size.width as i32,
                        bottom: self.size.height as i32,
                    },
                    default_color: glyphon::Color::rgb(0, 0, 0),
                }],
                &mut self.cache,
            )
            .unwrap();

But that does it with a offset. Now i would need something like the worlds famous translate(-50%) css trick... But I can't seem to find any API to get the size of the text. Also the TextBounds API is kinda weird because provides extra left and top values which are absolute so I need to pass the left and top in there as well...

DasLixou avatar Oct 04 '23 15:10 DasLixou

The plan was to let cosmic-text handle all alignment, e.g., through https://docs.rs/cosmic-text/latest/cosmic_text/struct.BufferLine.html#method.set_align or any other APIs they add upstream. So the idea is that you could let the buffer be sized to the full width of the window and center it horizontally that way.

The extra left/top are useful if you want to render a region of the text area, so in those cases the left/top might not be the same (area left/top are about shifting, while bounds left/top are about clipping/culling). We might be able to make this a little easier though.

grovesNL avatar Oct 04 '23 15:10 grovesNL

@grovesNL yeah from my perspective a more intuitive API would be to handle the left and top completely from the "align" sector and let the bounds be relative to the text and also provide a const Bounds::FULL

DasLixou avatar Oct 04 '23 16:10 DasLixou

@grovesNL Is there already a way to use the alignment or is it like from a PR?

DasLixou avatar Oct 04 '23 16:10 DasLixou

Do I see this correctly? https://docs.rs/cosmic-text/latest/cosmic_text/struct.BufferLine.html#method.set_align only provides basic left, middle, right alignment? No top, middle, down and no translating?

DasLixou avatar Oct 04 '23 16:10 DasLixou

Is there already a way to use the alignment or is it like from a PR?

I think you should already be able to call this function on your Buffers.

only provides basic left, middle, right alignment? No top, middle, down and no translating?

Vertical alignment was requested in https://github.com/pop-os/cosmic-text/issues/79 but hasn't been implemented yet as far as I know. I guess you can handle middle by approximating it if you have a maximum number of lines/can approximate the line heights. Translating is handled by the left/top in the text area.

grovesNL avatar Oct 04 '23 16:10 grovesNL

But then I would at least need an api to get the used size of the buffer And that shouldn't be that easy because it gets processed in the prepare function (because of wrapping etc.) So I would need to get a result of prepare in prepare

DasLixou avatar Oct 04 '23 16:10 DasLixou

Yeah it's not very convenient right now, you could do something as described in https://github.com/pop-os/cosmic-text/issues/70 to get the visible lines

grovesNL avatar Oct 04 '23 16:10 grovesNL

So in my dreams 💅 a more intuitive API would look like this:

self.text_renderer
    .prepare(
        &self.device,
        &self.queue,
        &mut self.font_system,
        &mut self.atlas,
        Resolution {
            width: self.size.width,
            height: self.size.height,
        },
        // note that this is now a slice, which enables us to store the info in a vec and just give a slice to it
        &[BufferAttachment {
            buffer: &self.buffer,
            horizontal_offset: x as f32,
            horizontal_alignment: Alignment::Center,
            horizontal_bounds: Bounds::Unbound, // replaces TextBounds
            vertical_offset: y as f32,
            vertical_alignment: Alignment::Center,
            vertical_bounds: Bounds::Unbound, // replaces TextBounds
            base_color: glyphon::Color::rgb(0, 0, 0), // base_color sounds better than default_color i think
            ..Default::default() // hide scale, or scissor & rotation when they're added
        }],
        &mut self.cache,
    )
    .unwrap();

The associated enums would look like this:

enum Alignment {
    Start,
    Center,
    End,
}
enum Bounds {
    Fixed(/* wait what type?..*/),
    /// The Text will go on without any limit
    Unbound,
    // maybe we can also have an option to automatically stop at resolution end?
}

Thoughts?

DasLixou avatar Oct 05 '23 14:10 DasLixou

  • I think buffer attachment sounds a bit too vague
  • horizontal_alignment and vertical_alignment would be set on buffer itself, so we don't control that in glyphon and it can't be specified at this level
  • I don't think I'd recommend using something like Bounds::Unbound because you almost always want to clip to some region (at least the window border) to avoid sending extra text to the GPU
  • base_color sounds like we're using it to mix colors but it's more like a default vs. custom color for part of the text

grovesNL avatar Oct 06 '23 01:10 grovesNL

  • I think buffer attachment sounds a bit too vague

    • horizontal_alignment and vertical_alignment would be set on buffer itself, so we don't control that in glyphon and it can't be specified at this level

    • I don't think I'd recommend using something like Bounds::Unbound because you almost always want to clip to some region (at least the window border) to avoid sending extra text to the GPU

    • base_color sounds like we're using it to mix colors but it's more like a default vs. custom color for part of the text

  • I just was confused with all the Text... things so I named it that way, but when you think TextArea is more suitable, it's fine.
  • So that would be something that happens at cosmic_text?
  • Wait did I understand TextBounds wrong? I thought its at which point it does a linebreak, like a box in which the text is laid out. Bounds::Unbound should say: 'I never need a linebreak, just ignore when you are outside of the window'
  • Oh yeah, base_color really is a bad choice with this in mind 😅

DasLixou avatar Oct 06 '23 13:10 DasLixou

So that would be something that happens at cosmic_text?

Exactly, most text styling, alignment, etc. all happen in cosmic-text itself instead of glyphon

Wait did I understand TextBounds wrong? I thought its at which point it does a linebreak, like a box in which the text is laid out.

Text bounds is about clipping/culling to a visible area, the size of the buffer (the one you give to cosmic-text when you create a buffer) controls where line breaks happen

grovesNL avatar Oct 10 '23 16:10 grovesNL

Wait... so when that's cosmic_texts stuff.. can we then not have the sizes of the text on render and use that to center it?

DasLixou avatar Oct 10 '23 19:10 DasLixou

At least for vertically centering you'd have to query the height based on the visible lines which is https://github.com/pop-os/cosmic-text/issues/70

grovesNL avatar Oct 10 '23 19:10 grovesNL

Why is this closed?

DasLixou avatar Jan 15 '24 18:01 DasLixou

Sorry we can reopen it if there's anything remaining - I thought there wasn't anything else required from glyphon's side to center text. Is there anything missing?

grovesNL avatar Jan 15 '24 18:01 grovesNL

Well it's nothing on glyphons side but still it's not possible yet... so i think as a sort of tracking issue this will do it

DasLixou avatar Jan 15 '24 19:01 DasLixou

Has someone tried implement cursor functionality with on top of cosmic-text/glyphon? Any recommendations what approach to use (cosmic-text alignment probably)?

madmaxio avatar Mar 15 '24 10:03 madmaxio

Has someone tried implement cursor functionality with on top of cosmic-text/glyphon? Any recommendations what approach to use (cosmic-text alignment probably)?

In the GUI lib I'm creating, I'm using the align inside of the text properties for horizontal alignment, and my own custom method for vertical alignment:

pub fn layout_text_bounds(
    bounds_size: Size,
    unclipped_text_size: Size,
    padding: Padding,
    min_clipped_size: Size,
    vertical_align: Align,
    font_size: f32,
) -> Rect {
    if unclipped_text_size.is_empty() {
        return Rect::default();
    }

    let content_rect = crate::layout::layout_inner_rect_with_min_size(
        padding,
        Rect::from_size(bounds_size),
        min_clipped_size,
    );

    // We need to vertically align the text ourselves as rootvg/glyphon does not do this.
    let text_bounds_y = match vertical_align {
        Align::Start => content_rect.min_y(),
        Align::Center => content_rect.min_y() + ((content_rect.height() - font_size) / 2.0) + 1.0,
        Align::End => content_rect.max_y() - unclipped_text_size.height,
    };

    Rect::new(
        Point::new(content_rect.min_x(), text_bounds_y),
        Size::new(content_rect.width(), unclipped_text_size.height),
    )
}

BillyDM avatar May 28 '24 22:05 BillyDM

Has someone tried implement cursor functionality with on top of cosmic-text/glyphon? Any recommendations what approach to use (cosmic-text alignment probably)?

In the GUI lib I'm creating, I'm using the align inside of the text properties for horizontal alignment, and my own custom method for vertical alignment:

pub fn layout_text_bounds(
    bounds_size: Size,
    unclipped_text_size: Size,
    padding: Padding,
    min_clipped_size: Size,
    vertical_align: Align,
    font_size: f32,
) -> Rect {
    if unclipped_text_size.is_empty() {
        return Rect::default();
    }

    let content_rect = crate::layout::layout_inner_rect_with_min_size(
        padding,
        Rect::from_size(bounds_size),
        min_clipped_size,
    );

    // We need to vertically align the text ourselves as rootvg/glyphon does not do this.
    let text_bounds_y = match vertical_align {
        Align::Start => content_rect.min_y(),
        Align::Center => content_rect.min_y() + ((content_rect.height() - font_size) / 2.0) + 1.0,
        Align::End => content_rect.max_y() - unclipped_text_size.height,
    };

    Rect::new(
        Point::new(content_rect.min_x(), text_bounds_y),
        Size::new(content_rect.width(), unclipped_text_size.height),
    )
}

Interesting, is it open source?

madmaxio avatar Jun 11 '24 17:06 madmaxio

Interesting, is it open source?

Yes, it is now. https://github.com/MeadowlarkDAW/Yarrow

BillyDM avatar Jun 12 '24 15:06 BillyDM