Add display config modal
This commit is contained in:
parent
ae78642ca9
commit
33715a38c7
12
README.md
12
README.md
@ -13,6 +13,15 @@ rustup run nightly cargo build --all -rr
|
|||||||
rustup run nightly cargo run -p rider-editor
|
rustup run nightly cargo run -p rider-editor
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Keyboard mapping
|
||||||
|
|
||||||
|
* `DELETE` - delete next character
|
||||||
|
* `BACKSPACE` - delete prev character
|
||||||
|
* `SHIFT + DELETE` - delete line
|
||||||
|
* `CTRL + O` - open file
|
||||||
|
* `CTRL + S` - save current file
|
||||||
|
* `ESCAPE` - close current modal
|
||||||
|
|
||||||
## Road map
|
## Road map
|
||||||
|
|
||||||
### v1.0
|
### v1.0
|
||||||
@ -25,10 +34,9 @@ rustup run nightly cargo run -p rider-editor
|
|||||||
* [x] Open file menu
|
* [x] Open file menu
|
||||||
* [x] `Save file` with button
|
* [x] `Save file` with button
|
||||||
* [x] `Save file` with shortcut
|
* [x] `Save file` with shortcut
|
||||||
* [ ] `Save file as...` with shortcut
|
|
||||||
* [x] Theme based menu UI
|
* [x] Theme based menu UI
|
||||||
* [x] Lock scroll when no available content
|
* [x] Lock scroll when no available content
|
||||||
* [ ] Config edit menu
|
* [x] Config edit menu
|
||||||
* [x] Project tree
|
* [x] Project tree
|
||||||
* [x] Cover `rider` with tests at least 50%
|
* [x] Cover `rider` with tests at least 50%
|
||||||
* [x] Handle resize window
|
* [x] Handle resize window
|
||||||
|
@ -205,7 +205,7 @@ mod test_getters {
|
|||||||
fn assert_menu_height() {
|
fn assert_menu_height() {
|
||||||
let config = Config::new();
|
let config = Config::new();
|
||||||
let result = config.menu_height();
|
let result = config.menu_height();
|
||||||
let expected = 60;
|
let expected = 40;
|
||||||
assert_eq!(result, expected);
|
assert_eq!(result, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ pub struct AppState {
|
|||||||
files: Vec<EditorFile>,
|
files: Vec<EditorFile>,
|
||||||
config: Arc<RwLock<Config>>,
|
config: Arc<RwLock<Config>>,
|
||||||
file_editor: FileEditor,
|
file_editor: FileEditor,
|
||||||
open_file_modal: Option<OpenFile>,
|
modal: Option<ModalType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppState {
|
impl AppState {
|
||||||
@ -29,7 +29,7 @@ impl AppState {
|
|||||||
),
|
),
|
||||||
files: vec![],
|
files: vec![],
|
||||||
file_editor: FileEditor::new(Arc::clone(&config)),
|
file_editor: FileEditor::new(Arc::clone(&config)),
|
||||||
open_file_modal: None,
|
modal: None,
|
||||||
config,
|
config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -65,13 +65,35 @@ impl AppState {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn open_settings<R>(&mut self, renderer: &mut R) -> Result<(), String>
|
||||||
|
where
|
||||||
|
R: Renderer + CharacterSizeManager,
|
||||||
|
{
|
||||||
|
println!("Open Settings...");
|
||||||
|
match self.modal {
|
||||||
|
None => {
|
||||||
|
let mut settings = Settings::new(self.config.clone());
|
||||||
|
settings.prepare_ui(renderer);
|
||||||
|
self.modal = Some(ModalType::Settings(settings));
|
||||||
|
}
|
||||||
|
_ => return Ok(()),
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn close_modal(&mut self) -> Result<(), String> {
|
||||||
|
self.modal = None;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn open_directory<R>(&mut self, dir_path: String, renderer: &mut R)
|
pub fn open_directory<R>(&mut self, dir_path: String, renderer: &mut R)
|
||||||
where
|
where
|
||||||
R: Renderer + CharacterSizeManager,
|
R: Renderer + CharacterSizeManager,
|
||||||
{
|
{
|
||||||
match self.open_file_modal.as_mut() {
|
match self.modal.as_mut() {
|
||||||
Some(modal) => modal.open_directory(dir_path, renderer),
|
Some(ModalType::OpenFile(modal)) => modal.open_directory(dir_path, renderer),
|
||||||
None => self.project_tree.open_directory(dir_path, renderer),
|
None => self.project_tree.open_directory(dir_path, renderer),
|
||||||
|
_ => (),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,19 +108,33 @@ impl AppState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_open_file_modal(&mut self, modal: Option<OpenFile>) {
|
pub fn set_open_file_modal(&mut self, modal: Option<OpenFile>) {
|
||||||
self.open_file_modal = modal;
|
self.modal = if let Some(modal) = modal {
|
||||||
|
Some(ModalType::OpenFile(modal))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn scroll_by(&mut self, x: i32, y: i32) {
|
pub fn scroll_by(&mut self, x: i32, y: i32) {
|
||||||
if let Some(modal) = self.open_file_modal.as_mut() {
|
match self.modal.as_mut() {
|
||||||
modal.scroll_by(x, y);
|
Some(ModalType::OpenFile(modal)) => modal.scroll_by(x, y),
|
||||||
} else {
|
Some(ModalType::Settings(modal)) => modal.scroll_by(x, y),
|
||||||
self.file_editor_mut().scroll_by(x, y);
|
_ => self.file_editor_mut().scroll_by(x, y),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_file_modal(&self) -> Option<&OpenFile> {
|
pub fn open_file_modal(&self) -> Option<&OpenFile> {
|
||||||
self.open_file_modal.as_ref()
|
match self.modal {
|
||||||
|
Some(ModalType::OpenFile(ref m)) => Some(m),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn settings_modal(&self) -> Option<&Settings> {
|
||||||
|
match self.modal {
|
||||||
|
Some(ModalType::Settings(ref m)) => Some(m),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,9 +155,14 @@ impl AppState {
|
|||||||
// project tree
|
// project tree
|
||||||
self.project_tree.render(canvas, renderer);
|
self.project_tree.render(canvas, renderer);
|
||||||
|
|
||||||
// open file modal
|
// settings modal
|
||||||
match self.open_file_modal.as_ref() {
|
match self.modal.as_ref() {
|
||||||
Some(modal) => modal.render(canvas, renderer, &RenderContext::Nothing),
|
Some(ModalType::OpenFile(modal)) => {
|
||||||
|
return modal.render(canvas, renderer, &RenderContext::Nothing)
|
||||||
|
}
|
||||||
|
Some(ModalType::Settings(modal)) => {
|
||||||
|
return modal.render(canvas, renderer, &RenderContext::Nothing)
|
||||||
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -136,10 +177,10 @@ impl AppState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&mut self, ticks: i32, context: &UpdateContext) -> UpdateResult {
|
pub fn update(&mut self, ticks: i32, context: &UpdateContext) -> UpdateResult {
|
||||||
// open file modal
|
let res = match self.modal.as_mut() {
|
||||||
let res = match self.open_file_modal.as_mut() {
|
Some(ModalType::OpenFile(modal)) => modal.update(ticks, context.clone()),
|
||||||
Some(modal) => modal.update(ticks, &UpdateContext::Nothing),
|
Some(ModalType::Settings(modal)) => modal.update(ticks, context.clone()),
|
||||||
_ => UpdateResult::NoOp,
|
None => UpdateResult::NoOp,
|
||||||
};
|
};
|
||||||
if res != UpdateResult::NoOp {
|
if res != UpdateResult::NoOp {
|
||||||
return res;
|
return res;
|
||||||
@ -171,8 +212,13 @@ impl AppState {
|
|||||||
.project_tree
|
.project_tree
|
||||||
.on_left_click(point, &UpdateContext::Nothing);
|
.on_left_click(point, &UpdateContext::Nothing);
|
||||||
}
|
}
|
||||||
match self.open_file_modal.as_mut() {
|
match self.modal.as_mut() {
|
||||||
Some(modal) => return modal.on_left_click(point, &UpdateContext::Nothing),
|
Some(ModalType::OpenFile(modal)) => {
|
||||||
|
return modal.on_left_click(point, &UpdateContext::Nothing)
|
||||||
|
}
|
||||||
|
Some(ModalType::Settings(modal)) => {
|
||||||
|
return modal.on_left_click(point, &UpdateContext::Nothing)
|
||||||
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
};
|
};
|
||||||
if self
|
if self
|
||||||
@ -188,10 +234,10 @@ impl AppState {
|
|||||||
return UpdateResult::NoOp;
|
return UpdateResult::NoOp;
|
||||||
} else {
|
} else {
|
||||||
video_subsystem.text_input().start();
|
video_subsystem.text_input().start();
|
||||||
self.file_editor
|
return self
|
||||||
|
.file_editor
|
||||||
.on_left_click(point, &UpdateContext::Nothing);
|
.on_left_click(point, &UpdateContext::Nothing);
|
||||||
}
|
}
|
||||||
UpdateResult::NoOp
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_left_click_target(&self, _point: &Point) -> bool {
|
pub fn is_left_click_target(&self, _point: &Point) -> bool {
|
||||||
|
@ -3,6 +3,7 @@ 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};
|
||||||
|
|
||||||
use sdl2::event::*;
|
use sdl2::event::*;
|
||||||
use sdl2::hint;
|
use sdl2::hint;
|
||||||
use sdl2::keyboard::Keycode;
|
use sdl2::keyboard::Keycode;
|
||||||
@ -24,7 +25,7 @@ use std::time::Duration;
|
|||||||
|
|
||||||
pub type WindowCanvas = Canvas<Window>;
|
pub type WindowCanvas = Canvas<Window>;
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
pub enum UpdateResult {
|
pub enum UpdateResult {
|
||||||
NoOp,
|
NoOp,
|
||||||
Stop,
|
Stop,
|
||||||
@ -35,6 +36,7 @@ pub enum UpdateResult {
|
|||||||
MoveCaret(Rect, CaretPosition),
|
MoveCaret(Rect, CaretPosition),
|
||||||
DeleteFront,
|
DeleteFront,
|
||||||
DeleteBack,
|
DeleteBack,
|
||||||
|
DeleteLine,
|
||||||
Input(String),
|
Input(String),
|
||||||
InsertNewLine,
|
InsertNewLine,
|
||||||
MoveCaretLeft,
|
MoveCaretLeft,
|
||||||
@ -49,6 +51,8 @@ pub enum UpdateResult {
|
|||||||
OpenFileModal,
|
OpenFileModal,
|
||||||
FileDropped(String),
|
FileDropped(String),
|
||||||
SaveCurrentFile,
|
SaveCurrentFile,
|
||||||
|
OpenSettings,
|
||||||
|
CloseModal,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
#[cfg_attr(tarpaulin, skip)]
|
||||||
@ -137,6 +141,7 @@ impl Application {
|
|||||||
let res = app_state.on_left_click(&point, &mut self.video_subsystem);
|
let res = app_state.on_left_click(&point, &mut self.video_subsystem);
|
||||||
match res {
|
match res {
|
||||||
UpdateResult::OpenDirectory(_) => new_tasks.push(res),
|
UpdateResult::OpenDirectory(_) => new_tasks.push(res),
|
||||||
|
UpdateResult::OpenSettings => new_tasks.push(res),
|
||||||
UpdateResult::OpenFile(_) => {
|
UpdateResult::OpenFile(_) => {
|
||||||
new_tasks.push(res);
|
new_tasks.push(res);
|
||||||
app_state.set_open_file_modal(None);
|
app_state.set_open_file_modal(None);
|
||||||
@ -154,9 +159,14 @@ impl Application {
|
|||||||
UpdateResult::Input(text) => app_state
|
UpdateResult::Input(text) => app_state
|
||||||
.file_editor_mut()
|
.file_editor_mut()
|
||||||
.insert_text(text.clone(), &mut renderer),
|
.insert_text(text.clone(), &mut renderer),
|
||||||
UpdateResult::InsertNewLine => {
|
UpdateResult::InsertNewLine => app_state
|
||||||
app_state.file_editor_mut().insert_new_line(&mut renderer);
|
.file_editor_mut()
|
||||||
}
|
.insert_new_line(&mut renderer)
|
||||||
|
.unwrap_or_else(|e| eprintln!("Failed to delete line {:?}", e)),
|
||||||
|
UpdateResult::DeleteLine => app_state
|
||||||
|
.file_editor_mut()
|
||||||
|
.delete_current_line(&mut renderer)
|
||||||
|
.unwrap_or_else(|e| eprintln!("Failed to delete line {:?}", e)),
|
||||||
UpdateResult::MoveCaretLeft => {
|
UpdateResult::MoveCaretLeft => {
|
||||||
app_state.file_editor_mut().move_caret(MoveDirection::Left);
|
app_state.file_editor_mut().move_caret(MoveDirection::Left);
|
||||||
}
|
}
|
||||||
@ -205,6 +215,12 @@ impl Application {
|
|||||||
UpdateResult::SaveCurrentFile => app_state
|
UpdateResult::SaveCurrentFile => app_state
|
||||||
.save_file()
|
.save_file()
|
||||||
.unwrap_or_else(|e| eprintln!("Failed to save {:?}", e)),
|
.unwrap_or_else(|e| eprintln!("Failed to save {:?}", e)),
|
||||||
|
UpdateResult::OpenSettings => app_state
|
||||||
|
.open_settings(&mut renderer)
|
||||||
|
.unwrap_or_else(|e| eprintln!("Failed to open settings {:?}", e)),
|
||||||
|
UpdateResult::CloseModal => app_state
|
||||||
|
.close_modal()
|
||||||
|
.unwrap_or_else(|e| eprintln!("Failed to close modal {:?}", e)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.tasks = new_tasks;
|
self.tasks = new_tasks;
|
||||||
@ -266,12 +282,18 @@ impl Application {
|
|||||||
.tasks
|
.tasks
|
||||||
.push(UpdateResult::MouseDragStart(Point::new(x, y))),
|
.push(UpdateResult::MouseDragStart(Point::new(x, y))),
|
||||||
Event::KeyDown { keycode, .. } if keycode.is_some() => match keycode.unwrap() {
|
Event::KeyDown { keycode, .. } if keycode.is_some() => match keycode.unwrap() {
|
||||||
|
Keycode::Escape => {
|
||||||
|
self.tasks.push(UpdateResult::CloseModal);
|
||||||
|
}
|
||||||
Keycode::Backspace => {
|
Keycode::Backspace => {
|
||||||
self.tasks.push(UpdateResult::DeleteFront);
|
self.tasks.push(UpdateResult::DeleteFront);
|
||||||
}
|
}
|
||||||
Keycode::Delete => {
|
Keycode::Delete if !shift_pressed => {
|
||||||
self.tasks.push(UpdateResult::DeleteBack);
|
self.tasks.push(UpdateResult::DeleteBack);
|
||||||
}
|
}
|
||||||
|
Keycode::Delete if shift_pressed => {
|
||||||
|
self.tasks.push(UpdateResult::DeleteLine);
|
||||||
|
}
|
||||||
Keycode::KpEnter | Keycode::Return => {
|
Keycode::KpEnter | Keycode::Return => {
|
||||||
self.tasks.push(UpdateResult::InsertNewLine);
|
self.tasks.push(UpdateResult::InsertNewLine);
|
||||||
}
|
}
|
||||||
@ -307,9 +329,7 @@ impl Application {
|
|||||||
MouseWheelDirection::Flipped => {
|
MouseWheelDirection::Flipped => {
|
||||||
self.tasks.push(UpdateResult::Scroll { x, y: -y });
|
self.tasks.push(UpdateResult::Scroll { x, y: -y });
|
||||||
}
|
}
|
||||||
_ => {
|
_ => (),
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
Event::Window {
|
Event::Window {
|
||||||
win_event: WindowEvent::Resized(w, h),
|
win_event: WindowEvent::Resized(w, h),
|
||||||
@ -318,7 +338,7 @@ impl Application {
|
|||||||
width: w,
|
width: w,
|
||||||
height: h,
|
height: h,
|
||||||
}),
|
}),
|
||||||
_ => {}
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,14 +104,14 @@ where
|
|||||||
file_editor.replace_current_file(new_file);
|
file_editor.replace_current_file(new_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_new_line<R>(file_editor: &mut FileEditor, renderer: &mut R)
|
pub fn insert_new_line<R>(file_editor: &mut FileEditor, renderer: &mut R) -> Result<(), String>
|
||||||
where
|
where
|
||||||
R: ConfigHolder + CharacterSizeManager + Renderer,
|
R: ConfigHolder + CharacterSizeManager + Renderer,
|
||||||
{
|
{
|
||||||
let mut buffer: String = match file_editor.file() {
|
let mut buffer: String = file_editor
|
||||||
Some(file) => file.buffer(),
|
.file()
|
||||||
None => return,
|
.map(|file| file.buffer())
|
||||||
};
|
.ok_or_else(|| "No file is open".to_string())?;
|
||||||
|
|
||||||
let maybe_character = file_editor
|
let maybe_character = file_editor
|
||||||
.file()
|
.file()
|
||||||
@ -134,6 +134,36 @@ where
|
|||||||
);
|
);
|
||||||
new_file.prepare_ui(renderer);
|
new_file.prepare_ui(renderer);
|
||||||
file_editor.replace_current_file(new_file);
|
file_editor.replace_current_file(new_file);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn delete_current_line<R>(file_editor: &mut FileEditor, renderer: &mut R) -> Result<(), String>
|
||||||
|
where
|
||||||
|
R: ConfigHolder + CharacterSizeManager + Renderer,
|
||||||
|
{
|
||||||
|
let file: &EditorFile = file_editor
|
||||||
|
.file()
|
||||||
|
.ok_or_else(|| "No file is open".to_string())?;
|
||||||
|
let mut new_buffer = String::new();
|
||||||
|
let target_line = file_editor.caret().line_number();
|
||||||
|
let mut current_line = 0;
|
||||||
|
for c in file.buffer_ref().chars() {
|
||||||
|
match c {
|
||||||
|
'\n' if current_line == target_line => {
|
||||||
|
current_line += 1;
|
||||||
|
}
|
||||||
|
'\n' => {
|
||||||
|
current_line += 1;
|
||||||
|
new_buffer.push(c);
|
||||||
|
}
|
||||||
|
_ if current_line == target_line => (),
|
||||||
|
_ => new_buffer.push(c),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut new_file = EditorFile::new(file.path(), new_buffer, file_editor.config().clone());
|
||||||
|
new_file.prepare_ui(renderer);
|
||||||
|
file_editor.replace_current_file(new_file);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -309,7 +339,8 @@ mod tests {
|
|||||||
let mut renderer = RendererMock::new(config.clone());
|
let mut renderer = RendererMock::new(config.clone());
|
||||||
let mut widget = FileEditor::new(config.clone());
|
let mut widget = FileEditor::new(config.clone());
|
||||||
widget.prepare_ui(&mut renderer);
|
widget.prepare_ui(&mut renderer);
|
||||||
widget.insert_new_line(&mut renderer);
|
let res: Result<(), String> = widget.insert_new_line(&mut renderer);
|
||||||
|
assert_eq!(res.is_ok(), false);
|
||||||
let expected = CaretPosition::new(0, 0, 0);
|
let expected = CaretPosition::new(0, 0, 0);
|
||||||
assert_eq!(widget.caret().position(), &expected);
|
assert_eq!(widget.caret().position(), &expected);
|
||||||
let expected = Rect::new(0, 0, 6, 15);
|
let expected = Rect::new(0, 0, 6, 15);
|
||||||
@ -324,7 +355,8 @@ mod tests {
|
|||||||
let file = EditorFile::new("".to_owned(), "".to_owned(), config.clone());
|
let file = EditorFile::new("".to_owned(), "".to_owned(), config.clone());
|
||||||
widget.open_file(file);
|
widget.open_file(file);
|
||||||
widget.prepare_ui(&mut renderer);
|
widget.prepare_ui(&mut renderer);
|
||||||
widget.insert_new_line(&mut renderer);
|
let res: Result<(), String> = widget.insert_new_line(&mut renderer);
|
||||||
|
assert_eq!(res.is_ok(), true);
|
||||||
let expected = CaretPosition::new(1, 1, 0);
|
let expected = CaretPosition::new(1, 1, 0);
|
||||||
assert_eq!(widget.caret().position(), &expected);
|
assert_eq!(widget.caret().position(), &expected);
|
||||||
let expected = Rect::new(0, 13, 6, 15);
|
let expected = Rect::new(0, 13, 6, 15);
|
||||||
@ -339,7 +371,8 @@ mod tests {
|
|||||||
let file = EditorFile::new("".to_owned(), "foo".to_owned(), config.clone());
|
let file = EditorFile::new("".to_owned(), "foo".to_owned(), config.clone());
|
||||||
widget.open_file(file);
|
widget.open_file(file);
|
||||||
widget.prepare_ui(&mut renderer);
|
widget.prepare_ui(&mut renderer);
|
||||||
widget.insert_new_line(&mut renderer);
|
let res: Result<(), String> = widget.insert_new_line(&mut renderer);
|
||||||
|
assert_eq!(res.is_ok(), true);
|
||||||
let expected = CaretPosition::new(1, 1, 0);
|
let expected = CaretPosition::new(1, 1, 0);
|
||||||
assert_eq!(widget.caret().position(), &expected);
|
assert_eq!(widget.caret().position(), &expected);
|
||||||
let expected = Rect::new(0, 13, 6, 15);
|
let expected = Rect::new(0, 13, 6, 15);
|
||||||
@ -359,7 +392,8 @@ mod tests {
|
|||||||
widget.prepare_ui(&mut renderer);
|
widget.prepare_ui(&mut renderer);
|
||||||
widget.move_caret(MoveDirection::Right);
|
widget.move_caret(MoveDirection::Right);
|
||||||
widget.move_caret(MoveDirection::Right);
|
widget.move_caret(MoveDirection::Right);
|
||||||
widget.insert_new_line(&mut renderer);
|
let res: Result<(), String> = widget.insert_new_line(&mut renderer);
|
||||||
|
assert_eq!(res.is_ok(), true);
|
||||||
let expected = CaretPosition::new(3, 1, 0);
|
let expected = CaretPosition::new(3, 1, 0);
|
||||||
assert_eq!(widget.caret().position(), &expected);
|
assert_eq!(widget.caret().position(), &expected);
|
||||||
let expected = Rect::new(0, 13, 6, 15);
|
let expected = Rect::new(0, 13, 6, 15);
|
||||||
|
5
rider-editor/src/ui/buttons/mod.rs
Normal file
5
rider-editor/src/ui/buttons/mod.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
pub mod save_button;
|
||||||
|
pub mod settings_button;
|
||||||
|
|
||||||
|
pub use self::save_button::*;
|
||||||
|
pub use self::settings_button::*;
|
@ -32,7 +32,7 @@ impl SaveButton {
|
|||||||
{
|
{
|
||||||
use std::borrow::*;
|
use std::borrow::*;
|
||||||
let mut dest = match context {
|
let mut dest = match context {
|
||||||
&RenderContext::RelativePosition(p) => move_render_point(p.clone(), &self.dest),
|
&RenderContext::ParentPosition(p) => move_render_point(p.clone(), &self.dest),
|
||||||
_ => self.dest.clone(),
|
_ => self.dest.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -78,8 +78,6 @@ impl SaveButton {
|
|||||||
|
|
||||||
impl Update for SaveButton {
|
impl Update for SaveButton {
|
||||||
fn update(&mut self, _ticks: i32, _context: &UpdateContext) -> UR {
|
fn update(&mut self, _ticks: i32, _context: &UpdateContext) -> UR {
|
||||||
let config = self.config.read().unwrap();
|
|
||||||
self.dest.set_width(config.width());
|
|
||||||
UR::NoOp
|
UR::NoOp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -92,7 +90,7 @@ impl ClickHandler for SaveButton {
|
|||||||
fn is_left_click_target(&self, point: &Point, context: &UpdateContext) -> bool {
|
fn is_left_click_target(&self, point: &Point, context: &UpdateContext) -> bool {
|
||||||
match *context {
|
match *context {
|
||||||
UpdateContext::ParentPosition(p) => move_render_point(p.clone(), &self.dest),
|
UpdateContext::ParentPosition(p) => move_render_point(p.clone(), &self.dest),
|
||||||
_ => self.dest(),
|
_ => self.dest,
|
||||||
}
|
}
|
||||||
.contains_point(point.clone())
|
.contains_point(point.clone())
|
||||||
}
|
}
|
@ -32,7 +32,7 @@ impl SettingsButton {
|
|||||||
{
|
{
|
||||||
use std::borrow::*;
|
use std::borrow::*;
|
||||||
let mut dest = match context {
|
let mut dest = match context {
|
||||||
&RenderContext::RelativePosition(p) => move_render_point(p.clone(), &self.dest),
|
&RenderContext::ParentPosition(p) => move_render_point(p.clone(), &self.dest),
|
||||||
_ => self.dest.clone(),
|
_ => self.dest.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -78,21 +78,19 @@ impl SettingsButton {
|
|||||||
|
|
||||||
impl Update for SettingsButton {
|
impl Update for SettingsButton {
|
||||||
fn update(&mut self, _ticks: i32, _context: &UpdateContext) -> UR {
|
fn update(&mut self, _ticks: i32, _context: &UpdateContext) -> UR {
|
||||||
let config = self.config.read().unwrap();
|
|
||||||
self.dest.set_width(config.width());
|
|
||||||
UR::NoOp
|
UR::NoOp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClickHandler for SettingsButton {
|
impl ClickHandler for SettingsButton {
|
||||||
fn on_left_click(&mut self, _point: &Point, _context: &UpdateContext) -> UR {
|
fn on_left_click(&mut self, _point: &Point, _context: &UpdateContext) -> UR {
|
||||||
UR::NoOp
|
UR::OpenSettings
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_left_click_target(&self, point: &Point, context: &UpdateContext) -> bool {
|
fn is_left_click_target(&self, point: &Point, context: &UpdateContext) -> bool {
|
||||||
match *context {
|
match *context {
|
||||||
UpdateContext::ParentPosition(p) => move_render_point(p.clone(), &self.dest),
|
UpdateContext::ParentPosition(p) => move_render_point(p.clone(), &self.dest),
|
||||||
_ => self.dest(),
|
_ => self.dest,
|
||||||
}
|
}
|
||||||
.contains_point(point.clone())
|
.contains_point(point.clone())
|
||||||
}
|
}
|
@ -72,7 +72,7 @@ impl Caret {
|
|||||||
use std::borrow::*;
|
use std::borrow::*;
|
||||||
|
|
||||||
let dest = match context.borrow() {
|
let dest = match context.borrow() {
|
||||||
RenderContext::RelativePosition(p) => move_render_point(p.clone(), &self.dest),
|
RenderContext::ParentPosition(p) => move_render_point(p.clone(), &self.dest),
|
||||||
_ => self.dest().clone(),
|
_ => self.dest().clone(),
|
||||||
};
|
};
|
||||||
let start = Point::new(dest.x(), dest.y());
|
let start = Point::new(dest.x(), dest.y());
|
||||||
@ -368,7 +368,7 @@ mod test_render {
|
|||||||
#[test]
|
#[test]
|
||||||
fn assert_render_line() {
|
fn assert_render_line() {
|
||||||
let config = build_config();
|
let config = build_config();
|
||||||
let context = RenderContext::RelativePosition(Point::new(10, 14));
|
let context = RenderContext::ParentPosition(Point::new(10, 14));
|
||||||
let mut canvas = CanvasMock {
|
let mut canvas = CanvasMock {
|
||||||
start: Point::new(0, 0),
|
start: Point::new(0, 0),
|
||||||
end: Point::new(0, 0),
|
end: Point::new(0, 0),
|
||||||
|
@ -47,6 +47,10 @@ impl EditorFile {
|
|||||||
self.buffer.clone()
|
self.buffer.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn buffer_ref(&self) -> &String {
|
||||||
|
&self.buffer
|
||||||
|
}
|
||||||
|
|
||||||
pub fn path(&self) -> String {
|
pub fn path(&self) -> String {
|
||||||
self.path.clone()
|
self.path.clone()
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,8 @@ impl EditorFileSection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn iter_char(&self) -> EditorFileSectionIterator {
|
#[inline]
|
||||||
|
pub fn iter_char(&self) -> EditorFileSectionIterator {
|
||||||
EditorFileSectionIterator::new(self)
|
EditorFileSectionIterator::new(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@ impl EditorFileToken {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn characters(&self) -> &Vec<TextCharacter> {
|
pub fn characters(&self) -> &Vec<TextCharacter> {
|
||||||
&self.characters
|
&self.characters
|
||||||
}
|
}
|
||||||
@ -59,7 +60,8 @@ impl EditorFileToken {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn iter_char(&self) -> EditorFileTokenIterator {
|
#[inline]
|
||||||
|
pub fn iter_char(&self) -> EditorFileTokenIterator {
|
||||||
EditorFileTokenIterator::new(self)
|
EditorFileTokenIterator::new(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -82,12 +84,10 @@ impl TextWidget for EditorFileToken {
|
|||||||
|
|
||||||
impl TextCollection for EditorFileToken {
|
impl TextCollection for EditorFileToken {
|
||||||
fn get_character_at(&self, index: usize) -> Option<TextCharacter> {
|
fn get_character_at(&self, index: usize) -> Option<TextCharacter> {
|
||||||
for character in self.characters.iter() {
|
self.characters
|
||||||
if character.position() == index {
|
.iter()
|
||||||
return Some(character.clone());
|
.find(|character| character.position() == index)
|
||||||
}
|
.cloned()
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_line(&self, line: &usize) -> Option<Vec<&TextCharacter>> {
|
fn get_line(&self, line: &usize) -> Option<Vec<&TextCharacter>> {
|
||||||
|
@ -106,11 +106,18 @@ impl FileEditor {
|
|||||||
file_content_manager::insert_text(self, text, renderer);
|
file_content_manager::insert_text(self, text, renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_new_line<R>(&mut self, renderer: &mut R)
|
pub fn insert_new_line<R>(&mut self, renderer: &mut R) -> Result<(), String>
|
||||||
where
|
where
|
||||||
R: ConfigHolder + CharacterSizeManager + Renderer,
|
R: ConfigHolder + CharacterSizeManager + Renderer,
|
||||||
{
|
{
|
||||||
file_content_manager::insert_new_line(self, renderer);
|
file_content_manager::insert_new_line(self, renderer)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn delete_current_line<R>(&mut self, renderer: &mut R) -> Result<(), String>
|
||||||
|
where
|
||||||
|
R: ConfigHolder + CharacterSizeManager + Renderer,
|
||||||
|
{
|
||||||
|
file_content_manager::delete_current_line(self, renderer)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_text_character_clicked(&self, point: &Point) -> bool {
|
fn is_text_character_clicked(&self, point: &Point) -> bool {
|
||||||
@ -264,22 +271,18 @@ impl FileEditor {
|
|||||||
Some(file) => file.render(
|
Some(file) => file.render(
|
||||||
canvas,
|
canvas,
|
||||||
renderer,
|
renderer,
|
||||||
&RenderContext::RelativePosition(self.render_start_point()),
|
&RenderContext::ParentPosition(self.render_start_point()),
|
||||||
),
|
),
|
||||||
_ => (),
|
_ => (),
|
||||||
};
|
};
|
||||||
self.caret.render(
|
self.caret.render(
|
||||||
canvas,
|
canvas,
|
||||||
&RenderContext::RelativePosition(self.render_start_point()),
|
&RenderContext::ParentPosition(self.render_start_point()),
|
||||||
);
|
|
||||||
self.vertical_scroll_bar.render(
|
|
||||||
canvas,
|
|
||||||
&RenderContext::RelativePosition(self.dest.top_left()),
|
|
||||||
);
|
|
||||||
self.horizontal_scroll_bar.render(
|
|
||||||
canvas,
|
|
||||||
&RenderContext::RelativePosition(self.dest.top_left()),
|
|
||||||
);
|
);
|
||||||
|
self.vertical_scroll_bar
|
||||||
|
.render(canvas, &RenderContext::ParentPosition(self.dest.top_left()));
|
||||||
|
self.horizontal_scroll_bar
|
||||||
|
.render(canvas, &RenderContext::ParentPosition(self.dest.top_left()));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prepare_ui<T>(&mut self, renderer: &mut T)
|
pub fn prepare_ui<T>(&mut self, renderer: &mut T)
|
||||||
|
@ -252,12 +252,12 @@ impl DirectoryView {
|
|||||||
self.icon_height as i32 + CHILD_MARGIN,
|
self.icon_height as i32 + CHILD_MARGIN,
|
||||||
);
|
);
|
||||||
for dir in self.directories.iter() {
|
for dir in self.directories.iter() {
|
||||||
let context = RenderContext::RelativePosition(point.clone());
|
let context = RenderContext::ParentPosition(point.clone());
|
||||||
dir.render(canvas, renderer, &context);
|
dir.render(canvas, renderer, &context);
|
||||||
point = point + Point::new(0, dir.height() as i32 + CHILD_MARGIN as i32);
|
point = point + Point::new(0, dir.height() as i32 + CHILD_MARGIN as i32);
|
||||||
}
|
}
|
||||||
for file in self.files.iter() {
|
for file in self.files.iter() {
|
||||||
let context = RenderContext::RelativePosition(point.clone());
|
let context = RenderContext::ParentPosition(point.clone());
|
||||||
file.render(canvas, renderer, &context);
|
file.render(canvas, renderer, &context);
|
||||||
point = point + Point::new(0, file.height() as i32 + CHILD_MARGIN as i32);
|
point = point + Point::new(0, file.height() as i32 + CHILD_MARGIN as i32);
|
||||||
}
|
}
|
||||||
@ -302,7 +302,7 @@ impl DirectoryView {
|
|||||||
{
|
{
|
||||||
let dest = self.dest();
|
let dest = self.dest();
|
||||||
let move_point = match context {
|
let move_point = match context {
|
||||||
&RenderContext::RelativePosition(p) => p.clone(),
|
&RenderContext::ParentPosition(p) => p.clone(),
|
||||||
_ => Point::new(0, 0),
|
_ => Point::new(0, 0),
|
||||||
};
|
};
|
||||||
let mut dest = move_render_point(move_point, &dest);
|
let mut dest = move_render_point(move_point, &dest);
|
||||||
|
@ -139,7 +139,7 @@ impl FileEntry {
|
|||||||
R: Renderer,
|
R: Renderer,
|
||||||
{
|
{
|
||||||
let mut dest = match context {
|
let mut dest = match context {
|
||||||
&RenderContext::RelativePosition(p) => move_render_point(p.clone(), &self.dest),
|
&RenderContext::ParentPosition(p) => move_render_point(p.clone(), &self.dest),
|
||||||
_ => self.dest.clone(),
|
_ => self.dest.clone(),
|
||||||
};
|
};
|
||||||
self.render_icon(canvas, renderer, &mut dest);
|
self.render_icon(canvas, renderer, &mut dest);
|
||||||
|
121
rider-editor/src/ui/label.rs
Normal file
121
rider-editor/src/ui/label.rs
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
use crate::app::*;
|
||||||
|
use crate::renderer::*;
|
||||||
|
use crate::ui::*;
|
||||||
|
use sdl2::pixels::Color;
|
||||||
|
use sdl2::rect::{Point, Rect};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
const DEST_WIDTH: u32 = 16;
|
||||||
|
const DEST_HEIGHT: u32 = 16;
|
||||||
|
const SRC_WIDTH: u32 = 64;
|
||||||
|
const SRC_HEIGHT: u32 = 64;
|
||||||
|
|
||||||
|
pub struct Label {
|
||||||
|
name_width: u32,
|
||||||
|
height: u32,
|
||||||
|
name: String,
|
||||||
|
source: Rect,
|
||||||
|
dest: Rect,
|
||||||
|
char_sizes: HashMap<char, Rect>,
|
||||||
|
config: ConfigAccess,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Label {
|
||||||
|
pub fn new(name: String, config: ConfigAccess) -> Self {
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
name_width: 0,
|
||||||
|
height: 0,
|
||||||
|
dest: Rect::new(0, 0, DEST_WIDTH, DEST_HEIGHT),
|
||||||
|
source: Rect::new(0, 0, SRC_WIDTH, SRC_HEIGHT),
|
||||||
|
config,
|
||||||
|
char_sizes: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name_width(&self) -> u32 {
|
||||||
|
self.name_width
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> String {
|
||||||
|
self.name.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render<C, R>(&self, canvas: &mut C, renderer: &mut R, context: &RenderContext)
|
||||||
|
where
|
||||||
|
C: CanvasAccess,
|
||||||
|
R: Renderer,
|
||||||
|
{
|
||||||
|
let dest = match context {
|
||||||
|
&RenderContext::ParentPosition(p) => move_render_point(p.clone(), &self.dest),
|
||||||
|
_ => self.dest.clone(),
|
||||||
|
};
|
||||||
|
let mut d = dest.clone();
|
||||||
|
d.set_x(dest.x() + NAME_MARGIN);
|
||||||
|
|
||||||
|
let font_details = build_font_details(self);
|
||||||
|
for c in self.name.chars() {
|
||||||
|
let size = self
|
||||||
|
.char_sizes
|
||||||
|
.get(&c)
|
||||||
|
.unwrap_or(&Rect::new(0, 0, 0, 0))
|
||||||
|
.clone();
|
||||||
|
let mut text_details = TextDetails {
|
||||||
|
color: Color::RGBA(255, 255, 255, 0),
|
||||||
|
text: c.to_string(),
|
||||||
|
font: font_details.clone(),
|
||||||
|
};
|
||||||
|
let maybe_texture = renderer.load_text_tex(&mut text_details, font_details.clone());
|
||||||
|
|
||||||
|
if let Ok(texture) = maybe_texture {
|
||||||
|
d.set_width(size.width());
|
||||||
|
d.set_height(size.height());
|
||||||
|
|
||||||
|
canvas
|
||||||
|
.render_image(texture, self.source.clone(), d.clone())
|
||||||
|
.unwrap_or_else(|_| panic!("Failed to draw directory entry texture"));
|
||||||
|
d.set_x(d.x() + size.width() as i32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn prepare_ui<R>(&mut self, renderer: &mut R)
|
||||||
|
where
|
||||||
|
R: Renderer + CharacterSizeManager,
|
||||||
|
{
|
||||||
|
let w_rect = renderer.load_character_size('W');
|
||||||
|
self.char_sizes.insert('W', w_rect.clone());
|
||||||
|
self.height = w_rect.height();
|
||||||
|
self.name_width = 0;
|
||||||
|
|
||||||
|
for c in self.name().chars() {
|
||||||
|
let size = { renderer.load_character_size(c.clone()) };
|
||||||
|
self.char_sizes.insert(c, size);
|
||||||
|
self.name_width += size.width();
|
||||||
|
}
|
||||||
|
self.dest.set_width(w_rect.height());
|
||||||
|
self.dest.set_height(w_rect.height());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RenderBox for Label {
|
||||||
|
fn render_start_point(&self) -> Point {
|
||||||
|
self.dest.top_left()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dest(&self) -> Rect {
|
||||||
|
self.dest.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Update for Label {
|
||||||
|
fn update(&mut self, _ticks: i32, _context: &UpdateContext) -> UpdateResult {
|
||||||
|
UpdateResult::NoOp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConfigHolder for Label {
|
||||||
|
fn config(&self) -> &ConfigAccess {
|
||||||
|
&self.config
|
||||||
|
}
|
||||||
|
}
|
@ -50,7 +50,7 @@ impl MenuBar {
|
|||||||
use std::borrow::*;
|
use std::borrow::*;
|
||||||
|
|
||||||
let relative_position = match context.borrow() {
|
let relative_position = match context.borrow() {
|
||||||
RenderContext::RelativePosition(p) => p.clone(),
|
RenderContext::ParentPosition(p) => p.clone(),
|
||||||
_ => Point::new(0, 0),
|
_ => Point::new(0, 0),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -64,21 +64,19 @@ impl MenuBar {
|
|||||||
canvas
|
canvas
|
||||||
.render_border(
|
.render_border(
|
||||||
match context.borrow() {
|
match context.borrow() {
|
||||||
RenderContext::RelativePosition(p) => {
|
RenderContext::ParentPosition(p) => move_render_point((*p).clone(), &self.dest),
|
||||||
move_render_point((*p).clone(), &self.dest)
|
|
||||||
}
|
|
||||||
_ => self.dest(),
|
_ => self.dest(),
|
||||||
},
|
},
|
||||||
self.border_color.clone(),
|
self.border_color.clone(),
|
||||||
)
|
)
|
||||||
.unwrap_or_else(|_| panic!("Failed to draw main menu background"));
|
.unwrap_or_else(|_| panic!("Failed to draw main menu background"));
|
||||||
|
|
||||||
let context = RenderContext::RelativePosition(
|
let context = RenderContext::ParentPosition(
|
||||||
relative_position.offset(SAVE_BUTTON_OFFSET_LEFT, SAVE_BUTTON_OFFSET_TOP),
|
relative_position.offset(SAVE_BUTTON_OFFSET_LEFT, SAVE_BUTTON_OFFSET_TOP),
|
||||||
);
|
);
|
||||||
self.save_button.render(canvas, renderer, &context);
|
self.save_button.render(canvas, renderer, &context);
|
||||||
|
|
||||||
let context = RenderContext::RelativePosition(
|
let context = RenderContext::ParentPosition(
|
||||||
relative_position.offset(SAVE_BUTTON_OFFSET_LEFT * 2, SAVE_BUTTON_OFFSET_TOP),
|
relative_position.offset(SAVE_BUTTON_OFFSET_LEFT * 2, SAVE_BUTTON_OFFSET_TOP),
|
||||||
);
|
);
|
||||||
self.settings_button.render(canvas, renderer, &context);
|
self.settings_button.render(canvas, renderer, &context);
|
||||||
@ -324,12 +322,12 @@ mod test_render {
|
|||||||
let mut widget = MenuBar::new(Arc::clone(&config));
|
let mut widget = MenuBar::new(Arc::clone(&config));
|
||||||
widget.prepare_ui();
|
widget.prepare_ui();
|
||||||
widget.render(&mut canvas, &mut renderer, &context);
|
widget.render(&mut canvas, &mut renderer, &context);
|
||||||
assert_eq!(widget.dest(), Rect::new(0, 0, 1024, 60));
|
assert_eq!(widget.dest(), Rect::new(0, 0, 1024, 40));
|
||||||
let expected = CanvasMock {
|
let expected = CanvasMock {
|
||||||
clipping: Rect::new(0, 0, 1024, 60),
|
clipping: Rect::new(32, 10, 32, 32),
|
||||||
background_rect: Rect::new(0, 0, 1024, 60),
|
background_rect: Rect::new(0, 0, 1024, 40),
|
||||||
background_color: Color::RGBA(18, 18, 18, 0),
|
background_color: Color::RGBA(18, 18, 18, 0),
|
||||||
border_rect: Rect::new(0, 0, 1024, 60),
|
border_rect: Rect::new(0, 0, 1024, 40),
|
||||||
border_color: Color::RGBA(200, 200, 200, 0),
|
border_color: Color::RGBA(200, 200, 200, 0),
|
||||||
};
|
};
|
||||||
assert_eq!(canvas, expected);
|
assert_eq!(canvas, expected);
|
||||||
@ -340,6 +338,6 @@ mod test_render {
|
|||||||
let config = support::build_config();
|
let config = support::build_config();
|
||||||
let mut widget = MenuBar::new(Arc::clone(&config));
|
let mut widget = MenuBar::new(Arc::clone(&config));
|
||||||
widget.prepare_ui();
|
widget.prepare_ui();
|
||||||
assert_eq!(widget.dest(), Rect::new(0, 0, 1024, 60));
|
assert_eq!(widget.dest(), Rect::new(0, 0, 1024, 40));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,29 +8,29 @@ use crate::app::UpdateResult as UR;
|
|||||||
use crate::renderer::managers::*;
|
use crate::renderer::managers::*;
|
||||||
use rider_config::*;
|
use rider_config::*;
|
||||||
|
|
||||||
|
pub mod buttons;
|
||||||
pub mod caret;
|
pub mod caret;
|
||||||
pub mod file;
|
pub mod file;
|
||||||
pub mod file_editor;
|
pub mod file_editor;
|
||||||
pub mod filesystem;
|
pub mod filesystem;
|
||||||
|
pub mod label;
|
||||||
pub mod menu_bar;
|
pub mod menu_bar;
|
||||||
pub mod modal;
|
pub mod modal;
|
||||||
pub mod project_tree;
|
pub mod project_tree;
|
||||||
pub mod save_button;
|
|
||||||
pub mod scroll_bar;
|
pub mod scroll_bar;
|
||||||
pub mod settings_button;
|
|
||||||
pub mod text_character;
|
pub mod text_character;
|
||||||
|
|
||||||
pub use crate::ui::caret::*;
|
pub use self::buttons::*;
|
||||||
pub use crate::ui::file::*;
|
pub use self::caret::*;
|
||||||
pub use crate::ui::file_editor::*;
|
pub use self::file::*;
|
||||||
pub use crate::ui::filesystem::*;
|
pub use self::file_editor::*;
|
||||||
pub use crate::ui::menu_bar::*;
|
pub use self::filesystem::*;
|
||||||
pub use crate::ui::modal::*;
|
pub use self::label::*;
|
||||||
pub use crate::ui::project_tree::*;
|
pub use self::menu_bar::*;
|
||||||
pub use crate::ui::save_button::*;
|
pub use self::modal::*;
|
||||||
pub use crate::ui::scroll_bar::*;
|
pub use self::project_tree::*;
|
||||||
pub use crate::ui::settings_button::*;
|
pub use self::scroll_bar::*;
|
||||||
pub use crate::ui::text_character::*;
|
pub use self::text_character::*;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum UpdateContext<'l> {
|
pub enum UpdateContext<'l> {
|
||||||
@ -42,7 +42,7 @@ pub enum UpdateContext<'l> {
|
|||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
pub enum RenderContext {
|
pub enum RenderContext {
|
||||||
Nothing,
|
Nothing,
|
||||||
RelativePosition(Point),
|
ParentPosition(Point),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait CanvasAccess {
|
pub trait CanvasAccess {
|
||||||
|
@ -1,3 +1,30 @@
|
|||||||
pub mod open_file;
|
pub mod open_file;
|
||||||
|
pub mod settings;
|
||||||
|
|
||||||
pub use crate::ui::modal::open_file::OpenFile;
|
pub use self::open_file::*;
|
||||||
|
pub use self::settings::*;
|
||||||
|
|
||||||
|
pub enum ModalType {
|
||||||
|
OpenFile(OpenFile),
|
||||||
|
Settings(Settings),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for ModalType {
|
||||||
|
fn eq(&self, other: &ModalType) -> bool {
|
||||||
|
match (self, other) {
|
||||||
|
(ModalType::OpenFile { .. }, ModalType::OpenFile { .. }) => true,
|
||||||
|
(ModalType::Settings { .. }, ModalType::Settings { .. }) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for ModalType {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||||
|
let name = match self {
|
||||||
|
ModalType::OpenFile(_) => "OpenFile",
|
||||||
|
ModalType::Settings(_) => "Settings",
|
||||||
|
};
|
||||||
|
write!(f, "<Modal::{:?} {{}}", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use crate::app::UpdateResult as UR;
|
||||||
use crate::renderer::renderer::Renderer;
|
use crate::renderer::renderer::Renderer;
|
||||||
use crate::ui::*;
|
use crate::ui::*;
|
||||||
use crate::ui::{RenderContext as RC, UpdateContext as UC};
|
use crate::ui::{RenderContext as RC, UpdateContext as UC};
|
||||||
@ -151,7 +152,7 @@ impl OpenFile {
|
|||||||
R: Renderer + CharacterSizeManager + ConfigHolder,
|
R: Renderer + CharacterSizeManager + ConfigHolder,
|
||||||
{
|
{
|
||||||
let dest = match context {
|
let dest = match context {
|
||||||
RC::RelativePosition(p) => move_render_point(p.clone(), &self.dest),
|
RC::ParentPosition(p) => move_render_point(p.clone(), &self.dest),
|
||||||
_ => self.dest.clone(),
|
_ => self.dest.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -164,7 +165,7 @@ impl OpenFile {
|
|||||||
.render_border(dest, self.border_color)
|
.render_border(dest, self.border_color)
|
||||||
.unwrap_or_else(|_| panic!("Failed to render open file modal border!"));
|
.unwrap_or_else(|_| panic!("Failed to render open file modal border!"));
|
||||||
|
|
||||||
let context = RC::RelativePosition(
|
let context = RC::ParentPosition(
|
||||||
dest.top_left() + Point::new(CONTENT_MARGIN_LEFT, CONTENT_MARGIN_TOP) + self.scroll(),
|
dest.top_left() + Point::new(CONTENT_MARGIN_LEFT, CONTENT_MARGIN_TOP) + self.scroll(),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -172,14 +173,10 @@ impl OpenFile {
|
|||||||
self.directory_view.render(canvas, renderer, &context);
|
self.directory_view.render(canvas, renderer, &context);
|
||||||
|
|
||||||
// Scroll bars
|
// Scroll bars
|
||||||
self.vertical_scroll_bar.render(
|
self.vertical_scroll_bar
|
||||||
canvas,
|
.render(canvas, &RenderContext::ParentPosition(self.dest.top_left()));
|
||||||
&RenderContext::RelativePosition(self.dest.top_left()),
|
self.horizontal_scroll_bar
|
||||||
);
|
.render(canvas, &RenderContext::ParentPosition(self.dest.top_left()));
|
||||||
self.horizontal_scroll_bar.render(
|
|
||||||
canvas,
|
|
||||||
&RenderContext::RelativePosition(self.dest.top_left()),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prepare_ui<R>(&mut self, renderer: &mut R)
|
pub fn prepare_ui<R>(&mut self, renderer: &mut R)
|
||||||
@ -397,7 +394,7 @@ mod tests {
|
|||||||
let mut canvas = CanvasMock::new();
|
let mut canvas = CanvasMock::new();
|
||||||
let widget = OpenFile::new(path.to_owned(), 100, 100, config);
|
let widget = OpenFile::new(path.to_owned(), 100, 100, config);
|
||||||
let p = Point::new(100, 100);
|
let p = Point::new(100, 100);
|
||||||
let context = RenderContext::RelativePosition(p);
|
let context = RenderContext::ParentPosition(p);
|
||||||
widget.render(&mut canvas, &mut renderer, &context);
|
widget.render(&mut canvas, &mut renderer, &context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
238
rider-editor/src/ui/modal/settings.rs
Normal file
238
rider-editor/src/ui/modal/settings.rs
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
use crate::app::UpdateResult as UR;
|
||||||
|
use crate::renderer::renderer::Renderer;
|
||||||
|
use crate::ui::*;
|
||||||
|
use crate::ui::{RenderContext as RC, UpdateContext as UC};
|
||||||
|
use rider_config::ConfigAccess;
|
||||||
|
use rider_config::ConfigHolder;
|
||||||
|
use sdl2::pixels::Color;
|
||||||
|
use sdl2::rect::{Point, Rect};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
const CONTENT_MARGIN_LEFT: i32 = 16;
|
||||||
|
const CONTENT_MARGIN_TOP: i32 = 24;
|
||||||
|
const DEFAULT_ICON_SIZE: u32 = 16;
|
||||||
|
|
||||||
|
pub struct Settings {
|
||||||
|
vertical_scroll_bar: VerticalScrollBar,
|
||||||
|
horizontal_scroll_bar: HorizontalScrollBar,
|
||||||
|
dest: Rect,
|
||||||
|
full_dest: Rect,
|
||||||
|
background_color: Color,
|
||||||
|
border_color: Color,
|
||||||
|
config: ConfigAccess,
|
||||||
|
font_label: Label,
|
||||||
|
font_value: Label,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Settings {
|
||||||
|
pub fn new(config: ConfigAccess) -> Self {
|
||||||
|
// let (window_width, window_height, background_color, border_color) = {
|
||||||
|
let c = config
|
||||||
|
.read()
|
||||||
|
.unwrap_or_else(|_| panic!("Failed to read config"));
|
||||||
|
let theme = c.theme();
|
||||||
|
let window_width = c.width();
|
||||||
|
let window_height = c.height();
|
||||||
|
let background_color = theme.background().into();
|
||||||
|
let border_color = theme.border_color().into();
|
||||||
|
// };
|
||||||
|
Self {
|
||||||
|
vertical_scroll_bar: VerticalScrollBar::new(Arc::clone(&config)),
|
||||||
|
horizontal_scroll_bar: HorizontalScrollBar::new(Arc::clone(&config)),
|
||||||
|
dest: Rect::new(
|
||||||
|
CONTENT_MARGIN_LEFT,
|
||||||
|
CONTENT_MARGIN_TOP,
|
||||||
|
window_width - (CONTENT_MARGIN_LEFT * 2) as u32,
|
||||||
|
window_height - (CONTENT_MARGIN_TOP * 2) as u32,
|
||||||
|
),
|
||||||
|
full_dest: Rect::new(0, 0, DEFAULT_ICON_SIZE, DEFAULT_ICON_SIZE),
|
||||||
|
background_color,
|
||||||
|
border_color,
|
||||||
|
font_label: Label::new("Font path".into(), config.clone()),
|
||||||
|
font_value: Label::new(c.editor_config().font_path().clone(), config.clone()),
|
||||||
|
config: config.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn full_rect(&self) -> &Rect {
|
||||||
|
&self.full_dest
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scroll_by(&mut self, x: i32, y: i32) {
|
||||||
|
let read_config = self.config.read().unwrap();
|
||||||
|
|
||||||
|
let value_x = read_config.scroll().speed() * x;
|
||||||
|
let value_y = read_config.scroll().speed() * y;
|
||||||
|
let old_x = self.horizontal_scroll_bar.scroll_value();
|
||||||
|
let old_y = self.vertical_scroll_bar.scroll_value();
|
||||||
|
|
||||||
|
if value_x + old_x >= 0 {
|
||||||
|
self.horizontal_scroll_bar.scroll_to(value_x + old_x);
|
||||||
|
if self.horizontal_scroll_bar.scrolled_part() > 1.0 {
|
||||||
|
self.horizontal_scroll_bar.scroll_to(old_x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if value_y + old_y >= 0 {
|
||||||
|
self.vertical_scroll_bar.scroll_to(value_y + old_y);
|
||||||
|
if self.vertical_scroll_bar.scrolled_part() > 1.0 {
|
||||||
|
self.vertical_scroll_bar.scroll_to(old_y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scroll(&self) -> Point {
|
||||||
|
Point::new(
|
||||||
|
-self.horizontal_scroll_bar.scroll_value(),
|
||||||
|
-self.vertical_scroll_bar.scroll_value(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render<C, R>(&self, canvas: &mut C, renderer: &mut R, context: &RC)
|
||||||
|
where
|
||||||
|
C: CanvasAccess,
|
||||||
|
R: Renderer + CharacterSizeManager + ConfigHolder,
|
||||||
|
{
|
||||||
|
let dest = match context {
|
||||||
|
RC::ParentPosition(p) => move_render_point(p.clone(), &self.dest),
|
||||||
|
_ => self.dest.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Background
|
||||||
|
canvas.set_clipping(dest.clone());
|
||||||
|
canvas
|
||||||
|
.render_rect(dest, self.background_color)
|
||||||
|
.unwrap_or_else(|_| panic!("Failed to render open file modal background!"));
|
||||||
|
canvas
|
||||||
|
.render_border(dest, self.border_color)
|
||||||
|
.unwrap_or_else(|_| panic!("Failed to render open file modal border!"));
|
||||||
|
|
||||||
|
self.font_label.render(
|
||||||
|
canvas,
|
||||||
|
renderer,
|
||||||
|
&RC::ParentPosition(
|
||||||
|
self.render_start_point()
|
||||||
|
+ Point::new(CONTENT_MARGIN_LEFT, CONTENT_MARGIN_TOP)
|
||||||
|
+ self.scroll(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
self.font_value.render(
|
||||||
|
canvas,
|
||||||
|
renderer,
|
||||||
|
&RC::ParentPosition(
|
||||||
|
self.render_start_point()
|
||||||
|
+ Point::new(
|
||||||
|
(CONTENT_MARGIN_LEFT * 2) + self.font_label.name_width() as i32,
|
||||||
|
CONTENT_MARGIN_TOP,
|
||||||
|
)
|
||||||
|
+ self.scroll(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Scroll bars
|
||||||
|
self.vertical_scroll_bar
|
||||||
|
.render(canvas, &RenderContext::ParentPosition(self.dest.top_left()));
|
||||||
|
self.horizontal_scroll_bar
|
||||||
|
.render(canvas, &RenderContext::ParentPosition(self.dest.top_left()));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn prepare_ui<R>(&mut self, renderer: &mut R)
|
||||||
|
where
|
||||||
|
R: Renderer + CharacterSizeManager,
|
||||||
|
{
|
||||||
|
self.font_label.prepare_ui(renderer);
|
||||||
|
self.font_value.prepare_ui(renderer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClickHandler for Settings {
|
||||||
|
fn on_left_click(&mut self, _point: &Point, context: &UpdateContext) -> UR {
|
||||||
|
let dest = match context {
|
||||||
|
UC::ParentPosition(p) => move_render_point(*p, &self.dest),
|
||||||
|
_ => self.dest,
|
||||||
|
};
|
||||||
|
let _context = UC::ParentPosition(
|
||||||
|
dest.top_left() + Point::new(CONTENT_MARGIN_LEFT, CONTENT_MARGIN_TOP) + self.scroll(),
|
||||||
|
);
|
||||||
|
// let res = self.directory_view.on_left_click(point, &context);
|
||||||
|
// {
|
||||||
|
// let dest = self.directory_view.dest();
|
||||||
|
// let full_dest = Rect::new(
|
||||||
|
// dest.x(),
|
||||||
|
// dest.y(),
|
||||||
|
// dest.width() + (2 * CONTENT_MARGIN_LEFT as u32),
|
||||||
|
// dest.height() + (2 * CONTENT_MARGIN_TOP as u32),
|
||||||
|
// );
|
||||||
|
// self.full_dest = full_dest;
|
||||||
|
// }
|
||||||
|
// res
|
||||||
|
UR::NoOp
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_left_click_target(&self, _point: &Point, context: &UpdateContext) -> bool {
|
||||||
|
let dest = match *context {
|
||||||
|
UC::ParentPosition(p) => move_render_point(p.clone(), &self.dest),
|
||||||
|
_ => self.dest.clone(),
|
||||||
|
};
|
||||||
|
let p =
|
||||||
|
dest.top_left() + Point::new(CONTENT_MARGIN_LEFT, CONTENT_MARGIN_TOP) + self.scroll();
|
||||||
|
let _context = UC::ParentPosition(p);
|
||||||
|
// if self.directory_view.is_left_click_target(point, &context) {
|
||||||
|
// true
|
||||||
|
// } else {
|
||||||
|
// Rect::new(p.x(), p.y(), dest.width(), dest.height()).contains_point(point.clone())
|
||||||
|
// }
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RenderBox for Settings {
|
||||||
|
fn render_start_point(&self) -> Point {
|
||||||
|
self.dest.top_left()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dest(&self) -> Rect {
|
||||||
|
self.dest.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Update for Settings {
|
||||||
|
fn update(&mut self, ticks: i32, context: &UpdateContext) -> UR {
|
||||||
|
let (window_width, window_height, color, scroll_width, scroll_margin) = {
|
||||||
|
let c = self.config.read().unwrap();
|
||||||
|
(
|
||||||
|
c.width(),
|
||||||
|
c.height(),
|
||||||
|
c.theme().background().into(),
|
||||||
|
c.scroll().width(),
|
||||||
|
c.scroll().margin_right(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
self.dest.set_x(CONTENT_MARGIN_LEFT);
|
||||||
|
self.dest
|
||||||
|
.set_width(window_width - (CONTENT_MARGIN_LEFT * 2) as u32);
|
||||||
|
self.dest.set_y(CONTENT_MARGIN_TOP);
|
||||||
|
self.dest
|
||||||
|
.set_height(window_height - (CONTENT_MARGIN_TOP * 2) as u32);
|
||||||
|
|
||||||
|
self.background_color = color;
|
||||||
|
|
||||||
|
// Scroll bars
|
||||||
|
self.vertical_scroll_bar
|
||||||
|
.set_full_size(self.full_dest.height()); // full dest
|
||||||
|
self.vertical_scroll_bar.set_viewport(self.dest.height());
|
||||||
|
self.vertical_scroll_bar
|
||||||
|
.set_location(self.dest.width() as i32 - (scroll_width as i32 + scroll_margin));
|
||||||
|
self.vertical_scroll_bar.update(ticks, context);
|
||||||
|
|
||||||
|
self.horizontal_scroll_bar
|
||||||
|
.set_full_size(self.full_dest.width()); // full dest
|
||||||
|
self.horizontal_scroll_bar.set_viewport(self.dest.width());
|
||||||
|
self.horizontal_scroll_bar
|
||||||
|
.set_location(self.dest.height() as i32 - (scroll_width as i32 + scroll_margin));
|
||||||
|
self.horizontal_scroll_bar.update(ticks, context);
|
||||||
|
|
||||||
|
// End
|
||||||
|
UR::NoOp
|
||||||
|
}
|
||||||
|
}
|
@ -98,7 +98,7 @@ impl ProjectTreeSidebar {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// dir view
|
// dir view
|
||||||
let context = RenderContext::RelativePosition(
|
let context = RenderContext::ParentPosition(
|
||||||
self.dest.top_left() + Point::new(CONTENT_MARGIN_LEFT, CONTENT_MARGIN_TOP),
|
self.dest.top_left() + Point::new(CONTENT_MARGIN_LEFT, CONTENT_MARGIN_TOP),
|
||||||
);
|
);
|
||||||
self.dir_view.render(canvas, renderer, &context);
|
self.dir_view.render(canvas, renderer, &context);
|
||||||
@ -271,7 +271,7 @@ mod tests {
|
|||||||
let mut renderer = RendererMock::new(config.clone());
|
let mut renderer = RendererMock::new(config.clone());
|
||||||
let mut widget = ProjectTreeSidebar::new("/tmp".to_owned(), config);
|
let mut widget = ProjectTreeSidebar::new("/tmp".to_owned(), config);
|
||||||
widget.prepare_ui(&mut renderer);
|
widget.prepare_ui(&mut renderer);
|
||||||
assert_eq!(widget.full_rect(), Rect::new(0, 60, 200, 860));
|
assert_eq!(widget.full_rect(), Rect::new(0, 40, 200, 860));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -279,7 +279,7 @@ mod tests {
|
|||||||
let config = build_config();
|
let config = build_config();
|
||||||
let mut widget = ProjectTreeSidebar::new("/tmp".to_owned(), config);
|
let mut widget = ProjectTreeSidebar::new("/tmp".to_owned(), config);
|
||||||
widget.update(0);
|
widget.update(0);
|
||||||
assert_eq!(widget.full_rect(), Rect::new(0, 60, 200, 800));
|
assert_eq!(widget.full_rect(), Rect::new(0, 40, 200, 820));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -288,7 +288,7 @@ mod tests {
|
|||||||
let mut renderer = RendererMock::new(config.clone());
|
let mut renderer = RendererMock::new(config.clone());
|
||||||
let mut widget = ProjectTreeSidebar::new("/tmp".to_owned(), config);
|
let mut widget = ProjectTreeSidebar::new("/tmp".to_owned(), config);
|
||||||
widget.prepare_ui(&mut renderer);
|
widget.prepare_ui(&mut renderer);
|
||||||
assert_eq!(widget.full_rect(), Rect::new(0, 60, 200, 860));
|
assert_eq!(widget.full_rect(), Rect::new(0, 40, 200, 860));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -66,7 +66,7 @@ impl HorizontalScrollBar {
|
|||||||
canvas
|
canvas
|
||||||
.render_rect(
|
.render_rect(
|
||||||
match context {
|
match context {
|
||||||
RenderContext::RelativePosition(p) => move_render_point(p.clone(), &self.rect),
|
RenderContext::ParentPosition(p) => move_render_point(p.clone(), &self.rect),
|
||||||
_ => self.rect.clone(),
|
_ => self.rect.clone(),
|
||||||
},
|
},
|
||||||
Color::RGBA(255, 255, 255, 0),
|
Color::RGBA(255, 255, 255, 0),
|
||||||
|
@ -66,7 +66,7 @@ impl VerticalScrollBar {
|
|||||||
canvas
|
canvas
|
||||||
.render_border(
|
.render_border(
|
||||||
match context {
|
match context {
|
||||||
RenderContext::RelativePosition(p) => move_render_point(p.clone(), &self.rect),
|
RenderContext::ParentPosition(p) => move_render_point(p.clone(), &self.rect),
|
||||||
_ => self.rect.clone(),
|
_ => self.rect.clone(),
|
||||||
},
|
},
|
||||||
Color::RGBA(255, 255, 255, 0),
|
Color::RGBA(255, 255, 255, 0),
|
||||||
|
@ -124,7 +124,7 @@ impl TextCharacter {
|
|||||||
font: font_details.clone(),
|
font: font_details.clone(),
|
||||||
};
|
};
|
||||||
let dest = match context {
|
let dest = match context {
|
||||||
RenderContext::RelativePosition(p) => move_render_point(p.clone(), &self.dest),
|
RenderContext::ParentPosition(p) => move_render_point(p.clone(), &self.dest),
|
||||||
_ => self.dest(),
|
_ => self.dest(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ fn main() -> std::io::Result<()> {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use std::env::set_var;
|
use std::env::set_var;
|
||||||
use std::fs::create_dir_all;
|
use std::fs::{create_dir_all, remove_dir_all};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
@ -48,73 +48,130 @@ mod tests {
|
|||||||
let uniq = Uuid::new_v4();
|
let uniq = Uuid::new_v4();
|
||||||
let joined = join("/tmp/rider-tests".to_owned(), uniq.to_string());
|
let joined = join("/tmp/rider-tests".to_owned(), uniq.to_string());
|
||||||
let test_path = joined.as_str();
|
let test_path = joined.as_str();
|
||||||
|
remove_dir_all(joined.clone()).unwrap_or_else(|_| ());
|
||||||
create_dir_all(test_path.to_owned()).unwrap();
|
create_dir_all(test_path.to_owned()).unwrap();
|
||||||
|
|
||||||
set_var("XDG_CONFIG_HOME", test_path);
|
set_var("XDG_CONFIG_HOME", test_path);
|
||||||
set_var("XDG_RUNTIME_DIR", test_path);
|
set_var("XDG_RUNTIME_DIR", test_path);
|
||||||
|
|
||||||
assert_eq!(exists(&test_path.to_owned(), ".rider"), false);
|
debug_assert!(
|
||||||
assert_eq!(main().is_ok(), true);
|
!exists(&test_path.to_owned(), ".rider"),
|
||||||
assert_eq!(exists(&test_path.to_owned(), ".rider"), true);
|
"rider config dir should not exists before generator run"
|
||||||
|
);
|
||||||
|
debug_assert!(main().is_ok(), "generator should not failed");
|
||||||
|
debug_assert!(
|
||||||
|
exists(&test_path.to_owned(), ".rider"),
|
||||||
|
"rider config dir should exists after generator run"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn assert_fonts_dir() {
|
fn assert_fonts_dir() {
|
||||||
let uniq = Uuid::new_v4();
|
let uniq = Uuid::new_v4();
|
||||||
let joined = join("/tmp/rider-tests".to_owned(), uniq.to_string());
|
let joined = join("/tmp/rider-tests".to_owned(), uniq.to_string());
|
||||||
|
|
||||||
|
remove_dir_all(joined.clone()).unwrap_or_else(|_| ());
|
||||||
create_dir_all(joined.clone()).unwrap();
|
create_dir_all(joined.clone()).unwrap();
|
||||||
|
|
||||||
set_var("XDG_CONFIG_HOME", joined.as_str().clone());
|
set_var("XDG_CONFIG_HOME", joined.as_str().clone());
|
||||||
set_var("XDG_RUNTIME_HOME", joined.as_str().clone());
|
set_var("XDG_RUNTIME_HOME", joined.as_str().clone());
|
||||||
assert_eq!(exists(&joined, "rider/fonts"), false);
|
|
||||||
assert_eq!(main().is_ok(), true);
|
debug_assert!(
|
||||||
assert_eq!(exists(&joined, "rider/fonts"), true);
|
!exists(&joined, "rider/fonts"),
|
||||||
|
"fonts director should not exists before run generator"
|
||||||
|
);
|
||||||
|
debug_assert!(main().is_ok(), "generator should not failed");
|
||||||
|
debug_assert!(
|
||||||
|
exists(&joined, "rider/fonts"),
|
||||||
|
"fonts director should exists after run generator"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn assert_log_dir() {
|
fn assert_log_dir() {
|
||||||
let uniq = Uuid::new_v4();
|
let uniq = Uuid::new_v4();
|
||||||
let joined = join("/tmp/rider-tests".to_owned(), uniq.to_string());
|
let joined = join("/tmp/rider-tests".to_owned(), uniq.to_string());
|
||||||
|
|
||||||
|
remove_dir_all(joined.clone()).unwrap_or_else(|_| ());
|
||||||
create_dir_all(joined.clone()).unwrap();
|
create_dir_all(joined.clone()).unwrap();
|
||||||
|
|
||||||
set_var("XDG_CONFIG_HOME", joined.as_str().clone());
|
set_var("XDG_CONFIG_HOME", joined.as_str().clone());
|
||||||
set_var("XDG_RUNTIME_HOME", joined.as_str().clone());
|
set_var("XDG_RUNTIME_HOME", joined.as_str().clone());
|
||||||
assert_eq!(exists(&joined, "rider/log"), false);
|
|
||||||
assert_eq!(main().is_ok(), true);
|
debug_assert!(
|
||||||
assert_eq!(exists(&joined, "rider/log"), true);
|
!exists(&joined, "rider/log"),
|
||||||
|
"log should not exists before run generator"
|
||||||
|
);
|
||||||
|
debug_assert!(main().is_ok(), "generator should not failed");
|
||||||
|
debug_assert!(
|
||||||
|
exists(&joined, "rider/log"),
|
||||||
|
"log should exists after run generator"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn assert_themes_dir() {
|
fn assert_themes_dir() {
|
||||||
let uniq = Uuid::new_v4();
|
let uniq = Uuid::new_v4();
|
||||||
let joined = join("/tmp/rider-tests".to_owned(), uniq.to_string());
|
let joined = join("/tmp/rider-tests".to_owned(), uniq.to_string());
|
||||||
|
|
||||||
|
remove_dir_all(joined.clone()).unwrap_or_else(|_| ());
|
||||||
create_dir_all(joined.clone()).unwrap();
|
create_dir_all(joined.clone()).unwrap();
|
||||||
|
|
||||||
set_var("XDG_CONFIG_HOME", joined.as_str().clone());
|
set_var("XDG_CONFIG_HOME", joined.as_str().clone());
|
||||||
set_var("XDG_RUNTIME_HOME", joined.as_str().clone());
|
set_var("XDG_RUNTIME_HOME", joined.as_str().clone());
|
||||||
assert_eq!(exists(&joined, "rider/themes"), false);
|
|
||||||
assert_eq!(main().is_ok(), true);
|
debug_assert!(
|
||||||
assert_eq!(exists(&joined, "rider/themes"), true);
|
!exists(&joined, "rider/themes"),
|
||||||
|
"themes should not exists before run generator"
|
||||||
|
);
|
||||||
|
debug_assert!(main().is_ok(), "generator should not failed");
|
||||||
|
debug_assert!(
|
||||||
|
exists(&joined, "rider/themes"),
|
||||||
|
"themes should exists after run generator"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn assert_default_json() {
|
fn assert_default_json() {
|
||||||
let uniq = Uuid::new_v4();
|
let uniq = Uuid::new_v4();
|
||||||
let joined = join("/tmp/rider-tests".to_owned(), uniq.to_string());
|
let joined = join("/tmp/rider-tests".to_owned(), uniq.to_string());
|
||||||
|
|
||||||
|
remove_dir_all(joined.clone()).unwrap_or_else(|_| ());
|
||||||
create_dir_all(joined.clone()).unwrap();
|
create_dir_all(joined.clone()).unwrap();
|
||||||
|
|
||||||
set_var("XDG_CONFIG_HOME", joined.as_str().clone());
|
set_var("XDG_CONFIG_HOME", joined.as_str().clone());
|
||||||
set_var("XDG_RUNTIME_HOME", joined.as_str().clone());
|
set_var("XDG_RUNTIME_HOME", joined.as_str().clone());
|
||||||
assert_eq!(exists(&joined, "rider/themes/default.json"), false);
|
|
||||||
assert_eq!(main().is_ok(), true);
|
debug_assert!(
|
||||||
assert_eq!(exists(&joined, "rider/themes/default.json"), true);
|
!exists(&joined, "rider/themes/default.json"),
|
||||||
|
"default theme should not exists before run generator"
|
||||||
|
);
|
||||||
|
debug_assert!(main().is_ok(), "generator should not failed");
|
||||||
|
debug_assert!(
|
||||||
|
exists(&joined, "rider/themes/default.json"),
|
||||||
|
"default theme should exists after run generator"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn assert_railscasts_json() {
|
fn assert_railscasts_json() {
|
||||||
let uniq = Uuid::new_v4();
|
let uniq = Uuid::new_v4();
|
||||||
let joined = join("/tmp/rider-tests".to_owned(), uniq.to_string());
|
let joined = join("/tmp/rider-tests".to_owned(), uniq.to_string());
|
||||||
|
|
||||||
|
remove_dir_all(joined.clone()).unwrap_or_else(|_| ());
|
||||||
create_dir_all(joined.clone()).unwrap();
|
create_dir_all(joined.clone()).unwrap();
|
||||||
|
|
||||||
set_var("XDG_CONFIG_HOME", joined.as_str().clone());
|
set_var("XDG_CONFIG_HOME", joined.as_str().clone());
|
||||||
set_var("XDG_RUNTIME_HOME", joined.as_str().clone());
|
set_var("XDG_RUNTIME_HOME", joined.as_str().clone());
|
||||||
assert_eq!(exists(&joined, "rider/themes/railscasts.json"), false);
|
|
||||||
assert_eq!(main().is_ok(), true);
|
debug_assert!(
|
||||||
assert_eq!(exists(&joined, "rider/themes/railscasts.json"), true);
|
!exists(&joined, "rider/themes/railscasts.json"),
|
||||||
|
"railscasts theme should not exists before run generator"
|
||||||
|
);
|
||||||
|
debug_assert!(main().is_ok(), "generator should not failed");
|
||||||
|
debug_assert!(
|
||||||
|
exists(&joined, "rider/themes/railscasts.json"),
|
||||||
|
"railscasts theme should exists after run generator"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user