mirror of https://github.com/sgoudham/neovide.git
updated readme
parent
5da81b4f26
commit
62d2ca407d
@ -1,146 +1,159 @@
|
|||||||
# Neovide [![Gitter](https://badges.gitter.im/neovide/community.svg)](https://gitter.im/neovide/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
# Neovide [![Gitter](https://badges.gitter.im/neovide/community.svg)](https://gitter.im/neovide/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||||
|
|
||||||
This is a simple graphical user interface for Neovim. Where possible there are some graphical improvements, but it should act
|
This is a simple graphical user interface for Neovim. Where possible there are some graphical improvements, but it should act
|
||||||
functionally like the terminal UI.
|
functionally like the terminal UI.
|
||||||
|
|
||||||
![Basic Screen Cap](./assets/BasicScreenCap.png)
|
![Basic Screen Cap](./assets/BasicScreenCap.png)
|
||||||
|
|
||||||
I've been using this as my daily driver since November 2019. It should be relatively stable, but I'm still working out some kinks
|
I've been using this as my daily driver since November 2019. It should be relatively stable, but I'm still working out some kinks
|
||||||
and ironing out some cross platform issues. In general it should be usable at this point, and if it isn't I consider that a bug and
|
and ironing out some cross platform issues. In general it should be usable at this point, and if it isn't I consider that a bug and
|
||||||
appreciate a report in the issues! Any help and ideas are also greatly appreciated.
|
appreciate a report in the issues! Any help and ideas are also greatly appreciated.
|
||||||
|
|
||||||
I'm also very interested in suggestions code quality/style wise when it comes to Rust. I'm pretty new to the language and appreciate
|
I'm also very interested in suggestions code quality/style wise when it comes to Rust. I'm pretty new to the language and appreciate
|
||||||
any critiques that you might have to offer. I won't take all of them, but I promise to consider anything you might have to offer.
|
any critiques that you might have to offer. I won't take all of them, but I promise to consider anything you might have to offer.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
Should be a standard full features Neovim GUI. Beyond that there are some visual niceties:
|
Should be a standard full features Neovim GUI. Beyond that there are some visual niceties:
|
||||||
|
|
||||||
### Ligatures
|
### Ligatures
|
||||||
|
|
||||||
Supports ligatures and full [HarfBuzz](https://www.freedesktop.org/wiki/Software/HarfBuzz/) backed font shaping.
|
Supports ligatures and full [HarfBuzz](https://www.freedesktop.org/wiki/Software/HarfBuzz/) backed font shaping.
|
||||||
|
|
||||||
![Ligatures](./assets/Ligatures.png)
|
![Ligatures](./assets/Ligatures.png)
|
||||||
|
|
||||||
### Animated Cursor
|
### Animated Cursor
|
||||||
|
|
||||||
Cursor animates into position with a smear effect to improve tracking of cursor position.
|
Cursor animates into position with a smear effect to improve tracking of cursor position.
|
||||||
|
|
||||||
![Animated Cursor](./assets/AnimatedCursor.gif)
|
![Animated Cursor](./assets/AnimatedCursor.gif)
|
||||||
|
|
||||||
### Emoji Support
|
### Animated Windows
|
||||||
|
|
||||||
Font fallback supports rendering of emoji not contained in the configured font.
|
Windows animate into position when they are moved making it easier to see how layout changes happen.
|
||||||
|
|
||||||
![Emoji](./assets/Emoji.png)
|
![Animated Windows](./assets/AnimatedWindows.gif)
|
||||||
|
|
||||||
### Some Nonsense ;)
|
### Blurred Floating Windows
|
||||||
|
|
||||||
```
|
The backgrounds of floating windows are blurred improving the visual separation between foreground and background from
|
||||||
let g:neovide_cursor_vfx_mode = "railgun"
|
built in window transparency.
|
||||||
```
|
|
||||||
|
![Blurred Floating Windows](./assets/BlurredFloatingWindows.png)
|
||||||
![Railgun](./assets/Railgun.gif)
|
|
||||||
|
### Emoji Support
|
||||||
### More to Come
|
|
||||||
|
Font fallback supports rendering of emoji not contained in the configured font.
|
||||||
I've got more ideas for simple unobtrusive improvements. More to come.
|
|
||||||
|
![Emoji](./assets/Emoji.png)
|
||||||
## Configuration
|
|
||||||
|
### Some Nonsense ;)
|
||||||
Configuration is done almost completely via global neovide variables in your vim config and can be manipulated live at runtime. Details can be found [here](https://github.com/Kethku/neovide/wiki/Configuration).
|
|
||||||
|
```
|
||||||
## Install
|
let g:neovide_cursor_vfx_mode = "railgun"
|
||||||
|
```
|
||||||
Relatively recent binaries can be found in the [project releases](https://github.com/Kethku/neovide/releases). But if you want the latest and greatest you should clone it and build yourself.
|
|
||||||
|
![Railgun](./assets/Railgun.gif)
|
||||||
Installing should be as simple as downloading the binary, making sure `nvim.exe` with version 0.4 or greater is on your path, and running it. Everything should be self contained.
|
|
||||||
|
### More to Come
|
||||||
## Building
|
|
||||||
|
I've got more ideas for simple unobtrusive improvements. More to come.
|
||||||
Building instructions are somewhat limited at the moment. All the libraries I use are cross platform and should have
|
|
||||||
support for Windows, Mac, and Linux. The rendering however is Vulkan-based, so driver support for Vulkan will be
|
## Configuration
|
||||||
necessary. On Windows this should be enabled by default if you have a relatively recent system.
|
|
||||||
|
Configuration is done almost completely via global neovide variables in your vim config and can be manipulated live at runtime. Details can be found [here](https://github.com/Kethku/neovide/wiki/Configuration).
|
||||||
Note: Neovide requires neovim version 0.4 or greater.
|
|
||||||
|
## Install
|
||||||
### Windows
|
|
||||||
|
Relatively recent binaries can be found in the [project releases](https://github.com/Kethku/neovide/releases). But if you want the latest and greatest you should clone it and build yourself.
|
||||||
1. Install the latest version of Rust. I recommend <https://rustup.rs/>
|
|
||||||
2. Install CMake. I use chocolatey: `choco install cmake --installargs '"ADD_CMAKE_TO_PATH=System"' -y`
|
Installing should be as simple as downloading the binary, making sure `nvim.exe` with version 0.4 or greater is on your path, and running it. Everything should be self contained.
|
||||||
3. Install LLVM. I use chocolatey: `choco install llvm -y`
|
|
||||||
4. Ensure graphics libraries are up to date.
|
## Building
|
||||||
5. `git clone https://github.com/Kethku/neovide`
|
|
||||||
6. `cd neovide`
|
Building instructions are somewhat limited at the moment. All the libraries I use are cross platform and should have
|
||||||
7. `cargo build --release`
|
support for Windows, Mac, and Linux. The rendering however is Vulkan-based, so driver support for Vulkan will be
|
||||||
8. Copy `./target/release/neovide.exe` to a known location and enjoy.
|
necessary. On Windows this should be enabled by default if you have a relatively recent system.
|
||||||
|
|
||||||
### Mac
|
Note: Neovide requires neovim version 0.4 or greater.
|
||||||
|
|
||||||
1. Install the latest version of Rust. I recommend <https://rustup.rs/>
|
### Windows
|
||||||
2. Install CMake. Using homebrew: `brew install cmake`
|
|
||||||
3. Install the Vulkan SDK. I'm told `brew cask install apenngrace/vulkan/vulkan-sdk` works, but I can't test locally to find out.
|
1. Install the latest version of Rust. I recommend <https://rustup.rs/>
|
||||||
4. `git clone https://github.com/Kethku/neovide`
|
2. Install CMake. I use chocolatey: `choco install cmake --installargs '"ADD_CMAKE_TO_PATH=System"' -y`
|
||||||
5. `cd neovide`
|
3. Install LLVM. I use chocolatey: `choco install llvm -y`
|
||||||
6. `cargo build --release`
|
4. Ensure graphics libraries are up to date.
|
||||||
7. Copy `./target/release/neovide` to a known location and enjoy.
|
5. `git clone https://github.com/Kethku/neovide`
|
||||||
|
6. `cd neovide`
|
||||||
Note: If you run into issues with the vulkan libraries being reported as not verified, this issue thread may help: https://github.com/Kethku/neovide/issues/167#issuecomment-593314579
|
7. `cargo build --release`
|
||||||
|
8. Copy `./target/release/neovide.exe` to a known location and enjoy.
|
||||||
### Linux
|
|
||||||
|
### Mac
|
||||||
#### Arch Linux
|
|
||||||
|
1. Install the latest version of Rust. I recommend <https://rustup.rs/>
|
||||||
There is an [AUR package for neovide](https://aur.archlinux.org/packages/neovide-git/).
|
2. Install CMake. Using homebrew: `brew install cmake`
|
||||||
|
3. Install the Vulkan SDK. I'm told `brew cask install apenngrace/vulkan/vulkan-sdk` works, but I can't test locally to find out.
|
||||||
```sh
|
4. `git clone https://github.com/Kethku/neovide`
|
||||||
git clone https://aur.archlinux.org/neovide-git.git
|
5. `cd neovide`
|
||||||
cd neovide
|
6. `cargo build --release`
|
||||||
makepkg -si
|
7. Copy `./target/release/neovide` to a known location and enjoy.
|
||||||
```
|
|
||||||
|
Note: If you run into issues with the vulkan libraries being reported as not verified, this issue thread may help: https://github.com/Kethku/neovide/issues/167#issuecomment-593314579
|
||||||
#### Debian/Ubuntu
|
|
||||||
|
### Linux
|
||||||
Note: Neovide has been successfully built on other destros but this reportedly works on ubuntu.
|
|
||||||
|
#### Arch Linux
|
||||||
1. Install necessary dependencies
|
|
||||||
|
There is an [AUR package for neovide](https://aur.archlinux.org/packages/neovide-git/).
|
||||||
```sh
|
|
||||||
sudo apt-get install -y curl \
|
```sh
|
||||||
gnupg ca-certificates git \
|
git clone https://aur.archlinux.org/neovide-git.git
|
||||||
gcc-multilib g++-multilib cmake libssl-dev pkg-config \
|
cd neovide
|
||||||
libfreetype6-dev libasound2-dev libexpat1-dev libxcb-composite0-dev \
|
makepkg -si
|
||||||
libbz2-dev libsndio-dev freeglut3-dev libxmu-dev libxi-dev
|
```
|
||||||
```
|
|
||||||
|
#### Debian/Ubuntu
|
||||||
2. Install Vulkan SDK
|
|
||||||
|
Note: Neovide has been successfully built on other destros but this reportedly works on ubuntu.
|
||||||
```sh
|
|
||||||
curl -sL "http://packages.lunarg.com/lunarg-signing-key-pub.asc" | sudo apt-key add -
|
1. Install necessary dependencies
|
||||||
sudo curl -sLo "/etc/apt/sources.list.d/lunarg-vulkan-1.2.131-bionic.list" "http://packages.lunarg.com/vulkan/1.2.131/lunarg-vulkan-1.2.131-bionic.list"
|
|
||||||
sudo apt-get update -y
|
```sh
|
||||||
sudo apt-get install -y vulkan-sdk
|
sudo apt-get install -y curl \
|
||||||
```
|
gnupg ca-certificates git \
|
||||||
|
gcc-multilib g++-multilib cmake libssl-dev pkg-config \
|
||||||
Alternatively if you are running an amd graphics card you may have more success by installing amdvlk.
|
libfreetype6-dev libasound2-dev libexpat1-dev libxcb-composite0-dev \
|
||||||
https://github.com/Kethku/neovide/issues/209
|
libbz2-dev libsndio-dev freeglut3-dev libxmu-dev libxi-dev
|
||||||
|
```
|
||||||
3. Install Rust
|
|
||||||
|
2. Install Vulkan SDK
|
||||||
`curl --proto '=https' --tlsv1.2 -sSf "https://sh.rustup.rs" | sh`
|
|
||||||
|
```sh
|
||||||
4. Clone the repository
|
curl -sL "http://packages.lunarg.com/lunarg-signing-key-pub.asc" | sudo apt-key add -
|
||||||
|
sudo curl -sLo "/etc/apt/sources.list.d/lunarg-vulkan-1.2.131-bionic.list" "http://packages.lunarg.com/vulkan/1.2.131/lunarg-vulkan-1.2.131-bionic.list"
|
||||||
`git clone "https://github.com/Kethku/neovide"`
|
sudo apt-get update -y
|
||||||
|
sudo apt-get install -y vulkan-sdk
|
||||||
5. Build
|
```
|
||||||
|
|
||||||
`cd neovide && ~/.cargo/bin/cargo build --release`
|
Alternatively if you are running an amd graphics card you may have more success by installing amdvlk.
|
||||||
|
https://github.com/Kethku/neovide/issues/209
|
||||||
6. Copy `./target/release/neovide` to a known location and enjoy.
|
|
||||||
|
3. Install Rust
|
||||||
If you see an error complaining about DRI3 settings, links in this issue may help:
|
|
||||||
<https://github.com/Kethku/neovide/issues/44#issuecomment-578618052>.
|
`curl --proto '=https' --tlsv1.2 -sSf "https://sh.rustup.rs" | sh`
|
||||||
|
|
||||||
Note: If you run into libsndio errors, try building without default features which will disable static linking of the SDL
|
4. Clone the repository
|
||||||
library.
|
|
||||||
|
`git clone "https://github.com/Kethku/neovide"`
|
||||||
|
|
||||||
|
5. Build
|
||||||
|
|
||||||
|
`cd neovide && ~/.cargo/bin/cargo build --release`
|
||||||
|
|
||||||
|
6. Copy `./target/release/neovide` to a known location and enjoy.
|
||||||
|
|
||||||
|
If you see an error complaining about DRI3 settings, links in this issue may help:
|
||||||
|
<https://github.com/Kethku/neovide/issues/44#issuecomment-578618052>.
|
||||||
|
|
||||||
|
Note: If you run into libsndio errors, try building without default features which will disable static linking of the SDL
|
||||||
|
library.
|
||||||
|
Binary file not shown.
After Width: | Height: | Size: 1.8 MiB |
Binary file not shown.
After Width: | Height: | Size: 346 KiB |
@ -1,335 +1,335 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::mpsc::Receiver;
|
use std::sync::mpsc::Receiver;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use log::{error, trace, warn};
|
use log::{error, trace, warn};
|
||||||
use skulpin::skia_safe::{colors, dash_path_effect, BlendMode, Canvas, Color, Paint, Rect};
|
use skulpin::skia_safe::{colors, dash_path_effect, BlendMode, Canvas, Color, Paint, Rect};
|
||||||
use skulpin::CoordinateSystemHelper;
|
use skulpin::CoordinateSystemHelper;
|
||||||
|
|
||||||
pub mod animation_utils;
|
pub mod animation_utils;
|
||||||
mod caching_shaper;
|
mod caching_shaper;
|
||||||
pub mod cursor_renderer;
|
pub mod cursor_renderer;
|
||||||
pub mod font_options;
|
pub mod font_options;
|
||||||
mod rendered_window;
|
mod rendered_window;
|
||||||
|
|
||||||
pub use caching_shaper::CachingShaper;
|
pub use caching_shaper::CachingShaper;
|
||||||
pub use font_options::*;
|
pub use font_options::*;
|
||||||
pub use rendered_window::{RenderedWindow, WindowDrawDetails};
|
pub use rendered_window::{RenderedWindow, WindowDrawDetails};
|
||||||
|
|
||||||
use crate::editor::{Colors, DrawCommand, Style, WindowDrawCommand};
|
use crate::editor::{Colors, DrawCommand, Style, WindowDrawCommand};
|
||||||
use crate::settings::*;
|
use crate::settings::*;
|
||||||
use cursor_renderer::CursorRenderer;
|
use cursor_renderer::CursorRenderer;
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct RendererSettings {
|
pub struct RendererSettings {
|
||||||
animation_length: f32,
|
animation_length: f32,
|
||||||
floating_opacity: f32,
|
floating_opacity: f32,
|
||||||
floating_blur: bool,
|
floating_blur: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn initialize_settings() {
|
pub fn initialize_settings() {
|
||||||
SETTINGS.set(&RendererSettings {
|
SETTINGS.set(&RendererSettings {
|
||||||
animation_length: 0.15,
|
animation_length: 0.15,
|
||||||
floating_opacity: 0.7,
|
floating_opacity: 0.7,
|
||||||
floating_blur: true,
|
floating_blur: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
register_nvim_setting!(
|
register_nvim_setting!(
|
||||||
"window_animation_length",
|
"window_animation_length",
|
||||||
RendererSettings::animation_length
|
RendererSettings::animation_length
|
||||||
);
|
);
|
||||||
register_nvim_setting!(
|
register_nvim_setting!(
|
||||||
"floating_window_opacity",
|
"floating_window_opacity",
|
||||||
RendererSettings::floating_opacity
|
RendererSettings::floating_opacity
|
||||||
);
|
);
|
||||||
register_nvim_setting!("floating_window_blur", RendererSettings::floating_blur);
|
register_nvim_setting!("floating_window_blur", RendererSettings::floating_blur);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
pub struct Renderer {
|
pub struct Renderer {
|
||||||
rendered_windows: HashMap<u64, RenderedWindow>,
|
rendered_windows: HashMap<u64, RenderedWindow>,
|
||||||
cursor_renderer: CursorRenderer,
|
cursor_renderer: CursorRenderer,
|
||||||
|
|
||||||
pub paint: Paint,
|
pub paint: Paint,
|
||||||
pub shaper: CachingShaper,
|
pub shaper: CachingShaper,
|
||||||
pub default_style: Arc<Style>,
|
pub default_style: Arc<Style>,
|
||||||
pub font_width: f32,
|
pub font_width: f32,
|
||||||
pub font_height: f32,
|
pub font_height: f32,
|
||||||
pub window_regions: Vec<WindowDrawDetails>,
|
pub window_regions: Vec<WindowDrawDetails>,
|
||||||
pub batched_draw_command_receiver: Receiver<Vec<DrawCommand>>,
|
pub batched_draw_command_receiver: Receiver<Vec<DrawCommand>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Renderer {
|
impl Renderer {
|
||||||
pub fn new(batched_draw_command_receiver: Receiver<Vec<DrawCommand>>) -> Renderer {
|
pub fn new(batched_draw_command_receiver: Receiver<Vec<DrawCommand>>) -> Renderer {
|
||||||
let rendered_windows = HashMap::new();
|
let rendered_windows = HashMap::new();
|
||||||
let cursor_renderer = CursorRenderer::new();
|
let cursor_renderer = CursorRenderer::new();
|
||||||
|
|
||||||
let mut paint = Paint::new(colors::WHITE, None);
|
let mut paint = Paint::new(colors::WHITE, None);
|
||||||
paint.set_anti_alias(false);
|
paint.set_anti_alias(false);
|
||||||
let mut shaper = CachingShaper::new();
|
let mut shaper = CachingShaper::new();
|
||||||
let (font_width, font_height) = shaper.font_base_dimensions();
|
let (font_width, font_height) = shaper.font_base_dimensions();
|
||||||
let default_style = Arc::new(Style::new(Colors::new(
|
let default_style = Arc::new(Style::new(Colors::new(
|
||||||
Some(colors::WHITE),
|
Some(colors::WHITE),
|
||||||
Some(colors::BLACK),
|
Some(colors::BLACK),
|
||||||
Some(colors::GREY),
|
Some(colors::GREY),
|
||||||
)));
|
)));
|
||||||
let window_regions = Vec::new();
|
let window_regions = Vec::new();
|
||||||
|
|
||||||
Renderer {
|
Renderer {
|
||||||
rendered_windows,
|
rendered_windows,
|
||||||
cursor_renderer,
|
cursor_renderer,
|
||||||
|
|
||||||
paint,
|
paint,
|
||||||
shaper,
|
shaper,
|
||||||
default_style,
|
default_style,
|
||||||
font_width,
|
font_width,
|
||||||
font_height,
|
font_height,
|
||||||
window_regions,
|
window_regions,
|
||||||
batched_draw_command_receiver,
|
batched_draw_command_receiver,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_font(&mut self, guifont_setting: &str) -> bool {
|
fn update_font(&mut self, guifont_setting: &str) -> bool {
|
||||||
let updated = self.shaper.update_font(guifont_setting);
|
let updated = self.shaper.update_font(guifont_setting);
|
||||||
if updated {
|
if updated {
|
||||||
let (font_width, font_height) = self.shaper.font_base_dimensions();
|
let (font_width, font_height) = self.shaper.font_base_dimensions();
|
||||||
self.font_width = font_width;
|
self.font_width = font_width;
|
||||||
self.font_height = font_height.ceil();
|
self.font_height = font_height.ceil();
|
||||||
}
|
}
|
||||||
updated
|
updated
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compute_text_region(&self, grid_pos: (u64, u64), cell_width: u64) -> Rect {
|
fn compute_text_region(&self, grid_pos: (u64, u64), cell_width: u64) -> Rect {
|
||||||
let (grid_x, grid_y) = grid_pos;
|
let (grid_x, grid_y) = grid_pos;
|
||||||
let x = grid_x as f32 * self.font_width;
|
let x = grid_x as f32 * self.font_width;
|
||||||
let y = grid_y as f32 * self.font_height;
|
let y = grid_y as f32 * self.font_height;
|
||||||
let width = cell_width as f32 * self.font_width as f32;
|
let width = cell_width as f32 * self.font_width as f32;
|
||||||
let height = self.font_height as f32;
|
let height = self.font_height as f32;
|
||||||
Rect::new(x, y, x + width, y + height)
|
Rect::new(x, y, x + width, y + height)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_background(
|
fn draw_background(
|
||||||
&mut self,
|
&mut self,
|
||||||
canvas: &mut Canvas,
|
canvas: &mut Canvas,
|
||||||
grid_pos: (u64, u64),
|
grid_pos: (u64, u64),
|
||||||
cell_width: u64,
|
cell_width: u64,
|
||||||
style: &Option<Arc<Style>>,
|
style: &Option<Arc<Style>>,
|
||||||
) {
|
) {
|
||||||
self.paint.set_blend_mode(BlendMode::Src);
|
self.paint.set_blend_mode(BlendMode::Src);
|
||||||
|
|
||||||
let region = self.compute_text_region(grid_pos, cell_width);
|
let region = self.compute_text_region(grid_pos, cell_width);
|
||||||
let style = style.as_ref().unwrap_or(&self.default_style);
|
let style = style.as_ref().unwrap_or(&self.default_style);
|
||||||
|
|
||||||
self.paint
|
self.paint
|
||||||
.set_color(style.background(&self.default_style.colors).to_color());
|
.set_color(style.background(&self.default_style.colors).to_color());
|
||||||
canvas.draw_rect(region, &self.paint);
|
canvas.draw_rect(region, &self.paint);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_foreground(
|
fn draw_foreground(
|
||||||
&mut self,
|
&mut self,
|
||||||
canvas: &mut Canvas,
|
canvas: &mut Canvas,
|
||||||
text: &str,
|
text: &str,
|
||||||
grid_pos: (u64, u64),
|
grid_pos: (u64, u64),
|
||||||
cell_width: u64,
|
cell_width: u64,
|
||||||
style: &Option<Arc<Style>>,
|
style: &Option<Arc<Style>>,
|
||||||
) {
|
) {
|
||||||
let (grid_x, grid_y) = grid_pos;
|
let (grid_x, grid_y) = grid_pos;
|
||||||
let x = grid_x as f32 * self.font_width;
|
let x = grid_x as f32 * self.font_width;
|
||||||
let y = grid_y as f32 * self.font_height;
|
let y = grid_y as f32 * self.font_height;
|
||||||
let width = cell_width as f32 * self.font_width;
|
let width = cell_width as f32 * self.font_width;
|
||||||
|
|
||||||
let style = style.as_ref().unwrap_or(&self.default_style);
|
let style = style.as_ref().unwrap_or(&self.default_style);
|
||||||
|
|
||||||
canvas.save();
|
canvas.save();
|
||||||
|
|
||||||
let region = self.compute_text_region(grid_pos, cell_width);
|
let region = self.compute_text_region(grid_pos, cell_width);
|
||||||
|
|
||||||
canvas.clip_rect(region, None, Some(false));
|
canvas.clip_rect(region, None, Some(false));
|
||||||
|
|
||||||
self.paint.set_blend_mode(BlendMode::Src);
|
self.paint.set_blend_mode(BlendMode::Src);
|
||||||
let transparent = Color::from_argb(0, 0, 0, 0);
|
let transparent = Color::from_argb(0, 0, 0, 0);
|
||||||
self.paint.set_color(transparent);
|
self.paint.set_color(transparent);
|
||||||
canvas.draw_rect(region, &self.paint);
|
canvas.draw_rect(region, &self.paint);
|
||||||
|
|
||||||
if style.underline || style.undercurl {
|
if style.underline || style.undercurl {
|
||||||
let line_position = self.shaper.underline_position();
|
let line_position = self.shaper.underline_position();
|
||||||
let stroke_width = self.shaper.options.size / 10.0;
|
let stroke_width = self.shaper.options.size / 10.0;
|
||||||
self.paint
|
self.paint
|
||||||
.set_color(style.special(&self.default_style.colors).to_color());
|
.set_color(style.special(&self.default_style.colors).to_color());
|
||||||
self.paint.set_stroke_width(stroke_width);
|
self.paint.set_stroke_width(stroke_width);
|
||||||
|
|
||||||
if style.undercurl {
|
if style.undercurl {
|
||||||
self.paint.set_path_effect(dash_path_effect::new(
|
self.paint.set_path_effect(dash_path_effect::new(
|
||||||
&[stroke_width * 2.0, stroke_width * 2.0],
|
&[stroke_width * 2.0, stroke_width * 2.0],
|
||||||
0.0,
|
0.0,
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
self.paint.set_path_effect(None);
|
self.paint.set_path_effect(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas.draw_line(
|
canvas.draw_line(
|
||||||
(x, y - line_position + self.font_height),
|
(x, y - line_position + self.font_height),
|
||||||
(x + width, y - line_position + self.font_height),
|
(x + width, y - line_position + self.font_height),
|
||||||
&self.paint,
|
&self.paint,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.paint
|
self.paint
|
||||||
.set_color(style.foreground(&self.default_style.colors).to_color());
|
.set_color(style.foreground(&self.default_style.colors).to_color());
|
||||||
let text = text.trim_end();
|
let text = text.trim_end();
|
||||||
if !text.is_empty() {
|
if !text.is_empty() {
|
||||||
for blob in self
|
for blob in self
|
||||||
.shaper
|
.shaper
|
||||||
.shape_cached(text, style.bold, style.italic)
|
.shape_cached(text, style.bold, style.italic)
|
||||||
.iter()
|
.iter()
|
||||||
{
|
{
|
||||||
canvas.draw_text_blob(blob, (x, y), &self.paint);
|
canvas.draw_text_blob(blob, (x, y), &self.paint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if style.strikethrough {
|
if style.strikethrough {
|
||||||
let line_position = region.center_y();
|
let line_position = region.center_y();
|
||||||
self.paint
|
self.paint
|
||||||
.set_color(style.special(&self.default_style.colors).to_color());
|
.set_color(style.special(&self.default_style.colors).to_color());
|
||||||
canvas.draw_line((x, line_position), (x + width, line_position), &self.paint);
|
canvas.draw_line((x, line_position), (x + width, line_position), &self.paint);
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas.restore();
|
canvas.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_draw_command(&mut self, root_canvas: &mut Canvas, draw_command: DrawCommand) {
|
pub fn handle_draw_command(&mut self, root_canvas: &mut Canvas, draw_command: DrawCommand) {
|
||||||
warn!("{:?}", &draw_command);
|
warn!("{:?}", &draw_command);
|
||||||
match draw_command {
|
match draw_command {
|
||||||
DrawCommand::Window {
|
DrawCommand::Window {
|
||||||
grid_id,
|
grid_id,
|
||||||
command: WindowDrawCommand::Close,
|
command: WindowDrawCommand::Close,
|
||||||
} => {
|
} => {
|
||||||
self.rendered_windows.remove(&grid_id);
|
self.rendered_windows.remove(&grid_id);
|
||||||
}
|
}
|
||||||
DrawCommand::Window { grid_id, command } => {
|
DrawCommand::Window { grid_id, command } => {
|
||||||
if let Some(rendered_window) = self.rendered_windows.remove(&grid_id) {
|
if let Some(rendered_window) = self.rendered_windows.remove(&grid_id) {
|
||||||
warn!("Window positioned {}", grid_id);
|
warn!("Window positioned {}", grid_id);
|
||||||
let rendered_window = rendered_window.handle_window_draw_command(self, command);
|
let rendered_window = rendered_window.handle_window_draw_command(self, command);
|
||||||
self.rendered_windows.insert(grid_id, rendered_window);
|
self.rendered_windows.insert(grid_id, rendered_window);
|
||||||
} else if let WindowDrawCommand::Position {
|
} else if let WindowDrawCommand::Position {
|
||||||
grid_left,
|
grid_left,
|
||||||
grid_top,
|
grid_top,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
..
|
..
|
||||||
} = command
|
} = command
|
||||||
{
|
{
|
||||||
warn!("Created window {}", grid_id);
|
warn!("Created window {}", grid_id);
|
||||||
let new_window = RenderedWindow::new(
|
let new_window = RenderedWindow::new(
|
||||||
root_canvas,
|
root_canvas,
|
||||||
&self,
|
&self,
|
||||||
grid_id,
|
grid_id,
|
||||||
(grid_left as f32, grid_top as f32).into(),
|
(grid_left as f32, grid_top as f32).into(),
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
);
|
);
|
||||||
self.rendered_windows.insert(grid_id, new_window);
|
self.rendered_windows.insert(grid_id, new_window);
|
||||||
} else {
|
} else {
|
||||||
error!("WindowDrawCommand sent for uninitialized grid {}", grid_id);
|
error!("WindowDrawCommand sent for uninitialized grid {}", grid_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DrawCommand::UpdateCursor(new_cursor) => {
|
DrawCommand::UpdateCursor(new_cursor) => {
|
||||||
self.cursor_renderer.update_cursor(new_cursor);
|
self.cursor_renderer.update_cursor(new_cursor);
|
||||||
}
|
}
|
||||||
DrawCommand::FontChanged(new_font) => {
|
DrawCommand::FontChanged(new_font) => {
|
||||||
if self.update_font(&new_font) {
|
if self.update_font(&new_font) {
|
||||||
// Resize all the grids
|
// Resize all the grids
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DrawCommand::DefaultStyleChanged(new_style) => {
|
DrawCommand::DefaultStyleChanged(new_style) => {
|
||||||
self.default_style = Arc::new(new_style);
|
self.default_style = Arc::new(new_style);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_frame(
|
pub fn draw_frame(
|
||||||
&mut self,
|
&mut self,
|
||||||
root_canvas: &mut Canvas,
|
root_canvas: &mut Canvas,
|
||||||
coordinate_system_helper: &CoordinateSystemHelper,
|
coordinate_system_helper: &CoordinateSystemHelper,
|
||||||
dt: f32,
|
dt: f32,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
trace!("Rendering");
|
trace!("Rendering");
|
||||||
let mut font_changed = false;
|
let mut font_changed = false;
|
||||||
|
|
||||||
let draw_commands: Vec<DrawCommand> = self
|
let draw_commands: Vec<DrawCommand> = self
|
||||||
.batched_draw_command_receiver
|
.batched_draw_command_receiver
|
||||||
.try_iter() // Iterator of Vec of DrawCommand
|
.try_iter() // Iterator of Vec of DrawCommand
|
||||||
.map(|batch| batch.into_iter()) // Iterator of Iterator of DrawCommand
|
.map(|batch| batch.into_iter()) // Iterator of Iterator of DrawCommand
|
||||||
.flatten() // Iterator of DrawCommand
|
.flatten() // Iterator of DrawCommand
|
||||||
.collect(); // Vec of DrawCommand
|
.collect(); // Vec of DrawCommand
|
||||||
for draw_command in draw_commands.into_iter() {
|
for draw_command in draw_commands.into_iter() {
|
||||||
if let DrawCommand::FontChanged(_) = draw_command {
|
if let DrawCommand::FontChanged(_) = draw_command {
|
||||||
font_changed = true;
|
font_changed = true;
|
||||||
}
|
}
|
||||||
self.handle_draw_command(root_canvas, draw_command);
|
self.handle_draw_command(root_canvas, draw_command);
|
||||||
}
|
}
|
||||||
|
|
||||||
root_canvas.clear(
|
root_canvas.clear(
|
||||||
self.default_style
|
self.default_style
|
||||||
.colors
|
.colors
|
||||||
.background
|
.background
|
||||||
.clone()
|
.clone()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_color(),
|
.to_color(),
|
||||||
);
|
);
|
||||||
|
|
||||||
root_canvas.save();
|
root_canvas.save();
|
||||||
|
|
||||||
if let Some(root_window) = self.rendered_windows.get(&1) {
|
if let Some(root_window) = self.rendered_windows.get(&1) {
|
||||||
let clip_rect = root_window.pixel_region(self.font_width, self.font_height);
|
let clip_rect = root_window.pixel_region(self.font_width, self.font_height);
|
||||||
root_canvas.clip_rect(&clip_rect, None, Some(false));
|
root_canvas.clip_rect(&clip_rect, None, Some(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
coordinate_system_helper.use_logical_coordinates(root_canvas);
|
coordinate_system_helper.use_logical_coordinates(root_canvas);
|
||||||
|
|
||||||
let windows: Vec<&mut RenderedWindow> = {
|
let windows: Vec<&mut RenderedWindow> = {
|
||||||
let (mut root_windows, mut floating_windows): (
|
let (mut root_windows, mut floating_windows): (
|
||||||
Vec<&mut RenderedWindow>,
|
Vec<&mut RenderedWindow>,
|
||||||
Vec<&mut RenderedWindow>,
|
Vec<&mut RenderedWindow>,
|
||||||
) = self
|
) = self
|
||||||
.rendered_windows
|
.rendered_windows
|
||||||
.values_mut()
|
.values_mut()
|
||||||
.filter(|window| !window.hidden)
|
.filter(|window| !window.hidden)
|
||||||
.partition(|window| !window.floating);
|
.partition(|window| !window.floating);
|
||||||
|
|
||||||
root_windows
|
root_windows
|
||||||
.sort_by(|window_a, window_b| window_a.id.partial_cmp(&window_b.id).unwrap());
|
.sort_by(|window_a, window_b| window_a.id.partial_cmp(&window_b.id).unwrap());
|
||||||
floating_windows
|
floating_windows
|
||||||
.sort_by(|window_a, window_b| window_a.id.partial_cmp(&window_b.id).unwrap());
|
.sort_by(|window_a, window_b| window_a.id.partial_cmp(&window_b.id).unwrap());
|
||||||
|
|
||||||
root_windows
|
root_windows
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.chain(floating_windows.into_iter())
|
.chain(floating_windows.into_iter())
|
||||||
.collect()
|
.collect()
|
||||||
};
|
};
|
||||||
|
|
||||||
let settings = SETTINGS.get::<RendererSettings>();
|
let settings = SETTINGS.get::<RendererSettings>();
|
||||||
let font_width = self.font_width;
|
let font_width = self.font_width;
|
||||||
let font_height = self.font_height;
|
let font_height = self.font_height;
|
||||||
self.window_regions = windows
|
self.window_regions = windows
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|window| window.draw(root_canvas, &settings, font_width, font_height, dt))
|
.map(|window| window.draw(root_canvas, &settings, font_width, font_height, dt))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
self.cursor_renderer.draw(
|
self.cursor_renderer.draw(
|
||||||
&self.default_style.colors,
|
&self.default_style.colors,
|
||||||
(self.font_width, self.font_height),
|
(self.font_width, self.font_height),
|
||||||
&mut self.shaper,
|
&mut self.shaper,
|
||||||
root_canvas,
|
root_canvas,
|
||||||
dt,
|
dt,
|
||||||
);
|
);
|
||||||
|
|
||||||
root_canvas.restore();
|
root_canvas.restore();
|
||||||
|
|
||||||
font_changed
|
font_changed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue