renderer: add support for floating-titlebars (#4)
Reviewed-on: https://git.kosslan.dev/wry/jay/pulls/4
This commit is contained in:
parent
4d803360dd
commit
6dba659978
13 changed files with 316 additions and 158 deletions
|
|
@ -1057,6 +1057,16 @@ impl ConfigClient {
|
||||||
show
|
show
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_floating_titles(&self, floating: bool) {
|
||||||
|
self.send(&ClientMessage::SetFloatingTitles { floating });
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_floating_titles(&self) -> bool {
|
||||||
|
let res = self.send_with_response(&ClientMessage::GetFloatingTitles);
|
||||||
|
get_response!(res, false, GetFloatingTitles { floating });
|
||||||
|
floating
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_bar_position(&self, position: BarPosition) {
|
pub fn set_bar_position(&self, position: BarPosition) {
|
||||||
self.send(&ClientMessage::SetBarPosition { position });
|
self.send(&ClientMessage::SetBarPosition { position });
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -812,6 +812,10 @@ pub enum ClientMessage<'a> {
|
||||||
show: bool,
|
show: bool,
|
||||||
},
|
},
|
||||||
GetShowTitles,
|
GetShowTitles,
|
||||||
|
SetFloatingTitles {
|
||||||
|
floating: bool,
|
||||||
|
},
|
||||||
|
GetFloatingTitles,
|
||||||
GetWorkspaceConnector {
|
GetWorkspaceConnector {
|
||||||
workspace: Workspace,
|
workspace: Workspace,
|
||||||
},
|
},
|
||||||
|
|
@ -1114,6 +1118,9 @@ pub enum Response {
|
||||||
GetShowTitles {
|
GetShowTitles {
|
||||||
show: bool,
|
show: bool,
|
||||||
},
|
},
|
||||||
|
GetFloatingTitles {
|
||||||
|
floating: bool,
|
||||||
|
},
|
||||||
GetWorkspaceConnector {
|
GetWorkspaceConnector {
|
||||||
connector: Connector,
|
connector: Connector,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -361,6 +361,27 @@ pub fn toggle_show_titles() {
|
||||||
get.set_show_titles(!get.get_show_titles());
|
get.set_show_titles(!get.get_show_titles());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets whether title bars float above window content instead of being attached.
|
||||||
|
///
|
||||||
|
/// When enabled, title bars are rendered on top of window content without consuming
|
||||||
|
/// layout space. Window borders do not extend to include the title bar area.
|
||||||
|
///
|
||||||
|
/// The default is `false`.
|
||||||
|
pub fn set_floating_titles(floating: bool) {
|
||||||
|
get!().set_floating_titles(floating)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns whether title bars float above window content.
|
||||||
|
pub fn get_floating_titles() -> bool {
|
||||||
|
get!(false).get_floating_titles()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Toggles whether title bars float above window content.
|
||||||
|
pub fn toggle_floating_titles() {
|
||||||
|
let get = get!();
|
||||||
|
get.set_floating_titles(!get.get_floating_titles());
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets a callback to run when this config is unloaded.
|
/// Sets a callback to run when this config is unloaded.
|
||||||
///
|
///
|
||||||
/// Only one callback can be set at a time. If another callback is already set, it will be
|
/// Only one callback can be set at a time. If another callback is already set, it will be
|
||||||
|
|
|
||||||
|
|
@ -370,5 +370,9 @@ pub mod sized {
|
||||||
///
|
///
|
||||||
/// Default: 0
|
/// Default: 0
|
||||||
const 05 => GAP,
|
const 05 => GAP,
|
||||||
|
/// The gap between the titlebar and the window content in pixels.
|
||||||
|
///
|
||||||
|
/// Default: 0
|
||||||
|
const 06 => TITLE_GAP,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1421,6 +1421,16 @@ impl ConfigProxyHandler {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_set_floating_titles(&self, floating: bool) {
|
||||||
|
self.state.set_floating_titles(floating);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_get_floating_titles(&self) {
|
||||||
|
self.respond(Response::GetFloatingTitles {
|
||||||
|
floating: self.state.theme.floating_titles.get(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_set_bar_position(&self, position: BarPosition) -> Result<(), CphError> {
|
fn handle_set_bar_position(&self, position: BarPosition) -> Result<(), CphError> {
|
||||||
let Ok(position) = position.try_into() else {
|
let Ok(position) = position.try_into() else {
|
||||||
return Err(CphError::UnknownBarPosition(position));
|
return Err(CphError::UnknownBarPosition(position));
|
||||||
|
|
@ -2441,6 +2451,7 @@ impl ConfigProxyHandler {
|
||||||
BAR_HEIGHT => ThemeSized::bar_height,
|
BAR_HEIGHT => ThemeSized::bar_height,
|
||||||
BAR_SEPARATOR_WIDTH => ThemeSized::bar_separator_width,
|
BAR_SEPARATOR_WIDTH => ThemeSized::bar_separator_width,
|
||||||
GAP => ThemeSized::gap,
|
GAP => ThemeSized::gap,
|
||||||
|
TITLE_GAP => ThemeSized::title_gap,
|
||||||
_ => return Err(CphError::UnknownSized(sized.0)),
|
_ => return Err(CphError::UnknownSized(sized.0)),
|
||||||
};
|
};
|
||||||
Ok(sized)
|
Ok(sized)
|
||||||
|
|
@ -3291,6 +3302,10 @@ impl ConfigProxyHandler {
|
||||||
ClientMessage::GetShowBar => self.handle_get_show_bar(),
|
ClientMessage::GetShowBar => self.handle_get_show_bar(),
|
||||||
ClientMessage::SetShowTitles { show } => self.handle_set_show_titles(show),
|
ClientMessage::SetShowTitles { show } => self.handle_set_show_titles(show),
|
||||||
ClientMessage::GetShowTitles => self.handle_get_show_titles(),
|
ClientMessage::GetShowTitles => self.handle_get_show_titles(),
|
||||||
|
ClientMessage::SetFloatingTitles { floating } => {
|
||||||
|
self.handle_set_floating_titles(floating)
|
||||||
|
}
|
||||||
|
ClientMessage::GetFloatingTitles => self.handle_get_floating_titles(),
|
||||||
ClientMessage::SetBarPosition { position } => self
|
ClientMessage::SetBarPosition { position } => self
|
||||||
.handle_set_bar_position(position)
|
.handle_set_bar_position(position)
|
||||||
.wrn("set_bar_position")?,
|
.wrn("set_bar_position")?,
|
||||||
|
|
|
||||||
235
src/renderer.rs
235
src/renderer.rs
|
|
@ -277,65 +277,70 @@ impl Renderer<'_> {
|
||||||
self.render_tl_aux(placeholder.tl_data(), bounds, true);
|
self.render_tl_aux(placeholder.tl_data(), bounds, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_container(&mut self, container: &ContainerNode, x: i32, y: i32) {
|
fn render_container_decorations(&mut self, container: &ContainerNode, x: i32, y: i32) {
|
||||||
{
|
let srgb_srgb = self.state.color_manager.srgb_gamma22();
|
||||||
let srgb_srgb = self.state.color_manager.srgb_gamma22();
|
let srgb = &srgb_srgb.linear;
|
||||||
let srgb = &srgb_srgb.linear;
|
let perceptual = RenderIntent::Perceptual;
|
||||||
let perceptual = RenderIntent::Perceptual;
|
let rd = container.render_data.borrow_mut();
|
||||||
let rd = container.render_data.borrow_mut();
|
let c = self.state.theme.colors.unfocused_title_background.get();
|
||||||
let c = self.state.theme.colors.unfocused_title_background.get();
|
self.base
|
||||||
|
.fill_boxes2(&rd.title_rects, &c, srgb, perceptual, x, y);
|
||||||
|
let c = self.state.theme.colors.focused_title_background.get();
|
||||||
|
self.base
|
||||||
|
.fill_boxes2(&rd.active_title_rects, &c, srgb, perceptual, x, y);
|
||||||
|
let c = self.state.theme.colors.attention_requested_background.get();
|
||||||
|
self.base
|
||||||
|
.fill_boxes2(&rd.attention_title_rects, &c, srgb, perceptual, x, y);
|
||||||
|
let c = self.state.theme.colors.separator.get();
|
||||||
|
self.base
|
||||||
|
.fill_boxes2(&rd.underline_rects, &c, srgb, perceptual, x, y);
|
||||||
|
let c = self.state.theme.colors.border.get();
|
||||||
|
self.base
|
||||||
|
.fill_boxes2(&rd.border_rects, &c, srgb, perceptual, x, y);
|
||||||
|
if let Some(lar) = &rd.last_active_rect {
|
||||||
|
let c = self
|
||||||
|
.state
|
||||||
|
.theme
|
||||||
|
.colors
|
||||||
|
.focused_inactive_title_background
|
||||||
|
.get();
|
||||||
self.base
|
self.base
|
||||||
.fill_boxes2(&rd.title_rects, &c, srgb, perceptual, x, y);
|
.fill_boxes2(std::slice::from_ref(lar), &c, srgb, perceptual, x, y);
|
||||||
let c = self.state.theme.colors.focused_title_background.get();
|
}
|
||||||
self.base
|
if let Some(titles) = rd.titles.get(&self.base.scale) {
|
||||||
.fill_boxes2(&rd.active_title_rects, &c, srgb, perceptual, x, y);
|
for title in titles {
|
||||||
let c = self.state.theme.colors.attention_requested_background.get();
|
let rect = title.rect.move_(x, y);
|
||||||
self.base
|
let bounds = self.base.scale_rect(rect);
|
||||||
.fill_boxes2(&rd.attention_title_rects, &c, srgb, perceptual, x, y);
|
let (x, y) = self.base.scale_point(rect.x1(), rect.y1());
|
||||||
let c = self.state.theme.colors.separator.get();
|
self.base.render_texture(
|
||||||
self.base
|
&title.tex,
|
||||||
.fill_boxes2(&rd.underline_rects, &c, srgb, perceptual, x, y);
|
None,
|
||||||
let c = self.state.theme.colors.border.get();
|
x,
|
||||||
self.base
|
y,
|
||||||
.fill_boxes2(&rd.border_rects, &c, srgb, perceptual, x, y);
|
None,
|
||||||
if let Some(lar) = &rd.last_active_rect {
|
None,
|
||||||
let c = self
|
self.base.scale,
|
||||||
.state
|
Some(&bounds),
|
||||||
.theme
|
None,
|
||||||
.colors
|
AcquireSync::None,
|
||||||
.focused_inactive_title_background
|
ReleaseSync::None,
|
||||||
.get();
|
false,
|
||||||
self.base
|
srgb_srgb,
|
||||||
.fill_boxes2(std::slice::from_ref(lar), &c, srgb, perceptual, x, y);
|
perceptual,
|
||||||
}
|
AlphaMode::PremultipliedElectrical,
|
||||||
if let Some(titles) = rd.titles.get(&self.base.scale) {
|
);
|
||||||
for title in titles {
|
|
||||||
let rect = title.rect.move_(x, y);
|
|
||||||
let bounds = self.base.scale_rect(rect);
|
|
||||||
let (x, y) = self.base.scale_point(rect.x1(), rect.y1());
|
|
||||||
self.base.render_texture(
|
|
||||||
&title.tex,
|
|
||||||
None,
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
self.base.scale,
|
|
||||||
Some(&bounds),
|
|
||||||
None,
|
|
||||||
AcquireSync::None,
|
|
||||||
ReleaseSync::None,
|
|
||||||
false,
|
|
||||||
srgb_srgb,
|
|
||||||
perceptual,
|
|
||||||
AlphaMode::PremultipliedElectrical,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render_container(&mut self, container: &ContainerNode, x: i32, y: i32) {
|
||||||
|
let floating = self.state.theme.floating_titles.get();
|
||||||
|
|
||||||
|
self.render_container_decorations(container, x, y);
|
||||||
|
|
||||||
if let Some(child) = container.mono_child.get() {
|
if let Some(child) = container.mono_child.get() {
|
||||||
let mb = container.mono_body.get();
|
let mb = container.mono_body.get();
|
||||||
if self.state.theme.sizes.gap.get() > 0 && !child.node.node_is_container() {
|
if self.state.theme.sizes.gap.get() != 0 {
|
||||||
let srgb_srgb = self.state.color_manager.srgb_gamma22();
|
let srgb_srgb = self.state.color_manager.srgb_gamma22();
|
||||||
let bw = self.state.theme.sizes.border_width.get();
|
let bw = self.state.theme.sizes.border_width.get();
|
||||||
let border_color = self.state.theme.colors.border.get();
|
let border_color = self.state.theme.colors.border.get();
|
||||||
|
|
@ -346,22 +351,48 @@ impl Renderer<'_> {
|
||||||
} else {
|
} else {
|
||||||
&border_color
|
&border_color
|
||||||
};
|
};
|
||||||
let full_h = mb.y2();
|
|
||||||
let full_w = mb.width();
|
let full_w = mb.width();
|
||||||
let frame_rects = [
|
let srgb = &srgb_srgb.linear;
|
||||||
Rect::new_sized_saturating(mb.x1() - bw, 0, bw, full_h),
|
let perceptual = RenderIntent::Perceptual;
|
||||||
Rect::new_sized_saturating(mb.x2(), 0, bw, full_h),
|
if floating {
|
||||||
Rect::new_sized_saturating(mb.x1() - bw, -bw, full_w + 2 * bw, bw),
|
if !child.node.node_is_container() {
|
||||||
Rect::new_sized_saturating(mb.x1() - bw, full_h, full_w + 2 * bw, bw),
|
let body_frame = [
|
||||||
];
|
Rect::new_sized_saturating(mb.x1() - bw, mb.y1(), bw, mb.y2() - mb.y1()),
|
||||||
self.base.fill_boxes2(
|
Rect::new_sized_saturating(mb.x2(), mb.y1(), bw, mb.y2() - mb.y1()),
|
||||||
&frame_rects,
|
Rect::new_sized_saturating(mb.x1() - bw, mb.y1() - bw, full_w + 2 * bw, bw),
|
||||||
c,
|
Rect::new_sized_saturating(mb.x1() - bw, mb.y2(), full_w + 2 * bw, bw),
|
||||||
&srgb_srgb.linear,
|
];
|
||||||
RenderIntent::Perceptual,
|
self.base.fill_boxes2(&body_frame, c, srgb, perceptual, x, y);
|
||||||
x,
|
}
|
||||||
y,
|
let th = self.state.theme.title_height();
|
||||||
);
|
if th > 0 {
|
||||||
|
for tab in container.children.iter() {
|
||||||
|
let tr = tab.title_rect.get();
|
||||||
|
let tc = if tab.active.get() {
|
||||||
|
&focused_border_color
|
||||||
|
} else {
|
||||||
|
&border_color
|
||||||
|
};
|
||||||
|
let tw = tr.width();
|
||||||
|
let tab_frame = [
|
||||||
|
Rect::new_sized_saturating(tr.x1() - bw, tr.y1() - bw, tw + 2 * bw, bw),
|
||||||
|
Rect::new_sized_saturating(tr.x1() - bw, tr.y1(), bw, th),
|
||||||
|
Rect::new_sized_saturating(tr.x2(), tr.y1(), bw, th),
|
||||||
|
Rect::new_sized_saturating(tr.x1() - bw, tr.y1() + th, tw + 2 * bw, bw),
|
||||||
|
];
|
||||||
|
self.base.fill_boxes2(&tab_frame, tc, srgb, perceptual, x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if !child.node.node_is_container() {
|
||||||
|
let full_h = mb.y2();
|
||||||
|
let frame_rects = [
|
||||||
|
Rect::new_sized_saturating(mb.x1() - bw, 0, bw, full_h),
|
||||||
|
Rect::new_sized_saturating(mb.x2(), 0, bw, full_h),
|
||||||
|
Rect::new_sized_saturating(mb.x1() - bw, -bw, full_w + 2 * bw, bw),
|
||||||
|
Rect::new_sized_saturating(mb.x1() - bw, full_h, full_w + 2 * bw, bw),
|
||||||
|
];
|
||||||
|
self.base.fill_boxes2(&frame_rects, c, srgb, perceptual, x, y);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let body = mb.move_(x, y);
|
let body = mb.move_(x, y);
|
||||||
let body = self.base.scale_rect(body);
|
let body = self.base.scale_rect(body);
|
||||||
|
|
@ -371,7 +402,7 @@ impl Renderer<'_> {
|
||||||
.node_render(self, x + content.x1(), y + content.y1(), Some(&body));
|
.node_render(self, x + content.x1(), y + content.y1(), Some(&body));
|
||||||
} else {
|
} else {
|
||||||
let gap = self.state.theme.sizes.gap.get();
|
let gap = self.state.theme.sizes.gap.get();
|
||||||
let (srgb_srgb, bw, border_color, focused_border_color, tpuh) = if gap > 0 {
|
let (srgb_srgb, bw, border_color, focused_border_color, tpuh) = if gap != 0 {
|
||||||
let srgb_srgb = self.state.color_manager.srgb_gamma22();
|
let srgb_srgb = self.state.color_manager.srgb_gamma22();
|
||||||
let bw = self.state.theme.sizes.border_width.get();
|
let bw = self.state.theme.sizes.border_width.get();
|
||||||
let border_color = self.state.theme.colors.border.get();
|
let border_color = self.state.theme.colors.border.get();
|
||||||
|
|
@ -393,41 +424,46 @@ impl Renderer<'_> {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if let Some(srgb_srgb) = srgb_srgb {
|
if let Some(srgb_srgb) = srgb_srgb {
|
||||||
if !child.node.node_is_container() {
|
let srgb = &srgb_srgb.linear;
|
||||||
let srgb = &srgb_srgb.linear;
|
let c = if floating {
|
||||||
let c = if child.border_color_is_focused.get() {
|
if child.active.get() { &focused_border_color } else { &border_color }
|
||||||
&focused_border_color
|
} else if child.border_color_is_focused.get() {
|
||||||
} else {
|
&focused_border_color
|
||||||
&border_color
|
} else {
|
||||||
};
|
&border_color
|
||||||
let title_rect = child.title_rect.get();
|
};
|
||||||
|
let title_rect = child.title_rect.get();
|
||||||
|
let full_w = body.width();
|
||||||
|
let perceptual = RenderIntent::Perceptual;
|
||||||
|
if floating && tpuh > 0 {
|
||||||
|
let tw = title_rect.width();
|
||||||
|
let title_h = title_rect.height();
|
||||||
|
let title_frame = [
|
||||||
|
Rect::new_sized_saturating(title_rect.x1() - bw, title_rect.y1() - bw, tw + 2 * bw, bw),
|
||||||
|
Rect::new_sized_saturating(title_rect.x1() - bw, title_rect.y1(), bw, title_h),
|
||||||
|
Rect::new_sized_saturating(title_rect.x2(), title_rect.y1(), bw, title_h),
|
||||||
|
Rect::new_sized_saturating(title_rect.x1() - bw, title_rect.y1() + title_h, tw + 2 * bw, bw),
|
||||||
|
];
|
||||||
|
self.base.fill_boxes2(&title_frame, c, srgb, perceptual, x, y);
|
||||||
|
if !child.node.node_is_container() && gap != 0 {
|
||||||
|
let body_frame = [
|
||||||
|
Rect::new_sized_saturating(body.x1() - bw, body.y1(), bw, body.y2() - body.y1()),
|
||||||
|
Rect::new_sized_saturating(body.x2(), body.y1(), bw, body.y2() - body.y1()),
|
||||||
|
Rect::new_sized_saturating(body.x1() - bw, body.y1() - bw, full_w + 2 * bw, bw),
|
||||||
|
Rect::new_sized_saturating(body.x1() - bw, body.y2(), full_w + 2 * bw, bw),
|
||||||
|
];
|
||||||
|
self.base.fill_boxes2(&body_frame, c, srgb, perceptual, x, y);
|
||||||
|
}
|
||||||
|
} else if !child.node.node_is_container() && gap != 0 {
|
||||||
let top_y = if tpuh > 0 { title_rect.y1() } else { body.y1() };
|
let top_y = if tpuh > 0 { title_rect.y1() } else { body.y1() };
|
||||||
let full_h = body.y2() - top_y;
|
let full_h = body.y2() - top_y;
|
||||||
let full_w = body.width();
|
|
||||||
let frame_rects = [
|
let frame_rects = [
|
||||||
Rect::new_sized_saturating(body.x1() - bw, top_y, bw, full_h),
|
Rect::new_sized_saturating(body.x1() - bw, top_y, bw, full_h),
|
||||||
Rect::new_sized_saturating(body.x2(), top_y, bw, full_h),
|
Rect::new_sized_saturating(body.x2(), top_y, bw, full_h),
|
||||||
Rect::new_sized_saturating(
|
Rect::new_sized_saturating(body.x1() - bw, top_y - bw, full_w + 2 * bw, bw),
|
||||||
body.x1() - bw,
|
Rect::new_sized_saturating(body.x1() - bw, body.y2(), full_w + 2 * bw, bw),
|
||||||
top_y - bw,
|
|
||||||
full_w + 2 * bw,
|
|
||||||
bw,
|
|
||||||
),
|
|
||||||
Rect::new_sized_saturating(
|
|
||||||
body.x1() - bw,
|
|
||||||
body.y2(),
|
|
||||||
full_w + 2 * bw,
|
|
||||||
bw,
|
|
||||||
),
|
|
||||||
];
|
];
|
||||||
self.base.fill_boxes2(
|
self.base.fill_boxes2(&frame_rects, c, srgb, perceptual, x, y);
|
||||||
&frame_rects,
|
|
||||||
c,
|
|
||||||
srgb,
|
|
||||||
RenderIntent::Perceptual,
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let body = body.move_(x, y);
|
let body = body.move_(x, y);
|
||||||
|
|
@ -438,6 +474,7 @@ impl Renderer<'_> {
|
||||||
.node_render(self, x + content.x1(), y + content.y1(), Some(&body));
|
.node_render(self, x + content.x1(), y + content.y1(), Some(&body));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.render_tl_aux(container.tl_data(), None, false);
|
self.render_tl_aux(container.tl_data(), None, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1861,6 +1861,11 @@ impl State {
|
||||||
self.spaces_changed();
|
self.spaces_changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_floating_titles(&self, floating: bool) {
|
||||||
|
self.theme.floating_titles.set(floating);
|
||||||
|
self.spaces_changed();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_ui_drag_enabled(&self, enabled: bool) {
|
pub fn set_ui_drag_enabled(&self, enabled: bool) {
|
||||||
self.ui_drag_enabled.set(enabled);
|
self.ui_drag_enabled.set(enabled);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
19
src/theme.rs
19
src/theme.rs
|
|
@ -587,6 +587,7 @@ sizes! {
|
||||||
border_width = (0, 1000, 4),
|
border_width = (0, 1000, 4),
|
||||||
bar_separator_width = (0, 1000, 1),
|
bar_separator_width = (0, 1000, 1),
|
||||||
gap = (0, 1000, 0),
|
gap = (0, 1000, 0),
|
||||||
|
title_gap = (0, 1000, 5),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StaticText for ThemeSized {
|
impl StaticText for ThemeSized {
|
||||||
|
|
@ -597,6 +598,7 @@ impl StaticText for ThemeSized {
|
||||||
ThemeSized::border_width => "Border Width",
|
ThemeSized::border_width => "Border Width",
|
||||||
ThemeSized::bar_separator_width => "Bar Separator Width",
|
ThemeSized::bar_separator_width => "Bar Separator Width",
|
||||||
ThemeSized::gap => "Gap",
|
ThemeSized::gap => "Gap",
|
||||||
|
ThemeSized::title_gap => "Title Gap",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -649,6 +651,7 @@ pub struct Theme {
|
||||||
pub title_font: CloneCell<Option<Arc<String>>>,
|
pub title_font: CloneCell<Option<Arc<String>>>,
|
||||||
pub default_font: Arc<String>,
|
pub default_font: Arc<String>,
|
||||||
pub show_titles: Cell<bool>,
|
pub show_titles: Cell<bool>,
|
||||||
|
pub floating_titles: Cell<bool>,
|
||||||
pub bar_position: Cell<BarPosition>,
|
pub bar_position: Cell<BarPosition>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -663,6 +666,7 @@ impl Default for Theme {
|
||||||
title_font: Default::default(),
|
title_font: Default::default(),
|
||||||
default_font,
|
default_font,
|
||||||
show_titles: Cell::new(true),
|
show_titles: Cell::new(true),
|
||||||
|
floating_titles: Cell::new(false),
|
||||||
bar_position: Default::default(),
|
bar_position: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -689,9 +693,22 @@ impl Theme {
|
||||||
if self.show_titles.get() { 1 } else { 0 }
|
if self.show_titles.get() { 1 } else { 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn floating_title_top_margin(&self) -> i32 {
|
||||||
|
if self.floating_titles.get() && self.sizes.gap.get() != 0 {
|
||||||
|
self.sizes.border_width.get()
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn title_plus_underline_height(&self) -> i32 {
|
pub fn title_plus_underline_height(&self) -> i32 {
|
||||||
if self.show_titles.get() {
|
if self.show_titles.get() {
|
||||||
self.sizes.title_height.get() + 1
|
if self.floating_titles.get() && self.sizes.gap.get() != 0 {
|
||||||
|
let bw = self.sizes.border_width.get();
|
||||||
|
3 * bw + self.sizes.title_height.get() + self.sizes.title_gap.get()
|
||||||
|
} else {
|
||||||
|
self.sizes.title_height.get() + 1
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -383,16 +383,26 @@ impl ContainerNode {
|
||||||
let mb = self.mono_body.get();
|
let mb = self.mono_body.get();
|
||||||
return (mb.width(), mb.height());
|
return (mb.width(), mb.height());
|
||||||
}
|
}
|
||||||
let spacing = self.state.theme.sizes.gap.get().max(
|
let gap = self.state.theme.sizes.gap.get();
|
||||||
self.state.theme.sizes.border_width.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;
|
let nc = self.num_children.get() as i32 + 1;
|
||||||
match self.split.get() {
|
match self.split.get() {
|
||||||
ContainerSplit::Horizontal => {
|
ContainerSplit::Horizontal => {
|
||||||
|
let spacing = if floating {
|
||||||
|
self.state.theme.sizes.title_gap.get() + 2 * bw
|
||||||
|
} else {
|
||||||
|
gap.max(bw)
|
||||||
|
};
|
||||||
let content_w = self.width.get().sub((nc - 1) * spacing).max(0);
|
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().sub(tpuh).max(0))
|
||||||
}
|
}
|
||||||
ContainerSplit::Vertical => {
|
ContainerSplit::Vertical => {
|
||||||
|
let spacing = if floating {
|
||||||
|
self.state.theme.sizes.title_gap.get() + bw
|
||||||
|
} else {
|
||||||
|
gap.max(bw)
|
||||||
|
};
|
||||||
let content_h = self
|
let content_h = self
|
||||||
.height
|
.height
|
||||||
.get()
|
.get()
|
||||||
|
|
@ -407,6 +417,7 @@ impl ContainerNode {
|
||||||
self.update_content_size();
|
self.update_content_size();
|
||||||
// log::info!("on_spaces_changed");
|
// log::info!("on_spaces_changed");
|
||||||
self.schedule_layout();
|
self.schedule_layout();
|
||||||
|
self.schedule_compute_render_positions();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_colors_changed(self: &Rc<Self>) {
|
pub fn on_colors_changed(self: &Rc<Self>) {
|
||||||
|
|
@ -416,7 +427,7 @@ impl ContainerNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn damage(&self) {
|
fn damage(&self) {
|
||||||
let bw = if self.state.theme.sizes.gap.get() > 0 {
|
let bw = if self.state.theme.sizes.gap.get() != 0 {
|
||||||
self.state.theme.sizes.border_width.get()
|
self.state.theme.sizes.border_width.get()
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
|
|
@ -485,8 +496,15 @@ impl ContainerNode {
|
||||||
|
|
||||||
let th = self.state.theme.title_height();
|
let th = self.state.theme.title_height();
|
||||||
let bw = self.state.theme.sizes.border_width.get();
|
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 num_children = self.num_children.get() as i32;
|
||||||
let content_width = self.width.get().sub(bw * (num_children - 1)).max(0);
|
let content_width = self.width.get().sub(spacing * (num_children - 1)).max(0);
|
||||||
let width_per_child = content_width / num_children;
|
let width_per_child = content_width / num_children;
|
||||||
let mut rem = content_width % num_children;
|
let mut rem = content_width % num_children;
|
||||||
let mut pos = 0;
|
let mut pos = 0;
|
||||||
|
|
@ -498,18 +516,28 @@ impl ContainerNode {
|
||||||
}
|
}
|
||||||
child
|
child
|
||||||
.title_rect
|
.title_rect
|
||||||
.set(Rect::new_sized_saturating(pos, 0, width, th));
|
.set(Rect::new_sized_saturating(pos, bw_top, width, th));
|
||||||
pos += width + bw;
|
pos += width + spacing;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn perform_split_layout(self: &Rc<Self>) {
|
fn perform_split_layout(self: &Rc<Self>) {
|
||||||
let sum_factors = self.sum_factors.get();
|
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 border_width = self.state.theme.sizes.border_width.get();
|
||||||
let spacing = self.state.theme.sizes.gap.get().max(border_width);
|
let floating = self.state.theme.floating_titles.get() && gap != 0;
|
||||||
let title_height_tmp = self.state.theme.title_height();
|
let title_height_tmp = self.state.theme.title_height();
|
||||||
let title_plus_underline_height = self.state.theme.title_plus_underline_height();
|
let tpuh = self.state.theme.title_plus_underline_height();
|
||||||
let split = self.split.get();
|
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 (content_size, other_content_size) = match split {
|
let (content_size, other_content_size) = match split {
|
||||||
ContainerSplit::Horizontal => (self.content_width.get(), self.content_height.get()),
|
ContainerSplit::Horizontal => (self.content_width.get(), self.content_height.get()),
|
||||||
ContainerSplit::Vertical => (self.content_height.get(), self.content_width.get()),
|
ContainerSplit::Vertical => (self.content_height.get(), self.content_width.get()),
|
||||||
|
|
@ -527,24 +555,14 @@ impl ContainerNode {
|
||||||
body_size = body_size.min(remaining_content_size);
|
body_size = body_size.min(remaining_content_size);
|
||||||
remaining_content_size -= body_size;
|
remaining_content_size -= body_size;
|
||||||
let (x1, y1, width, height) = match split {
|
let (x1, y1, width, height) = match split {
|
||||||
ContainerSplit::Horizontal => (
|
ContainerSplit::Horizontal => (pos, tpuh, body_size, other_content_size),
|
||||||
pos,
|
_ => (0, pos + tpuh, other_content_size, body_size),
|
||||||
title_plus_underline_height,
|
|
||||||
body_size,
|
|
||||||
other_content_size,
|
|
||||||
),
|
|
||||||
_ => (
|
|
||||||
0,
|
|
||||||
pos + title_plus_underline_height,
|
|
||||||
other_content_size,
|
|
||||||
body_size,
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
let body = Rect::new_sized_saturating(x1, y1, width, height);
|
let body = Rect::new_sized_saturating(x1, y1, width, height);
|
||||||
child.body.set(body);
|
child.body.set(body);
|
||||||
pos += body_size + spacing;
|
pos += body_size + spacing;
|
||||||
if split == ContainerSplit::Vertical {
|
if split == ContainerSplit::Vertical {
|
||||||
pos += title_plus_underline_height;
|
pos += tpuh;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if remaining_content_size > 0 {
|
if remaining_content_size > 0 {
|
||||||
|
|
@ -561,39 +579,28 @@ impl ContainerNode {
|
||||||
let (x1, y1, width, height, size) = match split {
|
let (x1, y1, width, height, size) = match split {
|
||||||
ContainerSplit::Horizontal => {
|
ContainerSplit::Horizontal => {
|
||||||
let width = body.width() + add;
|
let width = body.width() + add;
|
||||||
(
|
(pos, tpuh, width, other_content_size, width)
|
||||||
pos,
|
|
||||||
title_plus_underline_height,
|
|
||||||
width,
|
|
||||||
other_content_size,
|
|
||||||
width,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let height = body.height() + add;
|
let height = body.height() + add;
|
||||||
(
|
(0, pos + tpuh, other_content_size, height, height)
|
||||||
0,
|
|
||||||
pos + title_plus_underline_height,
|
|
||||||
other_content_size,
|
|
||||||
height,
|
|
||||||
height,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
body = Rect::new_sized_saturating(x1, y1, width, height);
|
body = Rect::new_sized_saturating(x1, y1, width, height);
|
||||||
child.body.set(body);
|
child.body.set(body);
|
||||||
pos += size + spacing;
|
pos += size + spacing;
|
||||||
if split == ContainerSplit::Vertical {
|
if split == ContainerSplit::Vertical {
|
||||||
pos += title_plus_underline_height;
|
pos += tpuh;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let bw_top = self.state.theme.floating_title_top_margin();
|
||||||
self.sum_factors.set(1.0);
|
self.sum_factors.set(1.0);
|
||||||
for child in self.children.iter() {
|
for child in self.children.iter() {
|
||||||
let body = child.body.get();
|
let body = child.body.get();
|
||||||
child.title_rect.set(Rect::new_sized_saturating(
|
child.title_rect.set(Rect::new_sized_saturating(
|
||||||
body.x1(),
|
body.x1(),
|
||||||
body.y1() - title_plus_underline_height,
|
body.y1() - tpuh + bw_top,
|
||||||
body.width(),
|
body.width(),
|
||||||
title_height_tmp,
|
title_height_tmp,
|
||||||
));
|
));
|
||||||
|
|
@ -604,25 +611,33 @@ impl ContainerNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_content_size(&self) {
|
fn update_content_size(&self) {
|
||||||
|
let gap = self.state.theme.sizes.gap.get();
|
||||||
let border_width = self.state.theme.sizes.border_width.get();
|
let border_width = self.state.theme.sizes.border_width.get();
|
||||||
let spacing = self.state.theme.sizes.gap.get().max(border_width);
|
let floating = self.state.theme.floating_titles.get() && gap != 0;
|
||||||
let title_plus_underline_height = self.state.theme.title_plus_underline_height();
|
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();
|
let nc = self.num_children.get();
|
||||||
match self.split.get() {
|
match self.split.get() {
|
||||||
ContainerSplit::Horizontal => {
|
ContainerSplit::Horizontal => {
|
||||||
|
let spacing = if floating {
|
||||||
|
title_gap + 2 * border_width
|
||||||
|
} else {
|
||||||
|
gap.max(border_width)
|
||||||
|
};
|
||||||
let new_content_size = self.width.get().sub((nc - 1) as i32 * spacing).max(0);
|
let new_content_size = self.width.get().sub((nc - 1) as i32 * spacing).max(0);
|
||||||
self.content_width.set(new_content_size);
|
self.content_width.set(new_content_size);
|
||||||
self.content_height
|
self.content_height.set(self.height.get().sub(tpuh).max(0));
|
||||||
.set(self.height.get().sub(title_plus_underline_height).max(0));
|
|
||||||
}
|
}
|
||||||
ContainerSplit::Vertical => {
|
ContainerSplit::Vertical => {
|
||||||
|
let spacing = if floating {
|
||||||
|
title_gap + border_width
|
||||||
|
} else {
|
||||||
|
gap.max(border_width)
|
||||||
|
};
|
||||||
let new_content_size = self
|
let new_content_size = self
|
||||||
.height
|
.height
|
||||||
.get()
|
.get()
|
||||||
.sub(
|
.sub(tpuh + (nc - 1) as i32 * (spacing + tpuh))
|
||||||
title_plus_underline_height
|
|
||||||
+ (nc - 1) as i32 * (spacing + title_plus_underline_height),
|
|
||||||
)
|
|
||||||
.max(0);
|
.max(0);
|
||||||
self.content_height.set(new_content_size);
|
self.content_height.set(new_content_size);
|
||||||
self.content_width.set(self.width.get());
|
self.content_width.set(self.width.get());
|
||||||
|
|
@ -630,9 +645,9 @@ impl ContainerNode {
|
||||||
}
|
}
|
||||||
self.mono_body.set(Rect::new_sized_saturating(
|
self.mono_body.set(Rect::new_sized_saturating(
|
||||||
0,
|
0,
|
||||||
title_plus_underline_height,
|
tpuh,
|
||||||
self.width.get(),
|
self.width.get(),
|
||||||
self.height.get() - title_plus_underline_height,
|
self.height.get() - tpuh,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -904,9 +919,9 @@ impl ContainerNode {
|
||||||
rect.height() + tuh,
|
rect.height() + tuh,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
if gap > 0 && !mono && !child.node.node_is_container() {
|
if gap != 0 && !mono && !child.node.node_is_container() {
|
||||||
child.border_color_is_focused.set(child.active.get());
|
child.border_color_is_focused.set(child.active.get());
|
||||||
} else if gap == 0 && i > 0 {
|
} else if i > 0 {
|
||||||
let sep = if mono {
|
let sep = if mono {
|
||||||
Rect::new_sized_saturating(rect.x1() - bw, 0, bw, th)
|
Rect::new_sized_saturating(rect.x1() - bw, 0, bw, th)
|
||||||
} else if split == ContainerSplit::Horizontal {
|
} else if split == ContainerSplit::Horizontal {
|
||||||
|
|
@ -914,7 +929,10 @@ impl ContainerNode {
|
||||||
} else {
|
} else {
|
||||||
Rect::new_sized_saturating(0, rect.y1() - bw, cwidth, bw)
|
Rect::new_sized_saturating(0, rect.y1() - bw, cwidth, bw)
|
||||||
};
|
};
|
||||||
rd.border_rects.push(sep);
|
let floating = self.state.theme.floating_titles.get();
|
||||||
|
if gap == 0 || (mono && !floating) {
|
||||||
|
rd.border_rects.push(sep);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if child.active.get() {
|
if child.active.get() {
|
||||||
rd.active_title_rects.push(rect);
|
rd.active_title_rects.push(rect);
|
||||||
|
|
@ -925,7 +943,7 @@ impl ContainerNode {
|
||||||
} else {
|
} else {
|
||||||
rd.title_rects.push(rect);
|
rd.title_rects.push(rect);
|
||||||
}
|
}
|
||||||
if !mono {
|
if !mono && (!self.state.theme.floating_titles.get() || gap == 0) {
|
||||||
let rect = Rect::new_sized_saturating(rect.x1(), rect.y2(), rect.width(), 1);
|
let rect = Rect::new_sized_saturating(rect.x1(), rect.y2(), rect.width(), 1);
|
||||||
rd.underline_rects.push(rect);
|
rd.underline_rects.push(rect);
|
||||||
}
|
}
|
||||||
|
|
@ -937,10 +955,14 @@ impl ContainerNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if mono {
|
if mono && (!self.state.theme.floating_titles.get() || gap == 0) {
|
||||||
rd.underline_rects
|
rd.underline_rects
|
||||||
.push(Rect::new_sized_saturating(0, th, cwidth, tuh));
|
.push(Rect::new_sized_saturating(0, th, cwidth, tuh));
|
||||||
}
|
}
|
||||||
|
if gap == 0 && th > 0 {
|
||||||
|
rd.underline_rects
|
||||||
|
.push(Rect::new_sized_saturating(0, 0, cwidth, tuh));
|
||||||
|
}
|
||||||
if self.toplevel_data.visible.get() && (mono || split == ContainerSplit::Horizontal) {
|
if self.toplevel_data.visible.get() && (mono || split == ContainerSplit::Horizontal) {
|
||||||
self.state
|
self.state
|
||||||
.damage(Rect::new_sized_saturating(abs_x, abs_y, cwidth, tpuh));
|
.damage(Rect::new_sized_saturating(abs_x, abs_y, cwidth, tpuh));
|
||||||
|
|
@ -1248,7 +1270,7 @@ impl ContainerNode {
|
||||||
// log::info!("node_child_active_changed");
|
// log::info!("node_child_active_changed");
|
||||||
self.schedule_render_titles();
|
self.schedule_render_titles();
|
||||||
self.schedule_compute_render_positions();
|
self.schedule_compute_render_positions();
|
||||||
if self.state.theme.sizes.gap.get() > 0 && self.toplevel_data.visible.get() {
|
if self.state.theme.sizes.gap.get() != 0 && self.toplevel_data.visible.get() {
|
||||||
self.damage();
|
self.damage();
|
||||||
}
|
}
|
||||||
if let Some(parent) = self.toplevel_data.parent.get() {
|
if let Some(parent) = self.toplevel_data.parent.get() {
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,8 @@ pub enum SimpleCommand {
|
||||||
ToggleBar,
|
ToggleBar,
|
||||||
ShowTitles(bool),
|
ShowTitles(bool),
|
||||||
ToggleTitles,
|
ToggleTitles,
|
||||||
|
FloatTitles(bool),
|
||||||
|
ToggleFloatTitles,
|
||||||
FocusHistory(Timeline),
|
FocusHistory(Timeline),
|
||||||
FocusLayerRel(LayerDirection),
|
FocusLayerRel(LayerDirection),
|
||||||
FocusTiles,
|
FocusTiles,
|
||||||
|
|
@ -224,6 +226,8 @@ pub struct Theme {
|
||||||
pub bar_position: Option<BarPosition>,
|
pub bar_position: Option<BarPosition>,
|
||||||
pub bar_separator_width: Option<i32>,
|
pub bar_separator_width: Option<i32>,
|
||||||
pub gap: Option<i32>,
|
pub gap: Option<i32>,
|
||||||
|
pub floating_titles: Option<bool>,
|
||||||
|
pub title_gap: Option<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
|
||||||
|
|
@ -153,6 +153,9 @@ impl ActionParser<'_> {
|
||||||
"show-titles" => ShowTitles(true),
|
"show-titles" => ShowTitles(true),
|
||||||
"hide-titles" => ShowTitles(false),
|
"hide-titles" => ShowTitles(false),
|
||||||
"toggle-titles" => ToggleTitles,
|
"toggle-titles" => ToggleTitles,
|
||||||
|
"float-titles" => FloatTitles(true),
|
||||||
|
"unfloat-titles" => FloatTitles(false),
|
||||||
|
"toggle-float-titles" => ToggleFloatTitles,
|
||||||
"focus-prev" => FocusHistory(Timeline::Older),
|
"focus-prev" => FocusHistory(Timeline::Older),
|
||||||
"focus-next" => FocusHistory(Timeline::Newer),
|
"focus-next" => FocusHistory(Timeline::Newer),
|
||||||
"focus-below" => FocusLayerRel(LayerDirection::Below),
|
"focus-below" => FocusLayerRel(LayerDirection::Below),
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use {
|
||||||
config::{
|
config::{
|
||||||
Theme,
|
Theme,
|
||||||
context::Context,
|
context::Context,
|
||||||
extractor::{Extractor, ExtractorError, opt, recover, s32, str, val},
|
extractor::{Extractor, ExtractorError, bol, opt, recover, s32, str, val},
|
||||||
parser::{DataType, ParseResult, Parser, UnexpectedDataType},
|
parser::{DataType, ParseResult, Parser, UnexpectedDataType},
|
||||||
parsers::color::ColorParser,
|
parsers::color::ColorParser,
|
||||||
},
|
},
|
||||||
|
|
@ -63,7 +63,7 @@ impl Parser for ThemeParser<'_> {
|
||||||
font,
|
font,
|
||||||
title_font,
|
title_font,
|
||||||
),
|
),
|
||||||
(bar_font, bar_position_val, bar_separator_width, gap),
|
(bar_font, bar_position_val, bar_separator_width, gap, floating_titles),
|
||||||
) = ext.extract((
|
) = ext.extract((
|
||||||
(
|
(
|
||||||
opt(val("attention-requested-bg-color")),
|
opt(val("attention-requested-bg-color")),
|
||||||
|
|
@ -94,8 +94,10 @@ impl Parser for ThemeParser<'_> {
|
||||||
recover(opt(str("bar-position"))),
|
recover(opt(str("bar-position"))),
|
||||||
recover(opt(s32("bar-separator-width"))),
|
recover(opt(s32("bar-separator-width"))),
|
||||||
recover(opt(s32("gap"))),
|
recover(opt(s32("gap"))),
|
||||||
|
recover(opt(bol("floating-titles"))),
|
||||||
),
|
),
|
||||||
))?;
|
))?;
|
||||||
|
let (title_gap,) = ext.extract((recover(opt(s32("title-gap"))),))?;
|
||||||
macro_rules! color {
|
macro_rules! color {
|
||||||
($e:expr) => {
|
($e:expr) => {
|
||||||
match $e {
|
match $e {
|
||||||
|
|
@ -148,6 +150,8 @@ impl Parser for ThemeParser<'_> {
|
||||||
bar_position,
|
bar_position,
|
||||||
bar_separator_width: bar_separator_width.despan(),
|
bar_separator_width: bar_separator_width.despan(),
|
||||||
gap: gap.despan(),
|
gap: gap.despan(),
|
||||||
|
floating_titles: floating_titles.despan(),
|
||||||
|
title_gap: title_gap.despan(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,8 @@ use {
|
||||||
on_devices_enumerated, on_idle, on_unload, quit, reload,
|
on_devices_enumerated, on_idle, on_unload, quit, reload,
|
||||||
set_color_management_enabled, set_default_workspace_capture, set_explicit_sync_enabled,
|
set_color_management_enabled, set_default_workspace_capture, set_explicit_sync_enabled,
|
||||||
set_float_above_fullscreen, set_idle, set_idle_grace_period,
|
set_float_above_fullscreen, set_idle, set_idle_grace_period,
|
||||||
set_middle_click_paste_enabled, set_show_bar, set_show_float_pin_icon, set_show_titles,
|
set_floating_titles, set_middle_click_paste_enabled, set_show_bar, set_show_float_pin_icon,
|
||||||
|
set_show_titles,
|
||||||
set_ui_drag_enabled, set_ui_drag_threshold,
|
set_ui_drag_enabled, set_ui_drag_threshold,
|
||||||
status::{set_i3bar_separator, set_status, set_status_command, unset_status_command},
|
status::{set_i3bar_separator, set_status, set_status_command, unset_status_command},
|
||||||
switch_to_vt,
|
switch_to_vt,
|
||||||
|
|
@ -48,7 +49,7 @@ use {
|
||||||
reset_colors, reset_font, reset_sizes, set_bar_font, set_bar_position, set_font,
|
reset_colors, reset_font, reset_sizes, set_bar_font, set_bar_position, set_font,
|
||||||
set_title_font,
|
set_title_font,
|
||||||
},
|
},
|
||||||
toggle_float_above_fullscreen, toggle_show_bar, toggle_show_titles,
|
toggle_float_above_fullscreen, toggle_floating_titles, toggle_show_bar, toggle_show_titles,
|
||||||
video::{
|
video::{
|
||||||
ColorSpace, Connector, DrmDevice, Eotf, connectors, create_virtual_output, drm_devices,
|
ColorSpace, Connector, DrmDevice, Eotf, connectors, create_virtual_output, drm_devices,
|
||||||
on_connector_connected, on_connector_disconnected, on_graphics_initialized,
|
on_connector_connected, on_connector_disconnected, on_graphics_initialized,
|
||||||
|
|
@ -206,6 +207,10 @@ impl Action {
|
||||||
SimpleCommand::ToggleBar => b.new(toggle_show_bar),
|
SimpleCommand::ToggleBar => b.new(toggle_show_bar),
|
||||||
SimpleCommand::ShowTitles(show) => b.new(move || set_show_titles(show)),
|
SimpleCommand::ShowTitles(show) => b.new(move || set_show_titles(show)),
|
||||||
SimpleCommand::ToggleTitles => b.new(toggle_show_titles),
|
SimpleCommand::ToggleTitles => b.new(toggle_show_titles),
|
||||||
|
SimpleCommand::FloatTitles(floating) => {
|
||||||
|
b.new(move || set_floating_titles(floating))
|
||||||
|
}
|
||||||
|
SimpleCommand::ToggleFloatTitles => b.new(toggle_floating_titles),
|
||||||
SimpleCommand::FocusHistory(timeline) => {
|
SimpleCommand::FocusHistory(timeline) => {
|
||||||
let persistent = state.persistent.clone();
|
let persistent = state.persistent.clone();
|
||||||
b.new(move || persistent.seat.focus_history(timeline))
|
b.new(move || persistent.seat.focus_history(timeline))
|
||||||
|
|
@ -1004,6 +1009,7 @@ impl State {
|
||||||
size!(BAR_HEIGHT, bar_height);
|
size!(BAR_HEIGHT, bar_height);
|
||||||
size!(BAR_SEPARATOR_WIDTH, bar_separator_width);
|
size!(BAR_SEPARATOR_WIDTH, bar_separator_width);
|
||||||
size!(GAP, gap);
|
size!(GAP, gap);
|
||||||
|
size!(TITLE_GAP, title_gap);
|
||||||
macro_rules! font {
|
macro_rules! font {
|
||||||
($fun:ident, $field:ident) => {
|
($fun:ident, $field:ident) => {
|
||||||
if let Some(font) = &theme.$field {
|
if let Some(font) = &theme.$field {
|
||||||
|
|
@ -1637,6 +1643,9 @@ fn load_config(initial_load: bool, auto_reload: bool, persistent: &Rc<Persistent
|
||||||
if let Some(v) = config.show_titles {
|
if let Some(v) = config.show_titles {
|
||||||
set_show_titles(v);
|
set_show_titles(v);
|
||||||
}
|
}
|
||||||
|
if let Some(v) = config.theme.floating_titles {
|
||||||
|
set_floating_titles(v);
|
||||||
|
}
|
||||||
if let Some(v) = config.theme.bar_position {
|
if let Some(v) = config.theme.bar_position {
|
||||||
set_bar_position(v);
|
set_bar_position(v);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue