Make render testable (#16)
* Make render testable * Add some tests * Format code * Fix render caret after input * Add kcov scripts * Fix caret position * Test move caret * Test move caret * Test move caret * Additional tests * Additional token to color test
This commit is contained in:
parent
c2e1369738
commit
08a5987a4a
2
.gitignore
vendored
2
.gitignore
vendored
@ -5,3 +5,5 @@ log
|
|||||||
.rider
|
.rider
|
||||||
.codecov
|
.codecov
|
||||||
cobertura.xml
|
cobertura.xml
|
||||||
|
cov
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::app::{UpdateResult, WindowCanvas as WC};
|
use crate::app::{UpdateResult, WindowCanvas as WC};
|
||||||
use crate::renderer::Renderer;
|
use crate::renderer::CanvasRenderer;
|
||||||
use crate::ui::*;
|
use crate::ui::*;
|
||||||
use rider_config::*;
|
use rider_config::*;
|
||||||
use sdl2::rect::Point;
|
use sdl2::rect::Point;
|
||||||
@ -27,7 +27,7 @@ impl AppState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
#[cfg_attr(tarpaulin, skip)]
|
||||||
pub fn open_file(&mut self, file_path: String, renderer: &mut Renderer) {
|
pub fn open_file(&mut self, file_path: String, renderer: &mut CanvasRenderer) {
|
||||||
if let Ok(buffer) = read_to_string(&file_path) {
|
if let Ok(buffer) = read_to_string(&file_path) {
|
||||||
let mut file = EditorFile::new(file_path.clone(), buffer, self.config.clone());
|
let mut file = EditorFile::new(file_path.clone(), buffer, self.config.clone());
|
||||||
file.prepare_ui(renderer);
|
file.prepare_ui(renderer);
|
||||||
@ -41,7 +41,7 @@ impl AppState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
#[cfg_attr(tarpaulin, skip)]
|
||||||
pub fn open_directory(&mut self, dir_path: String, renderer: &mut Renderer) {
|
pub fn open_directory(&mut self, dir_path: String, renderer: &mut CanvasRenderer) {
|
||||||
match self.open_file_modal.as_mut() {
|
match self.open_file_modal.as_mut() {
|
||||||
Some(modal) => modal.open_directory(dir_path, renderer),
|
Some(modal) => modal.open_directory(dir_path, renderer),
|
||||||
_ => (),
|
_ => (),
|
||||||
@ -74,20 +74,18 @@ impl AppState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
#[cfg_attr(tarpaulin, skip)]
|
||||||
impl Render for AppState {
|
impl AppState {
|
||||||
fn render(&self, canvas: &mut WC, renderer: &mut Renderer, _context: &RenderContext) {
|
pub fn render(&self, canvas: &mut WC, renderer: &mut CanvasRenderer, _context: &RenderContext) {
|
||||||
self.file_editor
|
self.file_editor.render(canvas, renderer);
|
||||||
.render(canvas, renderer, &RenderContext::Nothing);
|
self.menu_bar.render(canvas, &RenderContext::Nothing);
|
||||||
self.menu_bar
|
|
||||||
.render(canvas, renderer, &RenderContext::Nothing);
|
|
||||||
match self.open_file_modal.as_ref() {
|
match self.open_file_modal.as_ref() {
|
||||||
Some(modal) => modal.render(canvas, renderer, &RenderContext::Nothing),
|
Some(modal) => modal.render(canvas, renderer, &RenderContext::Nothing),
|
||||||
_ => (),
|
_ => (),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_ui(&mut self, renderer: &mut Renderer) {
|
pub fn prepare_ui(&mut self, renderer: &mut CanvasRenderer) {
|
||||||
self.menu_bar.prepare_ui(renderer);
|
self.menu_bar.prepare_ui();
|
||||||
self.file_editor.prepare_ui(renderer);
|
self.file_editor.prepare_ui(renderer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
pub use crate::app::app_state::AppState;
|
pub use crate::app::app_state::AppState;
|
||||||
pub use crate::renderer::Renderer;
|
pub use crate::renderer::CanvasRenderer;
|
||||||
use crate::ui::caret::{CaretPosition, MoveDirection};
|
use crate::ui::caret::{CaretPosition, MoveDirection};
|
||||||
use crate::ui::*;
|
use crate::ui::*;
|
||||||
pub use rider_config::{Config, ConfigAccess, ConfigHolder};
|
pub use rider_config::{Config, ConfigAccess, ConfigHolder};
|
||||||
@ -115,7 +115,8 @@ impl Application {
|
|||||||
let texture_creator = self.canvas.texture_creator();
|
let texture_creator = self.canvas.texture_creator();
|
||||||
let sleep_time = Duration::new(0, 1_000_000_000u32 / 60);
|
let sleep_time = Duration::new(0, 1_000_000_000u32 / 60);
|
||||||
let mut app_state = AppState::new(Arc::clone(&self.config));
|
let mut app_state = AppState::new(Arc::clone(&self.config));
|
||||||
let mut renderer = Renderer::new(Arc::clone(&self.config), &font_context, &texture_creator);
|
let mut renderer =
|
||||||
|
CanvasRenderer::new(Arc::clone(&self.config), &font_context, &texture_creator);
|
||||||
app_state.prepare_ui(&mut renderer);
|
app_state.prepare_ui(&mut renderer);
|
||||||
|
|
||||||
'running: loop {
|
'running: loop {
|
||||||
|
@ -41,27 +41,185 @@ pub fn move_caret_left(file_editor: &mut FileEditor) {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test_move_right {
|
mod test_move_right {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::renderer::managers::FontDetails;
|
||||||
|
use crate::renderer::managers::TextDetails;
|
||||||
|
use crate::renderer::renderer::Renderer;
|
||||||
use crate::tests::support;
|
use crate::tests::support;
|
||||||
|
use rider_config::config::Config;
|
||||||
|
use rider_config::ConfigHolder;
|
||||||
|
use sdl2::rect::Rect;
|
||||||
|
use sdl2::render::Texture;
|
||||||
|
use sdl2::ttf::Font;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::sync::RwLock;
|
||||||
|
|
||||||
|
struct RendererMock {
|
||||||
|
pub config: Arc<RwLock<Config>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RendererMock {
|
||||||
|
pub fn new(config: Arc<RwLock<Config>>) -> Self {
|
||||||
|
Self { config }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Renderer for RendererMock {
|
||||||
|
#[cfg_attr(tarpaulin, skip)]
|
||||||
|
fn load_font(&mut self, _details: FontDetails) -> Rc<Font> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_text_tex(
|
||||||
|
&mut self,
|
||||||
|
_details: &mut TextDetails,
|
||||||
|
_font_details: FontDetails,
|
||||||
|
) -> Result<Rc<Texture>, String> {
|
||||||
|
Err("skip render character".to_owned())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConfigHolder for RendererMock {
|
||||||
|
fn config(&self) -> &Arc<RwLock<Config>> {
|
||||||
|
&self.config
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CharacterSizeManager for RendererMock {
|
||||||
|
fn load_character_size(&mut self, c: char) -> Rect {
|
||||||
|
match c {
|
||||||
|
'\n' => Rect::new(0, 0, 12, 13),
|
||||||
|
_ => Rect::new(0, 0, 14, 15),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn must_do_nothing() {
|
fn assert_move_with_no_file() {
|
||||||
let config = support::build_config();
|
let config = support::build_config();
|
||||||
let mut editor = FileEditor::new(config);
|
let mut editor = FileEditor::new(config);
|
||||||
|
|
||||||
assert_eq!(move_caret_right(&mut editor), ());
|
assert_eq!(move_caret_right(&mut editor), ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_move_caret_with_empty_file() {
|
||||||
|
let config = support::build_config();
|
||||||
|
let mut renderer = RendererMock::new(config.clone());
|
||||||
|
let mut editor = FileEditor::new(config.clone());
|
||||||
|
let mut file = EditorFile::new("test.txt".to_owned(), "".to_owned(), config);
|
||||||
|
file.prepare_ui(&mut renderer);
|
||||||
|
editor.open_file(file);
|
||||||
|
editor.prepare_ui(&mut renderer);
|
||||||
|
editor.move_caret(MoveDirection::Left);
|
||||||
|
|
||||||
|
assert_eq!(move_caret_right(&mut editor), ());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_move_caret_with_filled_file() {
|
||||||
|
let config = support::build_config();
|
||||||
|
let mut renderer = RendererMock::new(config.clone());
|
||||||
|
let mut editor = FileEditor::new(config.clone());
|
||||||
|
let mut file = EditorFile::new("test.txt".to_owned(), "hello".to_owned(), config);
|
||||||
|
file.prepare_ui(&mut renderer);
|
||||||
|
editor.open_file(file);
|
||||||
|
editor.prepare_ui(&mut renderer);
|
||||||
|
editor.move_caret(MoveDirection::Left);
|
||||||
|
|
||||||
|
assert_eq!(move_caret_right(&mut editor), ());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test_move_left {
|
mod test_move_left {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::renderer::managers::FontDetails;
|
||||||
|
use crate::renderer::managers::TextDetails;
|
||||||
|
use crate::renderer::renderer::Renderer;
|
||||||
use crate::tests::support;
|
use crate::tests::support;
|
||||||
|
use rider_config::config::Config;
|
||||||
|
use rider_config::ConfigHolder;
|
||||||
|
use sdl2::rect::Rect;
|
||||||
|
use sdl2::render::Texture;
|
||||||
|
use sdl2::ttf::Font;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::sync::RwLock;
|
||||||
|
|
||||||
|
struct RendererMock {
|
||||||
|
pub config: Arc<RwLock<Config>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RendererMock {
|
||||||
|
pub fn new(config: Arc<RwLock<Config>>) -> Self {
|
||||||
|
Self { config }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Renderer for RendererMock {
|
||||||
|
#[cfg_attr(tarpaulin, skip)]
|
||||||
|
fn load_font(&mut self, _details: FontDetails) -> Rc<Font> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_text_tex(
|
||||||
|
&mut self,
|
||||||
|
_details: &mut TextDetails,
|
||||||
|
_font_details: FontDetails,
|
||||||
|
) -> Result<Rc<Texture>, String> {
|
||||||
|
Err("skip render character".to_owned())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConfigHolder for RendererMock {
|
||||||
|
fn config(&self) -> &Arc<RwLock<Config>> {
|
||||||
|
&self.config
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CharacterSizeManager for RendererMock {
|
||||||
|
fn load_character_size(&mut self, c: char) -> Rect {
|
||||||
|
match c {
|
||||||
|
'\n' => Rect::new(0, 0, 12, 13),
|
||||||
|
_ => Rect::new(0, 0, 14, 15),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn must_do_nothing() {
|
fn assert_move_caret_without_file() {
|
||||||
let config = support::build_config();
|
let config = support::build_config();
|
||||||
let mut editor = FileEditor::new(config);
|
let mut editor = FileEditor::new(config);
|
||||||
|
|
||||||
assert_eq!(move_caret_left(&mut editor), ());
|
assert_eq!(move_caret_left(&mut editor), ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_move_caret_with_empty_file() {
|
||||||
|
let config = support::build_config();
|
||||||
|
let mut renderer = RendererMock::new(config.clone());
|
||||||
|
let mut editor = FileEditor::new(config.clone());
|
||||||
|
let mut file = EditorFile::new("test.txt".to_owned(), "".to_owned(), config);
|
||||||
|
file.prepare_ui(&mut renderer);
|
||||||
|
editor.open_file(file);
|
||||||
|
editor.prepare_ui(&mut renderer);
|
||||||
|
editor.move_caret(MoveDirection::Right);
|
||||||
|
|
||||||
|
assert_eq!(move_caret_left(&mut editor), ());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_move_caret_with_filled_file() {
|
||||||
|
let config = support::build_config();
|
||||||
|
let mut renderer = RendererMock::new(config.clone());
|
||||||
|
let mut editor = FileEditor::new(config.clone());
|
||||||
|
let mut file = EditorFile::new("test.txt".to_owned(), "hello".to_owned(), config);
|
||||||
|
file.prepare_ui(&mut renderer);
|
||||||
|
editor.open_file(file);
|
||||||
|
editor.prepare_ui(&mut renderer);
|
||||||
|
editor.move_caret(MoveDirection::Right);
|
||||||
|
|
||||||
|
assert_eq!(move_caret_left(&mut editor), ());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::app::*;
|
use crate::app::*;
|
||||||
use crate::renderer::Renderer;
|
use crate::renderer::renderer::Renderer;
|
||||||
use crate::ui::*;
|
use crate::ui::*;
|
||||||
use sdl2::rect::{Point, Rect};
|
use sdl2::rect::{Point, Rect};
|
||||||
use std::sync::*;
|
use std::sync::*;
|
||||||
@ -11,7 +11,10 @@ pub fn current_file_path(file_editor: &mut FileEditor) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
#[cfg_attr(tarpaulin, skip)]
|
||||||
pub fn delete_front(file_editor: &mut FileEditor, renderer: &mut Renderer) {
|
pub fn delete_front<R>(file_editor: &mut FileEditor, renderer: &mut R)
|
||||||
|
where
|
||||||
|
R: ConfigHolder + CharacterSizeManager + Renderer,
|
||||||
|
{
|
||||||
let mut buffer: String = if let Some(file) = file_editor.file() {
|
let mut buffer: String = if let Some(file) = file_editor.file() {
|
||||||
file
|
file
|
||||||
} else {
|
} else {
|
||||||
@ -53,7 +56,10 @@ pub fn delete_front(file_editor: &mut FileEditor, renderer: &mut Renderer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
#[cfg_attr(tarpaulin, skip)]
|
||||||
pub fn delete_back(file_editor: &mut FileEditor, renderer: &mut Renderer) {
|
pub fn delete_back<R>(file_editor: &mut FileEditor, renderer: &mut R)
|
||||||
|
where
|
||||||
|
R: ConfigHolder + CharacterSizeManager + Renderer,
|
||||||
|
{
|
||||||
let file: &EditorFile = if let Some(file) = file_editor.file() {
|
let file: &EditorFile = if let Some(file) = file_editor.file() {
|
||||||
file
|
file
|
||||||
} else {
|
} else {
|
||||||
@ -70,30 +76,27 @@ pub fn delete_back(file_editor: &mut FileEditor, renderer: &mut Renderer) {
|
|||||||
file_editor.replace_current_file(new_file);
|
file_editor.replace_current_file(new_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
pub fn insert_text<R>(file_editor: &mut FileEditor, text: String, renderer: &mut R)
|
||||||
pub fn insert_text(file_editor: &mut FileEditor, text: String, renderer: &mut Renderer) {
|
where
|
||||||
let mut buffer: String = file_editor.file().map_or(String::new(), |f| f.buffer());
|
R: ConfigHolder + CharacterSizeManager + Renderer,
|
||||||
if buffer.is_empty() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let current = match file_editor
|
|
||||||
.file()
|
|
||||||
.and_then(|file| file.get_character_at(file_editor.caret().text_position()))
|
|
||||||
{
|
{
|
||||||
Some(c) => c,
|
let mut buffer: String = match file_editor.file() {
|
||||||
_ => return,
|
Some(f) => f.buffer(),
|
||||||
|
None => return,
|
||||||
};
|
};
|
||||||
let mut pos = if current.is_new_line() {
|
|
||||||
current.dest().top_left()
|
let maybe_character = file_editor
|
||||||
+ Point::new(0, renderer.load_character_size('\n').height() as i32)
|
.file()
|
||||||
} else {
|
.and_then(|file| file.get_character_at(file_editor.caret().text_position()));
|
||||||
current.dest().top_left()
|
|
||||||
|
let mut pos = match maybe_character {
|
||||||
|
Some(ref current) => current.dest().top_left(),
|
||||||
|
None => Point::new(0, 0),
|
||||||
};
|
};
|
||||||
let mut position: CaretPosition = file_editor.caret().position().clone();
|
let mut position: CaretPosition = file_editor.caret().position().clone();
|
||||||
for character in text.chars() {
|
for c in text.chars() {
|
||||||
buffer.insert(position.text_position(), character);
|
buffer.insert(position.text_position(), c);
|
||||||
let rect = renderer.load_character_size(character);
|
let rect = renderer.load_character_size(c);
|
||||||
pos = pos + Point::new(rect.width() as i32, 0);
|
pos = pos + Point::new(rect.width() as i32, 0);
|
||||||
position = position.moved(1, 0, 0);
|
position = position.moved(1, 0, 0);
|
||||||
file_editor.caret_mut().move_caret(position, pos.clone());
|
file_editor.caret_mut().move_caret(position, pos.clone());
|
||||||
@ -108,28 +111,27 @@ pub fn insert_text(file_editor: &mut FileEditor, text: String, renderer: &mut Re
|
|||||||
file_editor.replace_current_file(new_file);
|
file_editor.replace_current_file(new_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
pub fn insert_new_line<R>(file_editor: &mut FileEditor, renderer: &mut R)
|
||||||
pub fn insert_new_line(file_editor: &mut FileEditor, renderer: &mut Renderer) {
|
where
|
||||||
let mut buffer: String = if let Some(file) = file_editor.file() {
|
R: ConfigHolder + CharacterSizeManager + Renderer,
|
||||||
file
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
.buffer();
|
|
||||||
let current = match file_editor
|
|
||||||
.file()
|
|
||||||
.and_then(|file| file.get_character_at(file_editor.caret().text_position()))
|
|
||||||
{
|
{
|
||||||
Some(c) => c,
|
let mut buffer: String = match file_editor.file() {
|
||||||
_ => return,
|
Some(file) => file.buffer(),
|
||||||
|
None => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut pos = Point::new(current.dest().x(), current.dest().y());
|
let maybe_character = file_editor
|
||||||
|
.file()
|
||||||
|
.and_then(|file| file.get_character_at(file_editor.caret().text_position()));
|
||||||
|
let mut pos = match maybe_character {
|
||||||
|
None => Point::new(0, 0),
|
||||||
|
Some(current) => current.dest().top_left(),
|
||||||
|
};
|
||||||
let mut position: CaretPosition = file_editor.caret().position().clone();
|
let mut position: CaretPosition = file_editor.caret().position().clone();
|
||||||
buffer.insert(position.text_position(), '\n');
|
buffer.insert(position.text_position(), '\n');
|
||||||
let rect = renderer.load_character_size('\n');
|
let rect = renderer.load_character_size('\n');
|
||||||
pos = Point::new(0, pos.y() + rect.height() as i32);
|
pos = Point::new(0, pos.y() + rect.height() as i32);
|
||||||
position = position.moved(0, 1, 0);
|
position = position.moved(1, 1, -(position.line_position() as i32));
|
||||||
file_editor.caret_mut().move_caret(position, pos.clone());
|
file_editor.caret_mut().move_caret(position, pos.clone());
|
||||||
|
|
||||||
let mut new_file = EditorFile::new(
|
let mut new_file = EditorFile::new(
|
||||||
@ -144,7 +146,54 @@ pub fn insert_new_line(file_editor: &mut FileEditor, renderer: &mut Renderer) {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::renderer::managers::FontDetails;
|
||||||
|
use crate::renderer::managers::TextDetails;
|
||||||
use crate::tests::support;
|
use crate::tests::support;
|
||||||
|
use sdl2::render::Texture;
|
||||||
|
use sdl2::ttf::Font;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::sync::RwLock;
|
||||||
|
|
||||||
|
struct RendererMock {
|
||||||
|
pub config: Arc<RwLock<Config>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RendererMock {
|
||||||
|
pub fn new(config: Arc<RwLock<Config>>) -> Self {
|
||||||
|
Self { config }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Renderer for RendererMock {
|
||||||
|
#[cfg_attr(tarpaulin, skip)]
|
||||||
|
fn load_font(&mut self, _details: FontDetails) -> Rc<Font> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_text_tex(
|
||||||
|
&mut self,
|
||||||
|
_details: &mut TextDetails,
|
||||||
|
_font_details: FontDetails,
|
||||||
|
) -> Result<Rc<Texture>, String> {
|
||||||
|
Err("skip render character".to_owned())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConfigHolder for RendererMock {
|
||||||
|
fn config(&self) -> &Arc<RwLock<Config>> {
|
||||||
|
&self.config
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CharacterSizeManager for RendererMock {
|
||||||
|
fn load_character_size(&mut self, c: char) -> Rect {
|
||||||
|
match c {
|
||||||
|
'\n' => Rect::new(0, 0, 12, 13),
|
||||||
|
_ => Rect::new(0, 0, 14, 15),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn must_return_empty_string_when_no_file() {
|
fn must_return_empty_string_when_no_file() {
|
||||||
@ -167,4 +216,156 @@ mod tests {
|
|||||||
let result = current_file_path(&mut editor);
|
let result = current_file_path(&mut editor);
|
||||||
assert_eq!(result, "/foo/bar".to_owned());
|
assert_eq!(result, "/foo/bar".to_owned());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//##################################################
|
||||||
|
// insert text
|
||||||
|
//##################################################
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_insert_text_without_file() {
|
||||||
|
let config = support::build_config();
|
||||||
|
let mut renderer = RendererMock::new(config.clone());
|
||||||
|
let mut widget = FileEditor::new(config.clone());
|
||||||
|
widget.prepare_ui(&mut renderer);
|
||||||
|
widget.insert_text("foo".to_owned(), &mut renderer);
|
||||||
|
let expected = CaretPosition::new(0, 0, 0);
|
||||||
|
assert_eq!(widget.caret().position(), &expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_insert_text_to_empty_file() {
|
||||||
|
let config = support::build_config();
|
||||||
|
let mut renderer = RendererMock::new(config.clone());
|
||||||
|
let mut widget = FileEditor::new(config.clone());
|
||||||
|
let file = EditorFile::new("".to_owned(), "".to_owned(), config.clone());
|
||||||
|
widget.open_file(file);
|
||||||
|
widget.prepare_ui(&mut renderer);
|
||||||
|
widget.insert_text("foo".to_owned(), &mut renderer);
|
||||||
|
let expected = CaretPosition::new(3, 0, 0);
|
||||||
|
assert_eq!(widget.caret().position(), &expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_insert_text_to_file_without_new_line() {
|
||||||
|
let config = support::build_config();
|
||||||
|
let mut renderer = RendererMock::new(config.clone());
|
||||||
|
let mut widget = FileEditor::new(config.clone());
|
||||||
|
let mut file = EditorFile::new("".to_owned(), "bar".to_owned(), config.clone());
|
||||||
|
file.prepare_ui(&mut renderer);
|
||||||
|
widget.open_file(file);
|
||||||
|
widget.prepare_ui(&mut renderer);
|
||||||
|
widget.insert_text("foo".to_owned(), &mut renderer);
|
||||||
|
let expected = CaretPosition::new(3, 0, 0);
|
||||||
|
assert_eq!(widget.caret().position(), &expected);
|
||||||
|
assert_eq!(widget.file().is_some(), true);
|
||||||
|
let buffer = widget.file().unwrap().buffer();
|
||||||
|
let expected = "foobar";
|
||||||
|
assert_eq!(buffer, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_insert_text_to_file_with_new_line() {
|
||||||
|
let config = support::build_config();
|
||||||
|
let mut renderer = RendererMock::new(config.clone());
|
||||||
|
let mut widget = FileEditor::new(config.clone());
|
||||||
|
let mut file = EditorFile::new("".to_owned(), "bar\n".to_owned(), config.clone());
|
||||||
|
file.prepare_ui(&mut renderer);
|
||||||
|
widget.open_file(file);
|
||||||
|
widget.prepare_ui(&mut renderer);
|
||||||
|
widget.insert_text("foo".to_owned(), &mut renderer);
|
||||||
|
let expected = CaretPosition::new(3, 0, 0);
|
||||||
|
assert_eq!(widget.caret().position(), &expected);
|
||||||
|
assert_eq!(widget.file().is_some(), true);
|
||||||
|
let buffer = widget.file().unwrap().buffer();
|
||||||
|
let expected = "foobar\n";
|
||||||
|
assert_eq!(buffer, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_insert_text_to_file_with_new_line_with_caret_at_new_line() {
|
||||||
|
let config = support::build_config();
|
||||||
|
let mut renderer = RendererMock::new(config.clone());
|
||||||
|
let mut widget = FileEditor::new(config.clone());
|
||||||
|
let mut file = EditorFile::new("".to_owned(), "old content\n".to_owned(), config.clone());
|
||||||
|
file.prepare_ui(&mut renderer);
|
||||||
|
widget.open_file(file);
|
||||||
|
widget.prepare_ui(&mut renderer);
|
||||||
|
widget.set_caret_to_end_of_line(0);
|
||||||
|
widget.insert_text("new content".to_owned(), &mut renderer);
|
||||||
|
let expected = CaretPosition::new(22, 0, 0);
|
||||||
|
assert_eq!(widget.caret().position(), &expected);
|
||||||
|
assert_eq!(widget.file().is_some(), true);
|
||||||
|
let buffer = widget.file().unwrap().buffer();
|
||||||
|
let expected = "old contentnew content\n";
|
||||||
|
assert_eq!(buffer, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
//##################################################
|
||||||
|
// insert new line
|
||||||
|
//##################################################
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_insert_new_line_without_file() {
|
||||||
|
let config = support::build_config();
|
||||||
|
let mut renderer = RendererMock::new(config.clone());
|
||||||
|
let mut widget = FileEditor::new(config.clone());
|
||||||
|
widget.prepare_ui(&mut renderer);
|
||||||
|
widget.insert_new_line(&mut renderer);
|
||||||
|
let expected = CaretPosition::new(0, 0, 0);
|
||||||
|
assert_eq!(widget.caret().position(), &expected);
|
||||||
|
let expected = Rect::new(0, 0, 6, 15);
|
||||||
|
assert_eq!(widget.caret().dest(), expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_insert_new_line_to_empty_file() {
|
||||||
|
let config = support::build_config();
|
||||||
|
let mut renderer = RendererMock::new(config.clone());
|
||||||
|
let mut widget = FileEditor::new(config.clone());
|
||||||
|
let file = EditorFile::new("".to_owned(), "".to_owned(), config.clone());
|
||||||
|
widget.open_file(file);
|
||||||
|
widget.prepare_ui(&mut renderer);
|
||||||
|
widget.insert_new_line(&mut renderer);
|
||||||
|
let expected = CaretPosition::new(1, 1, 0);
|
||||||
|
assert_eq!(widget.caret().position(), &expected);
|
||||||
|
let expected = Rect::new(0, 13, 6, 15);
|
||||||
|
assert_eq!(widget.caret().dest(), expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_insert_new_line_to_file_at_beginning() {
|
||||||
|
let config = support::build_config();
|
||||||
|
let mut renderer = RendererMock::new(config.clone());
|
||||||
|
let mut widget = FileEditor::new(config.clone());
|
||||||
|
let file = EditorFile::new("".to_owned(), "foo".to_owned(), config.clone());
|
||||||
|
widget.open_file(file);
|
||||||
|
widget.prepare_ui(&mut renderer);
|
||||||
|
widget.insert_new_line(&mut renderer);
|
||||||
|
let expected = CaretPosition::new(1, 1, 0);
|
||||||
|
assert_eq!(widget.caret().position(), &expected);
|
||||||
|
let expected = Rect::new(0, 13, 6, 15);
|
||||||
|
assert_eq!(widget.caret().dest(), expected);
|
||||||
|
assert_eq!(widget.file().is_some(), true);
|
||||||
|
assert_eq!(widget.file().unwrap().buffer(), "\nfoo".to_owned());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_insert_new_line_to_file_in_middle() {
|
||||||
|
let config = support::build_config();
|
||||||
|
let mut renderer = RendererMock::new(config.clone());
|
||||||
|
let mut widget = FileEditor::new(config.clone());
|
||||||
|
let mut file = EditorFile::new("hello.txt".to_owned(), "abcd".to_owned(), config.clone());
|
||||||
|
file.prepare_ui(&mut renderer);
|
||||||
|
widget.open_file(file);
|
||||||
|
widget.prepare_ui(&mut renderer);
|
||||||
|
widget.move_caret(MoveDirection::Right);
|
||||||
|
widget.move_caret(MoveDirection::Right);
|
||||||
|
widget.insert_new_line(&mut renderer);
|
||||||
|
let expected = CaretPosition::new(3, 1, 0);
|
||||||
|
assert_eq!(widget.caret().position(), &expected);
|
||||||
|
let expected = Rect::new(0, 13, 6, 15);
|
||||||
|
assert_eq!(widget.caret().dest(), expected);
|
||||||
|
assert_eq!(widget.file().is_some(), true);
|
||||||
|
assert_eq!(widget.file().unwrap().buffer(), "ab\ncd".to_owned());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,7 +181,7 @@ pub trait TextTextureManager<'l> {
|
|||||||
fn load_text(
|
fn load_text(
|
||||||
&mut self,
|
&mut self,
|
||||||
details: &mut TextDetails,
|
details: &mut TextDetails,
|
||||||
font: &Rc<Font>,
|
font: Rc<Font>,
|
||||||
) -> Result<Rc<Texture<'l>>, String>;
|
) -> Result<Rc<Texture<'l>>, String>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,7 +191,7 @@ impl<'l> TextTextureManager<'l> for TextureManager<'l> {
|
|||||||
fn load_text(
|
fn load_text(
|
||||||
&mut self,
|
&mut self,
|
||||||
details: &mut TextDetails,
|
details: &mut TextDetails,
|
||||||
font: &Rc<Font>,
|
font: Rc<Font>,
|
||||||
) -> Result<Rc<Texture<'l>>, String> {
|
) -> Result<Rc<Texture<'l>>, String> {
|
||||||
let key = details.get_cache_key();
|
let key = details.get_cache_key();
|
||||||
self.cache.get(key.as_str()).cloned().map_or_else(
|
self.cache.get(key.as_str()).cloned().map_or_else(
|
||||||
|
@ -3,12 +3,25 @@ use crate::ui::get_text_character_rect;
|
|||||||
use crate::ui::text_character::CharacterSizeManager;
|
use crate::ui::text_character::CharacterSizeManager;
|
||||||
use rider_config::{ConfigAccess, ConfigHolder};
|
use rider_config::{ConfigAccess, ConfigHolder};
|
||||||
use sdl2::rect::Rect;
|
use sdl2::rect::Rect;
|
||||||
|
use sdl2::render::Texture;
|
||||||
use sdl2::render::TextureCreator;
|
use sdl2::render::TextureCreator;
|
||||||
|
use sdl2::ttf::Font;
|
||||||
use sdl2::ttf::Sdl2TtfContext;
|
use sdl2::ttf::Sdl2TtfContext;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
pub trait Renderer {
|
||||||
|
fn load_font(&mut self, details: FontDetails) -> Rc<Font>;
|
||||||
|
|
||||||
|
fn load_text_tex(
|
||||||
|
&mut self,
|
||||||
|
details: &mut TextDetails,
|
||||||
|
font_details: FontDetails,
|
||||||
|
) -> Result<Rc<Texture>, String>;
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
#[cfg_attr(tarpaulin, skip)]
|
||||||
pub struct Renderer<'l> {
|
pub struct CanvasRenderer<'l> {
|
||||||
config: ConfigAccess,
|
config: ConfigAccess,
|
||||||
font_manager: FontManager<'l>,
|
font_manager: FontManager<'l>,
|
||||||
texture_manager: TextureManager<'l>,
|
texture_manager: TextureManager<'l>,
|
||||||
@ -16,7 +29,7 @@ pub struct Renderer<'l> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
#[cfg_attr(tarpaulin, skip)]
|
||||||
impl<'l> Renderer<'l> {
|
impl<'l> CanvasRenderer<'l> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
config: ConfigAccess,
|
config: ConfigAccess,
|
||||||
font_context: &'l Sdl2TtfContext,
|
font_context: &'l Sdl2TtfContext,
|
||||||
@ -37,7 +50,8 @@ impl<'l> Renderer<'l> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'l> CharacterSizeManager for Renderer<'l> {
|
#[cfg_attr(tarpaulin, skip)]
|
||||||
|
impl<'l> CharacterSizeManager for CanvasRenderer<'l> {
|
||||||
fn load_character_size(&mut self, c: char) -> Rect {
|
fn load_character_size(&mut self, c: char) -> Rect {
|
||||||
let (font_path, font_size) = {
|
let (font_path, font_size) = {
|
||||||
let config = self.config().read().unwrap();
|
let config = self.config().read().unwrap();
|
||||||
@ -65,7 +79,7 @@ impl<'l> CharacterSizeManager for Renderer<'l> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
#[cfg_attr(tarpaulin, skip)]
|
||||||
impl<'l> ManagersHolder<'l> for Renderer<'l> {
|
impl<'l> ManagersHolder<'l> for CanvasRenderer<'l> {
|
||||||
fn font_manager(&mut self) -> &mut FontManager<'l> {
|
fn font_manager(&mut self) -> &mut FontManager<'l> {
|
||||||
&mut self.font_manager
|
&mut self.font_manager
|
||||||
}
|
}
|
||||||
@ -76,8 +90,31 @@ impl<'l> ManagersHolder<'l> for Renderer<'l> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
#[cfg_attr(tarpaulin, skip)]
|
||||||
impl<'l> ConfigHolder for Renderer<'l> {
|
impl<'l> ConfigHolder for CanvasRenderer<'l> {
|
||||||
fn config(&self) -> &ConfigAccess {
|
fn config(&self) -> &ConfigAccess {
|
||||||
&self.config
|
&self.config
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(tarpaulin, skip)]
|
||||||
|
impl<'l> Renderer for CanvasRenderer<'l> {
|
||||||
|
fn load_font(&mut self, details: FontDetails) -> Rc<Font> {
|
||||||
|
self.font_manager()
|
||||||
|
.load(&details)
|
||||||
|
.unwrap_or_else(|_| panic!("Font not found {:?}", details))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_text_tex(
|
||||||
|
&mut self,
|
||||||
|
details: &mut TextDetails,
|
||||||
|
font_details: FontDetails,
|
||||||
|
) -> Result<Rc<Texture>, String> {
|
||||||
|
use crate::renderer::managers::TextTextureManager;
|
||||||
|
let font = self
|
||||||
|
.font_manager()
|
||||||
|
.load(&font_details)
|
||||||
|
.unwrap_or_else(|_| panic!("Font not found {:?}", details));
|
||||||
|
let tex_manager = self.texture_manager();
|
||||||
|
tex_manager.load_text(details, font)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use crate::app::{UpdateResult as UR, WindowCanvas as WC};
|
use crate::app::UpdateResult as UR;
|
||||||
use crate::renderer::*;
|
|
||||||
use crate::ui::*;
|
use crate::ui::*;
|
||||||
use rider_config::ConfigAccess;
|
use rider_config::ConfigAccess;
|
||||||
use sdl2::rect::{Point, Rect};
|
use sdl2::rect::{Point, Rect};
|
||||||
@ -7,7 +6,6 @@ use std::ops::Deref;
|
|||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct Caret {
|
pub struct Caret {
|
||||||
pending: bool,
|
|
||||||
blink_delay: u8,
|
blink_delay: u8,
|
||||||
state: CaretState,
|
state: CaretState,
|
||||||
position: CaretPosition,
|
position: CaretPosition,
|
||||||
@ -25,7 +23,6 @@ impl Caret {
|
|||||||
blink_delay: 0,
|
blink_delay: 0,
|
||||||
dest: Rect::new(0, 0, 6, 0),
|
dest: Rect::new(0, 0, 6, 0),
|
||||||
colors: CaretColor::new(bright, blur),
|
colors: CaretColor::new(bright, blur),
|
||||||
pending: true,
|
|
||||||
position: CaretPosition::new(0, 0, 0),
|
position: CaretPosition::new(0, 0, 0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -67,8 +64,11 @@ impl Deref for Caret {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
#[cfg_attr(tarpaulin, skip)]
|
||||||
impl Render for Caret {
|
impl Caret {
|
||||||
fn render(&self, canvas: &mut WC, _renderer: &mut Renderer, context: &RenderContext) {
|
pub fn render<T>(&self, canvas: &mut T, context: &RenderContext)
|
||||||
|
where
|
||||||
|
T: CanvasAccess,
|
||||||
|
{
|
||||||
use std::borrow::*;
|
use std::borrow::*;
|
||||||
|
|
||||||
let dest = match context.borrow() {
|
let dest = match context.borrow() {
|
||||||
@ -82,26 +82,22 @@ impl Render for Caret {
|
|||||||
CaretState::Blur => self.colors.blur(),
|
CaretState::Blur => self.colors.blur(),
|
||||||
}
|
}
|
||||||
.clone();
|
.clone();
|
||||||
canvas.set_draw_color(color);
|
|
||||||
canvas
|
canvas
|
||||||
.draw_line(start, end)
|
.render_line(start, end, color)
|
||||||
.unwrap_or_else(|_| panic!("Failed to draw a caret"));
|
.unwrap_or_else(|_| panic!("Failed to draw a caret"));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_ui(&mut self, renderer: &mut Renderer) {
|
pub fn prepare_ui<T>(&mut self, renderer: &mut T)
|
||||||
if !self.pending {
|
where
|
||||||
return;
|
T: CharacterSizeManager,
|
||||||
}
|
{
|
||||||
|
let rect = renderer.load_character_size('I');
|
||||||
if let Some(rect) = get_text_character_rect('W', renderer) {
|
|
||||||
self.dest.set_height(rect.height());
|
self.dest.set_height(rect.height());
|
||||||
}
|
}
|
||||||
self.pending = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Update for Caret {
|
impl Caret {
|
||||||
fn update(&mut self, _ticks: i32, _context: &UpdateContext) -> UR {
|
pub fn update(&mut self) -> UR {
|
||||||
self.blink_delay += 1;
|
self.blink_delay += 1;
|
||||||
if self.blink_delay >= 30 {
|
if self.blink_delay >= 30 {
|
||||||
self.blink_delay = 0;
|
self.blink_delay = 0;
|
||||||
@ -312,3 +308,91 @@ mod test_click_handler {
|
|||||||
assert_eq!(result, expected);
|
assert_eq!(result, expected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test_render {
|
||||||
|
use crate::tests::support::build_config;
|
||||||
|
use crate::ui::*;
|
||||||
|
use sdl2::pixels::Color;
|
||||||
|
use sdl2::rect::{Point, Rect};
|
||||||
|
use sdl2::render::Texture;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
struct CanvasMock {
|
||||||
|
pub start: Point,
|
||||||
|
pub end: Point,
|
||||||
|
pub color: sdl2::pixels::Color,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CanvasAccess for CanvasMock {
|
||||||
|
fn render_rect(&mut self, _rect: Rect, _color: Color) -> Result<(), String> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_border(&mut self, _rect: Rect, _color: Color) -> Result<(), String> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_image(
|
||||||
|
&mut self,
|
||||||
|
_tex: Rc<Texture>,
|
||||||
|
_src: Rect,
|
||||||
|
_dest: Rect,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_line(
|
||||||
|
&mut self,
|
||||||
|
start: Point,
|
||||||
|
end: Point,
|
||||||
|
color: sdl2::pixels::Color,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
self.start = start;
|
||||||
|
self.end = end;
|
||||||
|
self.color = color;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_clipping(&mut self, _rect: Rect) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CharacterSizeManager for CanvasMock {
|
||||||
|
fn load_character_size(&mut self, _c: char) -> Rect {
|
||||||
|
Rect::new(0, 2, 12, 23)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_render_line() {
|
||||||
|
let config = build_config();
|
||||||
|
let context = RenderContext::RelativePosition(Point::new(10, 14));
|
||||||
|
let mut canvas = CanvasMock {
|
||||||
|
start: Point::new(0, 0),
|
||||||
|
end: Point::new(0, 0),
|
||||||
|
color: sdl2::pixels::Color::RGB(0, 0, 0),
|
||||||
|
};
|
||||||
|
let mut widget = Caret::new(config);
|
||||||
|
widget.move_caret(CaretPosition::new(0, 0, 0), Point::new(23, 23));
|
||||||
|
widget.render(&mut canvas, &context);
|
||||||
|
assert_eq!(canvas.start, Point::new(33, 37));
|
||||||
|
assert_eq!(canvas.end, Point::new(33, 38));
|
||||||
|
assert_eq!(canvas.color, sdl2::pixels::Color::RGBA(121, 121, 121, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_prepare_ui() {
|
||||||
|
let config = build_config();
|
||||||
|
let mut canvas = CanvasMock {
|
||||||
|
start: Point::new(0, 0),
|
||||||
|
end: Point::new(0, 0),
|
||||||
|
color: sdl2::pixels::Color::RGB(0, 0, 0),
|
||||||
|
};
|
||||||
|
let mut widget = Caret::new(config);
|
||||||
|
widget.move_caret(CaretPosition::new(0, 0, 0), Point::new(11, 12));
|
||||||
|
widget.prepare_ui(&mut canvas);
|
||||||
|
assert_eq!(widget.dest(), Rect::new(11, 12, 6, 23));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
use sdl2::rect::{Point, Rect};
|
use sdl2::rect::{Point, Rect};
|
||||||
use std::sync::*;
|
use std::sync::*;
|
||||||
|
|
||||||
use crate::app::{UpdateResult as UR, WindowCanvas as WC};
|
use crate::app::UpdateResult as UR;
|
||||||
use crate::renderer::Renderer;
|
use crate::renderer::renderer::Renderer;
|
||||||
use crate::ui::file::editor_file_section::EditorFileSection;
|
use crate::ui::file::editor_file_section::EditorFileSection;
|
||||||
use crate::ui::text_character::TextCharacter;
|
use crate::ui::text_character::TextCharacter;
|
||||||
use crate::ui::*;
|
use crate::ui::*;
|
||||||
use rider_config::Config;
|
use rider_config::Config;
|
||||||
|
use rider_config::ConfigHolder;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct EditorFile {
|
pub struct EditorFile {
|
||||||
@ -113,21 +114,27 @@ impl TextCollection for EditorFile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
impl EditorFile {
|
||||||
impl Render for EditorFile {
|
pub fn render<R, C>(&self, canvas: &mut C, renderer: &mut R, context: &RenderContext)
|
||||||
fn render(&self, canvas: &mut WC, renderer: &mut Renderer, context: &RenderContext) {
|
where
|
||||||
|
R: Renderer + ConfigHolder,
|
||||||
|
C: CanvasAccess,
|
||||||
|
{
|
||||||
for section in self.sections.iter() {
|
for section in self.sections.iter() {
|
||||||
section.render(canvas, renderer, context);
|
section.render(canvas, renderer, context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_ui(&mut self, renderer: &mut Renderer) {
|
pub fn prepare_ui<R>(&mut self, renderer: &mut R)
|
||||||
|
where
|
||||||
|
R: ConfigHolder + CharacterSizeManager + Renderer,
|
||||||
|
{
|
||||||
for section in self.sections.iter_mut() {
|
for section in self.sections.iter_mut() {
|
||||||
section.prepare_ui(renderer);
|
section.prepare_ui(renderer);
|
||||||
}
|
}
|
||||||
if let Some(r) = get_text_character_rect('W', renderer) {
|
|
||||||
|
let r = renderer.load_character_size('W');
|
||||||
self.line_height = r.height();
|
self.line_height = r.height();
|
||||||
}
|
|
||||||
self.refresh_characters_position();
|
self.refresh_characters_position();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -202,11 +209,72 @@ impl RenderBox for EditorFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test_render_box {
|
mod tests {
|
||||||
use crate::tests::support;
|
use crate::tests::support;
|
||||||
use crate::ui::*;
|
use crate::ui::*;
|
||||||
use sdl2::rect::{Point, Rect};
|
use sdl2::rect::{Point, Rect};
|
||||||
|
|
||||||
|
//##################################################
|
||||||
|
// path
|
||||||
|
//##################################################
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_path_txt() {
|
||||||
|
let config = support::build_config();
|
||||||
|
let buffer = "".to_owned();
|
||||||
|
let path = "/example.txt".to_owned();
|
||||||
|
let widget = EditorFile::new(path, buffer, config);
|
||||||
|
assert_eq!(widget.path(), "/example.txt".to_owned());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_path_rs() {
|
||||||
|
let config = support::build_config();
|
||||||
|
let buffer = "".to_owned();
|
||||||
|
let path = "/example.rs".to_owned();
|
||||||
|
let widget = EditorFile::new(path, buffer, config);
|
||||||
|
assert_eq!(widget.path(), "/example.rs".to_owned());
|
||||||
|
}
|
||||||
|
|
||||||
|
//##################################################
|
||||||
|
// buffer
|
||||||
|
//##################################################
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_empty_buffer() {
|
||||||
|
let config = support::build_config();
|
||||||
|
let buffer = "".to_owned();
|
||||||
|
let path = "/example.txt".to_owned();
|
||||||
|
let widget = EditorFile::new(path, buffer, config);
|
||||||
|
assert_eq!(widget.buffer(), "".to_owned());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_some_buffer() {
|
||||||
|
let config = support::build_config();
|
||||||
|
let buffer = "fn main(){}".to_owned();
|
||||||
|
let path = "some.rs".to_owned();
|
||||||
|
let widget = EditorFile::new(path, buffer, config);
|
||||||
|
assert_eq!(widget.buffer(), "fn main(){}".to_owned());
|
||||||
|
}
|
||||||
|
|
||||||
|
//##################################################
|
||||||
|
// line height
|
||||||
|
//##################################################
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_initial_line_height() {
|
||||||
|
let config = support::build_config();
|
||||||
|
let buffer = "".to_owned();
|
||||||
|
let path = "/example.txt".to_owned();
|
||||||
|
let widget = EditorFile::new(path, buffer, config);
|
||||||
|
assert_eq!(widget.line_height(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//##################################################
|
||||||
|
// render box
|
||||||
|
//##################################################
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn assert_dest() {
|
fn assert_dest() {
|
||||||
let config = support::build_config();
|
let config = support::build_config();
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
use sdl2::rect::{Point, Rect};
|
use sdl2::rect::{Point, Rect};
|
||||||
use std::sync::*;
|
use std::sync::*;
|
||||||
|
|
||||||
use crate::app::{UpdateResult as UR, WindowCanvas as WC};
|
use crate::app::UpdateResult as UR;
|
||||||
use crate::renderer::Renderer;
|
use crate::renderer::renderer::Renderer;
|
||||||
use crate::ui::file::editor_file_token::EditorFileToken;
|
use crate::ui::file::editor_file_token::EditorFileToken;
|
||||||
use crate::ui::text_character::TextCharacter;
|
use crate::ui::text_character::TextCharacter;
|
||||||
use crate::ui::*;
|
use crate::ui::*;
|
||||||
use rider_config::Config;
|
use rider_config::Config;
|
||||||
|
use rider_config::ConfigHolder;
|
||||||
use rider_lexers;
|
use rider_lexers;
|
||||||
use rider_lexers::Language;
|
use rider_lexers::Language;
|
||||||
|
|
||||||
@ -26,7 +27,7 @@ impl EditorFileSection {
|
|||||||
.get(ext.as_str())
|
.get(ext.as_str())
|
||||||
.unwrap_or(&Language::PlainText)
|
.unwrap_or(&Language::PlainText)
|
||||||
.clone();
|
.clone();
|
||||||
let lexer_tokens = rider_lexers::parse(buffer.clone(), language);
|
let lexer_tokens = rider_lexers::parse(buffer.clone(), language.clone());
|
||||||
|
|
||||||
let mut tokens: Vec<EditorFileToken> = vec![];
|
let mut tokens: Vec<EditorFileToken> = vec![];
|
||||||
let mut iterator = lexer_tokens.iter().peekable();
|
let mut iterator = lexer_tokens.iter().peekable();
|
||||||
@ -43,7 +44,6 @@ impl EditorFileSection {
|
|||||||
);
|
);
|
||||||
tokens.push(token);
|
tokens.push(token);
|
||||||
}
|
}
|
||||||
let language = Language::PlainText;
|
|
||||||
Self {
|
Self {
|
||||||
tokens,
|
tokens,
|
||||||
language,
|
language,
|
||||||
@ -51,11 +51,34 @@ impl EditorFileSection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn language(&self) -> Language {
|
||||||
|
self.language
|
||||||
|
}
|
||||||
|
|
||||||
pub fn update_positions(&mut self, current: &mut Rect) {
|
pub fn update_positions(&mut self, current: &mut Rect) {
|
||||||
for c in self.tokens.iter_mut() {
|
for c in self.tokens.iter_mut() {
|
||||||
c.update_position(current);
|
c.update_position(current);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn render<R, C>(&self, canvas: &mut C, renderer: &mut R, context: &RenderContext)
|
||||||
|
where
|
||||||
|
R: Renderer + ConfigHolder,
|
||||||
|
C: CanvasAccess,
|
||||||
|
{
|
||||||
|
for token in self.tokens.iter() {
|
||||||
|
token.render(canvas, renderer, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn prepare_ui<'l, T>(&mut self, renderer: &mut T)
|
||||||
|
where
|
||||||
|
T: ConfigHolder + CharacterSizeManager + Renderer,
|
||||||
|
{
|
||||||
|
for token in self.tokens.iter_mut() {
|
||||||
|
token.prepare_ui(renderer);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TextWidget for EditorFileSection {
|
impl TextWidget for EditorFileSection {
|
||||||
@ -125,21 +148,6 @@ impl TextCollection for EditorFileSection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
|
||||||
impl Render for EditorFileSection {
|
|
||||||
fn render(&self, canvas: &mut WC, renderer: &mut Renderer, context: &RenderContext) {
|
|
||||||
for token in self.tokens.iter() {
|
|
||||||
token.render(canvas, renderer, context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn prepare_ui(&mut self, renderer: &mut Renderer) {
|
|
||||||
for token in self.tokens.iter_mut() {
|
|
||||||
token.prepare_ui(renderer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Update for EditorFileSection {
|
impl Update for EditorFileSection {
|
||||||
fn update(&mut self, ticks: i32, context: &UpdateContext) -> UR {
|
fn update(&mut self, ticks: i32, context: &UpdateContext) -> UR {
|
||||||
let mut result = UR::NoOp;
|
let mut result = UR::NoOp;
|
||||||
@ -179,3 +187,35 @@ impl ClickHandler for EditorFileSection {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::tests::support::build_config;
|
||||||
|
|
||||||
|
impl EditorFileSection {
|
||||||
|
pub fn tokens(&self) -> Vec<EditorFileToken> {
|
||||||
|
self.tokens.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tokens_count(&self) -> usize {
|
||||||
|
self.tokens.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_new() {
|
||||||
|
let config = build_config();
|
||||||
|
let widget = EditorFileSection::new("".to_owned(), "rs".to_owned(), config);
|
||||||
|
assert_eq!(widget.language(), Language::Rust);
|
||||||
|
assert_eq!(widget.tokens_count(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_new_with_content() {
|
||||||
|
let config = build_config();
|
||||||
|
let widget = EditorFileSection::new("fn main() {}".to_owned(), "rs".to_owned(), config);
|
||||||
|
assert_eq!(widget.language(), Language::Rust);
|
||||||
|
assert_eq!(widget.tokens_count(), 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
use crate::app::{UpdateResult as UR, WindowCanvas as WC};
|
use crate::app::UpdateResult as UR;
|
||||||
use crate::renderer::*;
|
use crate::renderer::*;
|
||||||
use crate::ui::*;
|
use crate::ui::*;
|
||||||
use rider_config::Config;
|
use rider_config::Config;
|
||||||
|
use rider_config::ConfigHolder;
|
||||||
use rider_lexers::TokenType;
|
use rider_lexers::TokenType;
|
||||||
use sdl2::pixels::Color;
|
use sdl2::pixels::Color;
|
||||||
use sdl2::rect::{Point, Rect};
|
use sdl2::rect::{Point, Rect};
|
||||||
@ -123,13 +124,16 @@ impl TextCollection for EditorFileToken {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
impl EditorFileToken {
|
||||||
impl Render for EditorFileToken {
|
|
||||||
/**
|
/**
|
||||||
* Must first create targets so even if new line appear renderer will know
|
* Must first create targets so even if new line appear renderer will know
|
||||||
* where move render starting point
|
* where move render starting point
|
||||||
*/
|
*/
|
||||||
fn render(&self, canvas: &mut WC, renderer: &mut Renderer, context: &RenderContext) {
|
pub fn render<R, C>(&self, canvas: &mut C, renderer: &mut R, context: &RenderContext)
|
||||||
|
where
|
||||||
|
R: Renderer + ConfigHolder,
|
||||||
|
C: CanvasAccess,
|
||||||
|
{
|
||||||
if self.token_type.is_new_line() {
|
if self.token_type.is_new_line() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -138,7 +142,10 @@ impl Render for EditorFileToken {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_ui(&mut self, renderer: &mut Renderer) {
|
pub fn prepare_ui<R>(&mut self, renderer: &mut R)
|
||||||
|
where
|
||||||
|
R: ConfigHolder + CharacterSizeManager + Renderer,
|
||||||
|
{
|
||||||
if !self.characters.is_empty() {
|
if !self.characters.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -188,3 +195,505 @@ impl ClickHandler for EditorFileToken {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::tests::support::build_config;
|
||||||
|
use rider_lexers::Token;
|
||||||
|
use sdl2::pixels::PixelFormatEnum;
|
||||||
|
use sdl2::render::Texture;
|
||||||
|
use sdl2::render::TextureCreator;
|
||||||
|
use sdl2::surface::Surface;
|
||||||
|
use sdl2::surface::SurfaceContext;
|
||||||
|
use sdl2::ttf::Font;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::fmt::Error;
|
||||||
|
use std::fmt::Formatter;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
|
//##################################################
|
||||||
|
// models
|
||||||
|
//##################################################
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
struct RendererRect {
|
||||||
|
pub rect: Rect,
|
||||||
|
pub color: Color,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(tarpaulin, skip)]
|
||||||
|
struct CanvasMock {
|
||||||
|
pub rects: Vec<RendererRect>,
|
||||||
|
pub borders: Vec<RendererRect>,
|
||||||
|
pub lines: Vec<RendererRect>,
|
||||||
|
pub clippings: Vec<Rect>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(tarpaulin, skip)]
|
||||||
|
impl Debug for CanvasMock {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||||
|
write!(f, "CanvasMock {{}}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(tarpaulin, skip)]
|
||||||
|
impl PartialEq for CanvasMock {
|
||||||
|
fn eq(&self, other: &CanvasMock) -> bool {
|
||||||
|
self.rects == other.rects
|
||||||
|
&& self.borders == other.borders
|
||||||
|
&& self.clippings == other.clippings
|
||||||
|
&& self.lines == other.lines
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(tarpaulin, skip)]
|
||||||
|
impl CanvasMock {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
rects: vec![],
|
||||||
|
borders: vec![],
|
||||||
|
lines: vec![],
|
||||||
|
clippings: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(tarpaulin, skip)]
|
||||||
|
impl CanvasAccess for CanvasMock {
|
||||||
|
fn render_rect(&mut self, rect: Rect, color: Color) -> Result<(), String> {
|
||||||
|
self.rects.push(RendererRect { rect, color });
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_border(&mut self, rect: Rect, color: Color) -> Result<(), String> {
|
||||||
|
self.borders.push(RendererRect { rect, color });
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_image(
|
||||||
|
&mut self,
|
||||||
|
_tex: Rc<Texture>,
|
||||||
|
_src: Rect,
|
||||||
|
_dest: Rect,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_line(&mut self, start: Point, end: Point, color: Color) -> Result<(), String> {
|
||||||
|
self.lines.push(RendererRect {
|
||||||
|
rect: Rect::new(start.x(), start.y(), end.x() as u32, end.y() as u32),
|
||||||
|
color,
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_clipping(&mut self, rect: Rect) {
|
||||||
|
self.clippings.push(rect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(tarpaulin, skip)]
|
||||||
|
struct RendererMock<'l> {
|
||||||
|
pub config: Arc<RwLock<Config>>,
|
||||||
|
pub canvas: sdl2::render::Canvas<Surface<'l>>,
|
||||||
|
pub map: Vec<Rc<Texture<'l>>>,
|
||||||
|
pub creator: TextureCreator<SurfaceContext<'l>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(tarpaulin, skip)]
|
||||||
|
impl<'l> RendererMock<'l> {
|
||||||
|
pub fn new(config: Arc<RwLock<Config>>, surface: Surface<'l>) -> Self {
|
||||||
|
let canvas = sdl2::render::Canvas::from_surface(surface).unwrap();
|
||||||
|
Self {
|
||||||
|
config,
|
||||||
|
creator: canvas.texture_creator(),
|
||||||
|
canvas,
|
||||||
|
map: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(tarpaulin, skip)]
|
||||||
|
impl<'l> Renderer for RendererMock<'l> {
|
||||||
|
fn load_font(&mut self, _details: FontDetails) -> Rc<Font> {
|
||||||
|
unimplemented!("load_font")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_text_tex(
|
||||||
|
&mut self,
|
||||||
|
_details: &mut TextDetails,
|
||||||
|
_font_details: FontDetails,
|
||||||
|
) -> Result<Rc<Texture>, String> {
|
||||||
|
// self.map.get(0).cloned().map_or_else(|| {
|
||||||
|
// let surface = font
|
||||||
|
// .render(details.text.as_str())
|
||||||
|
// .blended(details.color)
|
||||||
|
// .unwrap();
|
||||||
|
// let texture = self.loader.create_texture_from_surface(&surface).unwrap();
|
||||||
|
// let resource = Rc::new(texture);
|
||||||
|
// self.map.push(resource.clone());
|
||||||
|
// Ok(resource)
|
||||||
|
// }, Ok)
|
||||||
|
Err("".to_owned())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'l> CharacterSizeManager for RendererMock<'l> {
|
||||||
|
fn load_character_size(&mut self, _c: char) -> Rect {
|
||||||
|
Rect::new(0, 0, 13, 14)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'l> ConfigHolder for RendererMock<'l> {
|
||||||
|
fn config(&self) -> &Arc<RwLock<Config>> {
|
||||||
|
&self.config
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//##################################################
|
||||||
|
// token_to_color
|
||||||
|
//##################################################
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_whitespace_to_color() {
|
||||||
|
let config = build_config();
|
||||||
|
let surface = Surface::new(1024, 800, PixelFormatEnum::RGBA8888).unwrap();
|
||||||
|
let mut renderer = RendererMock::new(config.clone(), surface);
|
||||||
|
let token_type = TokenType::Whitespace {
|
||||||
|
token: Token::new("".to_owned(), 0, 0, 0, 0),
|
||||||
|
};
|
||||||
|
let mut token = EditorFileToken::new(&token_type, false, config.clone());
|
||||||
|
token.prepare_ui(&mut renderer);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn assert_keyword_to_color() {
|
||||||
|
let config = build_config();
|
||||||
|
let surface = Surface::new(1024, 800, PixelFormatEnum::RGBA8888).unwrap();
|
||||||
|
let mut renderer = RendererMock::new(config.clone(), surface);
|
||||||
|
let token_type = TokenType::Keyword {
|
||||||
|
token: Token::new("".to_owned(), 0, 0, 0, 0),
|
||||||
|
};
|
||||||
|
let mut token = EditorFileToken::new(&token_type, false, config.clone());
|
||||||
|
token.prepare_ui(&mut renderer);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn assert_string_to_color() {
|
||||||
|
let config = build_config();
|
||||||
|
let surface = Surface::new(1024, 800, PixelFormatEnum::RGBA8888).unwrap();
|
||||||
|
let mut renderer = RendererMock::new(config.clone(), surface);
|
||||||
|
let token_type = TokenType::String {
|
||||||
|
token: Token::new("".to_owned(), 0, 0, 0, 0),
|
||||||
|
};
|
||||||
|
let mut token = EditorFileToken::new(&token_type, false, config.clone());
|
||||||
|
token.prepare_ui(&mut renderer);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn assert_identifier_to_color() {
|
||||||
|
let config = build_config();
|
||||||
|
let surface = Surface::new(1024, 800, PixelFormatEnum::RGBA8888).unwrap();
|
||||||
|
let mut renderer = RendererMock::new(config.clone(), surface);
|
||||||
|
let token_type = TokenType::Identifier {
|
||||||
|
token: Token::new("".to_owned(), 0, 0, 0, 0),
|
||||||
|
};
|
||||||
|
let mut token = EditorFileToken::new(&token_type, false, config.clone());
|
||||||
|
token.prepare_ui(&mut renderer);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn assert_literal_to_color() {
|
||||||
|
let config = build_config();
|
||||||
|
let surface = Surface::new(1024, 800, PixelFormatEnum::RGBA8888).unwrap();
|
||||||
|
let mut renderer = RendererMock::new(config.clone(), surface);
|
||||||
|
let token_type = TokenType::Literal {
|
||||||
|
token: Token::new("".to_owned(), 0, 0, 0, 0),
|
||||||
|
};
|
||||||
|
let mut token = EditorFileToken::new(&token_type, false, config.clone());
|
||||||
|
token.prepare_ui(&mut renderer);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn assert_comment_to_color() {
|
||||||
|
let config = build_config();
|
||||||
|
let surface = Surface::new(1024, 800, PixelFormatEnum::RGBA8888).unwrap();
|
||||||
|
let mut renderer = RendererMock::new(config.clone(), surface);
|
||||||
|
let token_type = TokenType::Comment {
|
||||||
|
token: Token::new("".to_owned(), 0, 0, 0, 0),
|
||||||
|
};
|
||||||
|
let mut token = EditorFileToken::new(&token_type, false, config.clone());
|
||||||
|
token.prepare_ui(&mut renderer);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn assert_operator_to_color() {
|
||||||
|
let config = build_config();
|
||||||
|
let surface = Surface::new(1024, 800, PixelFormatEnum::RGBA8888).unwrap();
|
||||||
|
let mut renderer = RendererMock::new(config.clone(), surface);
|
||||||
|
let token_type = TokenType::Operator {
|
||||||
|
token: Token::new("".to_owned(), 0, 0, 0, 0),
|
||||||
|
};
|
||||||
|
let mut token = EditorFileToken::new(&token_type, false, config.clone());
|
||||||
|
token.prepare_ui(&mut renderer);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn assert_separator_to_color() {
|
||||||
|
let config = build_config();
|
||||||
|
let surface = Surface::new(1024, 800, PixelFormatEnum::RGBA8888).unwrap();
|
||||||
|
let mut renderer = RendererMock::new(config.clone(), surface);
|
||||||
|
let token_type = TokenType::Separator {
|
||||||
|
token: Token::new("".to_owned(), 0, 0, 0, 0),
|
||||||
|
};
|
||||||
|
let mut token = EditorFileToken::new(&token_type, false, config.clone());
|
||||||
|
token.prepare_ui(&mut renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
//##################################################
|
||||||
|
// render
|
||||||
|
//##################################################
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_is_last_in_line() {
|
||||||
|
let config = build_config();
|
||||||
|
let token = TokenType::String {
|
||||||
|
token: Token::new("".to_string(), 0, 0, 0, 0),
|
||||||
|
};
|
||||||
|
let widget = EditorFileToken::new(&token, true, config);
|
||||||
|
assert_eq!(widget.is_last_in_line(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_is_not_last_in_line() {
|
||||||
|
let config = build_config();
|
||||||
|
let token = TokenType::String {
|
||||||
|
token: Token::new("".to_string(), 0, 0, 0, 0),
|
||||||
|
};
|
||||||
|
let widget = EditorFileToken::new(&token, false, config);
|
||||||
|
assert_eq!(widget.is_last_in_line(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_is_new_line() {
|
||||||
|
let config = build_config();
|
||||||
|
let token = TokenType::Whitespace {
|
||||||
|
token: Token::new("\n".to_string(), 0, 0, 0, 0),
|
||||||
|
};
|
||||||
|
let widget = EditorFileToken::new(&token, true, config);
|
||||||
|
assert_eq!(widget.is_new_line(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_is_not_new_line() {
|
||||||
|
let config = build_config();
|
||||||
|
let token = TokenType::String {
|
||||||
|
token: Token::new("".to_string(), 0, 0, 0, 0),
|
||||||
|
};
|
||||||
|
let widget = EditorFileToken::new(&token, false, config);
|
||||||
|
assert_eq!(widget.is_new_line(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_empty_characters_update_position() {
|
||||||
|
let config = build_config();
|
||||||
|
let surface = Surface::new(1024, 1024, PixelFormatEnum::RGBA8888).unwrap();
|
||||||
|
// let mut canvas = CanvasMock::new();
|
||||||
|
let mut renderer = RendererMock::new(config.clone(), surface);
|
||||||
|
let token = TokenType::String {
|
||||||
|
token: Token::new("".to_string(), 0, 0, 0, 0),
|
||||||
|
};
|
||||||
|
let mut widget = EditorFileToken::new(&token, false, config);
|
||||||
|
let mut rect = Rect::new(1, 2, 3, 4);
|
||||||
|
widget.prepare_ui(&mut renderer);
|
||||||
|
widget.update_position(&mut rect);
|
||||||
|
assert_eq!(widget.is_new_line(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_some_characters_update_position() {
|
||||||
|
let config = build_config();
|
||||||
|
let surface = Surface::new(1024, 1024, PixelFormatEnum::RGBA8888).unwrap();
|
||||||
|
// let mut canvas = CanvasMock::new();
|
||||||
|
let mut renderer = RendererMock::new(config.clone(), surface);
|
||||||
|
let token = TokenType::String {
|
||||||
|
token: Token::new("foo bar".to_string(), 0, 0, 0, 0),
|
||||||
|
};
|
||||||
|
let mut widget = EditorFileToken::new(&token, false, config);
|
||||||
|
let mut rect = Rect::new(1, 2, 3, 4);
|
||||||
|
widget.prepare_ui(&mut renderer);
|
||||||
|
widget.update_position(&mut rect);
|
||||||
|
assert_eq!(widget.is_new_line(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_prepare_ui_non_empty() {
|
||||||
|
let config = build_config();
|
||||||
|
let surface = Surface::new(1024, 1024, PixelFormatEnum::RGBA8888).unwrap();
|
||||||
|
// let mut canvas = CanvasMock::new();
|
||||||
|
let mut renderer = RendererMock::new(config.clone(), surface);
|
||||||
|
let token = TokenType::String {
|
||||||
|
token: Token::new("foo bar".to_string(), 0, 0, 0, 0),
|
||||||
|
};
|
||||||
|
let mut widget = EditorFileToken::new(&token, false, config);
|
||||||
|
widget.prepare_ui(&mut renderer);
|
||||||
|
widget.prepare_ui(&mut renderer);
|
||||||
|
assert_eq!(widget.is_new_line(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_update_empty() {
|
||||||
|
let config = build_config();
|
||||||
|
let token = TokenType::String {
|
||||||
|
token: Token::new("".to_string(), 0, 0, 0, 0),
|
||||||
|
};
|
||||||
|
let mut widget = EditorFileToken::new(&token, false, config);
|
||||||
|
widget.update(0, &UpdateContext::Nothing);
|
||||||
|
assert_eq!(widget.is_new_line(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_update_non_empty() {
|
||||||
|
let config = build_config();
|
||||||
|
let surface = Surface::new(1024, 1024, PixelFormatEnum::RGBA8888).unwrap();
|
||||||
|
// let mut canvas = CanvasMock::new();
|
||||||
|
let mut renderer = RendererMock::new(config.clone(), surface);
|
||||||
|
let token = TokenType::String {
|
||||||
|
token: Token::new("foo bar".to_string(), 0, 0, 0, 0),
|
||||||
|
};
|
||||||
|
let mut widget = EditorFileToken::new(&token, false, config);
|
||||||
|
widget.prepare_ui(&mut renderer);
|
||||||
|
widget.update(0, &UpdateContext::Nothing);
|
||||||
|
assert_eq!(widget.is_new_line(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_get_character_on_empty() {
|
||||||
|
let config = build_config();
|
||||||
|
let surface = Surface::new(1024, 1024, PixelFormatEnum::RGBA8888).unwrap();
|
||||||
|
// let mut canvas = CanvasMock::new();
|
||||||
|
let mut renderer = RendererMock::new(config.clone(), surface);
|
||||||
|
let token = TokenType::String {
|
||||||
|
token: Token::new("".to_string(), 0, 0, 0, 0),
|
||||||
|
};
|
||||||
|
let mut widget = EditorFileToken::new(&token, false, config);
|
||||||
|
widget.prepare_ui(&mut renderer);
|
||||||
|
let res = widget.get_character_at(0);
|
||||||
|
assert_eq!(res.is_none(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_get_character_non_empty() {
|
||||||
|
let config = build_config();
|
||||||
|
let surface = Surface::new(1024, 1024, PixelFormatEnum::RGBA8888).unwrap();
|
||||||
|
// let mut canvas = CanvasMock::new();
|
||||||
|
let mut renderer = RendererMock::new(config.clone(), surface);
|
||||||
|
let token = TokenType::String {
|
||||||
|
token: Token::new("foo bar".to_string(), 0, 0, 0, 0),
|
||||||
|
};
|
||||||
|
let mut widget = EditorFileToken::new(&token, false, config.clone());
|
||||||
|
widget.prepare_ui(&mut renderer);
|
||||||
|
let res = widget.get_character_at(0);
|
||||||
|
assert_eq!(res.is_none(), false);
|
||||||
|
let mut expected =
|
||||||
|
TextCharacter::new('f', 0, 0, false, Color::RGBA(135, 175, 95, 0), config);
|
||||||
|
expected.prepare_ui(&mut renderer);
|
||||||
|
assert_eq!(res, Some(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_get_character_at_5_pos_with_non_empty() {
|
||||||
|
let config = build_config();
|
||||||
|
let surface = Surface::new(1024, 1024, PixelFormatEnum::RGBA8888).unwrap();
|
||||||
|
// let mut canvas = CanvasMock::new();
|
||||||
|
let mut renderer = RendererMock::new(config.clone(), surface);
|
||||||
|
let token = TokenType::String {
|
||||||
|
token: Token::new("foo bar".to_string(), 0, 0, 0, 0),
|
||||||
|
};
|
||||||
|
let mut widget = EditorFileToken::new(&token, false, config.clone());
|
||||||
|
widget.prepare_ui(&mut renderer);
|
||||||
|
let res = widget.get_character_at(5);
|
||||||
|
assert_eq!(res.is_none(), false);
|
||||||
|
let mut expected =
|
||||||
|
TextCharacter::new('a', 5, 0, false, Color::RGBA(135, 175, 95, 0), config);
|
||||||
|
expected.prepare_ui(&mut renderer);
|
||||||
|
assert_eq!(res, Some(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_get_full_rect_on_empty() {
|
||||||
|
let config = build_config();
|
||||||
|
let surface = Surface::new(1024, 1024, PixelFormatEnum::RGBA8888).unwrap();
|
||||||
|
// let mut canvas = CanvasMock::new();
|
||||||
|
let mut renderer = RendererMock::new(config.clone(), surface);
|
||||||
|
let token = TokenType::String {
|
||||||
|
token: Token::new("".to_string(), 0, 0, 0, 0),
|
||||||
|
};
|
||||||
|
let mut widget = EditorFileToken::new(&token, false, config);
|
||||||
|
widget.prepare_ui(&mut renderer);
|
||||||
|
let res = widget.full_rect();
|
||||||
|
let expected = Rect::new(0, 0, 1, 1);
|
||||||
|
assert_eq!(res, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_get_full_rect_non_empty() {
|
||||||
|
let config = build_config();
|
||||||
|
let surface = Surface::new(1024, 1024, PixelFormatEnum::RGBA8888).unwrap();
|
||||||
|
// let mut canvas = CanvasMock::new();
|
||||||
|
let mut renderer = RendererMock::new(config.clone(), surface);
|
||||||
|
let token = TokenType::String {
|
||||||
|
token: Token::new("foo bar".to_string(), 0, 0, 0, 0),
|
||||||
|
};
|
||||||
|
let mut widget = EditorFileToken::new(&token, false, config.clone());
|
||||||
|
widget.prepare_ui(&mut renderer);
|
||||||
|
let res = widget.full_rect();
|
||||||
|
let expected = Rect::new(0, 0, 13, 14);
|
||||||
|
assert_eq!(res, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_render_on_empty() {
|
||||||
|
let config = build_config();
|
||||||
|
|
||||||
|
let surface = Surface::new(1024, 1024, PixelFormatEnum::RGBA8888).unwrap();
|
||||||
|
let mut canvas = CanvasMock::new();
|
||||||
|
let mut renderer = RendererMock::new(config.clone(), surface);
|
||||||
|
let token = TokenType::String {
|
||||||
|
token: Token::new("".to_string(), 0, 0, 0, 0),
|
||||||
|
};
|
||||||
|
let mut widget = EditorFileToken::new(&token, false, config);
|
||||||
|
widget.prepare_ui(&mut renderer);
|
||||||
|
widget.render(&mut canvas, &mut renderer, &RenderContext::Nothing);
|
||||||
|
// let surface = Surface::new(1024, 1024, PixelFormatEnum::RGBA8888).unwrap();
|
||||||
|
let expected = CanvasMock::new();
|
||||||
|
assert_eq!(canvas, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_render_non_empty() {
|
||||||
|
let config = build_config();
|
||||||
|
let surface = Surface::new(1024, 1024, PixelFormatEnum::RGBA8888).unwrap();
|
||||||
|
let mut canvas = CanvasMock::new();
|
||||||
|
let mut renderer = RendererMock::new(config.clone(), surface);
|
||||||
|
let token = TokenType::String {
|
||||||
|
token: Token::new("foo bar".to_string(), 0, 0, 0, 0),
|
||||||
|
};
|
||||||
|
let mut widget = EditorFileToken::new(&token, false, config.clone());
|
||||||
|
widget.prepare_ui(&mut renderer);
|
||||||
|
widget.render(&mut canvas, &mut renderer, &RenderContext::Nothing);
|
||||||
|
let expected = CanvasMock::new();
|
||||||
|
assert_eq!(canvas, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_render_new_line() {
|
||||||
|
let config = build_config();
|
||||||
|
let surface = Surface::new(1024, 1024, PixelFormatEnum::RGBA8888).unwrap();
|
||||||
|
let mut canvas = CanvasMock::new();
|
||||||
|
let mut renderer = RendererMock::new(config.clone(), surface);
|
||||||
|
let token = TokenType::Whitespace {
|
||||||
|
token: Token::new("\n".to_string(), 0, 0, 0, 0),
|
||||||
|
};
|
||||||
|
let mut widget = EditorFileToken::new(&token, false, config.clone());
|
||||||
|
widget.prepare_ui(&mut renderer);
|
||||||
|
widget.render(&mut canvas, &mut renderer, &RenderContext::Nothing);
|
||||||
|
let expected = CanvasMock::new();
|
||||||
|
assert_eq!(canvas, expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
|
use crate::app::UpdateResult as UR;
|
||||||
use crate::app::*;
|
use crate::app::*;
|
||||||
use crate::app::{UpdateResult as UR, WindowCanvas as WS};
|
use crate::renderer::renderer::Renderer;
|
||||||
use crate::ui::scroll_bar::horizontal_scroll_bar::*;
|
use crate::ui::scroll_bar::horizontal_scroll_bar::*;
|
||||||
use crate::ui::scroll_bar::vertical_scroll_bar::*;
|
use crate::ui::scroll_bar::vertical_scroll_bar::*;
|
||||||
use crate::ui::scroll_bar::Scrollable;
|
use crate::ui::scroll_bar::Scrollable;
|
||||||
@ -40,19 +41,31 @@ impl FileEditor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delete_front(&mut self, renderer: &mut Renderer) {
|
pub fn delete_front<R>(&mut self, renderer: &mut R)
|
||||||
|
where
|
||||||
|
R: ConfigHolder + CharacterSizeManager + Renderer,
|
||||||
|
{
|
||||||
file_content_manager::delete_front(self, renderer);
|
file_content_manager::delete_front(self, renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delete_back(&mut self, renderer: &mut Renderer) {
|
pub fn delete_back<R>(&mut self, renderer: &mut R)
|
||||||
|
where
|
||||||
|
R: ConfigHolder + CharacterSizeManager + Renderer,
|
||||||
|
{
|
||||||
file_content_manager::delete_back(self, renderer);
|
file_content_manager::delete_back(self, renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_text(&mut self, text: String, renderer: &mut Renderer) {
|
pub fn insert_text<R>(&mut self, text: String, renderer: &mut R)
|
||||||
|
where
|
||||||
|
R: ConfigHolder + CharacterSizeManager + Renderer,
|
||||||
|
{
|
||||||
file_content_manager::insert_text(self, text, renderer);
|
file_content_manager::insert_text(self, text, renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_new_line(&mut self, renderer: &mut Renderer) {
|
pub fn insert_new_line<R>(&mut self, renderer: &mut R)
|
||||||
|
where
|
||||||
|
R: ConfigHolder + CharacterSizeManager + Renderer,
|
||||||
|
{
|
||||||
file_content_manager::insert_new_line(self, renderer);
|
file_content_manager::insert_new_line(self, renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,10 +209,13 @@ impl CaretAccess for FileEditor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
impl FileEditor {
|
||||||
impl Render for FileEditor {
|
pub fn render<R, C>(&self, canvas: &mut C, renderer: &mut R)
|
||||||
fn render(&self, canvas: &mut WS, renderer: &mut Renderer, _context: &RenderContext) {
|
where
|
||||||
canvas.set_clip_rect(self.dest.clone());
|
R: Renderer + ConfigHolder,
|
||||||
|
C: CanvasAccess,
|
||||||
|
{
|
||||||
|
canvas.set_clipping(self.dest.clone());
|
||||||
match self.file() {
|
match self.file() {
|
||||||
Some(file) => file.render(
|
Some(file) => file.render(
|
||||||
canvas,
|
canvas,
|
||||||
@ -210,7 +226,6 @@ impl Render for FileEditor {
|
|||||||
};
|
};
|
||||||
self.caret.render(
|
self.caret.render(
|
||||||
canvas,
|
canvas,
|
||||||
renderer,
|
|
||||||
&RenderContext::RelativePosition(self.render_start_point()),
|
&RenderContext::RelativePosition(self.render_start_point()),
|
||||||
);
|
);
|
||||||
self.vertical_scroll_bar.render(
|
self.vertical_scroll_bar.render(
|
||||||
@ -223,7 +238,10 @@ impl Render for FileEditor {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_ui(&mut self, renderer: &mut Renderer) {
|
pub fn prepare_ui<T>(&mut self, renderer: &mut T)
|
||||||
|
where
|
||||||
|
T: CharacterSizeManager,
|
||||||
|
{
|
||||||
self.caret.prepare_ui(renderer);
|
self.caret.prepare_ui(renderer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -258,7 +276,7 @@ impl Update for FileEditor {
|
|||||||
.set_location(self.dest.height() as i32 - (scroll_width as i32 + scroll_margin));
|
.set_location(self.dest.height() as i32 - (scroll_width as i32 + scroll_margin));
|
||||||
self.horizontal_scroll_bar.update(ticks, context);
|
self.horizontal_scroll_bar.update(ticks, context);
|
||||||
|
|
||||||
self.caret.update(ticks, context);
|
self.caret.update();
|
||||||
match self.file_mut() {
|
match self.file_mut() {
|
||||||
Some(file) => file.update(ticks, context),
|
Some(file) => file.update(ticks, context),
|
||||||
_ => UR::NoOp,
|
_ => UR::NoOp,
|
||||||
|
@ -68,7 +68,7 @@ impl DirectoryView {
|
|||||||
&self.source
|
&self.source
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_directory(&mut self, dir_path: String, renderer: &mut Renderer) -> bool {
|
pub fn open_directory(&mut self, dir_path: String, renderer: &mut CanvasRenderer) -> bool {
|
||||||
match dir_path {
|
match dir_path {
|
||||||
_ if dir_path == self.path => {
|
_ if dir_path == self.path => {
|
||||||
if !self.opened {
|
if !self.opened {
|
||||||
@ -127,7 +127,7 @@ impl DirectoryView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_directory(&mut self, renderer: &mut Renderer) {
|
fn read_directory(&mut self, renderer: &mut CanvasRenderer) {
|
||||||
let entries: fs::ReadDir = match fs::read_dir(self.path.clone()) {
|
let entries: fs::ReadDir = match fs::read_dir(self.path.clone()) {
|
||||||
Ok(d) => d,
|
Ok(d) => d,
|
||||||
_ => return,
|
_ => return,
|
||||||
@ -167,9 +167,9 @@ impl DirectoryView {
|
|||||||
self.directories.sort_by(|a, b| a.name().cmp(&b.name()));
|
self.directories.sort_by(|a, b| a.name().cmp(&b.name()));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_icon<T>(&self, canvas: &mut T, renderer: &mut Renderer, dest: &mut Rect)
|
fn render_icon<T>(&self, canvas: &mut T, renderer: &mut CanvasRenderer, dest: &mut Rect)
|
||||||
where
|
where
|
||||||
T: RenderImage,
|
T: CanvasAccess,
|
||||||
{
|
{
|
||||||
let dir_texture_path = {
|
let dir_texture_path = {
|
||||||
let c = self.config.read().unwrap();
|
let c = self.config.read().unwrap();
|
||||||
@ -192,9 +192,9 @@ impl DirectoryView {
|
|||||||
.unwrap_or_else(|_| panic!("Failed to draw directory entry texture"));
|
.unwrap_or_else(|_| panic!("Failed to draw directory entry texture"));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_name<T>(&self, canvas: &mut T, renderer: &mut Renderer, dest: &mut Rect)
|
fn render_name<T>(&self, canvas: &mut T, renderer: &mut CanvasRenderer, dest: &mut Rect)
|
||||||
where
|
where
|
||||||
T: RenderImage,
|
T: CanvasAccess,
|
||||||
{
|
{
|
||||||
let mut d = dest.clone();
|
let mut d = dest.clone();
|
||||||
d.set_x(dest.x() + NAME_MARGIN);
|
d.set_x(dest.x() + NAME_MARGIN);
|
||||||
@ -213,7 +213,7 @@ impl DirectoryView {
|
|||||||
};
|
};
|
||||||
let text_texture = renderer
|
let text_texture = renderer
|
||||||
.texture_manager()
|
.texture_manager()
|
||||||
.load_text(&mut text_details, &font)
|
.load_text(&mut text_details, font.clone())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
d.set_width(size.width());
|
d.set_width(size.width());
|
||||||
d.set_height(size.height());
|
d.set_height(size.height());
|
||||||
@ -225,9 +225,9 @@ impl DirectoryView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_children<T>(&self, canvas: &mut T, renderer: &mut Renderer, dest: &mut Rect)
|
fn render_children<T>(&self, canvas: &mut T, renderer: &mut CanvasRenderer, dest: &mut Rect)
|
||||||
where
|
where
|
||||||
T: RenderImage,
|
T: CanvasAccess,
|
||||||
{
|
{
|
||||||
if !self.expanded {
|
if !self.expanded {
|
||||||
return;
|
return;
|
||||||
@ -249,7 +249,7 @@ impl DirectoryView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_size(&mut self, renderer: &mut Renderer) {
|
fn calculate_size(&mut self, renderer: &mut CanvasRenderer) {
|
||||||
let size = renderer.load_character_size('W');
|
let size = renderer.load_character_size('W');
|
||||||
self.height = size.height();
|
self.height = size.height();
|
||||||
self.icon_height = size.height();
|
self.icon_height = size.height();
|
||||||
@ -287,9 +287,9 @@ impl ConfigHolder for DirectoryView {
|
|||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
#[cfg_attr(tarpaulin, skip)]
|
||||||
impl DirectoryView {
|
impl DirectoryView {
|
||||||
pub fn render<T>(&self, canvas: &mut T, renderer: &mut Renderer, context: &RenderContext)
|
pub fn render<T>(&self, canvas: &mut T, renderer: &mut CanvasRenderer, context: &RenderContext)
|
||||||
where
|
where
|
||||||
T: RenderImage,
|
T: CanvasAccess,
|
||||||
{
|
{
|
||||||
let dest = self.dest();
|
let dest = self.dest();
|
||||||
let move_point = match context {
|
let move_point = match context {
|
||||||
@ -302,7 +302,7 @@ impl DirectoryView {
|
|||||||
self.render_children::<T>(canvas, renderer, &mut dest);
|
self.render_children::<T>(canvas, renderer, &mut dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prepare_ui(&mut self, renderer: &mut Renderer) {
|
pub fn prepare_ui(&mut self, renderer: &mut CanvasRenderer) {
|
||||||
if self.opened {
|
if self.opened {
|
||||||
for dir in self.directories.iter_mut() {
|
for dir in self.directories.iter_mut() {
|
||||||
dir.prepare_ui(renderer);
|
dir.prepare_ui(renderer);
|
||||||
|
@ -70,9 +70,9 @@ impl FileEntry {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_icon<T>(&self, canvas: &mut T, renderer: &mut Renderer, dest: &mut Rect)
|
fn render_icon<T>(&self, canvas: &mut T, renderer: &mut CanvasRenderer, dest: &mut Rect)
|
||||||
where
|
where
|
||||||
T: RenderImage,
|
T: CanvasAccess,
|
||||||
{
|
{
|
||||||
let dir_texture_path = {
|
let dir_texture_path = {
|
||||||
let c = self.config.read().unwrap();
|
let c = self.config.read().unwrap();
|
||||||
@ -92,9 +92,9 @@ impl FileEntry {
|
|||||||
.unwrap_or_else(|_| panic!("Failed to draw directory entry texture"));
|
.unwrap_or_else(|_| panic!("Failed to draw directory entry texture"));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_name<T>(&self, canvas: &mut T, renderer: &mut Renderer, dest: &mut Rect)
|
fn render_name<T>(&self, canvas: &mut T, renderer: &mut CanvasRenderer, dest: &mut Rect)
|
||||||
where
|
where
|
||||||
T: RenderImage,
|
T: CanvasAccess,
|
||||||
{
|
{
|
||||||
let mut d = dest.clone();
|
let mut d = dest.clone();
|
||||||
d.set_x(dest.x() + NAME_MARGIN);
|
d.set_x(dest.x() + NAME_MARGIN);
|
||||||
@ -115,7 +115,9 @@ impl FileEntry {
|
|||||||
text: c.to_string(),
|
text: c.to_string(),
|
||||||
font: font_details.clone(),
|
font: font_details.clone(),
|
||||||
};
|
};
|
||||||
let text_texture = texture_manager.load_text(&mut text_details, &font).unwrap();
|
let text_texture = texture_manager
|
||||||
|
.load_text(&mut text_details, font.clone())
|
||||||
|
.unwrap();
|
||||||
d.set_width(size.width());
|
d.set_width(size.width());
|
||||||
d.set_height(size.height());
|
d.set_height(size.height());
|
||||||
|
|
||||||
@ -135,9 +137,9 @@ impl ConfigHolder for FileEntry {
|
|||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
#[cfg_attr(tarpaulin, skip)]
|
||||||
impl FileEntry {
|
impl FileEntry {
|
||||||
pub fn render<T>(&self, canvas: &mut T, renderer: &mut Renderer, context: &RenderContext)
|
pub fn render<T>(&self, canvas: &mut T, renderer: &mut CanvasRenderer, context: &RenderContext)
|
||||||
where
|
where
|
||||||
T: RenderImage,
|
T: CanvasAccess,
|
||||||
{
|
{
|
||||||
let mut dest = match context {
|
let mut dest = match context {
|
||||||
&RenderContext::RelativePosition(p) => move_render_point(p.clone(), &self.dest),
|
&RenderContext::RelativePosition(p) => move_render_point(p.clone(), &self.dest),
|
||||||
@ -147,7 +149,7 @@ impl FileEntry {
|
|||||||
self.render_name(canvas, renderer, &mut dest.clone());
|
self.render_name(canvas, renderer, &mut dest.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prepare_ui(&mut self, renderer: &mut Renderer) {
|
pub fn prepare_ui(&mut self, renderer: &mut CanvasRenderer) {
|
||||||
let w_rect = get_text_character_rect('W', renderer).unwrap();
|
let w_rect = get_text_character_rect('W', renderer).unwrap();
|
||||||
self.char_sizes.insert('W', w_rect.clone());
|
self.char_sizes.insert('W', w_rect.clone());
|
||||||
self.height = w_rect.height();
|
self.height = w_rect.height();
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use crate::app::{UpdateResult as UR, WindowCanvas as WC};
|
use crate::app::UpdateResult as UR;
|
||||||
use crate::renderer::*;
|
|
||||||
use crate::ui::*;
|
use crate::ui::*;
|
||||||
use rider_config::ConfigAccess;
|
use rider_config::ConfigAccess;
|
||||||
use sdl2::pixels::Color;
|
use sdl2::pixels::Color;
|
||||||
@ -34,32 +33,37 @@ impl MenuBar {
|
|||||||
pub fn background_color(&self) -> &Color {
|
pub fn background_color(&self) -> &Color {
|
||||||
&self.background_color
|
&self.background_color
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
pub fn render<C>(&self, canvas: &mut C, context: &RenderContext)
|
||||||
impl Render for MenuBar {
|
where
|
||||||
fn render(&self, canvas: &mut WC, _renderer: &mut Renderer, context: &RenderContext) {
|
C: CanvasAccess,
|
||||||
|
{
|
||||||
use std::borrow::*;
|
use std::borrow::*;
|
||||||
|
|
||||||
canvas.set_clip_rect(self.dest.clone());
|
canvas.set_clipping(self.dest.clone());
|
||||||
canvas.set_draw_color(self.background_color.clone());
|
|
||||||
canvas
|
canvas
|
||||||
.fill_rect(match context.borrow() {
|
.render_rect(
|
||||||
|
match context.borrow() {
|
||||||
RenderContext::RelativePosition(p) => move_render_point(p.clone(), &self.dest),
|
RenderContext::RelativePosition(p) => move_render_point(p.clone(), &self.dest),
|
||||||
_ => self.dest(),
|
_ => self.dest(),
|
||||||
})
|
},
|
||||||
|
self.background_color.clone(),
|
||||||
|
)
|
||||||
.unwrap_or_else(|_| panic!("Failed to draw main menu background"));
|
.unwrap_or_else(|_| panic!("Failed to draw main menu background"));
|
||||||
|
|
||||||
canvas.set_draw_color(self.border_color);
|
|
||||||
canvas
|
canvas
|
||||||
.draw_rect(match context.borrow() {
|
.render_border(
|
||||||
RenderContext::RelativePosition(p) => move_render_point((*p).clone(), &self.dest),
|
match context.borrow() {
|
||||||
|
RenderContext::RelativePosition(p) => {
|
||||||
|
move_render_point((*p).clone(), &self.dest)
|
||||||
|
}
|
||||||
_ => self.dest(),
|
_ => self.dest(),
|
||||||
})
|
},
|
||||||
|
self.border_color.clone(),
|
||||||
|
)
|
||||||
.unwrap_or_else(|_| panic!("Failed to draw main menu background"));
|
.unwrap_or_else(|_| panic!("Failed to draw main menu background"));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_ui(&mut self, _renderer: &mut Renderer) {
|
pub fn prepare_ui(&mut self) {
|
||||||
let width = self.config.read().unwrap().width();
|
let width = self.config.read().unwrap().width();
|
||||||
let height = u32::from(self.config.read().unwrap().menu_height());
|
let height = u32::from(self.config.read().unwrap().menu_height());
|
||||||
self.dest = Rect::new(0, 0, width, height);
|
self.dest = Rect::new(0, 0, width, height);
|
||||||
@ -211,3 +215,87 @@ mod test_click_handler {
|
|||||||
assert_eq!(result, expected);
|
assert_eq!(result, expected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test_render {
|
||||||
|
use crate::tests::*;
|
||||||
|
use crate::ui::*;
|
||||||
|
use sdl2::pixels::Color;
|
||||||
|
use sdl2::rect::{Point, Rect};
|
||||||
|
use sdl2::render::Texture;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::sync::*;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
struct CanvasMock {
|
||||||
|
pub clipping: Rect,
|
||||||
|
pub background_rect: Rect,
|
||||||
|
pub background_color: Color,
|
||||||
|
pub border_rect: Rect,
|
||||||
|
pub border_color: Color,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CanvasAccess for CanvasMock {
|
||||||
|
fn render_rect(&mut self, rect: Rect, color: Color) -> Result<(), String> {
|
||||||
|
self.background_color = color;
|
||||||
|
self.background_rect = rect;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_border(&mut self, rect: Rect, color: Color) -> Result<(), String> {
|
||||||
|
self.border_color = color;
|
||||||
|
self.border_rect = rect;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_image(
|
||||||
|
&mut self,
|
||||||
|
_tex: Rc<Texture>,
|
||||||
|
_src: Rect,
|
||||||
|
_dest: Rect,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_line(&mut self, _start: Point, _end: Point, _color: Color) -> Result<(), String> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_clipping(&mut self, rect: Rect) {
|
||||||
|
self.clipping = rect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_render() {
|
||||||
|
let context = RenderContext::Nothing;
|
||||||
|
let config = support::build_config();
|
||||||
|
let mut canvas = CanvasMock {
|
||||||
|
clipping: Rect::new(0, 0, 0, 0),
|
||||||
|
background_rect: Rect::new(0, 0, 0, 0),
|
||||||
|
background_color: Color::RGB(0, 0, 0),
|
||||||
|
border_rect: Rect::new(0, 0, 0, 0),
|
||||||
|
border_color: Color::RGB(0, 0, 0),
|
||||||
|
};
|
||||||
|
let mut widget = MenuBar::new(Arc::clone(&config));
|
||||||
|
widget.prepare_ui();
|
||||||
|
widget.render(&mut canvas, &context);
|
||||||
|
assert_eq!(widget.dest(), Rect::new(0, 0, 1024, 60));
|
||||||
|
let expected = CanvasMock {
|
||||||
|
clipping: Rect::new(0, 0, 1024, 60),
|
||||||
|
background_rect: Rect::new(0, 0, 1024, 60),
|
||||||
|
background_color: Color::RGBA(18, 18, 18, 0),
|
||||||
|
border_rect: Rect::new(0, 0, 1024, 60),
|
||||||
|
border_color: Color::RGBA(200, 200, 200, 0),
|
||||||
|
};
|
||||||
|
assert_eq!(canvas, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assert_prepare_ui() {
|
||||||
|
let config = support::build_config();
|
||||||
|
let mut widget = MenuBar::new(Arc::clone(&config));
|
||||||
|
widget.prepare_ui();
|
||||||
|
assert_eq!(widget.dest(), Rect::new(0, 0, 1024, 60));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -4,9 +4,8 @@ use sdl2::render::Texture;
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::app::application::WindowCanvas;
|
use crate::app::application::WindowCanvas;
|
||||||
use crate::app::{UpdateResult as UR, WindowCanvas as WC};
|
use crate::app::UpdateResult as UR;
|
||||||
use crate::renderer::managers::*;
|
use crate::renderer::managers::*;
|
||||||
use crate::renderer::Renderer;
|
|
||||||
use rider_config::*;
|
use rider_config::*;
|
||||||
|
|
||||||
pub mod caret;
|
pub mod caret;
|
||||||
@ -42,36 +41,48 @@ pub enum RenderContext {
|
|||||||
RelativePosition(Point),
|
RelativePosition(Point),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait RenderRect {
|
pub trait CanvasAccess {
|
||||||
fn render_rect(&mut self, rect: Rect, color: sdl2::pixels::Color) -> Result<(), String>;
|
fn render_rect(&mut self, rect: Rect, color: sdl2::pixels::Color) -> Result<(), String>;
|
||||||
}
|
|
||||||
|
|
||||||
pub trait RenderBorder {
|
|
||||||
fn render_border(&mut self, rect: Rect, color: sdl2::pixels::Color) -> Result<(), String>;
|
fn render_border(&mut self, rect: Rect, color: sdl2::pixels::Color) -> Result<(), String>;
|
||||||
}
|
|
||||||
|
|
||||||
pub trait RenderImage {
|
|
||||||
fn render_image(&mut self, tex: Rc<Texture>, src: Rect, dest: Rect) -> Result<(), String>;
|
fn render_image(&mut self, tex: Rc<Texture>, src: Rect, dest: Rect) -> Result<(), String>;
|
||||||
|
fn render_line(
|
||||||
|
&mut self,
|
||||||
|
start: Point,
|
||||||
|
end: Point,
|
||||||
|
color: sdl2::pixels::Color,
|
||||||
|
) -> Result<(), String>;
|
||||||
|
|
||||||
|
fn set_clipping(&mut self, rect: Rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RenderRect for WindowCanvas {
|
impl CanvasAccess for WindowCanvas {
|
||||||
fn render_rect(&mut self, rect: Rect, color: sdl2::pixels::Color) -> Result<(), String> {
|
fn render_rect(&mut self, rect: Rect, color: sdl2::pixels::Color) -> Result<(), String> {
|
||||||
self.set_draw_color(color);
|
self.set_draw_color(color);
|
||||||
self.fill_rect(rect)
|
self.fill_rect(rect)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl RenderBorder for WindowCanvas {
|
|
||||||
fn render_border(&mut self, rect: Rect, color: sdl2::pixels::Color) -> Result<(), String> {
|
fn render_border(&mut self, rect: Rect, color: sdl2::pixels::Color) -> Result<(), String> {
|
||||||
self.set_draw_color(color);
|
self.set_draw_color(color);
|
||||||
self.draw_rect(rect)
|
self.draw_rect(rect)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl RenderImage for WindowCanvas {
|
|
||||||
fn render_image(&mut self, tex: Rc<Texture>, src: Rect, dest: Rect) -> Result<(), String> {
|
fn render_image(&mut self, tex: Rc<Texture>, src: Rect, dest: Rect) -> Result<(), String> {
|
||||||
self.copy_ex(&tex, Some(src), Some(dest), 0.0, None, false, false)
|
self.copy_ex(&tex, Some(src), Some(dest), 0.0, None, false, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn render_line(
|
||||||
|
&mut self,
|
||||||
|
start: Point,
|
||||||
|
end: Point,
|
||||||
|
color: sdl2::pixels::Color,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
self.set_draw_color(color);
|
||||||
|
self.draw_line(start, end)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_clipping(&mut self, rect: Rect) {
|
||||||
|
self.set_clip_rect(rect);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -109,13 +120,6 @@ pub fn move_render_point(p: Point, d: &Rect) -> Rect {
|
|||||||
Rect::new(d.x() + p.x(), d.y() + p.y(), d.width(), d.height())
|
Rect::new(d.x() + p.x(), d.y() + p.y(), d.width(), d.height())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
|
||||||
pub trait Render {
|
|
||||||
fn render(&self, canvas: &mut WC, renderer: &mut Renderer, context: &RenderContext);
|
|
||||||
|
|
||||||
fn prepare_ui(&mut self, renderer: &mut Renderer);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Update {
|
pub trait Update {
|
||||||
fn update(&mut self, ticks: i32, context: &UpdateContext) -> UR;
|
fn update(&mut self, ticks: i32, context: &UpdateContext) -> UR;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::renderer::Renderer;
|
use crate::renderer::CanvasRenderer;
|
||||||
use crate::ui::*;
|
use crate::ui::*;
|
||||||
use crate::ui::{RenderContext as RC, UpdateContext as UC};
|
use crate::ui::{RenderContext as RC, UpdateContext as UC};
|
||||||
use rider_config::ConfigAccess;
|
use rider_config::ConfigAccess;
|
||||||
@ -56,7 +56,7 @@ impl OpenFile {
|
|||||||
self.root_path.clone()
|
self.root_path.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_directory(&mut self, dir_path: String, renderer: &mut Renderer) {
|
pub fn open_directory(&mut self, dir_path: String, renderer: &mut CanvasRenderer) {
|
||||||
self.directory_view.open_directory(dir_path, renderer);
|
self.directory_view.open_directory(dir_path, renderer);
|
||||||
{
|
{
|
||||||
let dest = self.directory_view.dest();
|
let dest = self.directory_view.dest();
|
||||||
@ -147,9 +147,9 @@ impl Update for OpenFile {
|
|||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
#[cfg_attr(tarpaulin, skip)]
|
||||||
impl OpenFile {
|
impl OpenFile {
|
||||||
pub fn render<T>(&self, canvas: &mut T, renderer: &mut Renderer, context: &RC)
|
pub fn render<T>(&self, canvas: &mut T, renderer: &mut CanvasRenderer, context: &RC)
|
||||||
where
|
where
|
||||||
T: RenderRect + RenderBorder + RenderImage,
|
T: CanvasAccess,
|
||||||
{
|
{
|
||||||
let dest = match context {
|
let dest = match context {
|
||||||
RC::RelativePosition(p) => move_render_point(p.clone(), &self.dest),
|
RC::RelativePosition(p) => move_render_point(p.clone(), &self.dest),
|
||||||
@ -183,7 +183,7 @@ impl OpenFile {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prepare_ui(&mut self, renderer: &mut Renderer) {
|
pub fn prepare_ui(&mut self, renderer: &mut CanvasRenderer) {
|
||||||
self.directory_view.prepare_ui(renderer);
|
self.directory_view.prepare_ui(renderer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ impl Update for HorizontalScrollBar {
|
|||||||
impl HorizontalScrollBar {
|
impl HorizontalScrollBar {
|
||||||
pub fn render<T>(&self, canvas: &mut T, context: &RenderContext)
|
pub fn render<T>(&self, canvas: &mut T, context: &RenderContext)
|
||||||
where
|
where
|
||||||
T: RenderRect,
|
T: CanvasAccess,
|
||||||
{
|
{
|
||||||
if self.full_width < self.viewport {
|
if self.full_width < self.viewport {
|
||||||
return;
|
return;
|
||||||
|
@ -57,7 +57,7 @@ impl Update for VerticalScrollBar {
|
|||||||
impl VerticalScrollBar {
|
impl VerticalScrollBar {
|
||||||
pub fn render<T>(&self, canvas: &mut T, context: &RenderContext)
|
pub fn render<T>(&self, canvas: &mut T, context: &RenderContext)
|
||||||
where
|
where
|
||||||
T: RenderBorder,
|
T: CanvasAccess,
|
||||||
{
|
{
|
||||||
if self.full_height() < self.viewport() {
|
if self.full_height() < self.viewport() {
|
||||||
return;
|
return;
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use crate::app::{UpdateResult as UR, WindowCanvas as WC};
|
use crate::app::UpdateResult as UR;
|
||||||
use crate::renderer::managers::*;
|
|
||||||
use crate::renderer::*;
|
use crate::renderer::*;
|
||||||
use crate::ui::caret::CaretPosition;
|
use crate::ui::caret::CaretPosition;
|
||||||
use crate::ui::*;
|
use crate::ui::*;
|
||||||
@ -7,12 +6,15 @@ use rider_config::{ConfigAccess, ConfigHolder};
|
|||||||
|
|
||||||
use sdl2::pixels::Color;
|
use sdl2::pixels::Color;
|
||||||
use sdl2::rect::{Point, Rect};
|
use sdl2::rect::{Point, Rect};
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::fmt::Error;
|
||||||
|
use std::fmt::Formatter;
|
||||||
|
|
||||||
pub trait CharacterSizeManager {
|
pub trait CharacterSizeManager {
|
||||||
fn load_character_size(&mut self, c: char) -> Rect;
|
fn load_character_size(&mut self, c: char) -> Rect;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone)]
|
||||||
pub struct TextCharacter {
|
pub struct TextCharacter {
|
||||||
text_character: char,
|
text_character: char,
|
||||||
position: usize,
|
position: usize,
|
||||||
@ -99,13 +101,16 @@ impl TextCharacter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
|
||||||
impl TextCharacter {
|
impl TextCharacter {
|
||||||
/**
|
/**
|
||||||
* Must first create targets so even if new line appear renderer will know
|
* Must first create targets so even if new line appear renderer will know
|
||||||
* where move render starting point
|
* where move render starting point
|
||||||
*/
|
*/
|
||||||
pub fn render(&self, canvas: &mut WC, renderer: &mut Renderer, context: &RenderContext) {
|
pub fn render<R, C>(&self, canvas: &mut C, renderer: &mut R, context: &RenderContext)
|
||||||
|
where
|
||||||
|
R: Renderer + ConfigHolder,
|
||||||
|
C: CanvasAccess,
|
||||||
|
{
|
||||||
if self.is_new_line() {
|
if self.is_new_line() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -123,21 +128,9 @@ impl TextCharacter {
|
|||||||
_ => self.dest(),
|
_ => self.dest(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let font = renderer
|
if let Ok(texture) = renderer.load_text_tex(&mut details, font_details) {
|
||||||
.font_manager()
|
|
||||||
.load(&font_details)
|
|
||||||
.unwrap_or_else(|_| panic!("Could not load font for {:?}", font_details));
|
|
||||||
if let Ok(texture) = renderer.texture_manager().load_text(&mut details, &font) {
|
|
||||||
canvas
|
canvas
|
||||||
.copy_ex(
|
.render_image(texture, self.source.clone(), dest)
|
||||||
&texture,
|
|
||||||
Some(self.source.clone()),
|
|
||||||
Some(dest.clone()),
|
|
||||||
0.0,
|
|
||||||
None,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
// let c = Color::RGB(255, 0, 0);
|
// let c = Color::RGB(255, 0, 0);
|
||||||
@ -147,10 +140,9 @@ impl TextCharacter {
|
|||||||
|
|
||||||
pub fn prepare_ui<'l, T>(&mut self, renderer: &mut T)
|
pub fn prepare_ui<'l, T>(&mut self, renderer: &mut T)
|
||||||
where
|
where
|
||||||
T: ConfigHolder + CharacterSizeManager + ManagersHolder<'l>,
|
T: ConfigHolder + CharacterSizeManager + Renderer,
|
||||||
{
|
{
|
||||||
let font_details: FontDetails = renderer.config().read().unwrap().editor_config().into();
|
let font_details: FontDetails = renderer.config().read().unwrap().editor_config().into();
|
||||||
|
|
||||||
let rect = renderer.load_character_size(self.text_character);
|
let rect = renderer.load_character_size(self.text_character);
|
||||||
self.set_source(&rect);
|
self.set_source(&rect);
|
||||||
self.set_dest(&rect);
|
self.set_dest(&rect);
|
||||||
@ -161,14 +153,12 @@ impl TextCharacter {
|
|||||||
font: font_details.clone(),
|
font: font_details.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let font = renderer
|
if let Err(error_message) = renderer.load_text_tex(&mut details, font_details) {
|
||||||
.font_manager()
|
info!(
|
||||||
.load(&font_details)
|
"Could not create texture for '{:?}' with {:?}",
|
||||||
.unwrap_or_else(|_| panic!("Font not found {:?}", font_details));
|
self.text_character, error_message
|
||||||
renderer
|
)
|
||||||
.texture_manager()
|
}
|
||||||
.load_text(&mut details, &font)
|
|
||||||
.unwrap_or_else(|_| panic!("Could not create texture for {:?}", self.text_character));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,6 +195,33 @@ impl RenderBox for TextCharacter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialEq for TextCharacter {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.line == other.line
|
||||||
|
&& self.position == other.position
|
||||||
|
&& self.last_in_line == other.last_in_line
|
||||||
|
&& self.dest == other.dest
|
||||||
|
&& self.source == other.source
|
||||||
|
&& self.color == other.color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for TextCharacter {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"TextCharacter {{ text_character: {:?}, position: {:?}, line: {:?}, last_in_line: {:?}, source: {:?}, dest: {:?}, color: {:?} }}",
|
||||||
|
self.text_character,
|
||||||
|
self.position,
|
||||||
|
self.line,
|
||||||
|
self.last_in_line,
|
||||||
|
self.source,
|
||||||
|
self.dest,
|
||||||
|
self.color
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test_getters {
|
mod test_getters {
|
||||||
use crate::tests::*;
|
use crate::tests::*;
|
||||||
|
6
scripts/coverage.sh
Executable file
6
scripts/coverage.sh
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/env bash
|
||||||
|
|
||||||
|
rm -Rf cov
|
||||||
|
rm -Rf target/debug/*rider*
|
||||||
|
cargo test --no-run;kcov --exclude-pattern=github.com,target/debug --verify cov $(ls target/debug/rider_editor* | sed "s/\\.d\$//" | head -n1)
|
||||||
|
|
12
scripts/serve-editor.sh
Executable file
12
scripts/serve-editor.sh
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/env bash
|
||||||
|
|
||||||
|
nvm use 11.0.0
|
||||||
|
here=$(pwd)
|
||||||
|
target="cov/$(ls ${here}/cov | grep editor | grep "\\." | head -n1)"
|
||||||
|
if [[ -e "${target}" ]];
|
||||||
|
then
|
||||||
|
cd ${target} && echo "here: $(pwd)" && serve . && cd ${here}
|
||||||
|
else
|
||||||
|
echo "Target: '${target}' does not exists!"
|
||||||
|
fi
|
||||||
|
|
Loading…
Reference in New Issue
Block a user