1
1
mirror of https://github.com/wez/wezterm.git synced 2024-11-22 22:42:48 +03:00

integrated-title-bar: Add windows support

This commit is contained in:
YuraIz 2022-11-08 17:41:18 +03:00 committed by Wez Furlong
parent 36f41af81e
commit 93308317d7
No known key found for this signature in database
GPG Key ID: 7A7F66A31EC9B387
4 changed files with 316 additions and 37 deletions

View File

@ -208,6 +208,7 @@ impl PolyCommand {
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum PolyStyle {
Fill,
OutlineThin,
// A line with the thickness as underlines
Outline,
// A line with twice the thickness of underlines
@ -221,11 +222,13 @@ impl PolyStyle {
pixmap.fill_path(path, paint, FillRule::Winding, Transform::identity(), None);
}
PolyStyle::Outline | PolyStyle::OutlineHeavy => {
PolyStyle::OutlineThin | PolyStyle::Outline | PolyStyle::OutlineHeavy => {
let mut stroke = Stroke::default();
stroke.width = width;
if self == PolyStyle::OutlineHeavy {
stroke.width *= 3.0; // NOTE: Using 2.0, the difference is almost invisible
} else if self == PolyStyle::OutlineThin {
stroke.width = 1.2;
}
pixmap.stroke_path(path, paint, &stroke, Transform::identity(), None);
}

View File

@ -520,8 +520,6 @@ impl TabBarState {
x: button_start,
width,
});
// x += width;
}
}

View File

@ -156,7 +156,6 @@ const HIDE_BUTTON: &[Poly] = &[Poly {
const MAXIMIZE_BUTTON: &[Poly] = &[Poly {
path: &[
// PolyCommand::MoveTo(BlockCoord::Zero, BlockCoord::One),
PolyCommand::LineTo(BlockCoord::Zero, BlockCoord::One),
PolyCommand::LineTo(BlockCoord::One, BlockCoord::One),
PolyCommand::LineTo(BlockCoord::One, BlockCoord::Zero),
@ -166,12 +165,169 @@ const MAXIMIZE_BUTTON: &[Poly] = &[Poly {
style: PolyStyle::Outline,
}];
fn poly_for_window_button(window_button: TabBarItem) -> &'static [Poly] {
mod window_buttons {
use super::*;
pub(super) mod windows {
use super::*;
pub const CLOSE: &[Poly] = &[Poly {
path: &[
PolyCommand::LineTo(BlockCoord::One, BlockCoord::One),
PolyCommand::MoveTo(BlockCoord::One, BlockCoord::Zero),
PolyCommand::LineTo(BlockCoord::Zero, BlockCoord::One),
],
intensity: BlockAlpha::Full,
style: PolyStyle::OutlineThin,
}];
pub const HIDE: &[Poly] = &[Poly {
path: &[
PolyCommand::MoveTo(BlockCoord::Zero, BlockCoord::Frac(6, 10)),
PolyCommand::LineTo(BlockCoord::One, BlockCoord::Frac(6, 10)),
],
intensity: BlockAlpha::Full,
style: PolyStyle::OutlineThin,
}];
pub const MAXIMIZE: &[Poly] = &[Poly {
path: &[
PolyCommand::MoveTo(BlockCoord::Frac(2, 10), BlockCoord::Frac(1, 10)),
PolyCommand::LineTo(BlockCoord::Frac(9, 10), BlockCoord::Frac(1, 10)),
PolyCommand::LineTo(BlockCoord::Frac(10, 10), BlockCoord::Frac(2, 10)),
PolyCommand::LineTo(BlockCoord::Frac(10, 10), BlockCoord::Frac(9, 10)),
PolyCommand::LineTo(BlockCoord::Frac(9, 10), BlockCoord::Frac(10, 10)),
PolyCommand::LineTo(BlockCoord::Frac(2, 10), BlockCoord::Frac(10, 10)),
PolyCommand::LineTo(BlockCoord::Frac(1, 10), BlockCoord::Frac(9, 10)),
PolyCommand::LineTo(BlockCoord::Frac(1, 10), BlockCoord::Frac(2, 10)),
PolyCommand::LineTo(BlockCoord::Frac(2, 10), BlockCoord::Frac(1, 10)),
],
intensity: BlockAlpha::Full,
style: PolyStyle::OutlineThin,
}];
pub const RESTORE: &[Poly] = &[
Poly {
path: &[
PolyCommand::MoveTo(BlockCoord::Frac(5, 20), BlockCoord::Frac(1, 10)),
PolyCommand::LineTo(BlockCoord::Frac(8, 10), BlockCoord::Frac(1, 10)),
PolyCommand::LineTo(BlockCoord::Frac(10, 10), BlockCoord::Frac(3, 10)),
PolyCommand::LineTo(BlockCoord::Frac(10, 10), BlockCoord::Frac(15, 20)),
],
intensity: BlockAlpha::Full,
style: PolyStyle::OutlineThin,
},
Poly {
path: &[
PolyCommand::MoveTo(BlockCoord::Frac(2, 10), BlockCoord::Frac(3, 10)),
PolyCommand::LineTo(BlockCoord::Frac(7, 10), BlockCoord::Frac(3, 10)),
PolyCommand::LineTo(BlockCoord::Frac(8, 10), BlockCoord::Frac(4, 10)),
PolyCommand::LineTo(BlockCoord::Frac(8, 10), BlockCoord::Frac(9, 10)),
PolyCommand::LineTo(BlockCoord::Frac(7, 10), BlockCoord::Frac(10, 10)),
PolyCommand::LineTo(BlockCoord::Frac(2, 10), BlockCoord::Frac(10, 10)),
PolyCommand::LineTo(BlockCoord::Frac(1, 10), BlockCoord::Frac(9, 10)),
PolyCommand::LineTo(BlockCoord::Frac(1, 10), BlockCoord::Frac(4, 10)),
PolyCommand::LineTo(BlockCoord::Frac(2, 10), BlockCoord::Frac(3, 10)),
],
intensity: BlockAlpha::Full,
style: PolyStyle::OutlineThin,
},
];
pub fn sized_poly(poly: &'static [Poly]) -> SizedPoly {
let scale = 72.0 / 96.0;
let size = Dimension::Points(10. * scale);
SizedPoly {
poly,
width: size,
height: size,
}
}
}
}
fn window_button_element(
window_button: TabBarItem,
is_maximized: bool,
font: &Rc<LoadedFont>,
metrics: &RenderMetrics,
) -> Element {
let poly = if cfg!(windows) {
use window_buttons::windows::{CLOSE, HIDE, MAXIMIZE, RESTORE};
match window_button {
TabBarItem::WindowHideButton => HIDE,
TabBarItem::WindowMaximizeButton => {
if is_maximized {
RESTORE
} else {
MAXIMIZE
}
}
TabBarItem::WindowCloseButton => CLOSE,
_ => unreachable!(),
}
} else {
match window_button {
TabBarItem::WindowHideButton => HIDE_BUTTON,
TabBarItem::WindowMaximizeButton => MAXIMIZE_BUTTON,
TabBarItem::WindowCloseButton => X_BUTTON,
_ => unreachable!(),
}
};
let poly = if cfg!(windows) {
window_buttons::windows::sized_poly(poly)
} else {
SizedPoly {
poly,
width: Dimension::Pixels(metrics.cell_size.height as f32 / 2.),
height: Dimension::Pixels(metrics.cell_size.height as f32 / 2.),
}
};
match window_button {
TabBarItem::WindowHideButton => HIDE_BUTTON,
TabBarItem::WindowMaximizeButton => MAXIMIZE_BUTTON,
TabBarItem::WindowCloseButton => X_BUTTON,
_ => unreachable!(),
TabBarItem::WindowHideButton => log::debug!("BTN"),
_ => {}
}
let element = Element::new(
&font,
ElementContent::Poly {
line_width: metrics.underline_height.max(2),
poly,
},
);
if cfg!(windows) {
let left_padding = match window_button {
TabBarItem::WindowHideButton => 17.0,
_ => 18.0,
};
let scale = 72.0 / 96.0;
element
.zindex(1)
.vertical_align(VerticalAlign::Middle)
.padding(BoxDimension {
left: Dimension::Points(left_padding * scale),
right: Dimension::Points(18. * scale),
top: Dimension::Points(10. * scale),
bottom: Dimension::Points(10. * scale),
})
} else {
element
.zindex(1)
.vertical_align(VerticalAlign::Middle)
.margin(BoxDimension {
left: Dimension::Cells(0.),
right: Dimension::Cells(0.),
top: Dimension::Cells(0.),
bottom: Dimension::Cells(0.),
})
.padding(BoxDimension {
left: Dimension::Cells(1.0),
right: Dimension::Cells(1.0),
top: Dimension::Cells(0.6),
bottom: Dimension::Cells(0.6),
})
}
}
@ -837,33 +993,13 @@ impl super::TermWindow {
}),
TabBarItem::WindowHideButton
| TabBarItem::WindowMaximizeButton
| TabBarItem::WindowCloseButton => Element::new(
| TabBarItem::WindowCloseButton => window_button_element(
item.item.clone(),
self.window_state.contains(window::WindowState::MAXIMIZED),
&font,
ElementContent::Poly {
line_width: metrics.underline_height.max(2),
poly: SizedPoly {
poly: poly_for_window_button(item.item.clone()),
width: Dimension::Pixels(metrics.cell_size.height as f32 / 2.),
height: Dimension::Pixels(metrics.cell_size.height as f32 / 2.),
},
},
&metrics,
)
.zindex(1)
.vertical_align(VerticalAlign::Middle)
.item_type(UIItemType::TabBar(item.item.clone()))
.margin(BoxDimension {
left: Dimension::Cells(0.),
right: Dimension::Cells(0.),
top: Dimension::Cells(0.),
bottom: Dimension::Cells(0.),
})
.padding(BoxDimension {
left: Dimension::Cells(1.0),
right: Dimension::Cells(1.0),
top: Dimension::Cells(0.6),
bottom: Dimension::Cells(0.6),
})
// .border(BoxDimension::new(Dimension::Pixels(1.)))
.colors(ElementColors {
border: BorderColor::default(),
bg: new_tab.bg_color.to_linear().into(),

View File

@ -1037,7 +1037,9 @@ unsafe fn wm_nccalcsize(hwnd: HWND, _msg: UINT, wparam: WPARAM, lparam: LPARAM)
let inner = rc_from_hwnd(hwnd)?;
let inner = inner.borrow_mut();
if !(wparam == 1 && inner.config.window_decorations == WindowDecorations::RESIZE) {
if !(wparam == 1 && (inner.config.window_decorations == WindowDecorations::RESIZE)
|| (inner.config.window_decorations == WindowDecorations::FANCY))
{
return None;
}
@ -1077,12 +1079,29 @@ unsafe fn wm_nccalcsize(hwnd: HWND, _msg: UINT, wparam: WPARAM, lparam: LPARAM)
Some(0)
}
unsafe fn maximize_button_coords(
hwnd: HWND,
) -> euclid::Point2D<isize, wezterm_input_types::PixelUnit> {
let mut client_rect = RECT::default();
GetClientRect(hwnd, &mut client_rect);
let scale = GetDpiForWindow(hwnd) as f64 / 96.0;
let mut coords = mouse_coords(0);
coords.x = client_rect.right as isize - (60.0 * scale) as isize;
coords.y = 5;
coords
}
unsafe fn wm_nchittest(hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM) -> Option<LRESULT> {
let inner = rc_from_hwnd(hwnd)?;
let inner = inner.borrow_mut();
if inner.config.window_decorations != WindowDecorations::RESIZE {
return None;
match inner.config.window_decorations {
WindowDecorations::FANCY | WindowDecorations::RESIZE => {}
_ => return None,
}
// Let the default procedure handle resizing areas
@ -1153,6 +1172,21 @@ unsafe fn wm_nchittest(hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM) ->
}
}
if inner.config.window_decorations == WindowDecorations::FANCY && inner.config.use_fancy_tab_bar
{
let scale = GetDpiForWindow(inner.hwnd.0) as f64 / 96.0;
let button_height = (30.0 * scale) as isize;
if cursor_point.y >= client_rect.top as isize
&& cursor_point.y < client_rect.top as isize + button_height
{
let btn_width = (45.0 * scale) as isize;
let maximize_btn_pos = (client_rect.right as isize).saturating_sub(btn_width * 2);
if cursor_point.x >= maximize_btn_pos && cursor_point.x < maximize_btn_pos + btn_width {
return Some(HTMAXBUTTON);
}
}
}
Some(HTCLIENT)
}
@ -1522,6 +1556,48 @@ unsafe fn mouse_button(hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM) ->
Some(0)
}
unsafe fn nc_mouse_button(
hwnd: HWND,
msg: UINT,
wparam: WPARAM,
_lparam: LPARAM,
) -> Option<LRESULT> {
let inner = rc_from_hwnd(hwnd)?;
// To support dragging the window, capture when the left
// button goes down and release when it goes up.
// Without this, the drag state can be confused when dragging
// the mouse up outside of the client area.
if msg == WM_LBUTTONDOWN {
SetCapture(hwnd);
} else if msg == WM_LBUTTONUP {
ReleaseCapture();
}
if wparam != HTMAXBUTTON as _ {
return None;
}
let (modifiers, mouse_buttons) = mods_and_buttons(0);
let coords = maximize_button_coords(hwnd);
let event = MouseEvent {
kind: match msg {
WM_NCLBUTTONDOWN | WM_NCLBUTTONDBLCLK => MouseEventKind::Press(MousePress::Left),
_ => return None,
},
coords,
screen_coords: client_to_screen(hwnd, coords),
mouse_buttons,
modifiers,
};
inner
.borrow_mut()
.events
.dispatch(WindowEvent::MouseEvent(event));
Some(0)
}
unsafe fn mouse_move(hwnd: HWND, _msg: UINT, wparam: WPARAM, lparam: LPARAM) -> Option<LRESULT> {
let inner = rc_from_hwnd(hwnd)?;
let mut inner = inner.borrow_mut();
@ -1553,6 +1629,49 @@ unsafe fn mouse_move(hwnd: HWND, _msg: UINT, wparam: WPARAM, lparam: LPARAM) ->
Some(0)
}
unsafe fn nc_mouse_move(
hwnd: HWND,
_msg: UINT,
wparam: WPARAM,
_lparam: LPARAM,
) -> Option<LRESULT> {
let inner = rc_from_hwnd(hwnd)?;
let mut inner = inner.borrow_mut();
if !inner.track_mouse_leave {
inner.track_mouse_leave = true;
let mut trk = TRACKMOUSEEVENT {
cbSize: std::mem::size_of::<TRACKMOUSEEVENT>() as u32,
dwFlags: TME_LEAVE | TME_NONCLIENT,
hwndTrack: hwnd,
dwHoverTime: 0,
};
inner.track_mouse_leave = TrackMouseEvent(&mut trk) == winapi::shared::minwindef::TRUE;
}
if wparam != HTMAXBUTTON as _ {
return None;
}
let (modifiers, mouse_buttons) = mods_and_buttons(0);
let coords = maximize_button_coords(hwnd);
let event = MouseEvent {
kind: MouseEventKind::Move,
coords,
screen_coords: client_to_screen(hwnd, coords),
mouse_buttons,
modifiers,
};
inner.events.dispatch(WindowEvent::MouseEvent(event));
inner.events.dispatch(WindowEvent::NeedRepaint);
Some(0)
}
unsafe fn mouse_leave(hwnd: HWND, _msg: UINT, _wparam: WPARAM, _lparam: LPARAM) -> Option<LRESULT> {
let inner = rc_from_hwnd(hwnd)?;
let mut inner = inner.borrow_mut();
@ -2574,7 +2693,30 @@ unsafe fn do_wnd_proc(hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM) ->
}
None
}
_ => None,
_ => {
if matches!(
msg,
WM_NCMOUSEMOVE | WM_NCMOUSELEAVE | WM_NCLBUTTONDOWN | WM_NCLBUTTONDBLCLK
) {
let inner = rc_from_hwnd(hwnd)?;
let inner = inner.borrow();
let use_shap_layouts = inner.config.window_decorations == WindowDecorations::FANCY
&& inner.config.use_fancy_tab_bar;
std::mem::drop(inner);
if use_shap_layouts {
return match msg {
WM_NCMOUSEMOVE => nc_mouse_move(hwnd, msg, wparam, lparam),
WM_NCMOUSELEAVE => mouse_leave(hwnd, msg, wparam, lparam),
WM_NCLBUTTONDOWN | WM_NCLBUTTONDBLCLK => {
nc_mouse_button(hwnd, msg, wparam, lparam)
}
_ => None,
};
}
}
None
}
}
}