From 5392d9d5aea773320f541ea1fbf9742340c657e5 Mon Sep 17 00:00:00 2001 From: Lionel DARNIS Date: Wed, 19 Aug 2026 21:18:31 +0200 Subject: [PATCH] segmented_button: honour WindowControlsPosition for the tab close button The close button of closable tabs was pinned to the trailing edge, so enabling macOS-style window controls left the window buttons on the left and the tab crosses on the right. Read crate::config::window_controls_position() and, when Start, place the close button before the tab contents and shift them accordingly. The hit-test, the text width and the drawn icon all derive from the same position so they stay in sync. Co-Authored-By: Claude Opus 5 (1M context) --- src/widget/segmented_button/widget.rs | 56 ++++++++++++++++++++------- 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/src/widget/segmented_button/widget.rs b/src/widget/segmented_button/widget.rs index 61808fbe..6b2633fb 100644 --- a/src/widget/segmented_button/widget.rs +++ b/src/widget/segmented_button/widget.rs @@ -9,7 +9,7 @@ use crate::widget::menu::{ self, CloseCondition, ItemHeight, ItemWidth, MenuBarState, PathHighlight, menu_roots_children, menu_roots_diff, }; -use crate::widget::{Icon, icon}; +use crate::widget::{Icon, WindowControlsPosition, icon}; use crate::{Element, Renderer}; use derive_setters::Setters; use iced::clipboard::dnd::{ @@ -1608,8 +1608,11 @@ where } } - let close_button_bounds = - close_bounds(bounds, f32::from(self.close_icon.size)); + let close_button_bounds = close_bounds( + bounds, + f32::from(self.close_icon.size), + crate::config::window_controls_position(), + ); let over_close_button = self.model.items[key].closable && cursor_position.is_over(close_button_bounds); @@ -2420,6 +2423,25 @@ where } } + // Whether to show the close button on this tab. + let show_close_button = + (key_is_active || !self.show_close_icon_on_hover || key_is_hovered) + && self.model.is_closable(key); + + // Width of the icon used by the close button, which we will subtract from the text bounds. + let close_icon_width = if show_close_button { + f32::from(self.close_icon.size) + } else { + 0.0 + }; + + // With macOS-style controls the close button precedes the contents, so + // shift them right to make room for it. + let close_position = crate::config::window_controls_position(); + if show_close_button && close_position == WindowControlsPosition::Start { + bounds.x += close_icon_width + f32::from(self.button_spacing); + } + // Draw the image beside the text. if let Some(icon) = self.model.icon(key) { let mut image_bounds = bounds; @@ -2477,21 +2499,17 @@ where } } - // Whether to show the close button on this tab. - let show_close_button = - (key_is_active || !self.show_close_icon_on_hover || key_is_hovered) - && self.model.is_closable(key); - - // Width of the icon used by the close button, which we will subtract from the text bounds. - let close_icon_width = if show_close_button { - f32::from(self.close_icon.size) + // Room reserved after the contents: only needed when the close button + // trails them, since a leading one is already counted in `bounds.x`. + let trailing_close_width = if close_position == WindowControlsPosition::End { + close_icon_width } else { 0.0 }; bounds.width = original_bounds.width - (bounds.x - original_bounds.x) - - close_icon_width + - trailing_close_width - f32::from(self.button_padding[2]); bounds.y = center_y; @@ -2517,7 +2535,8 @@ where // Draw a close button if set. if show_close_button { - let close_button_bounds = close_bounds(original_bounds, close_icon_width); + let close_button_bounds = + close_bounds(original_bounds, close_icon_width, close_position); draw_icon::( renderer, @@ -3070,9 +3089,16 @@ impl From for widget::Id { } /// Calculates the bounds of the close button within the area of an item. -fn close_bounds(area: Rectangle, icon_size: f32) -> Rectangle { +fn close_bounds( + area: Rectangle, + icon_size: f32, + position: WindowControlsPosition, +) -> Rectangle { Rectangle { - x: area.x + area.width - icon_size - 8.0, + x: match position { + WindowControlsPosition::Start => area.x + 8.0, + WindowControlsPosition::End => area.x + area.width - icon_size - 8.0, + }, y: area.center_y() - (icon_size / 2.0), width: icon_size, height: icon_size,