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:
parent
36f41af81e
commit
93308317d7
@ -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);
|
||||
}
|
||||
|
@ -520,8 +520,6 @@ impl TabBarState {
|
||||
x: button_start,
|
||||
width,
|
||||
});
|
||||
|
||||
// x += width;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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(),
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user