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
|
||||
.codecov
|
||||
cobertura.xml
|
||||
cov
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::app::{UpdateResult, WindowCanvas as WC};
|
||||
use crate::renderer::Renderer;
|
||||
use crate::renderer::CanvasRenderer;
|
||||
use crate::ui::*;
|
||||
use rider_config::*;
|
||||
use sdl2::rect::Point;
|
||||
@ -27,7 +27,7 @@ impl AppState {
|
||||
}
|
||||
|
||||
#[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) {
|
||||
let mut file = EditorFile::new(file_path.clone(), buffer, self.config.clone());
|
||||
file.prepare_ui(renderer);
|
||||
@ -41,7 +41,7 @@ impl AppState {
|
||||
}
|
||||
|
||||
#[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() {
|
||||
Some(modal) => modal.open_directory(dir_path, renderer),
|
||||
_ => (),
|
||||
@ -74,20 +74,18 @@ impl AppState {
|
||||
}
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
impl Render for AppState {
|
||||
fn render(&self, canvas: &mut WC, renderer: &mut Renderer, _context: &RenderContext) {
|
||||
self.file_editor
|
||||
.render(canvas, renderer, &RenderContext::Nothing);
|
||||
self.menu_bar
|
||||
.render(canvas, renderer, &RenderContext::Nothing);
|
||||
impl AppState {
|
||||
pub fn render(&self, canvas: &mut WC, renderer: &mut CanvasRenderer, _context: &RenderContext) {
|
||||
self.file_editor.render(canvas, renderer);
|
||||
self.menu_bar.render(canvas, &RenderContext::Nothing);
|
||||
match self.open_file_modal.as_ref() {
|
||||
Some(modal) => modal.render(canvas, renderer, &RenderContext::Nothing),
|
||||
_ => (),
|
||||
};
|
||||
}
|
||||
|
||||
fn prepare_ui(&mut self, renderer: &mut Renderer) {
|
||||
self.menu_bar.prepare_ui(renderer);
|
||||
pub fn prepare_ui(&mut self, renderer: &mut CanvasRenderer) {
|
||||
self.menu_bar.prepare_ui();
|
||||
self.file_editor.prepare_ui(renderer);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
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::*;
|
||||
pub use rider_config::{Config, ConfigAccess, ConfigHolder};
|
||||
@ -115,7 +115,8 @@ impl Application {
|
||||
let texture_creator = self.canvas.texture_creator();
|
||||
let sleep_time = Duration::new(0, 1_000_000_000u32 / 60);
|
||||
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);
|
||||
|
||||
'running: loop {
|
||||
|
@ -41,27 +41,185 @@ pub fn move_caret_left(file_editor: &mut FileEditor) {
|
||||
#[cfg(test)]
|
||||
mod test_move_right {
|
||||
use super::*;
|
||||
use crate::renderer::managers::FontDetails;
|
||||
use crate::renderer::managers::TextDetails;
|
||||
use crate::renderer::renderer::Renderer;
|
||||
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]
|
||||
fn must_do_nothing() {
|
||||
fn assert_move_with_no_file() {
|
||||
let config = support::build_config();
|
||||
let mut editor = FileEditor::new(config);
|
||||
|
||||
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)]
|
||||
mod test_move_left {
|
||||
use super::*;
|
||||
use crate::renderer::managers::FontDetails;
|
||||
use crate::renderer::managers::TextDetails;
|
||||
use crate::renderer::renderer::Renderer;
|
||||
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]
|
||||
fn must_do_nothing() {
|
||||
fn assert_move_caret_without_file() {
|
||||
let config = support::build_config();
|
||||
let mut editor = FileEditor::new(config);
|
||||
|
||||
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::renderer::Renderer;
|
||||
use crate::renderer::renderer::Renderer;
|
||||
use crate::ui::*;
|
||||
use sdl2::rect::{Point, Rect};
|
||||
use std::sync::*;
|
||||
@ -11,7 +11,10 @@ pub fn current_file_path(file_editor: &mut FileEditor) -> String {
|
||||
}
|
||||
|
||||
#[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() {
|
||||
file
|
||||
} else {
|
||||
@ -53,7 +56,10 @@ pub fn delete_front(file_editor: &mut FileEditor, renderer: &mut Renderer) {
|
||||
}
|
||||
|
||||
#[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() {
|
||||
file
|
||||
} else {
|
||||
@ -70,30 +76,27 @@ pub fn delete_back(file_editor: &mut FileEditor, renderer: &mut Renderer) {
|
||||
file_editor.replace_current_file(new_file);
|
||||
}
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
pub fn insert_text(file_editor: &mut FileEditor, text: String, renderer: &mut Renderer) {
|
||||
let mut buffer: String = file_editor.file().map_or(String::new(), |f| f.buffer());
|
||||
if buffer.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let current = match file_editor
|
||||
.file()
|
||||
.and_then(|file| file.get_character_at(file_editor.caret().text_position()))
|
||||
pub fn insert_text<R>(file_editor: &mut FileEditor, text: String, renderer: &mut R)
|
||||
where
|
||||
R: ConfigHolder + CharacterSizeManager + Renderer,
|
||||
{
|
||||
Some(c) => c,
|
||||
_ => return,
|
||||
let mut buffer: String = match file_editor.file() {
|
||||
Some(f) => f.buffer(),
|
||||
None => return,
|
||||
};
|
||||
let mut pos = if current.is_new_line() {
|
||||
current.dest().top_left()
|
||||
+ Point::new(0, renderer.load_character_size('\n').height() as i32)
|
||||
} else {
|
||||
current.dest().top_left()
|
||||
|
||||
let maybe_character = file_editor
|
||||
.file()
|
||||
.and_then(|file| file.get_character_at(file_editor.caret().text_position()));
|
||||
|
||||
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();
|
||||
for character in text.chars() {
|
||||
buffer.insert(position.text_position(), character);
|
||||
let rect = renderer.load_character_size(character);
|
||||
for c in text.chars() {
|
||||
buffer.insert(position.text_position(), c);
|
||||
let rect = renderer.load_character_size(c);
|
||||
pos = pos + Point::new(rect.width() as i32, 0);
|
||||
position = position.moved(1, 0, 0);
|
||||
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);
|
||||
}
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
pub fn insert_new_line(file_editor: &mut FileEditor, renderer: &mut Renderer) {
|
||||
let mut buffer: String = if let Some(file) = file_editor.file() {
|
||||
file
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
.buffer();
|
||||
let current = match file_editor
|
||||
.file()
|
||||
.and_then(|file| file.get_character_at(file_editor.caret().text_position()))
|
||||
pub fn insert_new_line<R>(file_editor: &mut FileEditor, renderer: &mut R)
|
||||
where
|
||||
R: ConfigHolder + CharacterSizeManager + Renderer,
|
||||
{
|
||||
Some(c) => c,
|
||||
_ => return,
|
||||
let mut buffer: String = match file_editor.file() {
|
||||
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();
|
||||
buffer.insert(position.text_position(), '\n');
|
||||
let rect = renderer.load_character_size('\n');
|
||||
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());
|
||||
|
||||
let mut new_file = EditorFile::new(
|
||||
@ -144,7 +146,54 @@ pub fn insert_new_line(file_editor: &mut FileEditor, renderer: &mut Renderer) {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::renderer::managers::FontDetails;
|
||||
use crate::renderer::managers::TextDetails;
|
||||
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]
|
||||
fn must_return_empty_string_when_no_file() {
|
||||
@ -167,4 +216,156 @@ mod tests {
|
||||
let result = current_file_path(&mut editor);
|
||||
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(
|
||||
&mut self,
|
||||
details: &mut TextDetails,
|
||||
font: &Rc<Font>,
|
||||
font: Rc<Font>,
|
||||
) -> Result<Rc<Texture<'l>>, String>;
|
||||
}
|
||||
|
||||
@ -191,7 +191,7 @@ impl<'l> TextTextureManager<'l> for TextureManager<'l> {
|
||||
fn load_text(
|
||||
&mut self,
|
||||
details: &mut TextDetails,
|
||||
font: &Rc<Font>,
|
||||
font: Rc<Font>,
|
||||
) -> Result<Rc<Texture<'l>>, String> {
|
||||
let key = details.get_cache_key();
|
||||
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 rider_config::{ConfigAccess, ConfigHolder};
|
||||
use sdl2::rect::Rect;
|
||||
use sdl2::render::Texture;
|
||||
use sdl2::render::TextureCreator;
|
||||
use sdl2::ttf::Font;
|
||||
use sdl2::ttf::Sdl2TtfContext;
|
||||
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)]
|
||||
pub struct Renderer<'l> {
|
||||
pub struct CanvasRenderer<'l> {
|
||||
config: ConfigAccess,
|
||||
font_manager: FontManager<'l>,
|
||||
texture_manager: TextureManager<'l>,
|
||||
@ -16,7 +29,7 @@ pub struct Renderer<'l> {
|
||||
}
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
impl<'l> Renderer<'l> {
|
||||
impl<'l> CanvasRenderer<'l> {
|
||||
pub fn new(
|
||||
config: ConfigAccess,
|
||||
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 {
|
||||
let (font_path, font_size) = {
|
||||
let config = self.config().read().unwrap();
|
||||
@ -65,7 +79,7 @@ impl<'l> CharacterSizeManager for Renderer<'l> {
|
||||
}
|
||||
|
||||
#[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> {
|
||||
&mut self.font_manager
|
||||
}
|
||||
@ -76,8 +90,31 @@ impl<'l> ManagersHolder<'l> for Renderer<'l> {
|
||||
}
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
impl<'l> ConfigHolder for Renderer<'l> {
|
||||
impl<'l> ConfigHolder for CanvasRenderer<'l> {
|
||||
fn config(&self) -> &ConfigAccess {
|
||||
&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::renderer::*;
|
||||
use crate::app::UpdateResult as UR;
|
||||
use crate::ui::*;
|
||||
use rider_config::ConfigAccess;
|
||||
use sdl2::rect::{Point, Rect};
|
||||
@ -7,7 +6,6 @@ use std::ops::Deref;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Caret {
|
||||
pending: bool,
|
||||
blink_delay: u8,
|
||||
state: CaretState,
|
||||
position: CaretPosition,
|
||||
@ -25,7 +23,6 @@ impl Caret {
|
||||
blink_delay: 0,
|
||||
dest: Rect::new(0, 0, 6, 0),
|
||||
colors: CaretColor::new(bright, blur),
|
||||
pending: true,
|
||||
position: CaretPosition::new(0, 0, 0),
|
||||
}
|
||||
}
|
||||
@ -67,8 +64,11 @@ impl Deref for Caret {
|
||||
}
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
impl Render for Caret {
|
||||
fn render(&self, canvas: &mut WC, _renderer: &mut Renderer, context: &RenderContext) {
|
||||
impl Caret {
|
||||
pub fn render<T>(&self, canvas: &mut T, context: &RenderContext)
|
||||
where
|
||||
T: CanvasAccess,
|
||||
{
|
||||
use std::borrow::*;
|
||||
|
||||
let dest = match context.borrow() {
|
||||
@ -82,26 +82,22 @@ impl Render for Caret {
|
||||
CaretState::Blur => self.colors.blur(),
|
||||
}
|
||||
.clone();
|
||||
canvas.set_draw_color(color);
|
||||
canvas
|
||||
.draw_line(start, end)
|
||||
.render_line(start, end, color)
|
||||
.unwrap_or_else(|_| panic!("Failed to draw a caret"));
|
||||
}
|
||||
|
||||
fn prepare_ui(&mut self, renderer: &mut Renderer) {
|
||||
if !self.pending {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(rect) = get_text_character_rect('W', renderer) {
|
||||
pub fn prepare_ui<T>(&mut self, renderer: &mut T)
|
||||
where
|
||||
T: CharacterSizeManager,
|
||||
{
|
||||
let rect = renderer.load_character_size('I');
|
||||
self.dest.set_height(rect.height());
|
||||
}
|
||||
self.pending = false;
|
||||
}
|
||||
}
|
||||
|
||||
impl Update for Caret {
|
||||
fn update(&mut self, _ticks: i32, _context: &UpdateContext) -> UR {
|
||||
impl Caret {
|
||||
pub fn update(&mut self) -> UR {
|
||||
self.blink_delay += 1;
|
||||
if self.blink_delay >= 30 {
|
||||
self.blink_delay = 0;
|
||||
@ -312,3 +308,91 @@ mod test_click_handler {
|
||||
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 std::sync::*;
|
||||
|
||||
use crate::app::{UpdateResult as UR, WindowCanvas as WC};
|
||||
use crate::renderer::Renderer;
|
||||
use crate::app::UpdateResult as UR;
|
||||
use crate::renderer::renderer::Renderer;
|
||||
use crate::ui::file::editor_file_section::EditorFileSection;
|
||||
use crate::ui::text_character::TextCharacter;
|
||||
use crate::ui::*;
|
||||
use rider_config::Config;
|
||||
use rider_config::ConfigHolder;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct EditorFile {
|
||||
@ -113,21 +114,27 @@ impl TextCollection for EditorFile {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
impl Render for EditorFile {
|
||||
fn render(&self, canvas: &mut WC, renderer: &mut Renderer, context: &RenderContext) {
|
||||
impl EditorFile {
|
||||
pub fn render<R, C>(&self, canvas: &mut C, renderer: &mut R, context: &RenderContext)
|
||||
where
|
||||
R: Renderer + ConfigHolder,
|
||||
C: CanvasAccess,
|
||||
{
|
||||
for section in self.sections.iter() {
|
||||
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() {
|
||||
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.refresh_characters_position();
|
||||
}
|
||||
}
|
||||
@ -202,11 +209,72 @@ impl RenderBox for EditorFile {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_render_box {
|
||||
mod tests {
|
||||
use crate::tests::support;
|
||||
use crate::ui::*;
|
||||
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]
|
||||
fn assert_dest() {
|
||||
let config = support::build_config();
|
||||
|
@ -1,12 +1,13 @@
|
||||
use sdl2::rect::{Point, Rect};
|
||||
use std::sync::*;
|
||||
|
||||
use crate::app::{UpdateResult as UR, WindowCanvas as WC};
|
||||
use crate::renderer::Renderer;
|
||||
use crate::app::UpdateResult as UR;
|
||||
use crate::renderer::renderer::Renderer;
|
||||
use crate::ui::file::editor_file_token::EditorFileToken;
|
||||
use crate::ui::text_character::TextCharacter;
|
||||
use crate::ui::*;
|
||||
use rider_config::Config;
|
||||
use rider_config::ConfigHolder;
|
||||
use rider_lexers;
|
||||
use rider_lexers::Language;
|
||||
|
||||
@ -26,7 +27,7 @@ impl EditorFileSection {
|
||||
.get(ext.as_str())
|
||||
.unwrap_or(&Language::PlainText)
|
||||
.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 iterator = lexer_tokens.iter().peekable();
|
||||
@ -43,7 +44,6 @@ impl EditorFileSection {
|
||||
);
|
||||
tokens.push(token);
|
||||
}
|
||||
let language = Language::PlainText;
|
||||
Self {
|
||||
tokens,
|
||||
language,
|
||||
@ -51,11 +51,34 @@ impl EditorFileSection {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn language(&self) -> Language {
|
||||
self.language
|
||||
}
|
||||
|
||||
pub fn update_positions(&mut self, current: &mut Rect) {
|
||||
for c in self.tokens.iter_mut() {
|
||||
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 {
|
||||
@ -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 {
|
||||
fn update(&mut self, ticks: i32, context: &UpdateContext) -> UR {
|
||||
let mut result = UR::NoOp;
|
||||
@ -179,3 +187,35 @@ impl ClickHandler for EditorFileSection {
|
||||
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::ui::*;
|
||||
use rider_config::Config;
|
||||
use rider_config::ConfigHolder;
|
||||
use rider_lexers::TokenType;
|
||||
use sdl2::pixels::Color;
|
||||
use sdl2::rect::{Point, Rect};
|
||||
@ -123,13 +124,16 @@ impl TextCollection for EditorFileToken {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
impl Render for EditorFileToken {
|
||||
impl EditorFileToken {
|
||||
/**
|
||||
* Must first create targets so even if new line appear renderer will know
|
||||
* 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() {
|
||||
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() {
|
||||
return;
|
||||
}
|
||||
@ -188,3 +195,505 @@ impl ClickHandler for EditorFileToken {
|
||||
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::{UpdateResult as UR, WindowCanvas as WS};
|
||||
use crate::renderer::renderer::Renderer;
|
||||
use crate::ui::scroll_bar::horizontal_scroll_bar::*;
|
||||
use crate::ui::scroll_bar::vertical_scroll_bar::*;
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -196,10 +209,13 @@ impl CaretAccess for FileEditor {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
impl Render for FileEditor {
|
||||
fn render(&self, canvas: &mut WS, renderer: &mut Renderer, _context: &RenderContext) {
|
||||
canvas.set_clip_rect(self.dest.clone());
|
||||
impl FileEditor {
|
||||
pub fn render<R, C>(&self, canvas: &mut C, renderer: &mut R)
|
||||
where
|
||||
R: Renderer + ConfigHolder,
|
||||
C: CanvasAccess,
|
||||
{
|
||||
canvas.set_clipping(self.dest.clone());
|
||||
match self.file() {
|
||||
Some(file) => file.render(
|
||||
canvas,
|
||||
@ -210,7 +226,6 @@ impl Render for FileEditor {
|
||||
};
|
||||
self.caret.render(
|
||||
canvas,
|
||||
renderer,
|
||||
&RenderContext::RelativePosition(self.render_start_point()),
|
||||
);
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -258,7 +276,7 @@ impl Update for FileEditor {
|
||||
.set_location(self.dest.height() as i32 - (scroll_width as i32 + scroll_margin));
|
||||
self.horizontal_scroll_bar.update(ticks, context);
|
||||
|
||||
self.caret.update(ticks, context);
|
||||
self.caret.update();
|
||||
match self.file_mut() {
|
||||
Some(file) => file.update(ticks, context),
|
||||
_ => UR::NoOp,
|
||||
|
@ -68,7 +68,7 @@ impl DirectoryView {
|
||||
&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 {
|
||||
_ if dir_path == self.path => {
|
||||
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()) {
|
||||
Ok(d) => d,
|
||||
_ => return,
|
||||
@ -167,9 +167,9 @@ impl DirectoryView {
|
||||
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
|
||||
T: RenderImage,
|
||||
T: CanvasAccess,
|
||||
{
|
||||
let dir_texture_path = {
|
||||
let c = self.config.read().unwrap();
|
||||
@ -192,9 +192,9 @@ impl DirectoryView {
|
||||
.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
|
||||
T: RenderImage,
|
||||
T: CanvasAccess,
|
||||
{
|
||||
let mut d = dest.clone();
|
||||
d.set_x(dest.x() + NAME_MARGIN);
|
||||
@ -213,7 +213,7 @@ impl DirectoryView {
|
||||
};
|
||||
let text_texture = renderer
|
||||
.texture_manager()
|
||||
.load_text(&mut text_details, &font)
|
||||
.load_text(&mut text_details, font.clone())
|
||||
.unwrap();
|
||||
d.set_width(size.width());
|
||||
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
|
||||
T: RenderImage,
|
||||
T: CanvasAccess,
|
||||
{
|
||||
if !self.expanded {
|
||||
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');
|
||||
self.height = size.height();
|
||||
self.icon_height = size.height();
|
||||
@ -287,9 +287,9 @@ impl ConfigHolder for DirectoryView {
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
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
|
||||
T: RenderImage,
|
||||
T: CanvasAccess,
|
||||
{
|
||||
let dest = self.dest();
|
||||
let move_point = match context {
|
||||
@ -302,7 +302,7 @@ impl DirectoryView {
|
||||
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 {
|
||||
for dir in self.directories.iter_mut() {
|
||||
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
|
||||
T: RenderImage,
|
||||
T: CanvasAccess,
|
||||
{
|
||||
let dir_texture_path = {
|
||||
let c = self.config.read().unwrap();
|
||||
@ -92,9 +92,9 @@ impl FileEntry {
|
||||
.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
|
||||
T: RenderImage,
|
||||
T: CanvasAccess,
|
||||
{
|
||||
let mut d = dest.clone();
|
||||
d.set_x(dest.x() + NAME_MARGIN);
|
||||
@ -115,7 +115,9 @@ impl FileEntry {
|
||||
text: c.to_string(),
|
||||
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_height(size.height());
|
||||
|
||||
@ -135,9 +137,9 @@ impl ConfigHolder for FileEntry {
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
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
|
||||
T: RenderImage,
|
||||
T: CanvasAccess,
|
||||
{
|
||||
let mut dest = match context {
|
||||
&RenderContext::RelativePosition(p) => move_render_point(p.clone(), &self.dest),
|
||||
@ -147,7 +149,7 @@ impl FileEntry {
|
||||
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();
|
||||
self.char_sizes.insert('W', w_rect.clone());
|
||||
self.height = w_rect.height();
|
||||
|
@ -1,5 +1,4 @@
|
||||
use crate::app::{UpdateResult as UR, WindowCanvas as WC};
|
||||
use crate::renderer::*;
|
||||
use crate::app::UpdateResult as UR;
|
||||
use crate::ui::*;
|
||||
use rider_config::ConfigAccess;
|
||||
use sdl2::pixels::Color;
|
||||
@ -34,32 +33,37 @@ impl MenuBar {
|
||||
pub fn background_color(&self) -> &Color {
|
||||
&self.background_color
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
impl Render for MenuBar {
|
||||
fn render(&self, canvas: &mut WC, _renderer: &mut Renderer, context: &RenderContext) {
|
||||
pub fn render<C>(&self, canvas: &mut C, context: &RenderContext)
|
||||
where
|
||||
C: CanvasAccess,
|
||||
{
|
||||
use std::borrow::*;
|
||||
|
||||
canvas.set_clip_rect(self.dest.clone());
|
||||
canvas.set_draw_color(self.background_color.clone());
|
||||
canvas.set_clipping(self.dest.clone());
|
||||
canvas
|
||||
.fill_rect(match context.borrow() {
|
||||
.render_rect(
|
||||
match context.borrow() {
|
||||
RenderContext::RelativePosition(p) => move_render_point(p.clone(), &self.dest),
|
||||
_ => self.dest(),
|
||||
})
|
||||
},
|
||||
self.background_color.clone(),
|
||||
)
|
||||
.unwrap_or_else(|_| panic!("Failed to draw main menu background"));
|
||||
|
||||
canvas.set_draw_color(self.border_color);
|
||||
canvas
|
||||
.draw_rect(match context.borrow() {
|
||||
RenderContext::RelativePosition(p) => move_render_point((*p).clone(), &self.dest),
|
||||
.render_border(
|
||||
match context.borrow() {
|
||||
RenderContext::RelativePosition(p) => {
|
||||
move_render_point((*p).clone(), &self.dest)
|
||||
}
|
||||
_ => self.dest(),
|
||||
})
|
||||
},
|
||||
self.border_color.clone(),
|
||||
)
|
||||
.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 height = u32::from(self.config.read().unwrap().menu_height());
|
||||
self.dest = Rect::new(0, 0, width, height);
|
||||
@ -211,3 +215,87 @@ mod test_click_handler {
|
||||
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 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::Renderer;
|
||||
use rider_config::*;
|
||||
|
||||
pub mod caret;
|
||||
@ -42,36 +41,48 @@ pub enum RenderContext {
|
||||
RelativePosition(Point),
|
||||
}
|
||||
|
||||
pub trait RenderRect {
|
||||
pub trait CanvasAccess {
|
||||
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>;
|
||||
}
|
||||
|
||||
pub trait RenderImage {
|
||||
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> {
|
||||
self.set_draw_color(color);
|
||||
self.fill_rect(rect)
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderBorder for WindowCanvas {
|
||||
fn render_border(&mut self, rect: Rect, color: sdl2::pixels::Color) -> Result<(), String> {
|
||||
self.set_draw_color(color);
|
||||
self.draw_rect(rect)
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderImage for WindowCanvas {
|
||||
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)
|
||||
}
|
||||
|
||||
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]
|
||||
@ -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())
|
||||
}
|
||||
|
||||
#[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 {
|
||||
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::{RenderContext as RC, UpdateContext as UC};
|
||||
use rider_config::ConfigAccess;
|
||||
@ -56,7 +56,7 @@ impl OpenFile {
|
||||
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);
|
||||
{
|
||||
let dest = self.directory_view.dest();
|
||||
@ -147,9 +147,9 @@ impl Update for OpenFile {
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
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
|
||||
T: RenderRect + RenderBorder + RenderImage,
|
||||
T: CanvasAccess,
|
||||
{
|
||||
let dest = match context {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ impl Update for HorizontalScrollBar {
|
||||
impl HorizontalScrollBar {
|
||||
pub fn render<T>(&self, canvas: &mut T, context: &RenderContext)
|
||||
where
|
||||
T: RenderRect,
|
||||
T: CanvasAccess,
|
||||
{
|
||||
if self.full_width < self.viewport {
|
||||
return;
|
||||
|
@ -57,7 +57,7 @@ impl Update for VerticalScrollBar {
|
||||
impl VerticalScrollBar {
|
||||
pub fn render<T>(&self, canvas: &mut T, context: &RenderContext)
|
||||
where
|
||||
T: RenderBorder,
|
||||
T: CanvasAccess,
|
||||
{
|
||||
if self.full_height() < self.viewport() {
|
||||
return;
|
||||
|
@ -1,5 +1,4 @@
|
||||
use crate::app::{UpdateResult as UR, WindowCanvas as WC};
|
||||
use crate::renderer::managers::*;
|
||||
use crate::app::UpdateResult as UR;
|
||||
use crate::renderer::*;
|
||||
use crate::ui::caret::CaretPosition;
|
||||
use crate::ui::*;
|
||||
@ -7,12 +6,15 @@ use rider_config::{ConfigAccess, ConfigHolder};
|
||||
|
||||
use sdl2::pixels::Color;
|
||||
use sdl2::rect::{Point, Rect};
|
||||
use std::fmt::Debug;
|
||||
use std::fmt::Error;
|
||||
use std::fmt::Formatter;
|
||||
|
||||
pub trait CharacterSizeManager {
|
||||
fn load_character_size(&mut self, c: char) -> Rect;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone)]
|
||||
pub struct TextCharacter {
|
||||
text_character: char,
|
||||
position: usize,
|
||||
@ -99,13 +101,16 @@ impl TextCharacter {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
impl TextCharacter {
|
||||
/**
|
||||
* Must first create targets so even if new line appear renderer will know
|
||||
* 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() {
|
||||
return;
|
||||
}
|
||||
@ -123,21 +128,9 @@ impl TextCharacter {
|
||||
_ => self.dest(),
|
||||
};
|
||||
|
||||
let font = renderer
|
||||
.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) {
|
||||
if let Ok(texture) = renderer.load_text_tex(&mut details, font_details) {
|
||||
canvas
|
||||
.copy_ex(
|
||||
&texture,
|
||||
Some(self.source.clone()),
|
||||
Some(dest.clone()),
|
||||
0.0,
|
||||
None,
|
||||
false,
|
||||
false,
|
||||
)
|
||||
.render_image(texture, self.source.clone(), dest)
|
||||
.unwrap();
|
||||
}
|
||||
// let c = Color::RGB(255, 0, 0);
|
||||
@ -147,10 +140,9 @@ impl TextCharacter {
|
||||
|
||||
pub fn prepare_ui<'l, T>(&mut self, renderer: &mut T)
|
||||
where
|
||||
T: ConfigHolder + CharacterSizeManager + ManagersHolder<'l>,
|
||||
T: ConfigHolder + CharacterSizeManager + Renderer,
|
||||
{
|
||||
let font_details: FontDetails = renderer.config().read().unwrap().editor_config().into();
|
||||
|
||||
let rect = renderer.load_character_size(self.text_character);
|
||||
self.set_source(&rect);
|
||||
self.set_dest(&rect);
|
||||
@ -161,14 +153,12 @@ impl TextCharacter {
|
||||
font: font_details.clone(),
|
||||
};
|
||||
|
||||
let font = renderer
|
||||
.font_manager()
|
||||
.load(&font_details)
|
||||
.unwrap_or_else(|_| panic!("Font not found {:?}", font_details));
|
||||
renderer
|
||||
.texture_manager()
|
||||
.load_text(&mut details, &font)
|
||||
.unwrap_or_else(|_| panic!("Could not create texture for {:?}", self.text_character));
|
||||
if let Err(error_message) = renderer.load_text_tex(&mut details, font_details) {
|
||||
info!(
|
||||
"Could not create texture for '{:?}' with {:?}",
|
||||
self.text_character, error_message
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)]
|
||||
mod test_getters {
|
||||
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