all: remove traditional i3 titlebars, add corner rounding
This commit is contained in:
parent
e1928863d9
commit
a41dbae899
52 changed files with 1866 additions and 1047 deletions
|
|
@ -4,38 +4,29 @@ use {
|
|||
cursor::KnownCursor,
|
||||
cursor_user::CursorUser,
|
||||
fixed::Fixed,
|
||||
gfx_api::GfxTexture,
|
||||
ifs::wl_seat::{
|
||||
BTN_LEFT, BTN_RIGHT, NodeSeatState, SeatId, WlSeatGlobal, collect_kb_foci,
|
||||
BTN_LEFT, NodeSeatState, SeatId, WlSeatGlobal, collect_kb_foci,
|
||||
collect_kb_foci2,
|
||||
tablet::{TabletTool, TabletToolChanges, TabletToolId},
|
||||
wl_pointer::PendingScroll,
|
||||
},
|
||||
rect::Rect,
|
||||
renderer::Renderer,
|
||||
scale::Scale,
|
||||
state::State,
|
||||
text::TextTexture,
|
||||
tree::{
|
||||
ContainingNode, Direction, FindTreeResult, FindTreeUsecase, FloatNode, FoundNode, Node,
|
||||
NodeId, NodeLayerLink, NodeLocation, OutputNode, TddType, TileDragDestination,
|
||||
ToplevelData, ToplevelNode, ToplevelNodeBase, ToplevelType, WorkspaceNode,
|
||||
default_tile_drag_bounds, toplevel_set_floating, toplevel_set_workspace,
|
||||
default_tile_drag_bounds, toplevel_set_workspace,
|
||||
walker::NodeVisitor,
|
||||
},
|
||||
utils::{
|
||||
asyncevent::AsyncEvent,
|
||||
clonecell::CloneCell,
|
||||
double_click_state::DoubleClickState,
|
||||
errorfmt::ErrorFmt,
|
||||
event_listener::LazyEventSource,
|
||||
hash_map_ext::HashMapExt,
|
||||
linkedlist::{LinkedList, LinkedNode, NodeRef},
|
||||
numcell::NumCell,
|
||||
on_drop_event::OnDropEvent,
|
||||
rc_eq::rc_eq,
|
||||
scroller::Scroller,
|
||||
smallmap::SmallMapMut,
|
||||
threshold_counter::ThresholdCounter,
|
||||
},
|
||||
},
|
||||
|
|
@ -94,20 +85,9 @@ pub enum ContainerFocus {
|
|||
|
||||
tree_id!(ContainerNodeId);
|
||||
|
||||
pub struct ContainerTitle {
|
||||
pub rect: Rect,
|
||||
pub tex: Rc<dyn GfxTexture>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ContainerRenderData {
|
||||
pub title_rects: Vec<Rect>,
|
||||
pub active_title_rects: Vec<Rect>,
|
||||
pub attention_title_rects: Vec<Rect>,
|
||||
pub last_active_rect: Option<Rect>,
|
||||
pub border_rects: Vec<Rect>,
|
||||
pub underline_rects: Vec<Rect>,
|
||||
pub titles: SmallMapMut<Scale, Vec<ContainerTitle>, 2>,
|
||||
}
|
||||
|
||||
pub struct ContainerNode {
|
||||
|
|
@ -123,9 +103,8 @@ pub struct ContainerNode {
|
|||
pub content_width: Cell<i32>,
|
||||
pub content_height: Cell<i32>,
|
||||
pub sum_factors: Cell<f64>,
|
||||
layout_scheduled: Cell<bool>,
|
||||
pub layout_scheduled: Cell<bool>,
|
||||
compute_render_positions_scheduled: Cell<bool>,
|
||||
render_titles_scheduled: Cell<bool>,
|
||||
num_children: NumCell<usize>,
|
||||
pub children: LinkedList<ContainerChild>,
|
||||
focus_history: LinkedList<NodeRef<ContainerChild>>,
|
||||
|
|
@ -135,7 +114,6 @@ pub struct ContainerNode {
|
|||
cursors: RefCell<AHashMap<CursorType, CursorState>>,
|
||||
state: Rc<State>,
|
||||
pub render_data: RefCell<ContainerRenderData>,
|
||||
scroller: Scroller,
|
||||
toplevel_data: ToplevelData,
|
||||
attention_requests: ThresholdCounter,
|
||||
pub layout_complete: Rc<LazyEventSource>,
|
||||
|
|
@ -154,9 +132,6 @@ pub struct ContainerChild {
|
|||
pub node: Rc<dyn ToplevelNode>,
|
||||
pub active: Cell<bool>,
|
||||
pub attention_requested: Cell<bool>,
|
||||
title: RefCell<String>,
|
||||
pub title_tex: RefCell<SmallMapMut<Scale, TextTexture, 2>>,
|
||||
pub title_rect: Cell<Rect>,
|
||||
focus_history: Cell<Option<LinkedNode<NodeRef<ContainerChild>>>>,
|
||||
|
||||
// fields below only valid in tabbed layout
|
||||
|
|
@ -178,7 +153,6 @@ struct CursorState {
|
|||
x: i32,
|
||||
y: i32,
|
||||
op: Option<SeatOp>,
|
||||
double_click_state: DoubleClickState,
|
||||
}
|
||||
|
||||
impl ContainerChild {
|
||||
|
|
@ -212,9 +186,6 @@ impl ContainerNode {
|
|||
body: Default::default(),
|
||||
content: Default::default(),
|
||||
factor: Cell::new(1.0),
|
||||
title: Default::default(),
|
||||
title_tex: Default::default(),
|
||||
title_rect: Default::default(),
|
||||
focus_history: Default::default(),
|
||||
attention_requested: Cell::new(false),
|
||||
border_color_is_focused: Default::default(),
|
||||
|
|
@ -238,7 +209,6 @@ impl ContainerNode {
|
|||
sum_factors: Cell::new(1.0),
|
||||
layout_scheduled: Cell::new(false),
|
||||
compute_render_positions_scheduled: Cell::new(false),
|
||||
render_titles_scheduled: Cell::new(false),
|
||||
num_children: NumCell::new(1),
|
||||
children,
|
||||
focus_history: Default::default(),
|
||||
|
|
@ -248,7 +218,6 @@ impl ContainerNode {
|
|||
cursors: RefCell::new(Default::default()),
|
||||
state: state.clone(),
|
||||
render_data: Default::default(),
|
||||
scroller: Default::default(),
|
||||
toplevel_data: ToplevelData::new(
|
||||
state,
|
||||
Default::default(),
|
||||
|
|
@ -339,9 +308,6 @@ impl ContainerNode {
|
|||
|
||||
content: Default::default(),
|
||||
factor: Default::default(),
|
||||
title: Default::default(),
|
||||
title_tex: Default::default(),
|
||||
title_rect: Default::default(),
|
||||
focus_history: Default::default(),
|
||||
attention_requested: Default::default(),
|
||||
border_color_is_focused: Default::default(),
|
||||
|
|
@ -384,35 +350,25 @@ impl ContainerNode {
|
|||
}
|
||||
|
||||
pub fn predict_child_body_size(&self) -> (i32, i32) {
|
||||
let tpuh = self.state.theme.title_plus_underline_height();
|
||||
if self.mono_child.is_some() {
|
||||
let mb = self.mono_body.get();
|
||||
return (mb.width(), mb.height());
|
||||
}
|
||||
let gap = self.state.theme.sizes.gap.get();
|
||||
let bw = self.state.theme.sizes.border_width.get();
|
||||
let floating = self.state.theme.floating_titles.get() && gap != 0;
|
||||
let nc = self.num_children.get() as i32 + 1;
|
||||
match self.split.get() {
|
||||
ContainerSplit::Horizontal => {
|
||||
let spacing = if floating {
|
||||
self.state.theme.sizes.title_gap.get() + 2 * bw
|
||||
} else {
|
||||
gap.max(bw)
|
||||
};
|
||||
let spacing = gap.max(bw);
|
||||
let content_w = self.width.get().sub((nc - 1) * spacing).max(0);
|
||||
(content_w / nc, self.height.get().sub(tpuh).max(0))
|
||||
(content_w / nc, self.height.get())
|
||||
}
|
||||
ContainerSplit::Vertical => {
|
||||
let spacing = if floating {
|
||||
self.state.theme.sizes.title_gap.get() + bw
|
||||
} else {
|
||||
gap.max(bw)
|
||||
};
|
||||
let spacing = gap.max(bw);
|
||||
let content_h = self
|
||||
.height
|
||||
.get()
|
||||
.sub(tpuh + (nc - 1) * (spacing + tpuh))
|
||||
.sub((nc - 1) * spacing)
|
||||
.max(0);
|
||||
(self.width.get(), content_h / nc)
|
||||
}
|
||||
|
|
@ -427,8 +383,6 @@ impl ContainerNode {
|
|||
}
|
||||
|
||||
pub fn on_colors_changed(self: &Rc<Self>) {
|
||||
// log::info!("on_colors_changed");
|
||||
self.schedule_render_titles();
|
||||
self.schedule_compute_render_positions();
|
||||
}
|
||||
|
||||
|
|
@ -487,7 +441,6 @@ impl ContainerNode {
|
|||
}
|
||||
self.state.tree_changed();
|
||||
// log::info!("perform_layout");
|
||||
self.schedule_render_titles();
|
||||
self.schedule_compute_render_positions();
|
||||
self.layout_complete.trigger();
|
||||
if self.all_children_match_body() {
|
||||
|
|
@ -507,51 +460,14 @@ impl ContainerNode {
|
|||
.tl_change_extents(&mb.move_(self.abs_x1.get(), self.abs_y1.get()));
|
||||
self.mono_content
|
||||
.set(child.content.get().at_point(mb.x1(), mb.y1()));
|
||||
|
||||
let th = self.state.theme.title_height();
|
||||
let bw = self.state.theme.sizes.border_width.get();
|
||||
let bw_top = self.state.theme.floating_title_top_margin();
|
||||
let floating = self.state.theme.floating_titles.get();
|
||||
let spacing = if floating {
|
||||
self.state.theme.sizes.title_gap.get() + 2 * bw
|
||||
} else {
|
||||
bw
|
||||
};
|
||||
let num_children = self.num_children.get() as i32;
|
||||
let content_width = self.width.get().sub(spacing * (num_children - 1)).max(0);
|
||||
let width_per_child = content_width / num_children;
|
||||
let mut rem = content_width % num_children;
|
||||
let mut pos = 0;
|
||||
for child in self.children.iter() {
|
||||
let mut width = width_per_child;
|
||||
if rem > 0 {
|
||||
width += 1;
|
||||
rem -= 1;
|
||||
}
|
||||
child
|
||||
.title_rect
|
||||
.set(Rect::new_sized_saturating(pos, bw_top, width, th));
|
||||
pos += width + spacing;
|
||||
}
|
||||
}
|
||||
|
||||
fn perform_split_layout(self: &Rc<Self>) {
|
||||
let sum_factors = self.sum_factors.get();
|
||||
let gap = self.state.theme.sizes.gap.get();
|
||||
let border_width = self.state.theme.sizes.border_width.get();
|
||||
let floating = self.state.theme.floating_titles.get() && gap != 0;
|
||||
let title_height_tmp = self.state.theme.title_height();
|
||||
let tpuh = self.state.theme.title_plus_underline_height();
|
||||
let split = self.split.get();
|
||||
let spacing = if floating {
|
||||
let title_gap = self.state.theme.sizes.title_gap.get();
|
||||
match split {
|
||||
ContainerSplit::Horizontal => title_gap + 2 * border_width,
|
||||
ContainerSplit::Vertical => title_gap + border_width,
|
||||
}
|
||||
} else {
|
||||
gap.max(border_width)
|
||||
};
|
||||
let spacing = gap.max(border_width);
|
||||
let (content_size, other_content_size) = match split {
|
||||
ContainerSplit::Horizontal => (self.content_width.get(), self.content_height.get()),
|
||||
ContainerSplit::Vertical => (self.content_height.get(), self.content_width.get()),
|
||||
|
|
@ -569,15 +485,12 @@ impl ContainerNode {
|
|||
body_size = body_size.min(remaining_content_size);
|
||||
remaining_content_size -= body_size;
|
||||
let (x1, y1, width, height) = match split {
|
||||
ContainerSplit::Horizontal => (pos, tpuh, body_size, other_content_size),
|
||||
_ => (0, pos + tpuh, other_content_size, body_size),
|
||||
ContainerSplit::Horizontal => (pos, 0, body_size, other_content_size),
|
||||
_ => (0, pos, other_content_size, body_size),
|
||||
};
|
||||
let body = Rect::new_sized_saturating(x1, y1, width, height);
|
||||
child.body.set(body);
|
||||
pos += body_size + spacing;
|
||||
if split == ContainerSplit::Vertical {
|
||||
pos += tpuh;
|
||||
}
|
||||
}
|
||||
if remaining_content_size > 0 {
|
||||
let size_per = remaining_content_size / num_children as i32;
|
||||
|
|
@ -593,31 +506,21 @@ impl ContainerNode {
|
|||
let (x1, y1, width, height, size) = match split {
|
||||
ContainerSplit::Horizontal => {
|
||||
let width = body.width() + add;
|
||||
(pos, tpuh, width, other_content_size, width)
|
||||
(pos, 0, width, other_content_size, width)
|
||||
}
|
||||
_ => {
|
||||
let height = body.height() + add;
|
||||
(0, pos + tpuh, other_content_size, height, height)
|
||||
(0, pos, other_content_size, height, height)
|
||||
}
|
||||
};
|
||||
body = Rect::new_sized_saturating(x1, y1, width, height);
|
||||
child.body.set(body);
|
||||
pos += size + spacing;
|
||||
if split == ContainerSplit::Vertical {
|
||||
pos += tpuh;
|
||||
}
|
||||
}
|
||||
}
|
||||
let bw_top = self.state.theme.floating_title_top_margin();
|
||||
self.sum_factors.set(1.0);
|
||||
for child in self.children.iter() {
|
||||
let body = child.body.get();
|
||||
child.title_rect.set(Rect::new_sized_saturating(
|
||||
body.x1(),
|
||||
body.y1() - tpuh + bw_top,
|
||||
body.width(),
|
||||
title_height_tmp,
|
||||
));
|
||||
let body = body.move_(self.abs_x1.get(), self.abs_y1.get());
|
||||
child.node.clone().tl_change_extents(&body);
|
||||
child.position_content();
|
||||
|
|
@ -627,31 +530,20 @@ impl ContainerNode {
|
|||
fn update_content_size(&self) {
|
||||
let gap = self.state.theme.sizes.gap.get();
|
||||
let border_width = self.state.theme.sizes.border_width.get();
|
||||
let floating = self.state.theme.floating_titles.get() && gap != 0;
|
||||
let title_gap = self.state.theme.sizes.title_gap.get();
|
||||
let tpuh = self.state.theme.title_plus_underline_height();
|
||||
let nc = self.num_children.get();
|
||||
match self.split.get() {
|
||||
ContainerSplit::Horizontal => {
|
||||
let spacing = if floating {
|
||||
title_gap + 2 * border_width
|
||||
} else {
|
||||
gap.max(border_width)
|
||||
};
|
||||
let spacing = gap.max(border_width);
|
||||
let new_content_size = self.width.get().sub((nc - 1) as i32 * spacing).max(0);
|
||||
self.content_width.set(new_content_size);
|
||||
self.content_height.set(self.height.get().sub(tpuh).max(0));
|
||||
self.content_height.set(self.height.get());
|
||||
}
|
||||
ContainerSplit::Vertical => {
|
||||
let spacing = if floating {
|
||||
title_gap + border_width
|
||||
} else {
|
||||
gap.max(border_width)
|
||||
};
|
||||
let spacing = gap.max(border_width);
|
||||
let new_content_size = self
|
||||
.height
|
||||
.get()
|
||||
.sub(tpuh + (nc - 1) as i32 * (spacing + tpuh))
|
||||
.sub((nc - 1) as i32 * spacing)
|
||||
.max(0);
|
||||
self.content_height.set(new_content_size);
|
||||
self.content_width.set(self.width.get());
|
||||
|
|
@ -659,15 +551,15 @@ impl ContainerNode {
|
|||
}
|
||||
self.mono_body.set(Rect::new_sized_saturating(
|
||||
0,
|
||||
tpuh,
|
||||
0,
|
||||
self.width.get(),
|
||||
self.height.get() - tpuh,
|
||||
self.height.get(),
|
||||
));
|
||||
}
|
||||
|
||||
fn pointer_move(
|
||||
self: &Rc<Self>,
|
||||
seat: &Rc<WlSeatGlobal>,
|
||||
_seat: &Rc<WlSeatGlobal>,
|
||||
id: CursorType,
|
||||
cursor: &CursorUser,
|
||||
x: Fixed,
|
||||
|
|
@ -676,7 +568,6 @@ impl ContainerNode {
|
|||
) {
|
||||
let mut x = x.round_down();
|
||||
let mut y = y.round_down();
|
||||
let title_plus_underline_height = self.state.theme.title_plus_underline_height();
|
||||
let mut seats = self.cursors.borrow_mut();
|
||||
let seat_state = seats.entry(id).or_insert_with(|| CursorState {
|
||||
cursor: KnownCursor::Default,
|
||||
|
|
@ -684,7 +575,6 @@ impl ContainerNode {
|
|||
x,
|
||||
y,
|
||||
op: None,
|
||||
double_click_state: Default::default(),
|
||||
});
|
||||
let mut changed = false;
|
||||
changed |= mem::replace(&mut seat_state.x, x) != x;
|
||||
|
|
@ -694,15 +584,6 @@ impl ContainerNode {
|
|||
}
|
||||
if let Some(op) = &seat_state.op {
|
||||
match op.kind {
|
||||
SeatOpKind::Move => {
|
||||
if let CursorType::Seat(_) = id
|
||||
&& self.state.ui_drag_threshold_reached((x, y), (op.x, op.y))
|
||||
{
|
||||
let node = op.child.node.clone();
|
||||
drop(seats);
|
||||
seat.start_tile_drag(&node);
|
||||
}
|
||||
}
|
||||
SeatOpKind::Resize {
|
||||
dist_left,
|
||||
dist_right,
|
||||
|
|
@ -748,19 +629,13 @@ impl ContainerNode {
|
|||
let new_cursor = if self.mono_child.is_some() {
|
||||
KnownCursor::Default
|
||||
} else if self.split.get() == ContainerSplit::Horizontal {
|
||||
if y < title_plus_underline_height {
|
||||
KnownCursor::Default
|
||||
} else {
|
||||
KnownCursor::EwResize
|
||||
}
|
||||
KnownCursor::EwResize
|
||||
} else {
|
||||
let mut cursor = KnownCursor::Default;
|
||||
for child in self.children.iter() {
|
||||
let body = child.body.get();
|
||||
if body.y1() > y {
|
||||
if body.y1() - y > title_plus_underline_height {
|
||||
cursor = KnownCursor::NsResize
|
||||
}
|
||||
cursor = KnownCursor::NsResize;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -773,121 +648,6 @@ impl ContainerNode {
|
|||
}
|
||||
}
|
||||
|
||||
fn update_title(&self) {
|
||||
let mut title = self.toplevel_data.title.borrow_mut();
|
||||
title.clear();
|
||||
let split = match (self.mono_child.is_some(), self.split.get()) {
|
||||
(true, _) => "T",
|
||||
(_, ContainerSplit::Horizontal) => "H",
|
||||
(_, ContainerSplit::Vertical) => "V",
|
||||
};
|
||||
title.push_str(split);
|
||||
title.push_str("[");
|
||||
for (i, c) in self.children.iter().enumerate() {
|
||||
if i > 0 {
|
||||
title.push_str(", ");
|
||||
}
|
||||
title.push_str(c.title.borrow_mut().deref());
|
||||
}
|
||||
title.push_str("]");
|
||||
drop(title);
|
||||
self.tl_title_changed();
|
||||
}
|
||||
|
||||
pub fn schedule_render_titles(self: &Rc<Self>) {
|
||||
if !self.render_titles_scheduled.replace(true) {
|
||||
self.state.pending_container_render_title.push(self.clone());
|
||||
}
|
||||
}
|
||||
|
||||
fn last_active(&self) -> Option<NodeId> {
|
||||
match self.mono_child.get() {
|
||||
Some(c) => Some(c.node.node_id()),
|
||||
None => self.focus_history.last().map(|v| v.node.node_id()),
|
||||
}
|
||||
}
|
||||
|
||||
fn render_titles(&self) -> Rc<AsyncEvent> {
|
||||
let on_completed = Rc::new(OnDropEvent::default());
|
||||
let Some(ctx) = self.state.render_ctx.get() else {
|
||||
return on_completed.event();
|
||||
};
|
||||
let theme = &self.state.theme;
|
||||
let th = theme.title_height();
|
||||
let font = theme.title_font();
|
||||
let last_active = self.last_active();
|
||||
let have_active = self.children.iter().any(|c| c.active.get());
|
||||
let scales = self.state.scales.lock();
|
||||
for child in self.children.iter() {
|
||||
let rect = child.title_rect.get();
|
||||
let color = if child.active.get() {
|
||||
theme.colors.focused_title_text.get()
|
||||
} else if child.attention_requested.get() {
|
||||
theme.colors.unfocused_title_text.get()
|
||||
} else if !have_active && last_active == Some(child.node.node_id()) {
|
||||
theme.colors.focused_inactive_title_text.get()
|
||||
} else {
|
||||
theme.colors.unfocused_title_text.get()
|
||||
};
|
||||
let title = child.title.borrow_mut();
|
||||
let tt = &mut *child.title_tex.borrow_mut();
|
||||
for (scale, _) in scales.iter() {
|
||||
let tex = tt.get_or_insert_with(*scale, || TextTexture::new(&self.state, &ctx));
|
||||
let mut th = th;
|
||||
let mut scalef = None;
|
||||
let mut width = rect.width();
|
||||
if *scale != 1 {
|
||||
let scale = scale.to_f64();
|
||||
th = (th as f64 * scale).round() as _;
|
||||
width = (width as f64 * scale).round() as _;
|
||||
scalef = Some(scale);
|
||||
}
|
||||
tex.schedule_render(
|
||||
on_completed.clone(),
|
||||
1,
|
||||
None,
|
||||
width,
|
||||
th,
|
||||
1,
|
||||
&font,
|
||||
title.deref(),
|
||||
color,
|
||||
true,
|
||||
false,
|
||||
scalef,
|
||||
);
|
||||
}
|
||||
}
|
||||
on_completed.event()
|
||||
}
|
||||
|
||||
fn compute_title_data(&self) {
|
||||
let rd = &mut *self.render_data.borrow_mut();
|
||||
for (_, v) in rd.titles.iter_mut() {
|
||||
v.clear();
|
||||
}
|
||||
let abs_x = self.abs_x1.get();
|
||||
let abs_y = self.abs_y1.get();
|
||||
for child in self.children.iter() {
|
||||
let rect = child.title_rect.get();
|
||||
if self.toplevel_data.visible.get() {
|
||||
self.state.damage(rect.move_(abs_x, abs_y));
|
||||
}
|
||||
let title = child.title.borrow_mut();
|
||||
let tt = &*child.title_tex.borrow();
|
||||
for (scale, tex) in tt {
|
||||
if let Err(e) = tex.flip() {
|
||||
log::error!("Could not render title {}: {}", title, ErrorFmt(e));
|
||||
}
|
||||
if let Some(tex) = tex.texture() {
|
||||
let titles = rd.titles.get_or_default_mut(*scale);
|
||||
titles.push(ContainerTitle { rect, tex })
|
||||
}
|
||||
}
|
||||
}
|
||||
rd.titles.remove_if(|_, v| v.is_empty());
|
||||
}
|
||||
|
||||
fn schedule_compute_render_positions(self: &Rc<Self>) {
|
||||
if !self.compute_render_positions_scheduled.replace(true) {
|
||||
self.state
|
||||
|
|
@ -901,110 +661,36 @@ impl ContainerNode {
|
|||
let mut rd = self.render_data.borrow_mut();
|
||||
let rd = rd.deref_mut();
|
||||
let theme = &self.state.theme;
|
||||
let th = theme.title_height();
|
||||
let tpuh = theme.title_plus_underline_height();
|
||||
let tuh = theme.title_underline_height();
|
||||
let bw = theme.sizes.border_width.get();
|
||||
let cwidth = self.width.get();
|
||||
let cheight = self.height.get();
|
||||
for (_, v) in rd.titles.iter_mut() {
|
||||
v.clear();
|
||||
}
|
||||
rd.title_rects.clear();
|
||||
rd.active_title_rects.clear();
|
||||
rd.attention_title_rects.clear();
|
||||
rd.border_rects.clear();
|
||||
rd.underline_rects.clear();
|
||||
rd.last_active_rect.take();
|
||||
let last_active = self.last_active();
|
||||
let mono = self.mono_child.is_some();
|
||||
let split = self.split.get();
|
||||
let have_active = self.children.iter().any(|c| c.active.get());
|
||||
let abs_x = self.abs_x1.get();
|
||||
let abs_y = self.abs_y1.get();
|
||||
let gap = self.state.theme.sizes.gap.get();
|
||||
let floating_titles = self.state.theme.floating_titles.get();
|
||||
let title_bw = if gap != 0 && !floating_titles { bw } else { 0 };
|
||||
for (i, child) in self.children.iter().enumerate() {
|
||||
let rect = child.title_rect.get();
|
||||
if self.toplevel_data.visible.get() && !mono && split != ContainerSplit::Horizontal {
|
||||
self.state.damage(Rect::new_sized_saturating(
|
||||
abs_x - title_bw,
|
||||
abs_y + rect.y1(),
|
||||
cwidth + 2 * title_bw,
|
||||
rect.height() + tuh,
|
||||
));
|
||||
}
|
||||
if gap != 0 && !mono && !child.node.node_is_container() {
|
||||
child.border_color_is_focused.set(child.active.get());
|
||||
} else if i > 0 {
|
||||
let body = child.body.get();
|
||||
let sep = if mono {
|
||||
Rect::new_sized_saturating(rect.x1() - bw, 0, bw, th)
|
||||
// In mono mode, no separators needed without title tabs
|
||||
continue;
|
||||
} else if split == ContainerSplit::Horizontal {
|
||||
Rect::new_sized_saturating(rect.x1() - bw, 0, bw, cheight)
|
||||
Rect::new_sized_saturating(body.x1() - bw, 0, bw, cheight)
|
||||
} else {
|
||||
Rect::new_sized_saturating(0, rect.y1() - bw, cwidth, bw)
|
||||
Rect::new_sized_saturating(0, body.y1() - bw, cwidth, bw)
|
||||
};
|
||||
if gap == 0 || (mono && !floating_titles) {
|
||||
if gap == 0 {
|
||||
rd.border_rects.push(sep);
|
||||
}
|
||||
}
|
||||
if child.active.get() {
|
||||
rd.active_title_rects.push(rect);
|
||||
} else if child.attention_requested.get() {
|
||||
rd.attention_title_rects.push(rect);
|
||||
} else if !have_active && last_active == Some(child.node.node_id()) {
|
||||
rd.last_active_rect = Some(rect);
|
||||
} else {
|
||||
rd.title_rects.push(rect);
|
||||
}
|
||||
if !mono && (!floating_titles || gap == 0) {
|
||||
let rect = Rect::new_sized_saturating(rect.x1(), rect.y2(), rect.width(), 1);
|
||||
rd.underline_rects.push(rect);
|
||||
}
|
||||
let tt = &*child.title_tex.borrow();
|
||||
for (scale, tex) in tt {
|
||||
if let Some(tex) = tex.texture() {
|
||||
let titles = rd.titles.get_or_default_mut(*scale);
|
||||
titles.push(ContainerTitle { rect, tex })
|
||||
}
|
||||
}
|
||||
}
|
||||
if mono && (!floating_titles || gap == 0) {
|
||||
rd.underline_rects
|
||||
.push(Rect::new_sized_saturating(0, th, cwidth, tuh));
|
||||
if self.toplevel_data.visible.get() {
|
||||
self.state.damage(Rect::new_sized_saturating(abs_x, abs_y, cwidth, cheight));
|
||||
}
|
||||
if gap == 0 && th > 0 {
|
||||
rd.underline_rects
|
||||
.push(Rect::new_sized_saturating(0, 0, cwidth, tuh));
|
||||
}
|
||||
if title_bw > 0 {
|
||||
let extend = |r: Rect| {
|
||||
let x1 = if r.x1() == 0 { -title_bw } else { r.x1() };
|
||||
let x2 = if r.x2() == cwidth { r.x2() + title_bw } else { r.x2() };
|
||||
Rect::new_sized_saturating(x1, r.y1(), x2 - x1, r.height())
|
||||
};
|
||||
for r in &mut rd.title_rects {
|
||||
*r = extend(*r);
|
||||
}
|
||||
for r in &mut rd.active_title_rects {
|
||||
*r = extend(*r);
|
||||
}
|
||||
for r in &mut rd.attention_title_rects {
|
||||
*r = extend(*r);
|
||||
}
|
||||
if let Some(r) = &mut rd.last_active_rect {
|
||||
*r = extend(*r);
|
||||
}
|
||||
for r in &mut rd.underline_rects {
|
||||
*r = extend(*r);
|
||||
}
|
||||
}
|
||||
if self.toplevel_data.visible.get() && (mono || split == ContainerSplit::Horizontal) {
|
||||
self.state
|
||||
.damage(Rect::new_sized_saturating(abs_x - title_bw, abs_y, cwidth + 2 * title_bw, tpuh));
|
||||
}
|
||||
rd.titles.remove_if(|_, v| v.is_empty());
|
||||
}
|
||||
|
||||
fn activate_child(self: &Rc<Self>, child: &NodeRef<ContainerChild>) {
|
||||
|
|
@ -1081,7 +767,6 @@ impl ContainerNode {
|
|||
self.mono_child.set(child);
|
||||
// log::info!("set_mono");
|
||||
self.schedule_layout();
|
||||
self.update_title();
|
||||
}
|
||||
|
||||
pub fn set_split(self: &Rc<Self>, split: ContainerSplit) {
|
||||
|
|
@ -1089,7 +774,6 @@ impl ContainerNode {
|
|||
self.update_content_size();
|
||||
// log::info!("set_split");
|
||||
self.schedule_layout();
|
||||
self.update_title();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1279,20 +963,6 @@ impl ContainerNode {
|
|||
}
|
||||
}
|
||||
|
||||
fn update_child_title(self: &Rc<Self>, child: &ContainerChild, title: &str) {
|
||||
{
|
||||
let mut ct = child.title.borrow_mut();
|
||||
if ct.deref() == title {
|
||||
return;
|
||||
}
|
||||
ct.clear();
|
||||
ct.push_str(title);
|
||||
}
|
||||
self.update_title();
|
||||
// log::info!("node_child_title_changed");
|
||||
self.schedule_render_titles();
|
||||
}
|
||||
|
||||
fn update_child_active(
|
||||
self: &Rc<Self>,
|
||||
node: &NodeRef<ContainerChild>,
|
||||
|
|
@ -1307,7 +977,6 @@ impl ContainerNode {
|
|||
.set(Some(self.focus_history.add_last(node.clone())));
|
||||
}
|
||||
// log::info!("node_child_active_changed");
|
||||
self.schedule_render_titles();
|
||||
self.schedule_compute_render_positions();
|
||||
if self.state.theme.sizes.gap.get() != 0 && self.toplevel_data.visible.get() {
|
||||
self.damage();
|
||||
|
|
@ -1338,7 +1007,6 @@ impl ContainerNode {
|
|||
self.mod_attention_requests(true);
|
||||
}
|
||||
}
|
||||
self.update_child_title(child, &data.title.borrow());
|
||||
self.update_child_active(child, data.active(), 1);
|
||||
{
|
||||
let pos = data.pos.get();
|
||||
|
|
@ -1362,19 +1030,11 @@ impl ContainerNode {
|
|||
}
|
||||
}
|
||||
|
||||
fn toggle_mono(self: &Rc<Self>) {
|
||||
if self.mono_child.is_some() {
|
||||
self.set_mono(None);
|
||||
} else if let Some(last) = self.focus_history.last() {
|
||||
self.set_mono(Some(&*last.node));
|
||||
}
|
||||
}
|
||||
|
||||
fn button(
|
||||
self: Rc<Self>,
|
||||
id: CursorType,
|
||||
seat: &Rc<WlSeatGlobal>,
|
||||
time_usec: u64,
|
||||
_seat: &Rc<WlSeatGlobal>,
|
||||
_time_usec: u64,
|
||||
pressed: bool,
|
||||
button: u32,
|
||||
) {
|
||||
|
|
@ -1383,20 +1043,6 @@ impl ContainerNode {
|
|||
Some(s) => s,
|
||||
_ => return,
|
||||
};
|
||||
if button == BTN_RIGHT && pressed {
|
||||
if self.mono_child.is_some() || self.split.get() == ContainerSplit::Horizontal {
|
||||
if seat_data.y < self.state.theme.title_height() {
|
||||
self.toggle_mono();
|
||||
}
|
||||
} else {
|
||||
for child in self.children.iter() {
|
||||
if child.title_rect.get().contains(seat_data.x, seat_data.y) {
|
||||
self.toggle_mono();
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if button != BTN_LEFT {
|
||||
return;
|
||||
}
|
||||
|
|
@ -1407,17 +1053,9 @@ impl ContainerNode {
|
|||
let (kind, child) = 'res: {
|
||||
let mono = self.mono_child.is_some();
|
||||
for child in self.children.iter() {
|
||||
let rect = child.title_rect.get();
|
||||
if rect.contains(seat_data.x, seat_data.y) {
|
||||
self.activate_child(&child);
|
||||
child
|
||||
.node
|
||||
.clone()
|
||||
.node_do_focus(seat, Direction::Unspecified);
|
||||
break 'res (SeatOpKind::Move, child);
|
||||
} else if !mono {
|
||||
if !mono {
|
||||
if self.split.get() == ContainerSplit::Horizontal {
|
||||
if seat_data.x < rect.x1() {
|
||||
if seat_data.x < child.body.get().x1() {
|
||||
break 'res (
|
||||
SeatOpKind::Resize {
|
||||
dist_left: seat_data.x
|
||||
|
|
@ -1428,7 +1066,7 @@ impl ContainerNode {
|
|||
);
|
||||
}
|
||||
} else {
|
||||
if seat_data.y < rect.y1() {
|
||||
if seat_data.y < child.body.get().y1() {
|
||||
break 'res (
|
||||
SeatOpKind::Resize {
|
||||
dist_left: seat_data.y
|
||||
|
|
@ -1443,20 +1081,9 @@ impl ContainerNode {
|
|||
}
|
||||
return;
|
||||
};
|
||||
if seat_data
|
||||
.double_click_state
|
||||
.click(&self.state, time_usec, seat_data.x, seat_data.y)
|
||||
&& kind == SeatOpKind::Move
|
||||
{
|
||||
drop(seat_datas);
|
||||
toplevel_set_floating(&self.state, child.node.clone(), true);
|
||||
return;
|
||||
}
|
||||
seat_data.op = Some(SeatOp {
|
||||
child,
|
||||
kind,
|
||||
x: seat_data.x,
|
||||
y: seat_data.y,
|
||||
})
|
||||
} else if !pressed {
|
||||
seat_data.op = None;
|
||||
|
|
@ -1464,65 +1091,6 @@ impl ContainerNode {
|
|||
}
|
||||
}
|
||||
|
||||
fn tile_drag_destination_mono_titles(
|
||||
self: &Rc<Self>,
|
||||
source: NodeId,
|
||||
abs_bounds: Rect,
|
||||
abs_x: i32,
|
||||
abs_y: i32,
|
||||
) -> Option<TileDragDestination> {
|
||||
let mut prev_is_source = false;
|
||||
let mut prev_center = 0;
|
||||
for child in self.children.iter() {
|
||||
if child.node.node_id() == source {
|
||||
prev_is_source = true;
|
||||
continue;
|
||||
}
|
||||
let rect = child.title_rect.get();
|
||||
let center = (rect.x1() + rect.x2()) / 2;
|
||||
if !prev_is_source {
|
||||
let rect = Rect::new(prev_center, 0, center, rect.height())?
|
||||
.move_(self.abs_x1.get(), self.abs_y1.get())
|
||||
.intersect(abs_bounds);
|
||||
if rect.contains(abs_x, abs_y) {
|
||||
return Some(TileDragDestination {
|
||||
highlight: rect,
|
||||
ty: TddType::Insert {
|
||||
container: self.clone(),
|
||||
neighbor: child.node.clone(),
|
||||
before: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
prev_center = center;
|
||||
prev_is_source = false;
|
||||
}
|
||||
if prev_is_source {
|
||||
return None;
|
||||
}
|
||||
let last = self.children.last()?;
|
||||
let rect = Rect::new(
|
||||
prev_center,
|
||||
0,
|
||||
self.width.get(),
|
||||
self.state.theme.title_height(),
|
||||
)?
|
||||
.move_(self.abs_x1.get(), self.abs_y1.get())
|
||||
.intersect(abs_bounds);
|
||||
if rect.contains(abs_x, abs_y) {
|
||||
return Some(TileDragDestination {
|
||||
highlight: rect,
|
||||
ty: TddType::Insert {
|
||||
container: self.clone(),
|
||||
neighbor: last.node.clone(),
|
||||
before: false,
|
||||
},
|
||||
});
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn tile_drag_destination_mono(
|
||||
self: &Rc<Self>,
|
||||
mc: &ContainerChild,
|
||||
|
|
@ -1531,10 +1099,6 @@ impl ContainerNode {
|
|||
abs_x: i32,
|
||||
abs_y: i32,
|
||||
) -> Option<TileDragDestination> {
|
||||
let th = self.state.theme.title_height();
|
||||
if abs_y < self.abs_y1.get() + th {
|
||||
return self.tile_drag_destination_mono_titles(source, abs_bounds, abs_x, abs_y);
|
||||
}
|
||||
let body = self.mono_body.get();
|
||||
let mut bounds = body
|
||||
.move_(self.abs_x1.get(), self.abs_y1.get())
|
||||
|
|
@ -1696,13 +1260,10 @@ impl ContainerNode {
|
|||
struct SeatOp {
|
||||
child: NodeRef<ContainerChild>,
|
||||
kind: SeatOpKind,
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
enum SeatOpKind {
|
||||
Move,
|
||||
Resize { dist_left: i32, dist_right: i32 },
|
||||
}
|
||||
|
||||
|
|
@ -1724,17 +1285,6 @@ pub async fn container_render_positions(state: Rc<State>) {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn container_render_titles(state: Rc<State>) {
|
||||
loop {
|
||||
let container = state.pending_container_render_title.pop().await;
|
||||
if container.render_titles_scheduled.get() {
|
||||
container.render_titles_scheduled.set(false);
|
||||
container.render_titles().triggered().await;
|
||||
container.compute_title_data();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Node for ContainerNode {
|
||||
fn node_id(&self) -> NodeId {
|
||||
self.id.into()
|
||||
|
|
@ -1779,10 +1329,8 @@ impl Node for ContainerNode {
|
|||
self.toplevel_data.node_layer()
|
||||
}
|
||||
|
||||
fn node_child_title_changed(self: Rc<Self>, child: &dyn Node, title: &str) {
|
||||
if let Some(child) = self.child_nodes.borrow().get(&child.node_id()) {
|
||||
self.update_child_title(child, title);
|
||||
}
|
||||
fn node_child_title_changed(self: Rc<Self>, _child: &dyn Node, _title: &str) {
|
||||
// Titlebars removed; no title tracking needed
|
||||
}
|
||||
|
||||
fn node_do_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, direction: Direction) {
|
||||
|
|
@ -1885,41 +1433,8 @@ impl Node for ContainerNode {
|
|||
self.button(id, seat, time_usec, state == ButtonState::Pressed, button);
|
||||
}
|
||||
|
||||
fn node_on_axis_event(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, event: &PendingScroll) {
|
||||
let mut seat_datas = self.cursors.borrow_mut();
|
||||
let id = CursorType::Seat(seat.id());
|
||||
let seat_data = match seat_datas.get_mut(&id) {
|
||||
Some(s) => s,
|
||||
_ => return,
|
||||
};
|
||||
if seat_data.y > self.state.theme.title_height() {
|
||||
return;
|
||||
}
|
||||
let cur_mc = match self.mono_child.get() {
|
||||
Some(mc) => mc,
|
||||
_ => return,
|
||||
};
|
||||
let discrete = match self.scroller.handle(event) {
|
||||
Some(d) => d,
|
||||
_ => return,
|
||||
};
|
||||
let mut new_mc = cur_mc.clone();
|
||||
for _ in 0..discrete.abs() {
|
||||
let new = if discrete < 0 {
|
||||
new_mc.prev()
|
||||
} else {
|
||||
new_mc.next()
|
||||
};
|
||||
new_mc = match new {
|
||||
Some(n) => n,
|
||||
None => break,
|
||||
};
|
||||
}
|
||||
self.activate_child(&new_mc);
|
||||
new_mc
|
||||
.node
|
||||
.clone()
|
||||
.node_do_focus(seat, Direction::Unspecified);
|
||||
fn node_on_axis_event(self: Rc<Self>, _seat: &Rc<WlSeatGlobal>, _event: &PendingScroll) {
|
||||
// Scroll-to-switch-tabs was a title bar feature; no-op without titles
|
||||
}
|
||||
|
||||
fn node_on_leave(&self, seat: &WlSeatGlobal) {
|
||||
|
|
@ -2051,9 +1566,6 @@ impl ContainingNode for ContainerNode {
|
|||
|
||||
content: Default::default(),
|
||||
factor: Cell::new(node.factor.get()),
|
||||
title: Default::default(),
|
||||
title_tex: Default::default(),
|
||||
title_rect: Cell::new(node.title_rect.get()),
|
||||
focus_history: Cell::new(None),
|
||||
attention_requested: Cell::new(false),
|
||||
border_color_is_focused: Default::default(),
|
||||
|
|
@ -2132,7 +1644,6 @@ impl ContainingNode for ContainerNode {
|
|||
}
|
||||
}
|
||||
self.sum_factors.set(sum);
|
||||
self.update_title();
|
||||
// log::info!("cnode_remove_child2");
|
||||
self.schedule_layout();
|
||||
self.cancel_seat_ops();
|
||||
|
|
@ -2186,9 +1697,8 @@ impl ContainingNode for ContainerNode {
|
|||
let Some(parent) = self.toplevel_data.parent.get() else {
|
||||
return;
|
||||
};
|
||||
let tpuh = self.state.theme.title_plus_underline_height();
|
||||
if self.mono_child.is_some() {
|
||||
parent.cnode_set_child_position(&*self, x, y - tpuh);
|
||||
parent.cnode_set_child_position(&*self, x, y);
|
||||
} else {
|
||||
let children = self.child_nodes.borrow();
|
||||
let Some(child) = children.get(&child.node_id()) else {
|
||||
|
|
@ -2209,7 +1719,6 @@ impl ContainingNode for ContainerNode {
|
|||
new_y2: Option<i32>,
|
||||
) {
|
||||
let theme = &self.state.theme;
|
||||
let tpuh = theme.title_plus_underline_height();
|
||||
let bw = theme.sizes.border_width.get();
|
||||
let mut left_outside = false;
|
||||
let mut right_outside = false;
|
||||
|
|
@ -2251,7 +1760,7 @@ impl ContainingNode for ContainerNode {
|
|||
}
|
||||
let (new_delta, between) = match split {
|
||||
ContainerSplit::Horizontal => (self.abs_x1.get(), bw),
|
||||
ContainerSplit::Vertical => (self.abs_y1.get(), bw + tpuh),
|
||||
ContainerSplit::Vertical => (self.abs_y1.get(), bw),
|
||||
};
|
||||
let new_i1 = new_i1.map(|v| v - new_delta);
|
||||
let new_i2 = new_i2.map(|v| v - new_delta);
|
||||
|
|
@ -2319,10 +1828,10 @@ impl ContainingNode for ContainerNode {
|
|||
x2 = new_x2.map(|v| v.max(x1.unwrap_or(pos.x1())));
|
||||
}
|
||||
if top_outside {
|
||||
y1 = new_y1.map(|v| (v - tpuh).min(pos.y2() - tpuh));
|
||||
y1 = new_y1.map(|v| v.min(pos.y2()));
|
||||
}
|
||||
if bottom_outside {
|
||||
y2 = new_y2.map(|v| v.max(y1.unwrap_or(pos.y1()) + tpuh));
|
||||
y2 = new_y2.map(|v| v.max(y1.unwrap_or(pos.y1())));
|
||||
}
|
||||
if ((x1.is_some() && x1 != Some(pos.x1()))
|
||||
|| (x2.is_some() && x2 != Some(pos.x2()))
|
||||
|
|
|
|||
|
|
@ -10,27 +10,22 @@ use {
|
|||
},
|
||||
rect::Rect,
|
||||
renderer::Renderer,
|
||||
scale::Scale,
|
||||
state::State,
|
||||
text::TextTexture,
|
||||
tree::{
|
||||
ContainingNode, Direction, FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId,
|
||||
NodeLayerLink, NodeLocation, OutputNode, PinnedNode, StackedNode, TileDragDestination,
|
||||
ToplevelNode, WorkspaceNode, toplevel_set_floating, walker::NodeVisitor,
|
||||
},
|
||||
utils::{
|
||||
asyncevent::AsyncEvent, clonecell::CloneCell, double_click_state::DoubleClickState,
|
||||
errorfmt::ErrorFmt, event_listener::LazyEventSource, linkedlist::LinkedNode,
|
||||
on_drop_event::OnDropEvent, smallmap::SmallMapMut,
|
||||
clonecell::CloneCell, double_click_state::DoubleClickState,
|
||||
event_listener::LazyEventSource, linkedlist::LinkedNode,
|
||||
},
|
||||
},
|
||||
ahash::AHashMap,
|
||||
arrayvec::ArrayVec,
|
||||
std::{
|
||||
cell::{Cell, RefCell},
|
||||
fmt::{Debug, Formatter},
|
||||
mem,
|
||||
ops::Deref,
|
||||
rc::Rc,
|
||||
},
|
||||
};
|
||||
|
|
@ -50,10 +45,6 @@ pub struct FloatNode {
|
|||
pub active: Cell<bool>,
|
||||
pub seat_state: NodeSeatState,
|
||||
pub layout_scheduled: Cell<bool>,
|
||||
pub render_titles_scheduled: Cell<bool>,
|
||||
pub title_rect: Cell<Rect>,
|
||||
pub title: RefCell<String>,
|
||||
pub title_textures: RefCell<SmallMapMut<Scale, TextTexture, 2>>,
|
||||
cursors: RefCell<AHashMap<CursorType, CursorState>>,
|
||||
pub attention_requested: Cell<bool>,
|
||||
pub layout_complete: Rc<LazyEventSource>,
|
||||
|
|
@ -99,17 +90,6 @@ pub async fn float_layout(state: Rc<State>) {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn float_titles(state: Rc<State>) {
|
||||
loop {
|
||||
let node = state.pending_float_titles.pop().await;
|
||||
if node.render_titles_scheduled.get() {
|
||||
node.render_titles_scheduled.set(false);
|
||||
node.render_title_phase1().triggered().await;
|
||||
node.render_title_phase2();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FloatNode {
|
||||
pub fn new(
|
||||
state: &Rc<State>,
|
||||
|
|
@ -131,10 +111,6 @@ impl FloatNode {
|
|||
active: Cell::new(false),
|
||||
seat_state: Default::default(),
|
||||
layout_scheduled: Cell::new(false),
|
||||
render_titles_scheduled: Cell::new(false),
|
||||
title_rect: Default::default(),
|
||||
title: Default::default(),
|
||||
title_textures: Default::default(),
|
||||
cursors: Default::default(),
|
||||
attention_requested: Cell::new(false),
|
||||
layout_complete: state.post_layout_event_sources.create_source(),
|
||||
|
|
@ -162,7 +138,7 @@ impl FloatNode {
|
|||
}
|
||||
|
||||
pub fn on_colors_changed(self: &Rc<Self>) {
|
||||
self.schedule_render_titles();
|
||||
// No title rendering needed
|
||||
}
|
||||
|
||||
pub fn schedule_layout(self: &Rc<Self>) {
|
||||
|
|
@ -179,95 +155,17 @@ impl FloatNode {
|
|||
let pos = self.position.get();
|
||||
let theme = &self.state.theme;
|
||||
let bw = theme.sizes.border_width.get();
|
||||
let th = theme.title_height();
|
||||
let tpuh = theme.title_plus_underline_height();
|
||||
let cpos = Rect::new_sized_saturating(
|
||||
pos.x1() + bw,
|
||||
pos.y1() + bw + tpuh,
|
||||
pos.y1() + bw,
|
||||
pos.width() - 2 * bw,
|
||||
pos.height() - 2 * bw - tpuh,
|
||||
pos.height() - 2 * bw,
|
||||
);
|
||||
let tr = Rect::new_sized_saturating(bw, bw, pos.width() - 2 * bw, th);
|
||||
child.clone().tl_change_extents(&cpos);
|
||||
self.title_rect.set(tr);
|
||||
self.layout_scheduled.set(false);
|
||||
self.schedule_render_titles();
|
||||
self.layout_complete.trigger();
|
||||
}
|
||||
|
||||
pub fn schedule_render_titles(self: &Rc<Self>) {
|
||||
if !self.render_titles_scheduled.replace(true) {
|
||||
self.state.pending_float_titles.push(self.clone());
|
||||
}
|
||||
}
|
||||
|
||||
fn render_title_phase1(&self) -> Rc<AsyncEvent> {
|
||||
let on_completed = Rc::new(OnDropEvent::default());
|
||||
let theme = &self.state.theme;
|
||||
let tc = match self.active.get() {
|
||||
true => theme.colors.focused_title_text.get(),
|
||||
false => theme.colors.unfocused_title_text.get(),
|
||||
};
|
||||
let font = theme.title_font();
|
||||
let title = self.title.borrow_mut();
|
||||
let ctx = match self.state.render_ctx.get() {
|
||||
Some(c) => c,
|
||||
_ => return on_completed.event(),
|
||||
};
|
||||
let scales = self.state.scales.lock();
|
||||
let tr = self.title_rect.get();
|
||||
let tt = &mut *self.title_textures.borrow_mut();
|
||||
for (scale, _) in scales.iter() {
|
||||
let tex = tt.get_or_insert_with(*scale, || TextTexture::new(&self.state, &ctx));
|
||||
let mut th = tr.height();
|
||||
let mut scalef = None;
|
||||
let mut width = tr.width();
|
||||
if self.state.show_pin_icon.get() || self.pinned_link.borrow().is_some() {
|
||||
width = (width - th).max(0);
|
||||
}
|
||||
if *scale != 1 {
|
||||
let scale = scale.to_f64();
|
||||
th = (th as f64 * scale).round() as _;
|
||||
width = (width as f64 * scale).round() as _;
|
||||
scalef = Some(scale);
|
||||
}
|
||||
tex.schedule_render(
|
||||
on_completed.clone(),
|
||||
1,
|
||||
None,
|
||||
width,
|
||||
th,
|
||||
1,
|
||||
&font,
|
||||
&title,
|
||||
tc,
|
||||
true,
|
||||
false,
|
||||
scalef,
|
||||
);
|
||||
}
|
||||
on_completed.event()
|
||||
}
|
||||
|
||||
fn render_title_phase2(&self) {
|
||||
let theme = &self.state.theme;
|
||||
let th = theme.title_height();
|
||||
let bw = theme.sizes.border_width.get();
|
||||
let title = self.title.borrow();
|
||||
let tt = &*self.title_textures.borrow();
|
||||
for (_, tt) in tt {
|
||||
if let Err(e) = tt.flip() {
|
||||
log::error!("Could not render title {}: {}", title, ErrorFmt(e));
|
||||
}
|
||||
}
|
||||
let pos = self.position.get();
|
||||
if self.visible.get() && pos.width() >= 2 * bw {
|
||||
let tr =
|
||||
Rect::new_sized_saturating(pos.x1() + bw, pos.y1() + bw, pos.width() - 2 * bw, th);
|
||||
self.state.damage(tr);
|
||||
}
|
||||
}
|
||||
|
||||
fn pointer_move(
|
||||
self: &Rc<Self>,
|
||||
id: CursorType,
|
||||
|
|
@ -280,7 +178,6 @@ impl FloatNode {
|
|||
let y = y.round_down();
|
||||
let theme = &self.state.theme;
|
||||
let bw = theme.sizes.border_width.get();
|
||||
let tpuh = theme.title_plus_underline_height();
|
||||
let mut seats = self.cursors.borrow_mut();
|
||||
let seat_state = seats.entry(id).or_insert_with(|| CursorState {
|
||||
cursor: KnownCursor::Default,
|
||||
|
|
@ -316,7 +213,7 @@ impl FloatNode {
|
|||
}
|
||||
OpType::ResizeTop => {
|
||||
y1 += y - seat_state.dist_ver;
|
||||
y1 = y1.min(y2 - 2 * bw - tpuh);
|
||||
y1 = y1.min(y2 - 2 * bw);
|
||||
}
|
||||
OpType::ResizeRight => {
|
||||
x2 += x - pos.width() + seat_state.dist_hor;
|
||||
|
|
@ -324,31 +221,31 @@ impl FloatNode {
|
|||
}
|
||||
OpType::ResizeBottom => {
|
||||
y2 += y - pos.height() + seat_state.dist_ver;
|
||||
y2 = y2.max(y1 + 2 * bw + tpuh);
|
||||
y2 = y2.max(y1 + 2 * bw);
|
||||
}
|
||||
OpType::ResizeTopLeft => {
|
||||
x1 += x - seat_state.dist_hor;
|
||||
y1 += y - seat_state.dist_ver;
|
||||
x1 = x1.min(x2 - 2 * bw);
|
||||
y1 = y1.min(y2 - 2 * bw - tpuh);
|
||||
y1 = y1.min(y2 - 2 * bw);
|
||||
}
|
||||
OpType::ResizeTopRight => {
|
||||
x2 += x - pos.width() + seat_state.dist_hor;
|
||||
y1 += y - seat_state.dist_ver;
|
||||
x2 = x2.max(x1 + 2 * bw);
|
||||
y1 = y1.min(y2 - 2 * bw - tpuh);
|
||||
y1 = y1.min(y2 - 2 * bw);
|
||||
}
|
||||
OpType::ResizeBottomLeft => {
|
||||
x1 += x - seat_state.dist_hor;
|
||||
y2 += y - pos.height() + seat_state.dist_ver;
|
||||
x1 = x1.min(x2 - 2 * bw);
|
||||
y2 = y2.max(y1 + 2 * bw + tpuh);
|
||||
y2 = y2.max(y1 + 2 * bw);
|
||||
}
|
||||
OpType::ResizeBottomRight => {
|
||||
x2 += x - pos.width() + seat_state.dist_hor;
|
||||
y2 += y - pos.height() + seat_state.dist_ver;
|
||||
x2 = x2.max(x1 + 2 * bw);
|
||||
y2 = y2.max(y1 + 2 * bw + tpuh);
|
||||
y2 = y2.max(y1 + 2 * bw);
|
||||
}
|
||||
}
|
||||
let new_pos = Rect::new_saturating(x1, y1, x2, y2);
|
||||
|
|
@ -474,18 +371,12 @@ impl FloatNode {
|
|||
self.schedule_layout();
|
||||
}
|
||||
|
||||
fn update_child_title(self: &Rc<Self>, title: &str) {
|
||||
let mut t = self.title.borrow_mut();
|
||||
if t.deref() != title {
|
||||
t.clear();
|
||||
t.push_str(title);
|
||||
self.schedule_render_titles();
|
||||
}
|
||||
fn update_child_title(self: &Rc<Self>, _title: &str) {
|
||||
// No title rendering
|
||||
}
|
||||
|
||||
fn update_child_active(self: &Rc<Self>, active: bool) {
|
||||
if self.active.replace(active) != active {
|
||||
self.schedule_render_titles();
|
||||
if active {
|
||||
self.restack();
|
||||
}
|
||||
|
|
@ -542,7 +433,6 @@ impl FloatNode {
|
|||
if let Some(tl) = self.child.get() {
|
||||
tl.tl_data().pinned.set(pl.is_some());
|
||||
}
|
||||
self.schedule_render_titles();
|
||||
}
|
||||
|
||||
fn button(
|
||||
|
|
@ -558,34 +448,6 @@ impl FloatNode {
|
|||
Some(s) => s,
|
||||
_ => return,
|
||||
};
|
||||
let bw = self.state.theme.sizes.border_width.get();
|
||||
let th = self.state.theme.title_height();
|
||||
let mut is_icon_press = false;
|
||||
if pressed && cursor_data.x >= bw && cursor_data.y >= bw && cursor_data.y < bw + th {
|
||||
enum FloatIcon {
|
||||
Pin,
|
||||
}
|
||||
let mut icons = ArrayVec::<FloatIcon, 1>::new();
|
||||
if self.state.show_pin_icon.get() || self.pinned_link.borrow().is_some() {
|
||||
icons.push(FloatIcon::Pin);
|
||||
}
|
||||
let mut x2 = bw + th;
|
||||
let icon = 'icon: {
|
||||
for icon in icons {
|
||||
if cursor_data.x < x2 {
|
||||
break 'icon Some(icon);
|
||||
}
|
||||
x2 += th;
|
||||
}
|
||||
None
|
||||
};
|
||||
if let Some(icon) = icon {
|
||||
is_icon_press = true;
|
||||
match icon {
|
||||
FloatIcon::Pin => self.toggle_pinned(),
|
||||
}
|
||||
}
|
||||
}
|
||||
if !cursor_data.op_active {
|
||||
if !pressed {
|
||||
return;
|
||||
|
|
@ -601,7 +463,6 @@ impl FloatNode {
|
|||
cursor_data.x,
|
||||
cursor_data.y,
|
||||
) && cursor_data.op_type == OpType::Move
|
||||
&& !is_icon_press
|
||||
&& let Some(tl) = self.child.get()
|
||||
{
|
||||
drop(cursors);
|
||||
|
|
@ -653,11 +514,10 @@ impl FloatNode {
|
|||
let child = self.child.get()?;
|
||||
let theme = &self.state.theme.sizes;
|
||||
let bw = theme.border_width.get();
|
||||
let tpuh = self.state.theme.title_plus_underline_height();
|
||||
let pos = self.position.get();
|
||||
let body = Rect::new(
|
||||
pos.x1() + bw,
|
||||
pos.y1() + bw + tpuh,
|
||||
pos.y1() + bw,
|
||||
pos.x2() - bw,
|
||||
pos.y2() - bw,
|
||||
)?;
|
||||
|
|
@ -713,8 +573,8 @@ impl Node for FloatNode {
|
|||
NodeLayerLink::Stacked(l)
|
||||
}
|
||||
|
||||
fn node_child_title_changed(self: Rc<Self>, _child: &dyn Node, title: &str) {
|
||||
self.update_child_title(title);
|
||||
fn node_child_title_changed(self: Rc<Self>, _child: &dyn Node, _title: &str) {
|
||||
// No title rendering
|
||||
}
|
||||
|
||||
fn node_accepts_focus(&self) -> bool {
|
||||
|
|
@ -738,13 +598,12 @@ impl Node for FloatNode {
|
|||
usecase: FindTreeUsecase,
|
||||
) -> FindTreeResult {
|
||||
let theme = &self.state.theme;
|
||||
let tpuh = theme.title_plus_underline_height();
|
||||
let bw = theme.sizes.border_width.get();
|
||||
let pos = self.position.get();
|
||||
if x < bw || x >= pos.width() - bw {
|
||||
return FindTreeResult::AcceptsInput;
|
||||
}
|
||||
if y < bw + tpuh || y >= pos.height() - bw {
|
||||
if y < bw || y >= pos.height() - bw {
|
||||
return FindTreeResult::AcceptsInput;
|
||||
}
|
||||
let child = match self.child.get() {
|
||||
|
|
@ -752,7 +611,7 @@ impl Node for FloatNode {
|
|||
_ => return FindTreeResult::Other,
|
||||
};
|
||||
let x = x - bw;
|
||||
let y = y - bw - tpuh;
|
||||
let y = y - bw;
|
||||
tree.push(FoundNode {
|
||||
node: child.clone(),
|
||||
x,
|
||||
|
|
@ -934,9 +793,8 @@ impl ContainingNode for FloatNode {
|
|||
|
||||
fn cnode_set_child_position(self: Rc<Self>, _child: &dyn Node, x: i32, y: i32) {
|
||||
let theme = &self.state.theme;
|
||||
let tpuh = theme.title_plus_underline_height();
|
||||
let bw = theme.sizes.border_width.get();
|
||||
let (x, y) = (x - bw, y - tpuh - bw);
|
||||
let (x, y) = (x - bw, y - bw);
|
||||
let pos = self.position.get();
|
||||
if pos.position() != (x, y) {
|
||||
let new_pos = pos.at_point(x, y);
|
||||
|
|
@ -956,7 +814,6 @@ impl ContainingNode for FloatNode {
|
|||
new_y2: Option<i32>,
|
||||
) {
|
||||
let theme = &self.state.theme;
|
||||
let tpuh = theme.title_plus_underline_height();
|
||||
let bw = theme.sizes.border_width.get();
|
||||
let pos = self.position.get();
|
||||
let mut x1 = pos.x1();
|
||||
|
|
@ -970,10 +827,10 @@ impl ContainingNode for FloatNode {
|
|||
x2 = (v + bw).max(x1 + bw + bw);
|
||||
}
|
||||
if let Some(v) = new_y1 {
|
||||
y1 = (v - tpuh - bw).min(y2 - bw - tpuh - bw);
|
||||
y1 = (v - bw).min(y2 - bw - bw);
|
||||
}
|
||||
if let Some(v) = new_y2 {
|
||||
y2 = (v + bw).max(y1 + bw + tpuh + bw);
|
||||
y2 = (v + bw).max(y1 + bw + bw);
|
||||
}
|
||||
let new_pos = Rect::new_saturating(x1, y1, x2, y2);
|
||||
if new_pos != pos {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue