mirror of
https://github.com/wez/wezterm.git
synced 2024-12-18 10:52:16 +03:00
ensure that we set the cursor attributes
Set the cursor to match the positioning info reported by the focused widget
This commit is contained in:
parent
837cfae566
commit
b3346b9a43
@ -1,7 +1,10 @@
|
|||||||
|
//! This example shows how to make a basic widget that accumulates
|
||||||
|
//! text input and renders it to the screen
|
||||||
extern crate failure;
|
extern crate failure;
|
||||||
extern crate termwiz;
|
extern crate termwiz;
|
||||||
|
|
||||||
use failure::Error;
|
use failure::Error;
|
||||||
|
use std::cell::Cell;
|
||||||
use termwiz::caps::Capabilities;
|
use termwiz::caps::Capabilities;
|
||||||
use termwiz::color::AnsiColor;
|
use termwiz::color::AnsiColor;
|
||||||
use termwiz::input::*;
|
use termwiz::input::*;
|
||||||
@ -14,6 +17,7 @@ use termwiz::widgets::*;
|
|||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct MainScreen {
|
struct MainScreen {
|
||||||
buf: String,
|
buf: String,
|
||||||
|
cursor: Cell<ParentRelativeCoords>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WidgetImpl for MainScreen {
|
impl WidgetImpl for MainScreen {
|
||||||
@ -45,6 +49,18 @@ impl WidgetImpl for MainScreen {
|
|||||||
fn render_to_surface(&self, surface: &mut Surface) {
|
fn render_to_surface(&self, surface: &mut Surface) {
|
||||||
surface.add_change(Change::ClearScreen(AnsiColor::Blue.into()));
|
surface.add_change(Change::ClearScreen(AnsiColor::Blue.into()));
|
||||||
surface.add_change(self.buf.clone());
|
surface.add_change(self.buf.clone());
|
||||||
|
// Allow the surface rendering code to figure out where the
|
||||||
|
// cursor ends up, then stash a copy of that information for
|
||||||
|
// later retrieval by get_cursor_shape_and_position().
|
||||||
|
let (x, y) = surface.cursor_position();
|
||||||
|
self.cursor.set(ParentRelativeCoords::new(x, y));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_cursor_shape_and_position(&self) -> CursorShapeAndPosition {
|
||||||
|
CursorShapeAndPosition {
|
||||||
|
coords: self.cursor.get(),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ use escape::csi::{Cursor, Edit, EraseInDisplay, EraseInLine, Sgr, CSI};
|
|||||||
use escape::osc::OperatingSystemCommand;
|
use escape::osc::OperatingSystemCommand;
|
||||||
use failure;
|
use failure;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use surface::{Change, Position};
|
use surface::{Change, CursorShape, Position};
|
||||||
use terminal::unix::UnixTty;
|
use terminal::unix::UnixTty;
|
||||||
use terminfo::{capability as cap, Capability as TermInfoCapability};
|
use terminfo::{capability as cap, Capability as TermInfoCapability};
|
||||||
|
|
||||||
@ -14,6 +14,8 @@ pub struct TerminfoRenderer {
|
|||||||
caps: Capabilities,
|
caps: Capabilities,
|
||||||
current_attr: CellAttributes,
|
current_attr: CellAttributes,
|
||||||
pending_attr: Option<CellAttributes>,
|
pending_attr: Option<CellAttributes>,
|
||||||
|
/* TODO: we should record cursor position, shape and color here
|
||||||
|
* so that we can optimize updating them on screen. */
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TerminfoRenderer {
|
impl TerminfoRenderer {
|
||||||
@ -477,6 +479,39 @@ impl TerminfoRenderer {
|
|||||||
change
|
change
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Change::CursorColor(_color) => {
|
||||||
|
// TODO: this isn't spec'd by terminfo, but some terminals
|
||||||
|
// support it. Add this to capabilities?
|
||||||
|
}
|
||||||
|
Change::CursorShape(shape) => match shape {
|
||||||
|
CursorShape::Default => {
|
||||||
|
if let Some(reset) = self.get_capability::<cap::ResetCursorStyle>() {
|
||||||
|
reset.expand().to(out.by_ref())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CursorShape::Hidden => {
|
||||||
|
if let Some(hide) = self.get_capability::<cap::CursorInvisible>() {
|
||||||
|
hide.expand().to(out.by_ref())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
if let Some(show) = self.get_capability::<cap::CursorVisible>() {
|
||||||
|
show.expand().to(out.by_ref())?;
|
||||||
|
}
|
||||||
|
let param = match shape {
|
||||||
|
CursorShape::Default | CursorShape::Hidden => unreachable!(),
|
||||||
|
CursorShape::BlinkingBlock => 1,
|
||||||
|
CursorShape::SteadyBlock => 2,
|
||||||
|
CursorShape::BlinkingUnderline => 3,
|
||||||
|
CursorShape::SteadyUnderline => 4,
|
||||||
|
CursorShape::BlinkingBar => 6,
|
||||||
|
CursorShape::SteadyBar => 7,
|
||||||
|
};
|
||||||
|
if let Some(set) = self.get_capability::<cap::SetCursorStyle>() {
|
||||||
|
set.expand().kind(param).to(out.by_ref())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,6 +260,8 @@ impl WindowsConsoleRenderer {
|
|||||||
Change::AllAttributes(all) => {
|
Change::AllAttributes(all) => {
|
||||||
self.current_attr = all.clone();
|
self.current_attr = all.clone();
|
||||||
}
|
}
|
||||||
|
Change::CursorColor(_color) => {}
|
||||||
|
Change::CursorShape(_shape) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out.flush()?;
|
out.flush()?;
|
||||||
|
@ -19,6 +19,24 @@ pub enum Position {
|
|||||||
EndRelative(usize),
|
EndRelative(usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum CursorShape {
|
||||||
|
Hidden,
|
||||||
|
Default,
|
||||||
|
BlinkingBlock,
|
||||||
|
SteadyBlock,
|
||||||
|
BlinkingUnderline,
|
||||||
|
SteadyUnderline,
|
||||||
|
BlinkingBar,
|
||||||
|
SteadyBar,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for CursorShape {
|
||||||
|
fn default() -> CursorShape {
|
||||||
|
CursorShape::Default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// `Change` describes an update operation to be applied to a `Surface`.
|
/// `Change` describes an update operation to be applied to a `Surface`.
|
||||||
/// Changes to the active attributes (color, style), moving the cursor
|
/// Changes to the active attributes (color, style), moving the cursor
|
||||||
/// and outputting text are examples of some of the values.
|
/// and outputting text are examples of some of the values.
|
||||||
@ -52,8 +70,11 @@ pub enum Change {
|
|||||||
ClearToEndOfScreen(ColorAttribute),
|
ClearToEndOfScreen(ColorAttribute),
|
||||||
/// Move the cursor to the specified `Position`.
|
/// Move the cursor to the specified `Position`.
|
||||||
CursorPosition { x: Position, y: Position },
|
CursorPosition { x: Position, y: Position },
|
||||||
/* CursorVisibility(bool),
|
/// Change the cursor color.
|
||||||
* ChangeScrollRegion{top: usize, bottom: usize}, */
|
CursorColor(ColorAttribute),
|
||||||
|
/// Change the cursor shape
|
||||||
|
CursorShape(CursorShape),
|
||||||
|
/* ChangeScrollRegion{top: usize, bottom: usize}, */
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Change {
|
impl Change {
|
||||||
@ -206,6 +227,8 @@ pub struct Surface {
|
|||||||
ypos: usize,
|
ypos: usize,
|
||||||
seqno: SequenceNo,
|
seqno: SequenceNo,
|
||||||
changes: Vec<Change>,
|
changes: Vec<Change>,
|
||||||
|
cursor_shape: CursorShape,
|
||||||
|
cursor_color: ColorAttribute,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Surface {
|
impl Surface {
|
||||||
@ -225,6 +248,10 @@ impl Surface {
|
|||||||
(self.width, self.height)
|
(self.width, self.height)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn cursor_position(&self) -> (usize, usize) {
|
||||||
|
(self.xpos, self.ypos)
|
||||||
|
}
|
||||||
|
|
||||||
/// Resize the Surface to the specified width and height.
|
/// Resize the Surface to the specified width and height.
|
||||||
/// If the width and/or height are smaller than previously, the rows and/or
|
/// If the width and/or height are smaller than previously, the rows and/or
|
||||||
/// columns are truncated. If the width and/or height are larger than
|
/// columns are truncated. If the width and/or height are larger than
|
||||||
@ -294,6 +321,8 @@ impl Surface {
|
|||||||
Change::ClearScreen(color) => self.clear_screen(color),
|
Change::ClearScreen(color) => self.clear_screen(color),
|
||||||
Change::ClearToEndOfLine(color) => self.clear_eol(color),
|
Change::ClearToEndOfLine(color) => self.clear_eol(color),
|
||||||
Change::ClearToEndOfScreen(color) => self.clear_eos(color),
|
Change::ClearToEndOfScreen(color) => self.clear_eos(color),
|
||||||
|
Change::CursorColor(color) => self.cursor_color = color.clone(),
|
||||||
|
Change::CursorShape(shape) => self.cursor_shape = shape.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ impl<T: Terminal> BufferedTerminal<T> {
|
|||||||
// renders all.
|
// renders all.
|
||||||
self.seqno = 0;
|
self.seqno = 0;
|
||||||
self.terminal.render(&changes)?;
|
self.terminal.render(&changes)?;
|
||||||
self.terminal.flush()?;
|
//self.terminal.flush()?;
|
||||||
self.seqno = seq;
|
self.seqno = seq;
|
||||||
}
|
}
|
||||||
self.surface.flush_changes_older_than(self.seqno);
|
self.surface.flush_changes_older_than(self.seqno);
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
|
use color::ColorAttribute;
|
||||||
use input::InputEvent;
|
use input::InputEvent;
|
||||||
use std::cell::{Ref, RefCell, RefMut};
|
use std::cell::{Ref, RefCell, RefMut};
|
||||||
use std::rc::{Rc, Weak};
|
use std::rc::{Rc, Weak};
|
||||||
use surface::{SequenceNo, Surface};
|
use surface::{Change, CursorShape, Position, SequenceNo, Surface};
|
||||||
|
|
||||||
/// Describes an event that may need to be processed by the widget
|
/// Describes an event that may need to be processed by the widget
|
||||||
pub enum WidgetEvent {
|
pub enum WidgetEvent {
|
||||||
@ -46,6 +47,13 @@ impl SizeConstraints {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
||||||
|
pub struct CursorShapeAndPosition {
|
||||||
|
pub shape: CursorShape,
|
||||||
|
pub coords: ParentRelativeCoords,
|
||||||
|
pub color: ColorAttribute,
|
||||||
|
}
|
||||||
|
|
||||||
pub trait WidgetImpl {
|
pub trait WidgetImpl {
|
||||||
/// Called once by the widget manager to inform the widget
|
/// Called once by the widget manager to inform the widget
|
||||||
/// of its identifier
|
/// of its identifier
|
||||||
@ -58,12 +66,17 @@ pub trait WidgetImpl {
|
|||||||
fn get_size_constraints(&self) -> SizeConstraints;
|
fn get_size_constraints(&self) -> SizeConstraints;
|
||||||
|
|
||||||
fn render_to_surface(&self, surface: &mut Surface);
|
fn render_to_surface(&self, surface: &mut Surface);
|
||||||
|
|
||||||
|
/// Called for the focused widget to determine how to render
|
||||||
|
/// the cursor.
|
||||||
|
fn get_cursor_shape_and_position(&self) -> CursorShapeAndPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Relative to the top left of the parent container
|
/// Relative to the top left of the parent container
|
||||||
|
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||||
pub struct ParentRelativeCoords {
|
pub struct ParentRelativeCoords {
|
||||||
x: usize,
|
pub x: usize,
|
||||||
y: usize,
|
pub y: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParentRelativeCoords {
|
impl ParentRelativeCoords {
|
||||||
@ -73,9 +86,10 @@ impl ParentRelativeCoords {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Relative to the top left of the screen
|
/// Relative to the top left of the screen
|
||||||
|
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||||
pub struct ScreenRelativeCoords {
|
pub struct ScreenRelativeCoords {
|
||||||
x: usize,
|
pub x: usize,
|
||||||
y: usize,
|
pub y: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScreenRelativeCoords {
|
impl ScreenRelativeCoords {
|
||||||
@ -192,6 +206,25 @@ impl Widget {
|
|||||||
pub fn add_child(&mut self, widget: &WidgetHandle) {
|
pub fn add_child(&mut self, widget: &WidgetHandle) {
|
||||||
self.children.push(widget.clone());
|
self.children.push(widget.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_screen_coords(&self, coords: &ParentRelativeCoords) -> ScreenRelativeCoords {
|
||||||
|
let mut x = coords.x;
|
||||||
|
let mut y = coords.y;
|
||||||
|
let mut widget = self.parent();
|
||||||
|
loop {
|
||||||
|
let parent = match widget {
|
||||||
|
Some(parent) => {
|
||||||
|
let p = parent.borrow();
|
||||||
|
x += p.coordinates.x;
|
||||||
|
y += p.coordinates.y;
|
||||||
|
p.parent()
|
||||||
|
}
|
||||||
|
None => break,
|
||||||
|
};
|
||||||
|
widget = parent;
|
||||||
|
}
|
||||||
|
ScreenRelativeCoords { x, y }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Screen {
|
pub struct Screen {
|
||||||
@ -243,5 +276,18 @@ impl Screen {
|
|||||||
/// and then progresses up through its children.
|
/// and then progresses up through its children.
|
||||||
pub fn render_to_screen(&mut self, screen: &mut Surface) {
|
pub fn render_to_screen(&mut self, screen: &mut Surface) {
|
||||||
self.root_widget.borrow_mut().render_to_screen(screen);
|
self.root_widget.borrow_mut().render_to_screen(screen);
|
||||||
|
|
||||||
|
let focused = self.focused_widget.borrow();
|
||||||
|
let cursor = focused.inner.get_cursor_shape_and_position();
|
||||||
|
let coords = focused.to_screen_coords(&cursor.coords);
|
||||||
|
|
||||||
|
screen.add_changes(vec![
|
||||||
|
Change::CursorShape(cursor.shape),
|
||||||
|
Change::CursorColor(cursor.color),
|
||||||
|
Change::CursorPosition {
|
||||||
|
x: Position::Absolute(coords.x),
|
||||||
|
y: Position::Absolute(coords.y),
|
||||||
|
},
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user