cosmic-applets icon indicating copy to clipboard operation
cosmic-applets copied to clipboard

[Bug] Fix COSMIC Time Applet Size to Prevent Applet Shifting in Panel

Open iamkartiknayak opened this issue 9 months ago • 10 comments

Issue/Description:
Currently, the COSMIC Time applet dynamically resizes when seconds are enabled, causing other applets in the panel to shift. This results in a distracting and inconsistent layout.

Version:

cosmic-applets:
  Installed: 0.1.0~1741529755~24.04~f53e3bd

Steps to Reproduce:

  • Add the COSMIC Time applet to the panel.
  • Enable seconds in the time format.
  • Observe how the panel's applets shift due to the changing width of the time display.

Proposed Solution:

  • Use variable fixed width for time applet when seconds are toggled.
  • When seconds are enabled it'll use more width but the width won't change when number changes
  • When seconds are disabled it'll use less width & width won't change when number changes

Expected Behavior:
The COSMIC Time applet should have a fixed width that accommodates both the time format with and without seconds, ensuring that other panel elements remain stable.

iamkartiknayak avatar Mar 12 '25 10:03 iamkartiknayak

This recent commit implementing widths for applets seems to have fixed this issue: https://github.com/pop-os/cosmic-applets/commit/61d1d1b91d8462bc169e70ff920b5f6850b0d85d

cappsyco avatar Mar 17 '25 17:03 cappsyco

If I'm not wrong they're for applet pop-ups

iamkartiknayak avatar Mar 17 '25 17:03 iamkartiknayak

Ah apologies, you're correct.

Are you still seeing the issue? I have tested using default fonts in various positions among the other applets and not observed any shifting.

cappsyco avatar Mar 17 '25 18:03 cappsyco

I also do not observe any shifting

CarsonBurke avatar Mar 17 '25 20:03 CarsonBurke

It only happens if font doesn't have tabular numbers (e.g. Poppins).
This can be solved if each digit has fixed container size & digit itself is centered inside that container. This would allow most of the fonts to render without changing applet size when variable font such as 7 or 8 occurs.

.digit-container {
            display: inline-block;
            width: 0.6em;
            text-align: center;
        }

This was attainable in CSS not sure how it works in libcosmic or cosmic-text

iamkartiknayak avatar Mar 18 '25 04:03 iamkartiknayak

Do you know of a few fonts to test this with?

I'm aesthetically challenged. I clicked through 30 fonts without finding one to replicate. 😅

joshuamegnauth54 avatar Apr 03 '25 05:04 joshuamegnauth54

I tried it on Poppins but many pre-installed non mono fonts also does it

iamkartiknayak avatar Apr 03 '25 05:04 iamkartiknayak

Yeah I managed to replicate by installing poppins and setting that as the main font. I was unable to find a clean way to resolve the issue.

cappsyco avatar Apr 03 '25 09:04 cappsyco

Alright. Thanks for the confirmation from both of you. I have an idea for a solution to this issue, but I may have to mess with it after the weekend.

joshuamegnauth54 avatar Apr 04 '25 06:04 joshuamegnauth54

The way I fixed this in my applet was to first measure the "worst case/widest string that could be shown". It seems other toolkits have measurement functions, like QT:

QFontMetrics metrics(font);
int width = metrics.horizontalAdvance("Hello");

For my purpose I implemented below, not sure if there's a better way:

    fn measure_text_width(&mut self, text: &str, attrs: &Attrs) -> Option<f32> {
        let font_size = self.label_font_size();

        let metrics = Metrics::new(font_size.into(), font_size.into());
        // Create a buffer to shape the text
        let mut buffer = Buffer::new(&mut self.font_system, metrics);
        buffer.set_text(&mut self.font_system, text, attrs, Shaping::Advanced);

        // Get the width of the first layout line
        buffer
            .lines
            .first()
            .and_then(|line| line.layout_opt())
            .and_then(|layouts| layouts.first().map(|layout| layout.w.ceil()))
    }

Then for example for seconds measure widest possibility, such as ":88", then create a widget with that fixed width and Left/Center/Right justify as desired.

widget::text(seconds)
                .size(size)
                .width(w)
                .wrapping(iced::core::text::Wrapping::None)
                .align_x(Horizontal::Left)

Thus avoiding forcing a specific font. It does require listening to font configuration changes and redo the measurement if the user changes font settings. I suppose it could also be used on individual digits to emulate tabular digits with a text widget per digit, as suggested.

Hyperchaotic avatar Aug 07 '25 21:08 Hyperchaotic