Aşama 1: Layout yönetim UI — yeniden adlandırma, silme, context menüsü
- Layout sekme sağ-tıklamasında context menüsü (Yeniden Adlandır / Sil) - Inline rename: sekme metin-giriş alanına dönüşür, Enter ile commit, ✕ ile iptal - LayoutDelete: layout ve sahip olduğu tüm entity'leri kaldırır - LayoutRename: Layout nesnesinin adını yerinde günceller - LayoutCreate çakışma koruması: mevcut isimler arasında benzersiz ad bulur - Escape tuşu açık rename/context menüsünü kapatır Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
527cce8ff0
commit
9b14719ec5
5 changed files with 341 additions and 36 deletions
|
|
@ -57,6 +57,10 @@ pub(super) struct H7CAD {
|
||||||
clipboard: Vec<acadrust::EntityType>,
|
clipboard: Vec<acadrust::EntityType>,
|
||||||
/// Centroid of the clipboard entities (XZ plane, Y-up).
|
/// Centroid of the clipboard entities (XZ plane, Y-up).
|
||||||
clipboard_centroid: glam::Vec3,
|
clipboard_centroid: glam::Vec3,
|
||||||
|
/// Which layout tab has its context menu open (None = closed).
|
||||||
|
layout_context_menu: Option<String>,
|
||||||
|
/// Inline rename state: (original_name, current_edit_value).
|
||||||
|
layout_rename_state: Option<(String, String)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
@ -210,6 +214,20 @@ pub enum Message {
|
||||||
LayoutSwitch(String),
|
LayoutSwitch(String),
|
||||||
/// Create a new paper space layout.
|
/// Create a new paper space layout.
|
||||||
LayoutCreate,
|
LayoutCreate,
|
||||||
|
/// Delete the named paper space layout (Model cannot be deleted).
|
||||||
|
LayoutDelete(String),
|
||||||
|
/// Begin inline rename for the given layout tab.
|
||||||
|
LayoutRenameStart(String),
|
||||||
|
/// Live-update the rename text input buffer.
|
||||||
|
LayoutRenameEdit(String),
|
||||||
|
/// Commit the rename (Enter pressed in the text input).
|
||||||
|
LayoutRenameCommit,
|
||||||
|
/// Cancel an in-progress rename (Escape).
|
||||||
|
LayoutRenameCancel,
|
||||||
|
/// Open the right-click context menu for the given layout tab.
|
||||||
|
LayoutContextMenu(String),
|
||||||
|
/// Close the layout context menu.
|
||||||
|
LayoutContextMenuClose,
|
||||||
/// A window was closed by the OS (e.g. the user clicked the title-bar ✕).
|
/// A window was closed by the OS (e.g. the user clicked the title-bar ✕).
|
||||||
OsWindowClosed(window::Id),
|
OsWindowClosed(window::Id),
|
||||||
/// No-op — used as a fallback when a TabEvent has no host mapping.
|
/// No-op — used as a fallback when a TabEvent has no host mapping.
|
||||||
|
|
@ -241,6 +259,8 @@ impl H7CAD {
|
||||||
main_window: None,
|
main_window: None,
|
||||||
clipboard: Vec::new(),
|
clipboard: Vec::new(),
|
||||||
clipboard_centroid: glam::Vec3::ZERO,
|
clipboard_centroid: glam::Vec3::ZERO,
|
||||||
|
layout_context_menu: None,
|
||||||
|
layout_rename_state: None,
|
||||||
};
|
};
|
||||||
app.sync_ribbon_layers();
|
app.sync_ribbon_layers();
|
||||||
app
|
app
|
||||||
|
|
|
||||||
|
|
@ -302,6 +302,10 @@ impl H7CAD {
|
||||||
}
|
}
|
||||||
|
|
||||||
Message::CommandEscape => {
|
Message::CommandEscape => {
|
||||||
|
// Cancel layout rename / context menu first, then fall through.
|
||||||
|
if self.layout_rename_state.take().is_some() || self.layout_context_menu.take().is_some() {
|
||||||
|
return Task::none();
|
||||||
|
}
|
||||||
let i = self.active_tab;
|
let i = self.active_tab;
|
||||||
if self.tabs[i].active_cmd.is_some() {
|
if self.tabs[i].active_cmd.is_some() {
|
||||||
let result = self.tabs[i].active_cmd.as_mut().map(|c| c.on_escape());
|
let result = self.tabs[i].active_cmd.as_mut().map(|c| c.on_escape());
|
||||||
|
|
@ -1427,6 +1431,9 @@ impl H7CAD {
|
||||||
Message::LayoutSwitch(name) => {
|
Message::LayoutSwitch(name) => {
|
||||||
let i = self.active_tab;
|
let i = self.active_tab;
|
||||||
let going_to_paper = name != "Model";
|
let going_to_paper = name != "Model";
|
||||||
|
// Cancel any pending rename/context-menu when switching layouts.
|
||||||
|
self.layout_rename_state = None;
|
||||||
|
self.layout_context_menu = None;
|
||||||
self.tabs[i].scene.current_layout = name;
|
self.tabs[i].scene.current_layout = name;
|
||||||
self.tabs[i].scene.deselect_all();
|
self.tabs[i].scene.deselect_all();
|
||||||
self.tabs[i].scene.fit_all();
|
self.tabs[i].scene.fit_all();
|
||||||
|
|
@ -1442,8 +1449,16 @@ impl H7CAD {
|
||||||
|
|
||||||
Message::LayoutCreate => {
|
Message::LayoutCreate => {
|
||||||
let i = self.active_tab;
|
let i = self.active_tab;
|
||||||
let count = self.tabs[i].scene.layout_names().len();
|
// Find a unique name (e.g. Layout2, Layout3, ...).
|
||||||
let new_name = format!("Layout{}", count);
|
let existing = self.tabs[i].scene.layout_names();
|
||||||
|
let mut idx = existing.len();
|
||||||
|
let new_name = loop {
|
||||||
|
let candidate = format!("Layout{}", idx);
|
||||||
|
if !existing.contains(&candidate) {
|
||||||
|
break candidate;
|
||||||
|
}
|
||||||
|
idx += 1;
|
||||||
|
};
|
||||||
self.push_undo_snapshot(i, "LAYOUT");
|
self.push_undo_snapshot(i, "LAYOUT");
|
||||||
match self.tabs[i].scene.document.add_layout(&new_name) {
|
match self.tabs[i].scene.document.add_layout(&new_name) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
|
|
@ -1463,6 +1478,87 @@ impl H7CAD {
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Message::LayoutDelete(name) => {
|
||||||
|
let i = self.active_tab;
|
||||||
|
self.push_undo_snapshot(i, "LAYOUT DEL");
|
||||||
|
if self.tabs[i].scene.delete_layout(&name) {
|
||||||
|
self.layout_context_menu = None;
|
||||||
|
self.layout_rename_state = None;
|
||||||
|
// If we fell back to Model space, update ribbon.
|
||||||
|
if self.tabs[i].scene.current_layout == "Model"
|
||||||
|
&& self.ribbon.active_is_layout()
|
||||||
|
{
|
||||||
|
self.ribbon.select(0);
|
||||||
|
}
|
||||||
|
self.command_line.push_output(&format!("Layout \"{name}\" silindi"));
|
||||||
|
self.tabs[i].dirty = true;
|
||||||
|
}
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
|
|
||||||
|
Message::LayoutRenameStart(name) => {
|
||||||
|
if name != "Model" {
|
||||||
|
self.layout_rename_state = Some((name.clone(), name));
|
||||||
|
self.layout_context_menu = None;
|
||||||
|
}
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
|
|
||||||
|
Message::LayoutRenameEdit(val) => {
|
||||||
|
if let Some((orig, _)) = &self.layout_rename_state {
|
||||||
|
let orig = orig.clone();
|
||||||
|
self.layout_rename_state = Some((orig, val));
|
||||||
|
}
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
|
|
||||||
|
Message::LayoutRenameCommit => {
|
||||||
|
if let Some((orig, new_name)) = self.layout_rename_state.take() {
|
||||||
|
let new_name = new_name.trim().to_string();
|
||||||
|
if !new_name.is_empty() && new_name != orig {
|
||||||
|
let i = self.active_tab;
|
||||||
|
let exists = self.tabs[i]
|
||||||
|
.scene
|
||||||
|
.layout_names()
|
||||||
|
.iter()
|
||||||
|
.any(|n| *n == new_name);
|
||||||
|
if exists {
|
||||||
|
self.command_line.push_error(&format!(
|
||||||
|
"\"{}\" adı zaten kullanımda",
|
||||||
|
new_name
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
self.push_undo_snapshot(i, "LAYOUT RENAME");
|
||||||
|
self.tabs[i].scene.rename_layout(&orig, &new_name);
|
||||||
|
if self.tabs[i].scene.current_layout == orig {
|
||||||
|
self.tabs[i].scene.current_layout = new_name.clone();
|
||||||
|
}
|
||||||
|
self.tabs[i].dirty = true;
|
||||||
|
self.command_line
|
||||||
|
.push_output(&format!("Layout \"{orig}\" → \"{new_name}\""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
|
|
||||||
|
Message::LayoutRenameCancel => {
|
||||||
|
self.layout_rename_state = None;
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
|
|
||||||
|
Message::LayoutContextMenu(name) => {
|
||||||
|
if name != "Model" {
|
||||||
|
self.layout_context_menu = Some(name);
|
||||||
|
}
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
|
|
||||||
|
Message::LayoutContextMenuClose => {
|
||||||
|
self.layout_context_menu = None;
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
|
|
||||||
Message::Undo => { self.undo_active_tab(); Task::none() }
|
Message::Undo => { self.undo_active_tab(); Task::none() }
|
||||||
Message::Redo => { self.redo_active_tab(); Task::none() }
|
Message::Redo => { self.redo_active_tab(); Task::none() }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -163,7 +163,8 @@ impl H7CAD {
|
||||||
self.polar_mode,
|
self.polar_mode,
|
||||||
self.show_grid,
|
self.show_grid,
|
||||||
tab.scene.layout_names(),
|
tab.scene.layout_names(),
|
||||||
tab.scene.current_layout.clone()
|
tab.scene.current_layout.clone(),
|
||||||
|
self.layout_rename_state.as_ref(),
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
.width(Fill)
|
.width(Fill)
|
||||||
|
|
@ -190,7 +191,14 @@ impl H7CAD {
|
||||||
)
|
)
|
||||||
.unwrap_or_else(|| iced::widget::Space::new().width(0).height(0).into());
|
.unwrap_or_else(|| iced::widget::Space::new().width(0).height(0).into());
|
||||||
|
|
||||||
stack![main_ui, self.app_menu.view(), snap_layer, dropdown_layer].into()
|
let layout_ctx_layer: Element<'_, Message> =
|
||||||
|
if let Some(name) = &self.layout_context_menu {
|
||||||
|
layout_context_menu_overlay(name)
|
||||||
|
} else {
|
||||||
|
iced::widget::Space::new().width(0).height(0).into()
|
||||||
|
};
|
||||||
|
|
||||||
|
stack![main_ui, self.app_menu.view(), snap_layer, dropdown_layer, layout_ctx_layer].into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn subscription(&self) -> Subscription<Message> {
|
pub fn subscription(&self) -> Subscription<Message> {
|
||||||
|
|
@ -367,3 +375,70 @@ pub(super) fn doc_tab_bar<'a>(tabs: &'a [DocumentTab], active_tab: usize) -> Ele
|
||||||
.padding([0, 2])
|
.padding([0, 2])
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Layout context-menu overlay ────────────────────────────────────────────
|
||||||
|
|
||||||
|
/// A small right-click context menu rendered above the status bar.
|
||||||
|
/// The `name` is the layout tab that was right-clicked.
|
||||||
|
fn layout_context_menu_overlay(name: &str) -> Element<'_, Message> {
|
||||||
|
const MENU_BG: Color = Color { r: 0.17, g: 0.17, b: 0.17, a: 1.0 };
|
||||||
|
const MENU_BORDER: Color = Color { r: 0.35, g: 0.35, b: 0.35, a: 1.0 };
|
||||||
|
const ITEM_HOVER: Color = Color { r: 0.25, g: 0.45, b: 0.70, a: 1.0 };
|
||||||
|
const TEXT_COLOR: Color = Color { r: 0.88, g: 0.88, b: 0.88, a: 1.0 };
|
||||||
|
|
||||||
|
let item = |label: &'static str, msg: Message| {
|
||||||
|
button(text(label).size(12).color(TEXT_COLOR))
|
||||||
|
.on_press(msg)
|
||||||
|
.style(|_: &Theme, status| button::Style {
|
||||||
|
background: Some(Background::Color(match status {
|
||||||
|
button::Status::Hovered | button::Status::Pressed => ITEM_HOVER,
|
||||||
|
_ => Color::TRANSPARENT,
|
||||||
|
})),
|
||||||
|
text_color: TEXT_COLOR,
|
||||||
|
border: Border::default(),
|
||||||
|
shadow: iced::Shadow::default(),
|
||||||
|
snap: false,
|
||||||
|
})
|
||||||
|
.padding([4, 12])
|
||||||
|
.width(Fill)
|
||||||
|
};
|
||||||
|
|
||||||
|
let rename_name = name.to_string();
|
||||||
|
let delete_name = name.to_string();
|
||||||
|
|
||||||
|
let menu = container(
|
||||||
|
column![
|
||||||
|
item("Yeniden Adlandır", Message::LayoutRenameStart(rename_name)),
|
||||||
|
item("Sil", Message::LayoutDelete(delete_name)),
|
||||||
|
]
|
||||||
|
.spacing(0)
|
||||||
|
.width(160),
|
||||||
|
)
|
||||||
|
.style(move |_: &Theme| container::Style {
|
||||||
|
background: Some(Background::Color(MENU_BG)),
|
||||||
|
border: Border {
|
||||||
|
color: MENU_BORDER,
|
||||||
|
width: 1.0,
|
||||||
|
radius: 4.0.into(),
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.padding([4, 0]);
|
||||||
|
|
||||||
|
// Click-catcher fills the whole screen to close the menu when clicking outside.
|
||||||
|
let catcher = mouse_area(
|
||||||
|
container(iced::widget::Space::new().width(Fill).height(Fill))
|
||||||
|
.width(Fill)
|
||||||
|
.height(Fill),
|
||||||
|
)
|
||||||
|
.on_press(Message::LayoutContextMenuClose)
|
||||||
|
.on_right_press(Message::LayoutContextMenuClose);
|
||||||
|
|
||||||
|
// Position the menu above the status bar at the left.
|
||||||
|
let positioned = container(menu)
|
||||||
|
.align_bottom(Fill)
|
||||||
|
.align_left(Fill)
|
||||||
|
.padding(iced::Padding { top: 0.0, right: 0.0, bottom: 30.0, left: 8.0 });
|
||||||
|
|
||||||
|
stack![catcher, positioned].into()
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -385,6 +385,65 @@ impl Scene {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Layout management ─────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/// Rename a paper-space layout. Updates the Layout object name in the document.
|
||||||
|
pub fn rename_layout(&mut self, old_name: &str, new_name: &str) {
|
||||||
|
for obj in self.document.objects.values_mut() {
|
||||||
|
if let ObjectType::Layout(l) = obj {
|
||||||
|
if l.name == old_name {
|
||||||
|
l.name = new_name.to_string();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delete a paper-space layout and all entities owned by it.
|
||||||
|
/// Returns `false` if the layout was not found or is "Model".
|
||||||
|
pub fn delete_layout(&mut self, name: &str) -> bool {
|
||||||
|
if name == "Model" {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let layout_info = self.document.objects.values().find_map(|obj| {
|
||||||
|
if let ObjectType::Layout(l) = obj {
|
||||||
|
if l.name == name {
|
||||||
|
return Some((l.handle, l.block_record));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
});
|
||||||
|
|
||||||
|
let (layout_handle, block_handle) = match layout_info {
|
||||||
|
Some(info) => info,
|
||||||
|
None => return false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Remove all entities that belong to this layout's block record.
|
||||||
|
let to_remove: Vec<Handle> = self
|
||||||
|
.document
|
||||||
|
.entities()
|
||||||
|
.filter(|e| e.common().owner_handle == block_handle)
|
||||||
|
.map(|e| e.common().handle)
|
||||||
|
.collect();
|
||||||
|
for h in &to_remove {
|
||||||
|
self.hatches.remove(h);
|
||||||
|
self.meshes.remove(h);
|
||||||
|
self.document.remove_entity(*h);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the Layout object itself.
|
||||||
|
self.document.objects.remove(&layout_handle);
|
||||||
|
|
||||||
|
// If the deleted layout was active, fall back to Model space.
|
||||||
|
if self.current_layout == name {
|
||||||
|
self.current_layout = "Model".to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
// ── Entity management ─────────────────────────────────────────────────
|
// ── Entity management ─────────────────────────────────────────────────
|
||||||
|
|
||||||
pub fn add_entity(&mut self, entity: EntityType) -> Handle {
|
pub fn add_entity(&mut self, entity: EntityType) -> Handle {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
//! Bottom status bar — Model/Layout tabs + OSNAP toggle + status info
|
//! Bottom status bar — Model/Layout tabs + OSNAP toggle + status info
|
||||||
|
|
||||||
use iced::widget::tooltip::Position as TipPos;
|
use iced::widget::tooltip::Position as TipPos;
|
||||||
use iced::widget::{button, container, row, text, tooltip, Row};
|
use iced::widget::{button, container, mouse_area, row, text, text_input, tooltip, Row};
|
||||||
use iced::{Background, Border, Color, Element, Length, Theme};
|
use iced::{Background, Border, Color, Element, Length, Theme};
|
||||||
|
|
||||||
use crate::snap::Snapper;
|
use crate::snap::Snapper;
|
||||||
|
|
@ -29,6 +29,8 @@ impl StatusBar {
|
||||||
show_grid: bool,
|
show_grid: bool,
|
||||||
layouts: Vec<String>,
|
layouts: Vec<String>,
|
||||||
current_layout: String,
|
current_layout: String,
|
||||||
|
// If `Some((original, edit_value))`, the named tab shows a text input.
|
||||||
|
rename_state: Option<&'a (String, String)>,
|
||||||
) -> Element<'a, Message> {
|
) -> Element<'a, Message> {
|
||||||
let menu_btn = button(text("≡").size(14).color(ICON_COLOR))
|
let menu_btn = button(text("≡").size(14).color(ICON_COLOR))
|
||||||
.on_press(Message::Command("MENU".into()))
|
.on_press(Message::Command("MENU".into()))
|
||||||
|
|
@ -82,7 +84,10 @@ impl StatusBar {
|
||||||
bar = bar.push(menu_btn);
|
bar = bar.push(menu_btn);
|
||||||
for name in layouts {
|
for name in layouts {
|
||||||
let is_active = name == current_layout;
|
let is_active = name == current_layout;
|
||||||
bar = bar.push(space_tab(name, is_active));
|
let renaming = rename_state
|
||||||
|
.filter(|(orig, _)| *orig == name)
|
||||||
|
.map(|(_, edit)| edit.as_str());
|
||||||
|
bar = bar.push(space_tab(name, is_active, renaming));
|
||||||
}
|
}
|
||||||
bar = bar.push(add_btn);
|
bar = bar.push(add_btn);
|
||||||
bar = bar.push(iced::widget::Space::new().width(Length::Fill));
|
bar = bar.push(iced::widget::Space::new().width(Length::Fill));
|
||||||
|
|
@ -262,40 +267,90 @@ fn osnap_btn(active: bool, snap_enabled: bool, open: bool) -> Element<'static, M
|
||||||
|
|
||||||
// ── Helpers ───────────────────────────────────────────────────────────────
|
// ── Helpers ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
fn space_tab(label: String, is_active: bool) -> Element<'static, Message> {
|
/// A layout tab button.
|
||||||
let msg = Message::LayoutSwitch(label.clone());
|
///
|
||||||
button(text(label).size(11))
|
/// When `rename_edit` is `Some(value)` the tab shows an inline text input
|
||||||
.on_press(msg)
|
/// instead of the normal button. The tab is not renameable when it is the
|
||||||
.style(move |_: &Theme, status| button::Style {
|
/// "Model" tab (callers simply never pass `Some` for that name).
|
||||||
background: Some(Background::Color(match (is_active, status) {
|
fn space_tab<'a>(label: String, is_active: bool, rename_edit: Option<&'a str>) -> Element<'a, Message> {
|
||||||
(true, _) => TAB_ACTIVE,
|
let bg = move |is_active: bool, hovered: bool| {
|
||||||
(false, button::Status::Hovered) => TAB_HOVER,
|
if is_active {
|
||||||
_ => Color::TRANSPARENT,
|
TAB_ACTIVE
|
||||||
})),
|
} else if hovered {
|
||||||
text_color: if is_active {
|
TAB_HOVER
|
||||||
Color::WHITE
|
|
||||||
} else {
|
|
||||||
Color {
|
|
||||||
r: 0.65,
|
|
||||||
g: 0.65,
|
|
||||||
b: 0.65,
|
|
||||||
a: 1.0,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
border: Border {
|
|
||||||
color: if is_active {
|
|
||||||
ACCENT
|
|
||||||
} else {
|
} else {
|
||||||
Color::TRANSPARENT
|
Color::TRANSPARENT
|
||||||
},
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let border = Border {
|
||||||
|
color: if is_active { ACCENT } else { Color::TRANSPARENT },
|
||||||
width: if is_active { 1.0 } else { 0.0 },
|
width: if is_active { 1.0 } else { 0.0 },
|
||||||
radius: 2.0.into(),
|
radius: 2.0.into(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let text_color = if is_active {
|
||||||
|
Color::WHITE
|
||||||
|
} else {
|
||||||
|
Color { r: 0.65, g: 0.65, b: 0.65, a: 1.0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(edit_val) = rename_edit {
|
||||||
|
// Inline rename text input with a cancel (✕) button.
|
||||||
|
let input = text_input("", edit_val)
|
||||||
|
.on_input(Message::LayoutRenameEdit)
|
||||||
|
.on_submit(Message::LayoutRenameCommit)
|
||||||
|
.size(11)
|
||||||
|
.style(|_: &Theme, _| text_input::Style {
|
||||||
|
background: Background::Color(TAB_ACTIVE),
|
||||||
|
border: Border {
|
||||||
|
color: ACCENT,
|
||||||
|
width: 1.0,
|
||||||
|
radius: 2.0.into(),
|
||||||
},
|
},
|
||||||
|
icon: Color::WHITE,
|
||||||
|
placeholder: Color { r: 0.5, g: 0.5, b: 0.5, a: 1.0 },
|
||||||
|
value: Color::WHITE,
|
||||||
|
selection: Color { r: 0.20, g: 0.55, b: 0.90, a: 0.4 },
|
||||||
|
})
|
||||||
|
.padding([2, 6])
|
||||||
|
.width(Length::Fixed(90.0));
|
||||||
|
|
||||||
|
let cancel_btn = button(
|
||||||
|
text("✕").size(10).color(Color { r: 0.65, g: 0.65, b: 0.65, a: 1.0 }),
|
||||||
|
)
|
||||||
|
.on_press(Message::LayoutRenameCancel)
|
||||||
|
.style(|_: &Theme, _| button::Style {
|
||||||
|
background: Some(Background::Color(Color::TRANSPARENT)),
|
||||||
|
border: Border::default(),
|
||||||
shadow: iced::Shadow::default(),
|
shadow: iced::Shadow::default(),
|
||||||
snap: false,
|
snap: false,
|
||||||
|
..Default::default()
|
||||||
})
|
})
|
||||||
.padding([3, 10])
|
.padding([2, 4]);
|
||||||
|
|
||||||
|
row![input, cancel_btn].spacing(0).align_y(iced::Center).into()
|
||||||
|
} else {
|
||||||
|
// Normal clickable tab — left click switches, right click opens context menu.
|
||||||
|
let display = container(
|
||||||
|
text(label.clone()).size(11).color(text_color),
|
||||||
|
)
|
||||||
|
.style(move |_: &Theme| container::Style {
|
||||||
|
background: Some(Background::Color(bg(is_active, false))),
|
||||||
|
border,
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.padding([3, 10]);
|
||||||
|
|
||||||
|
let switch_msg = Message::LayoutSwitch(label.clone());
|
||||||
|
let ctx_msg = Message::LayoutContextMenu(label.clone());
|
||||||
|
|
||||||
|
// Use mouse_area so we can capture right-click for the context menu.
|
||||||
|
mouse_area(display)
|
||||||
|
.on_press(switch_msg)
|
||||||
|
.on_right_press(ctx_msg)
|
||||||
.into()
|
.into()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn status_pill(label: &str) -> Element<'_, Message> {
|
fn status_pill(label: &str) -> Element<'_, Message> {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue