Draw caret and handle click.
This commit is contained in:
parent
f01ad336eb
commit
fdf5d0332a
BIN
assets/fonts/DejaVuSansMono.ttf
Normal file
BIN
assets/fonts/DejaVuSansMono.ttf
Normal file
Binary file not shown.
@ -37,9 +37,6 @@ italic
|
|||||||
``keyword
|
``keyword
|
||||||
#CB7832
|
#CB7832
|
||||||
|
|
||||||
``keyword
|
|
||||||
#CB7832
|
|
||||||
|
|
||||||
``regex
|
``regex
|
||||||
#A4C260
|
#A4C260
|
||||||
|
|
||||||
|
@ -1,42 +1,51 @@
|
|||||||
use std::rc::Rc;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use std::boxed::Box;
|
|
||||||
use crate::app::{UpdateResult, WindowCanvas};
|
use crate::app::{UpdateResult, WindowCanvas};
|
||||||
use crate::ui::*;
|
use crate::config::Config;
|
||||||
use crate::ui::caret::Caret;
|
|
||||||
use crate::file::*;
|
use crate::file::*;
|
||||||
use crate::file::editor_file::EditorFile;
|
use crate::file::editor_file::EditorFile;
|
||||||
use crate::renderer::Renderer;
|
use crate::renderer::Renderer;
|
||||||
|
use crate::ui::*;
|
||||||
|
use crate::ui::caret::Caret;
|
||||||
|
use crate::ui::menu_bar::MenuBar;
|
||||||
|
use sdl2::rect::Point;
|
||||||
|
use std::boxed::Box;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub struct AppState {
|
pub struct AppState {
|
||||||
pub files: Vec<EditorFile>,
|
menu_bar: MenuBar,
|
||||||
pub current_file: i16,
|
files: Vec<EditorFile>,
|
||||||
|
current_file: usize,
|
||||||
caret: Caret,
|
caret: Caret,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppState {
|
impl AppState {
|
||||||
pub fn new() -> Self {
|
pub fn new(config: &Config) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
menu_bar: MenuBar::new(),
|
||||||
files: vec![],
|
files: vec![],
|
||||||
current_file: -1,
|
current_file: 0,
|
||||||
caret: Caret::new(),
|
caret: Caret::new(config),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_file(&mut self, file_path: String) {
|
pub fn open_file(&mut self, file_path: String, config: &Config) {
|
||||||
use std::fs::read_to_string;
|
use std::fs::read_to_string;
|
||||||
if let Ok(buffer) = read_to_string(&file_path) {
|
if let Ok(buffer) = read_to_string(&file_path) {
|
||||||
println!("read: {}\n{}", file_path, buffer);
|
let file = EditorFile::new(file_path.clone(), buffer, config);
|
||||||
let file = EditorFile::new(file_path.clone(), buffer);
|
self.current_file = self.files.len();
|
||||||
self.current_file = self.files.len() as i16;
|
|
||||||
self.files.push(file);
|
self.files.push(file);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn caret(&mut self) -> &mut Caret {
|
||||||
|
&mut self.caret
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Render for AppState {
|
impl Render for AppState {
|
||||||
fn render(&mut self, canvas: &mut WindowCanvas, renderer: &mut Renderer) -> UpdateResult {
|
fn render(&mut self, canvas: &mut WindowCanvas, renderer: &mut Renderer) -> UpdateResult {
|
||||||
if let Some(file) = self.files.get_mut(self.current_file as usize) {
|
self.menu_bar.render(canvas, renderer);
|
||||||
|
if let Some(file) = self.files.get_mut(self.current_file) {
|
||||||
file.render(canvas, renderer);
|
file.render(canvas, renderer);
|
||||||
}
|
}
|
||||||
self.caret.render(canvas, renderer);
|
self.caret.render(canvas, renderer);
|
||||||
@ -46,10 +55,34 @@ impl Render for AppState {
|
|||||||
|
|
||||||
impl Update for AppState {
|
impl Update for AppState {
|
||||||
fn update(&mut self, ticks: i32) -> UpdateResult {
|
fn update(&mut self, ticks: i32) -> UpdateResult {
|
||||||
if let Some(file) = self.files.get_mut(self.current_file as usize) {
|
self.menu_bar.update(ticks);
|
||||||
|
if let Some(file) = self.files.get_mut(self.current_file) {
|
||||||
file.update(ticks);
|
file.update(ticks);
|
||||||
}
|
}
|
||||||
self.caret.update(ticks);
|
self.caret.update(ticks);
|
||||||
UpdateResult::NoOp
|
UpdateResult::NoOp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ClickHandler for AppState {
|
||||||
|
fn on_left_click(&mut self, point: &Point, config: &Config) -> UpdateResult {
|
||||||
|
if self.menu_bar.is_left_click_target(point) {
|
||||||
|
return self.menu_bar.on_left_click(point, config);
|
||||||
|
}
|
||||||
|
if let Some(current_file) = self.files.get_mut(self.current_file) {
|
||||||
|
if current_file.is_left_click_target(point) {
|
||||||
|
match current_file.on_left_click(point, config) {
|
||||||
|
UpdateResult::MoveCaret(rect) => {
|
||||||
|
self.caret.move_caret(Point::new(rect.x(), rect.y()));
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UpdateResult::NoOp
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_left_click_target(&self, _point: &Point) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
use crate::themes::Theme;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct EditorConfig {
|
|
||||||
pub character_size: u16,
|
|
||||||
pub font_path: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Config {
|
|
||||||
pub width: u32,
|
|
||||||
pub height: u32,
|
|
||||||
pub editor_config: EditorConfig,
|
|
||||||
pub theme: Theme,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Config {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
width: 1024,
|
|
||||||
height: 860,
|
|
||||||
editor_config: EditorConfig {
|
|
||||||
character_size: 24,
|
|
||||||
font_path: "./assets/fonts/hinted-ElaineSans-Medium.ttf".to_string(),
|
|
||||||
},
|
|
||||||
theme: Theme::load("default".to_string()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,30 +1,31 @@
|
|||||||
pub mod app_state;
|
use crate::app::app_state::AppState;
|
||||||
pub mod config;
|
use crate::config::Config;
|
||||||
|
use crate::renderer::Renderer;
|
||||||
|
use crate::themes::*;
|
||||||
|
use crate::ui::*;
|
||||||
|
use sdl2::{Sdl, TimerSubsystem};
|
||||||
use sdl2::event::Event;
|
use sdl2::event::Event;
|
||||||
|
use sdl2::EventPump;
|
||||||
use sdl2::hint;
|
use sdl2::hint;
|
||||||
|
use sdl2::mouse::MouseButton;
|
||||||
use sdl2::pixels::Color;
|
use sdl2::pixels::Color;
|
||||||
|
use sdl2::rect::{Point, Rect};
|
||||||
use sdl2::render::Canvas;
|
use sdl2::render::Canvas;
|
||||||
use sdl2::video::Window;
|
use sdl2::video::Window;
|
||||||
use sdl2::EventPump;
|
|
||||||
use sdl2::{Sdl, TimerSubsystem};
|
|
||||||
|
|
||||||
use std::thread::sleep;
|
use std::thread::sleep;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
pub type WindowCanvas = Canvas<Window>;
|
pub mod app_state;
|
||||||
|
|
||||||
use crate::app::app_state::AppState;
|
pub type WindowCanvas = Canvas<Window>;
|
||||||
use crate::app::config::Config;
|
|
||||||
use crate::themes::Theme;
|
|
||||||
use crate::ui::*;
|
|
||||||
use crate::renderer::Renderer;
|
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Debug)]
|
#[derive(PartialEq, Clone, Debug)]
|
||||||
pub enum UpdateResult {
|
pub enum UpdateResult {
|
||||||
NoOp,
|
NoOp,
|
||||||
Stop,
|
Stop,
|
||||||
RefreshPositions,
|
RefreshPositions,
|
||||||
|
MouseLeftClicked(Point),
|
||||||
|
MoveCaret(Rect),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Task {
|
pub enum Task {
|
||||||
@ -36,6 +37,7 @@ pub struct Application {
|
|||||||
sdl_context: Sdl,
|
sdl_context: Sdl,
|
||||||
canvas: WindowCanvas,
|
canvas: WindowCanvas,
|
||||||
tasks: Vec<Task>,
|
tasks: Vec<Task>,
|
||||||
|
clear_color: Color,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Application {
|
impl Application {
|
||||||
@ -49,7 +51,7 @@ impl Application {
|
|||||||
hint::set("SDL_HINT_VIDEO_ALLOW_SCREENSAVER", "1");
|
hint::set("SDL_HINT_VIDEO_ALLOW_SCREENSAVER", "1");
|
||||||
let video_subsystem = sdl_context.video().unwrap();
|
let video_subsystem = sdl_context.video().unwrap();
|
||||||
let window = video_subsystem
|
let window = video_subsystem
|
||||||
.window("Editor", config.width, config.height)
|
.window("Editor", config.width(), config.height())
|
||||||
.position_centered()
|
.position_centered()
|
||||||
.opengl()
|
.opengl()
|
||||||
.build()
|
.build()
|
||||||
@ -58,10 +60,11 @@ impl Application {
|
|||||||
let canvas = window.into_canvas().accelerated().build().unwrap();
|
let canvas = window.into_canvas().accelerated().build().unwrap();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
config,
|
|
||||||
sdl_context,
|
sdl_context,
|
||||||
canvas,
|
canvas,
|
||||||
tasks: vec![],
|
tasks: vec![],
|
||||||
|
clear_color: config.theme().background().into(),
|
||||||
|
config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,25 +78,25 @@ impl Application {
|
|||||||
let font_context = sdl2::ttf::init().unwrap();
|
let font_context = sdl2::ttf::init().unwrap();
|
||||||
let texture_creator = self.canvas.texture_creator();
|
let texture_creator = self.canvas.texture_creator();
|
||||||
let sleep_time = Duration::new(0, 1_000_000_000u32 / 60);
|
let sleep_time = Duration::new(0, 1_000_000_000u32 / 60);
|
||||||
let mut app_state = AppState::new();
|
let mut app_state = AppState::new(&self.config);
|
||||||
let mut renderer = Renderer::new(
|
let mut renderer = Renderer::new(self.config.clone(), &font_context, &texture_creator);
|
||||||
self.config.clone(),
|
|
||||||
&font_context,
|
|
||||||
&texture_creator
|
|
||||||
);
|
|
||||||
|
|
||||||
'running: loop {
|
'running: loop {
|
||||||
match self.handle_events(&mut event_pump) {
|
match self.handle_events(&mut event_pump) {
|
||||||
UpdateResult::Stop => break 'running,
|
UpdateResult::Stop => break 'running,
|
||||||
UpdateResult::RefreshPositions => (),
|
UpdateResult::RefreshPositions => (),
|
||||||
UpdateResult::NoOp => (),
|
UpdateResult::NoOp => (),
|
||||||
|
UpdateResult::MoveCaret(_) => (),
|
||||||
|
UpdateResult::MouseLeftClicked(point) => {
|
||||||
|
app_state.on_left_click(&point, renderer.config());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for task in self.tasks.iter() {
|
for task in self.tasks.iter() {
|
||||||
match task {
|
match task {
|
||||||
Task::OpenFile { file_path } => {
|
Task::OpenFile { file_path } => {
|
||||||
use crate::file::editor_file::*;
|
use crate::file::editor_file::*;
|
||||||
app_state.open_file(file_path.clone());
|
app_state.open_file(file_path.clone(), renderer.config());
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.tasks.clear();
|
self.tasks.clear();
|
||||||
@ -117,7 +120,7 @@ impl Application {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn clear(&mut self) {
|
fn clear(&mut self) {
|
||||||
self.canvas.set_draw_color(Color::RGB(255, 255, 255));
|
self.canvas.set_draw_color(self.clear_color.clone());
|
||||||
self.canvas.clear();
|
self.canvas.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,6 +128,12 @@ impl Application {
|
|||||||
for event in event_pump.poll_iter() {
|
for event in event_pump.poll_iter() {
|
||||||
match event {
|
match event {
|
||||||
Event::Quit { .. } => return UpdateResult::Stop,
|
Event::Quit { .. } => return UpdateResult::Stop,
|
||||||
|
Event::MouseButtonUp {
|
||||||
|
mouse_btn, x, y, ..
|
||||||
|
} => match mouse_btn {
|
||||||
|
MouseButton::Left => return UpdateResult::MouseLeftClicked(Point::new(x, y)),
|
||||||
|
_ => (),
|
||||||
|
},
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
35
src/config/creator.rs
Normal file
35
src/config/creator.rs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
use crate::config::directories::*;
|
||||||
|
use crate::themes::config_creator;
|
||||||
|
use dirs;
|
||||||
|
use std::fs;
|
||||||
|
use std::path;
|
||||||
|
|
||||||
|
pub fn create() {
|
||||||
|
if !themes_dir().exists() {
|
||||||
|
fs::create_dir_all(&themes_dir())
|
||||||
|
.unwrap_or_else(|_| panic!("Cannot create themes config directory"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if !fonts_dir().exists() {
|
||||||
|
fs::create_dir_all(&fonts_dir())
|
||||||
|
.unwrap_or_else(|_| panic!("Cannot create fonts config directory"));
|
||||||
|
write_default_fonts();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_default_fonts() {
|
||||||
|
{
|
||||||
|
let mut default_font_path = fonts_dir();
|
||||||
|
default_font_path.push("DejaVuSansMono.ttf");
|
||||||
|
let contents = include_bytes!("../../assets/fonts/DejaVuSansMono.ttf");
|
||||||
|
fs::write(default_font_path, contents.to_vec())
|
||||||
|
.unwrap_or_else(|_| panic!("Cannot write default font file!"));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let mut default_font_path = fonts_dir();
|
||||||
|
default_font_path.push("ElaineSans-Medium.ttf");
|
||||||
|
let contents = include_bytes!("../../assets/fonts/ElaineSans-Medium.ttf");
|
||||||
|
fs::write(default_font_path, contents.to_vec())
|
||||||
|
.unwrap_or_else(|_| panic!("Cannot write default font file!"));
|
||||||
|
}
|
||||||
|
}
|
22
src/config/directories.rs
Normal file
22
src/config/directories.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
use dirs;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
pub fn themes_dir() -> PathBuf {
|
||||||
|
let mut themes_dir = config_dir();
|
||||||
|
themes_dir.push("themes");
|
||||||
|
themes_dir
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fonts_dir() -> PathBuf {
|
||||||
|
let mut fonts_dir = config_dir();
|
||||||
|
fonts_dir.push("fonts");
|
||||||
|
fonts_dir
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn config_dir() -> PathBuf {
|
||||||
|
let home_dir = dirs::config_dir().unwrap();
|
||||||
|
|
||||||
|
let mut config_dir = home_dir.clone();
|
||||||
|
config_dir.push("rider");
|
||||||
|
config_dir
|
||||||
|
}
|
99
src/config/mod.rs
Normal file
99
src/config/mod.rs
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
use crate::themes::Theme;
|
||||||
|
use dirs;
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
mod creator;
|
||||||
|
pub mod directories;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct EditorConfig {
|
||||||
|
character_size: u16,
|
||||||
|
font_path: String,
|
||||||
|
current_theme: String,
|
||||||
|
margin_left: u16,
|
||||||
|
margin_top: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EditorConfig {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let mut default_font_path = directories::fonts_dir();
|
||||||
|
default_font_path.push("DejaVuSansMono.ttf");
|
||||||
|
Self {
|
||||||
|
character_size: 24,
|
||||||
|
font_path: default_font_path.to_str().unwrap().to_string(),
|
||||||
|
current_theme: "railscasts".to_string(),
|
||||||
|
margin_left: 10,
|
||||||
|
margin_top: 10,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn character_size(&self) -> u16 {
|
||||||
|
self.character_size
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn font_path(&self) -> &String {
|
||||||
|
&self.font_path
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn current_theme(&self) -> &String {
|
||||||
|
&self.current_theme
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn margin_left(&self) -> u16 {
|
||||||
|
self.margin_left
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn margin_top(&self) -> u16 {
|
||||||
|
self.margin_top
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Config {
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
menu_height: u16,
|
||||||
|
editor_config: EditorConfig,
|
||||||
|
theme: Theme,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Config {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
creator::create();
|
||||||
|
let editor_config = EditorConfig::new();
|
||||||
|
Self {
|
||||||
|
width: 1024,
|
||||||
|
height: 860,
|
||||||
|
menu_height: 60,
|
||||||
|
theme: Theme::load(editor_config.current_theme().clone()),
|
||||||
|
editor_config,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn width(&self) -> u32 {
|
||||||
|
self.width
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn height(&self) -> u32 {
|
||||||
|
self.height
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn editor_config(&self) -> &EditorConfig {
|
||||||
|
&self.editor_config
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn theme(&self) -> &Theme {
|
||||||
|
&self.theme
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn menu_height(&self) -> u16 {
|
||||||
|
self.menu_height
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn editor_top_margin(&self) -> i32 {
|
||||||
|
(self.menu_height() as i32) + (self.editor_config().margin_top() as i32)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn editor_left_margin(&self) -> i32 {
|
||||||
|
self.editor_config().margin_left() as i32
|
||||||
|
}
|
||||||
|
}
|
@ -1,26 +1,34 @@
|
|||||||
use sdl2::rect::Rect;
|
use crate::app::{UpdateResult, WindowCanvas};
|
||||||
|
use crate::config::Config;
|
||||||
use crate::file::editor_file_section::EditorFileSection;
|
use crate::file::editor_file_section::EditorFileSection;
|
||||||
use crate::renderer::Renderer;
|
use crate::renderer::Renderer;
|
||||||
use crate::app::{UpdateResult, WindowCanvas};
|
|
||||||
use crate::ui::*;
|
use crate::ui::*;
|
||||||
|
use sdl2::rect::{Point, Rect};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct EditorFile {
|
pub struct EditorFile {
|
||||||
pub path: String,
|
path: String,
|
||||||
pub sections: Vec<EditorFileSection>,
|
sections: Vec<EditorFileSection>,
|
||||||
|
render_position: Rect,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EditorFile {
|
impl EditorFile {
|
||||||
pub fn new(path: String, buffer: String) -> Self {
|
pub fn new(path: String, buffer: String, config: &Config) -> Self {
|
||||||
let section = EditorFileSection::new(buffer);
|
let section = EditorFileSection::new(buffer, config);
|
||||||
let sections = vec![section];
|
let sections = vec![section];
|
||||||
Self { path, sections }
|
let x = config.editor_left_margin();
|
||||||
|
let y = config.editor_top_margin();
|
||||||
|
Self {
|
||||||
|
path,
|
||||||
|
sections,
|
||||||
|
render_position: Rect::new(x, y, 0, 0),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn refresh_characters_position(&mut self) {
|
fn refresh_characters_position(&mut self, config: &Config) {
|
||||||
let mut current: Rect = Rect::new(0, 0, 0, 0);
|
let mut current: Rect = self.render_position.clone();
|
||||||
for section in self.sections.iter_mut() {
|
for section in self.sections.iter_mut() {
|
||||||
section.update_positions(&mut current);
|
section.update_positions(&mut current, config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -32,7 +40,7 @@ impl Render for EditorFile {
|
|||||||
res = section.render(canvas, renderer);
|
res = section.render(canvas, renderer);
|
||||||
}
|
}
|
||||||
if res == UpdateResult::RefreshPositions {
|
if res == UpdateResult::RefreshPositions {
|
||||||
self.refresh_characters_position();
|
self.refresh_characters_position(renderer.config());
|
||||||
for section in self.sections.iter_mut() {
|
for section in self.sections.iter_mut() {
|
||||||
section.render(canvas, renderer);
|
section.render(canvas, renderer);
|
||||||
}
|
}
|
||||||
@ -50,3 +58,23 @@ impl Update for EditorFile {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ClickHandler for EditorFile {
|
||||||
|
fn on_left_click(&mut self, point: &Point, config: &Config) -> UpdateResult {
|
||||||
|
for section in self.sections.iter_mut() {
|
||||||
|
if section.is_left_click_target(point) {
|
||||||
|
return section.on_left_click(point, config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UpdateResult::NoOp
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_left_click_target(&self, point: &Point) -> bool {
|
||||||
|
for section in self.sections.iter() {
|
||||||
|
if section.is_left_click_target(point) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,34 +1,34 @@
|
|||||||
use sdl2::rect::Rect;
|
use crate::app::{UpdateResult, WindowCanvas};
|
||||||
use crate::lexer::Language;
|
use crate::config::Config;
|
||||||
use crate::app::UpdateResult;
|
|
||||||
use crate::app::WindowCanvas;
|
|
||||||
use crate::renderer::Renderer;
|
|
||||||
use crate::file::editor_file_token::EditorFileToken;
|
use crate::file::editor_file_token::EditorFileToken;
|
||||||
|
use crate::lexer::Language;
|
||||||
|
use crate::renderer::Renderer;
|
||||||
use crate::ui::*;
|
use crate::ui::*;
|
||||||
|
use sdl2::rect::{Point, Rect};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct EditorFileSection {
|
pub struct EditorFileSection {
|
||||||
pub tokens: Vec<EditorFileToken>,
|
tokens: Vec<EditorFileToken>,
|
||||||
pub language: Language,
|
language: Language,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EditorFileSection {
|
impl EditorFileSection {
|
||||||
pub fn new(buffer: String) -> Self {
|
pub fn new(buffer: String, config: &Config) -> Self {
|
||||||
use crate::lexer;
|
use crate::lexer;
|
||||||
let lexer_tokens = lexer::parse(buffer.clone(), Language::PlainText);
|
let lexer_tokens = lexer::parse(buffer.clone(), Language::PlainText);
|
||||||
|
|
||||||
let mut tokens: Vec<EditorFileToken> = vec![];
|
let mut tokens: Vec<EditorFileToken> = vec![];
|
||||||
for token_type in lexer_tokens {
|
for token_type in lexer_tokens {
|
||||||
let token = EditorFileToken::new(token_type);
|
let token = EditorFileToken::new(token_type, config);
|
||||||
tokens.push(token.clone());
|
tokens.push(token.clone());
|
||||||
}
|
}
|
||||||
let language = Language::PlainText;
|
let language = Language::PlainText;
|
||||||
Self { tokens, language }
|
Self { tokens, language }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_positions(&mut self, current: &mut Rect) {
|
pub fn update_positions(&mut self, current: &mut Rect, config: &Config) {
|
||||||
for c in self.tokens.iter_mut() {
|
for c in self.tokens.iter_mut() {
|
||||||
c.update_position(current);
|
c.update_position(current, config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -55,3 +55,23 @@ impl Update for EditorFileSection {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ClickHandler for EditorFileSection {
|
||||||
|
fn on_left_click(&mut self, point: &Point, config: &Config) -> UpdateResult {
|
||||||
|
for token in self.tokens.iter_mut() {
|
||||||
|
if token.is_left_click_target(point) {
|
||||||
|
return token.on_left_click(point, config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UpdateResult::NoOp
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_left_click_target(&self, point: &Point) -> bool {
|
||||||
|
for token in self.tokens.iter() {
|
||||||
|
if token.is_left_click_target(point) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,22 +1,15 @@
|
|||||||
use std::rc::Rc;
|
|
||||||
use sdl2::rect::Rect;
|
|
||||||
use sdl2::render::Texture;
|
|
||||||
use sdl2::ttf::Font;
|
|
||||||
use sdl2::pixels::Color;
|
|
||||||
|
|
||||||
use crate::lexer::TokenType;
|
|
||||||
use crate::renderer::Renderer;
|
|
||||||
use crate::renderer::managers::TextDetails;
|
|
||||||
use crate::app::{UpdateResult, WindowCanvas};
|
use crate::app::{UpdateResult, WindowCanvas};
|
||||||
use crate::renderer::managers::FontDetails;
|
use crate::config::Config;
|
||||||
|
use crate::lexer::TokenType;
|
||||||
|
use crate::renderer::managers::{FontDetails, TextDetails};
|
||||||
|
use crate::renderer::Renderer;
|
||||||
use crate::ui::*;
|
use crate::ui::*;
|
||||||
use crate::ui::text_character::*;
|
use crate::ui::text_character::*;
|
||||||
|
use sdl2::pixels::Color;
|
||||||
#[derive(Clone)]
|
use sdl2::rect::{Point, Rect};
|
||||||
pub struct TextCharacterMeasure {
|
use sdl2::render::Texture;
|
||||||
source: Rect,
|
use sdl2::ttf::Font;
|
||||||
dest: Rect,
|
use std::rc::Rc;
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct EditorFileToken {
|
pub struct EditorFileToken {
|
||||||
@ -24,36 +17,36 @@ pub struct EditorFileToken {
|
|||||||
token_type: TokenType,
|
token_type: TokenType,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<Color> for TokenType {
|
|
||||||
fn into(self) -> Color {
|
|
||||||
match &self {
|
|
||||||
&TokenType::Whitespace { .. } => Color::RGBA(220, 220, 220, 90),
|
|
||||||
_ => Color::RGBA(0, 0, 0, 0),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EditorFileToken {
|
impl EditorFileToken {
|
||||||
pub fn new(token_type: TokenType) -> Self {
|
pub fn new(token_type: TokenType, _config: &Config) -> Self {
|
||||||
Self {
|
Self {
|
||||||
characters: vec![],
|
characters: vec![],
|
||||||
token_type,
|
token_type,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_position(&mut self, current: &mut Rect) {
|
pub fn update_position(&mut self, current: &mut Rect, config: &Config) {
|
||||||
for text_character in self.characters.iter_mut() {
|
for text_character in self.characters.iter_mut() {
|
||||||
text_character.update_position(current);
|
text_character.update_position(current, config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_view(&mut self, renderer: &mut Renderer) -> UpdateResult {
|
fn update_view(&mut self, renderer: &mut Renderer) -> UpdateResult {
|
||||||
|
let config = renderer.config().theme().code_highlighting();
|
||||||
|
let color: Color = match self.token_type {
|
||||||
|
TokenType::Whitespace { .. } => config.whitespace().color().into(),
|
||||||
|
TokenType::Keyword { .. } => config.keyword().color().into(),
|
||||||
|
TokenType::String { .. } => config.string().color().into(),
|
||||||
|
TokenType::Number { .. } => config.number().color().into(),
|
||||||
|
TokenType::Identifier { .. } => config.identifier().color().into(),
|
||||||
|
TokenType::Literal { .. } => config.literal().color().into(),
|
||||||
|
TokenType::Comment { .. } => config.comment().color().into(),
|
||||||
|
TokenType::Operator { .. } => config.operator().color().into(),
|
||||||
|
TokenType::Separator { .. } => config.separator().color().into(),
|
||||||
|
};
|
||||||
for c in self.token_type.text().chars() {
|
for c in self.token_type.text().chars() {
|
||||||
let mut text_character = TextCharacter::new(
|
let mut text_character =
|
||||||
c.clone(),
|
TextCharacter::new(c.clone(), self.token_type.line(), color.clone());
|
||||||
self.token_type.line(),
|
|
||||||
self.token_type.clone().into(),
|
|
||||||
);
|
|
||||||
text_character.update_view(renderer);
|
text_character.update_view(renderer);
|
||||||
self.characters.push(text_character);
|
self.characters.push(text_character);
|
||||||
}
|
}
|
||||||
@ -89,3 +82,23 @@ impl Update for EditorFileToken {
|
|||||||
UpdateResult::NoOp
|
UpdateResult::NoOp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ClickHandler for EditorFileToken {
|
||||||
|
fn on_left_click(&mut self, point: &Point, config: &Config) -> UpdateResult {
|
||||||
|
for text_character in self.characters.iter_mut() {
|
||||||
|
if text_character.is_left_click_target(point) {
|
||||||
|
return text_character.on_left_click(point, config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UpdateResult::NoOp
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_left_click_target(&self, point: &Point) -> bool {
|
||||||
|
for text_character in self.characters.iter() {
|
||||||
|
if text_character.is_left_click_target(point) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -92,7 +92,7 @@ pub struct Token {
|
|||||||
character: usize,
|
character: usize,
|
||||||
start: usize,
|
start: usize,
|
||||||
end: usize,
|
end: usize,
|
||||||
pub text: String,
|
text: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
13
src/main.rs
13
src/main.rs
@ -1,24 +1,25 @@
|
|||||||
#![allow(unused_imports)]
|
#![allow(unused_imports)]
|
||||||
|
|
||||||
|
extern crate dirs;
|
||||||
extern crate plex;
|
extern crate plex;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
extern crate sdl2;
|
extern crate sdl2;
|
||||||
extern crate dirs;
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde_json;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde_json;
|
||||||
|
|
||||||
|
use crate::app::Application;
|
||||||
|
|
||||||
pub mod app;
|
pub mod app;
|
||||||
pub mod ui;
|
pub mod config;
|
||||||
pub mod file;
|
pub mod file;
|
||||||
pub mod lexer;
|
pub mod lexer;
|
||||||
pub mod renderer;
|
pub mod renderer;
|
||||||
pub mod themes;
|
pub mod themes;
|
||||||
|
pub mod ui;
|
||||||
use crate::app::Application;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut app = Application::new();
|
let mut app = Application::new();
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
use sdl2::image::LoadTexture;
|
||||||
|
use sdl2::pixels::Color;
|
||||||
|
use sdl2::render::{Texture, TextureCreator};
|
||||||
|
use sdl2::ttf::{Font, Sdl2TtfContext};
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
@ -5,11 +9,6 @@ use std::env;
|
|||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use sdl2::image::LoadTexture;
|
|
||||||
use sdl2::pixels::Color;
|
|
||||||
use sdl2::render::{Texture, TextureCreator};
|
|
||||||
use sdl2::ttf::{Font, Sdl2TtfContext};
|
|
||||||
|
|
||||||
pub trait ResourceLoader<'l, R> {
|
pub trait ResourceLoader<'l, R> {
|
||||||
type Args: ?Sized;
|
type Args: ?Sized;
|
||||||
|
|
||||||
@ -34,7 +33,8 @@ impl TextDetails {
|
|||||||
format!(
|
format!(
|
||||||
"text({}) size({}) {:?}",
|
"text({}) size({}) {:?}",
|
||||||
self.text, self.font.size, self.color
|
self.text, self.font.size, self.color
|
||||||
).to_string()
|
)
|
||||||
|
.to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,6 +66,7 @@ impl<'a> From<&'a FontDetails> for FontDetails {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection RsWrongLifetimeParametersNumber
|
||||||
pub type TextureManager<'l, T> = ResourceManager<'l, String, Texture<'l>, TextureCreator<T>>;
|
pub type TextureManager<'l, T> = ResourceManager<'l, String, Texture<'l>, TextureCreator<T>>;
|
||||||
pub type FontManager<'l> = ResourceManager<'l, FontDetails, Font<'l, 'static>, Sdl2TtfContext>;
|
pub type FontManager<'l> = ResourceManager<'l, FontDetails, Font<'l, 'static>, Sdl2TtfContext>;
|
||||||
|
|
||||||
@ -85,7 +86,10 @@ impl<'l, K, R, L> ResourceManager<'l, K, R, L>
|
|||||||
L: ResourceLoader<'l, R>,
|
L: ResourceLoader<'l, R>,
|
||||||
{
|
{
|
||||||
pub fn new(loader: &'l L) -> Self {
|
pub fn new(loader: &'l L) -> Self {
|
||||||
Self { cache: HashMap::new(), loader }
|
Self {
|
||||||
|
cache: HashMap::new(),
|
||||||
|
loader,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load<D>(&mut self, details: &D) -> Result<Rc<R>, String>
|
pub fn load<D>(&mut self, details: &D) -> Result<Rc<R>, String>
|
||||||
@ -109,6 +113,7 @@ impl<'l, K, R, L> ResourceManager<'l, K, R, L>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection RsWrongLifetimeParametersNumber
|
||||||
impl<'l, T> ResourceLoader<'l, Texture<'l>> for TextureCreator<T> {
|
impl<'l, T> ResourceLoader<'l, Texture<'l>> for TextureCreator<T> {
|
||||||
type Args = str;
|
type Args = str;
|
||||||
|
|
||||||
@ -128,6 +133,7 @@ impl<'l> ResourceLoader<'l, Font<'l, 'static>> for Sdl2TtfContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'l, T> TextureManager<'l, T> {
|
impl<'l, T> TextureManager<'l, T> {
|
||||||
|
//noinspection RsWrongLifetimeParametersNumber
|
||||||
pub fn load_text(
|
pub fn load_text(
|
||||||
&mut self,
|
&mut self,
|
||||||
details: &mut TextDetails,
|
details: &mut TextDetails,
|
||||||
@ -143,6 +149,7 @@ impl<'l, T> TextureManager<'l, T> {
|
|||||||
let texture = self.loader.create_texture_from_surface(&surface).unwrap();
|
let texture = self.loader.create_texture_from_surface(&surface).unwrap();
|
||||||
let resource = Rc::new(texture);
|
let resource = Rc::new(texture);
|
||||||
self.cache.insert(key, resource.clone());
|
self.cache.insert(key, resource.clone());
|
||||||
|
println!("texture for '{}' created", details.text);
|
||||||
Ok(resource)
|
Ok(resource)
|
||||||
},
|
},
|
||||||
Ok,
|
Ok,
|
||||||
|
@ -1,23 +1,20 @@
|
|||||||
pub mod managers;
|
use crate::app::WindowCanvas;
|
||||||
|
use crate::config::Config;
|
||||||
use crate::renderer::managers::{FontManager, TextureManager};
|
use crate::renderer::managers::{FontManager, TextureManager};
|
||||||
|
use crate::renderer::managers::TextDetails;
|
||||||
use sdl2::rect::{Point, Rect};
|
use sdl2::rect::{Point, Rect};
|
||||||
use sdl2::render::{Texture, TextureCreator};
|
use sdl2::render::{Texture, TextureCreator};
|
||||||
use sdl2::ttf::Sdl2TtfContext;
|
use sdl2::ttf::Sdl2TtfContext;
|
||||||
use sdl2::video::WindowContext;
|
use sdl2::video::WindowContext;
|
||||||
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::app::config::Config;
|
pub mod managers;
|
||||||
use crate::app::WindowCanvas;
|
|
||||||
use crate::renderer::managers::TextDetails;
|
|
||||||
|
|
||||||
pub struct Renderer<'a> {
|
pub struct Renderer<'a> {
|
||||||
pub config: Config,
|
config: Config,
|
||||||
pub font_manager: FontManager<'a>,
|
font_manager: FontManager<'a>,
|
||||||
pub texture_manager: TextureManager<'a, WindowContext>,
|
texture_manager: TextureManager<'a, WindowContext>,
|
||||||
pub scroll: Point,
|
scroll: Point,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Renderer<'a> {
|
impl<'a> Renderer<'a> {
|
||||||
@ -34,7 +31,29 @@ impl<'a> Renderer<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_texture(&mut self, canvas: &mut WindowCanvas, texture: &Rc<Texture>, src: &Rect, dest: &Rect) {
|
pub fn config(&self) -> &Config {
|
||||||
|
&self.config
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn font_manager(&mut self) -> &mut FontManager<'a> {
|
||||||
|
&mut self.font_manager
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn texture_manager(&mut self) -> &mut TextureManager<'a, WindowContext> {
|
||||||
|
&mut self.texture_manager
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scroll(&self) -> &Point {
|
||||||
|
&self.scroll
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render_texture(
|
||||||
|
&mut self,
|
||||||
|
canvas: &mut WindowCanvas,
|
||||||
|
texture: &Rc<Texture>,
|
||||||
|
src: &Rect,
|
||||||
|
dest: &Rect,
|
||||||
|
) {
|
||||||
canvas
|
canvas
|
||||||
.copy_ex(
|
.copy_ex(
|
||||||
texture,
|
texture,
|
||||||
@ -50,9 +69,7 @@ impl<'a> Renderer<'a> {
|
|||||||
|
|
||||||
pub fn render_text(&mut self, details: TextDetails) -> Option<Rc<Texture>> {
|
pub fn render_text(&mut self, details: TextDetails) -> Option<Rc<Texture>> {
|
||||||
let font = self.font_manager.load(&details.font).unwrap();
|
let font = self.font_manager.load(&details.font).unwrap();
|
||||||
let surface = font
|
let surface = font.render(details.text.as_str()).blended(details.color);
|
||||||
.render(details.text.as_str())
|
|
||||||
.blended(details.color);
|
|
||||||
let surface = if let Ok(s) = surface {
|
let surface = if let Ok(s) = surface {
|
||||||
s
|
s
|
||||||
} else {
|
} else {
|
||||||
|
155
src/themes/config_creator.rs
Normal file
155
src/themes/config_creator.rs
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
use crate::config::directories::*;
|
||||||
|
use crate::themes::*;
|
||||||
|
use dirs;
|
||||||
|
use std::fs;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
pub fn create() {
|
||||||
|
fs::create_dir_all(themes_dir())
|
||||||
|
.unwrap_or_else(|_| panic!("Cannot create theme config directory"));
|
||||||
|
for theme in default_styles() {
|
||||||
|
write_theme(&theme);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_theme(theme: &Theme) {
|
||||||
|
let mut theme_path = themes_dir();
|
||||||
|
theme_path.push(format!("{}.json", theme.name));
|
||||||
|
let contents = serde_json::to_string_pretty(&theme).unwrap();
|
||||||
|
fs::write(&theme_path, contents.clone())
|
||||||
|
.unwrap_or_else(|_| panic!("Failed to crate theme config file"));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_styles() -> Vec<Theme> {
|
||||||
|
vec![default_theme(), railscasts_theme()]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_theme() -> Theme {
|
||||||
|
Theme::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn railscasts_theme() -> Theme {
|
||||||
|
Theme {
|
||||||
|
name: "railscasts".to_string(),
|
||||||
|
background: SerdeColor {
|
||||||
|
r: 60,
|
||||||
|
g: 60,
|
||||||
|
b: 60,
|
||||||
|
a: 0,
|
||||||
|
},
|
||||||
|
caret: CaretColor {
|
||||||
|
bright: ThemeConfig {
|
||||||
|
color: SerdeColor {
|
||||||
|
r: 121,
|
||||||
|
g: 121,
|
||||||
|
b: 121,
|
||||||
|
a: 0,
|
||||||
|
},
|
||||||
|
italic: false,
|
||||||
|
bold: false,
|
||||||
|
},
|
||||||
|
blur: ThemeConfig {
|
||||||
|
color: SerdeColor {
|
||||||
|
r: 21,
|
||||||
|
g: 21,
|
||||||
|
b: 21,
|
||||||
|
a: 0,
|
||||||
|
},
|
||||||
|
italic: false,
|
||||||
|
bold: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
code_highlighting: CodeHighlightingColor {
|
||||||
|
whitespace: ThemeConfig {
|
||||||
|
color: SerdeColor {
|
||||||
|
r: 220,
|
||||||
|
g: 220,
|
||||||
|
b: 220,
|
||||||
|
a: 90,
|
||||||
|
},
|
||||||
|
italic: false,
|
||||||
|
bold: false,
|
||||||
|
},
|
||||||
|
keyword: ThemeConfig {
|
||||||
|
color: SerdeColor {
|
||||||
|
r: 203,
|
||||||
|
g: 120,
|
||||||
|
b: 50,
|
||||||
|
a: 0,
|
||||||
|
},
|
||||||
|
italic: false,
|
||||||
|
bold: true,
|
||||||
|
},
|
||||||
|
string: ThemeConfig {
|
||||||
|
color: SerdeColor {
|
||||||
|
r: 164,
|
||||||
|
g: 194,
|
||||||
|
b: 96,
|
||||||
|
a: 0,
|
||||||
|
},
|
||||||
|
italic: false,
|
||||||
|
bold: false,
|
||||||
|
},
|
||||||
|
number: ThemeConfig {
|
||||||
|
color: SerdeColor {
|
||||||
|
r: 164,
|
||||||
|
g: 194,
|
||||||
|
b: 96,
|
||||||
|
a: 0,
|
||||||
|
},
|
||||||
|
italic: false,
|
||||||
|
bold: false,
|
||||||
|
},
|
||||||
|
identifier: ThemeConfig {
|
||||||
|
color: SerdeColor {
|
||||||
|
r: 21,
|
||||||
|
g: 21,
|
||||||
|
b: 21,
|
||||||
|
a: 0,
|
||||||
|
},
|
||||||
|
italic: false,
|
||||||
|
bold: false,
|
||||||
|
},
|
||||||
|
literal: ThemeConfig {
|
||||||
|
color: SerdeColor {
|
||||||
|
r: 21,
|
||||||
|
g: 21,
|
||||||
|
b: 21,
|
||||||
|
a: 0,
|
||||||
|
},
|
||||||
|
italic: false,
|
||||||
|
bold: false,
|
||||||
|
},
|
||||||
|
comment: ThemeConfig {
|
||||||
|
color: SerdeColor {
|
||||||
|
r: 188,
|
||||||
|
g: 147,
|
||||||
|
b: 88,
|
||||||
|
a: 0,
|
||||||
|
},
|
||||||
|
italic: true,
|
||||||
|
bold: false,
|
||||||
|
},
|
||||||
|
operator: ThemeConfig {
|
||||||
|
color: SerdeColor {
|
||||||
|
r: 0,
|
||||||
|
g: 0,
|
||||||
|
b: 0,
|
||||||
|
a: 0,
|
||||||
|
},
|
||||||
|
italic: false,
|
||||||
|
bold: false,
|
||||||
|
},
|
||||||
|
separator: ThemeConfig {
|
||||||
|
color: SerdeColor {
|
||||||
|
r: 21,
|
||||||
|
g: 21,
|
||||||
|
b: 21,
|
||||||
|
a: 0,
|
||||||
|
},
|
||||||
|
italic: false,
|
||||||
|
bold: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
@ -1,16 +1,19 @@
|
|||||||
|
use crate::config::directories::*;
|
||||||
|
use sdl2::pixels::Color;
|
||||||
|
use serde::ser::{Serialize, SerializeMap, Serializer, SerializeSeq};
|
||||||
|
use serde_json;
|
||||||
|
use std::env;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::env;
|
|
||||||
use sdl2::pixels::Color;
|
pub mod config_creator;
|
||||||
use serde_json;
|
|
||||||
use serde::ser::{Serialize, Serializer, SerializeSeq, SerializeMap};
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
|
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
|
||||||
pub struct SerdeColor {
|
pub struct SerdeColor {
|
||||||
pub r: u8,
|
pub r: u8,
|
||||||
pub g: u8,
|
pub g: u8,
|
||||||
pub b: u8,
|
pub b: u8,
|
||||||
pub a: u8
|
pub a: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SerdeColor {
|
impl SerdeColor {
|
||||||
@ -19,13 +22,13 @@ impl SerdeColor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<Color> for SerdeColor {
|
impl Into<Color> for &SerdeColor {
|
||||||
fn into(self) -> Color {
|
fn into(self) -> Color {
|
||||||
Color {
|
Color {
|
||||||
r: self.r,
|
r: self.r,
|
||||||
g: self.g,
|
g: self.g,
|
||||||
b: self.b,
|
b: self.b,
|
||||||
a: self.a
|
a: self.a,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -197,8 +200,9 @@ pub struct Theme {
|
|||||||
|
|
||||||
impl Default for Theme {
|
impl Default for Theme {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
use crate::themes::config_creator;
|
||||||
Self {
|
Self {
|
||||||
name: "Default".to_string(),
|
name: "default".to_string(),
|
||||||
background: SerdeColor::new(255, 255, 255, 0),
|
background: SerdeColor::new(255, 255, 255, 0),
|
||||||
caret: CaretColor::default(),
|
caret: CaretColor::default(),
|
||||||
code_highlighting: CodeHighlightingColor::default(),
|
code_highlighting: CodeHighlightingColor::default(),
|
||||||
@ -223,152 +227,26 @@ impl Theme {
|
|||||||
&self.code_highlighting
|
&self.code_highlighting
|
||||||
}
|
}
|
||||||
|
|
||||||
fn railscasts() -> Self {
|
pub fn load(theme_name: String) -> Self {
|
||||||
Self {
|
|
||||||
name: "railscasts".to_string(),
|
|
||||||
background: SerdeColor {
|
|
||||||
r: 60,
|
|
||||||
g: 60,
|
|
||||||
b: 60,
|
|
||||||
a: 0
|
|
||||||
},
|
|
||||||
caret: CaretColor { bright: ThemeConfig {
|
|
||||||
color: SerdeColor {
|
|
||||||
r: 0,
|
|
||||||
g: 0,
|
|
||||||
b: 0,
|
|
||||||
a: 0
|
|
||||||
},
|
|
||||||
italic: false,
|
|
||||||
bold: false
|
|
||||||
}, blur: ThemeConfig {
|
|
||||||
color: SerdeColor {
|
|
||||||
r: 0,
|
|
||||||
g: 0,
|
|
||||||
b: 0,
|
|
||||||
a: 0
|
|
||||||
},
|
|
||||||
italic: false,
|
|
||||||
bold: false
|
|
||||||
} },
|
|
||||||
code_highlighting: CodeHighlightingColor {
|
|
||||||
whitespace: ThemeConfig {
|
|
||||||
color: SerdeColor {
|
|
||||||
r: 0,
|
|
||||||
g: 0,
|
|
||||||
b: 0,
|
|
||||||
a: 0
|
|
||||||
},
|
|
||||||
italic: false,
|
|
||||||
bold: false
|
|
||||||
},
|
|
||||||
keyword: ThemeConfig {
|
|
||||||
color: SerdeColor {
|
|
||||||
r: 203,
|
|
||||||
g: 120,
|
|
||||||
b: 50,
|
|
||||||
a: 0
|
|
||||||
},
|
|
||||||
italic: false,
|
|
||||||
bold: true
|
|
||||||
},
|
|
||||||
string: ThemeConfig {
|
|
||||||
color: SerdeColor {
|
|
||||||
r: 0,
|
|
||||||
g: 0,
|
|
||||||
b: 0,
|
|
||||||
a: 0
|
|
||||||
},
|
|
||||||
italic: false,
|
|
||||||
bold: false
|
|
||||||
},
|
|
||||||
number: ThemeConfig {
|
|
||||||
color: SerdeColor {
|
|
||||||
r: 0,
|
|
||||||
g: 0,
|
|
||||||
b: 0,
|
|
||||||
a: 0
|
|
||||||
},
|
|
||||||
italic: false,
|
|
||||||
bold: false
|
|
||||||
},
|
|
||||||
identifier: ThemeConfig {
|
|
||||||
color: SerdeColor {
|
|
||||||
r: 0,
|
|
||||||
g: 0,
|
|
||||||
b: 0,
|
|
||||||
a: 0
|
|
||||||
},
|
|
||||||
italic: false,
|
|
||||||
bold: false
|
|
||||||
},
|
|
||||||
literal: ThemeConfig {
|
|
||||||
color: SerdeColor {
|
|
||||||
r: 0,
|
|
||||||
g: 0,
|
|
||||||
b: 0,
|
|
||||||
a: 0
|
|
||||||
},
|
|
||||||
italic: false,
|
|
||||||
bold: false
|
|
||||||
},
|
|
||||||
comment: ThemeConfig {
|
|
||||||
color: SerdeColor {
|
|
||||||
r: 188,
|
|
||||||
g: 147,
|
|
||||||
b: 88,
|
|
||||||
a: 0
|
|
||||||
},
|
|
||||||
italic: true,
|
|
||||||
bold: false
|
|
||||||
},
|
|
||||||
operator: ThemeConfig {
|
|
||||||
color: SerdeColor {
|
|
||||||
r: 0,
|
|
||||||
g: 0,
|
|
||||||
b: 0,
|
|
||||||
a: 0
|
|
||||||
},
|
|
||||||
italic: false,
|
|
||||||
bold: false
|
|
||||||
},
|
|
||||||
separator: ThemeConfig {
|
|
||||||
color: SerdeColor {
|
|
||||||
r: 0,
|
|
||||||
g: 0,
|
|
||||||
b: 0,
|
|
||||||
a: 0
|
|
||||||
},
|
|
||||||
italic: false,
|
|
||||||
bold: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn load(_theme_name: String) -> Self {
|
|
||||||
use dirs;
|
use dirs;
|
||||||
let home_dir = dirs::config_dir().unwrap();
|
let home_dir = dirs::config_dir().unwrap();
|
||||||
let mut config_dir = home_dir.clone();
|
let mut config_dir = home_dir.clone();
|
||||||
config_dir.push("rider/themes");
|
config_dir.push("rider");
|
||||||
fs::create_dir_all(&config_dir)
|
fs::create_dir_all(&config_dir)
|
||||||
.unwrap_or_else(|_| panic!("Cannot create config directory"));
|
.unwrap_or_else(|_| panic!("Cannot create config directory"));
|
||||||
let theme = Self::load_content(&config_dir, "default.json");
|
Self::load_content(format!("{}.json", theme_name).as_str())
|
||||||
println!("theme config:\n{:?}", theme);
|
|
||||||
theme
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_content(config_dir: &PathBuf, file_name: &str) -> Theme {
|
fn load_content(file_name: &str) -> Theme {
|
||||||
let mut config_file = config_dir.clone();
|
let mut config_file = themes_dir();
|
||||||
config_file.push(file_name);
|
config_file.push(file_name);
|
||||||
let contents = match fs::read_to_string(&config_file) {
|
let contents = match fs::read_to_string(&config_file) {
|
||||||
Ok(s) => s,
|
Ok(s) => s,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
let contents = serde_json::to_string_pretty(&Theme::default())
|
use crate::themes::config_creator;
|
||||||
.unwrap();
|
config_creator::create();
|
||||||
fs::write(&config_file, contents.clone())
|
fs::read_to_string(&config_file)
|
||||||
.unwrap_or_else(|_| panic!("Failed to crate theme config file"));
|
.unwrap_or_else(|_| panic!("Failed to load theme config file"))
|
||||||
contents.to_string()
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
serde_json::from_str(&contents).unwrap_or_default()
|
serde_json::from_str(&contents).unwrap_or_default()
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
use sdl2::rect::Rect;
|
use crate::app::{UpdateResult, WindowCanvas};
|
||||||
use sdl2::render::Texture;
|
use crate::config::Config;
|
||||||
use sdl2::pixels::Color;
|
use crate::renderer::Renderer;
|
||||||
use crate::app::{WindowCanvas, UpdateResult};
|
|
||||||
use crate::ui::*;
|
use crate::ui::*;
|
||||||
use crate::ui::text_character::TextCharacter;
|
use crate::ui::text_character::TextCharacter;
|
||||||
use crate::renderer::Renderer;
|
use sdl2::pixels::Color;
|
||||||
|
use sdl2::rect::{Point, Rect};
|
||||||
const CARET_CHARACTER: char = '│';
|
use sdl2::render::Texture;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
enum CaretState {
|
enum CaretState {
|
||||||
@ -14,21 +13,31 @@ enum CaretState {
|
|||||||
Blur,
|
Blur,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Caret {
|
pub struct Caret {
|
||||||
state: CaretState,
|
state: CaretState,
|
||||||
bright_character: TextCharacter,
|
|
||||||
blur_character: TextCharacter,
|
|
||||||
blink_delay: u8,
|
blink_delay: u8,
|
||||||
|
position: Rect,
|
||||||
|
bright_character_color: Color,
|
||||||
|
blur_character_color: Color,
|
||||||
|
pending: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Caret {
|
impl Caret {
|
||||||
pub fn new() -> Self {
|
pub fn new(config: &Config) -> Self {
|
||||||
|
let bright_character_color = config.theme().caret().bright().color().into();
|
||||||
|
let blur_character_color = config.theme().caret().blur().color().into();
|
||||||
Self {
|
Self {
|
||||||
bright_character: TextCharacter::new(CARET_CHARACTER, 0, Color::RGBA(0, 0, 0, 0)),
|
|
||||||
blur_character: TextCharacter::new(CARET_CHARACTER, 0, Color::RGBA(100, 100, 100, 0)),
|
|
||||||
state: CaretState::Bright,
|
state: CaretState::Bright,
|
||||||
blink_delay: 0,
|
blink_delay: 0,
|
||||||
|
position: Rect::new(
|
||||||
|
config.editor_left_margin(),
|
||||||
|
config.editor_top_margin(),
|
||||||
|
4,
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
bright_character_color,
|
||||||
|
blur_character_color,
|
||||||
|
pending: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,20 +48,44 @@ impl Caret {
|
|||||||
CaretState::Bright
|
CaretState::Bright
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn move_caret(&mut self, pos: Point) {
|
||||||
|
self.position.set_x(pos.x());
|
||||||
|
self.position.set_y(pos.y());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Render for Caret {
|
impl Render for Caret {
|
||||||
fn render(&mut self, canvas: &mut WindowCanvas, renderer: &mut Renderer) -> UpdateResult {
|
fn render(&mut self, canvas: &mut WindowCanvas, renderer: &mut Renderer) -> UpdateResult {
|
||||||
match self.state {
|
if self.pending {
|
||||||
CaretState::Bright => {
|
use crate::renderer::managers::FontDetails;
|
||||||
self.bright_character.update_position(&mut Rect::new(100, 220, 0, 0));
|
let config = renderer.config().clone();
|
||||||
self.bright_character.render(canvas, renderer)
|
let font = renderer
|
||||||
},
|
.font_manager()
|
||||||
CaretState::Blur => {
|
.load(&FontDetails {
|
||||||
self.blur_character.update_position(&mut Rect::new(100, 220, 0, 0));
|
path: config.editor_config().font_path().clone(),
|
||||||
self.blur_character.render(canvas, renderer)
|
size: config.editor_config().character_size(),
|
||||||
},
|
})
|
||||||
|
.unwrap_or_else(|_| panic!("Unable to load font"));
|
||||||
|
if let Ok((_, h)) = font.size_of_char('W') {
|
||||||
|
self.position.set_height(h);
|
||||||
}
|
}
|
||||||
|
self.pending = false;
|
||||||
|
}
|
||||||
|
let start = Point::new(self.position.x(), self.position.y());
|
||||||
|
let end = Point::new(
|
||||||
|
self.position.x(),
|
||||||
|
self.position.y() + self.position.height() as i32,
|
||||||
|
);
|
||||||
|
let color = match self.state {
|
||||||
|
CaretState::Bright => &self.bright_character_color,
|
||||||
|
CaretState::Blur => &self.blur_character_color,
|
||||||
|
};
|
||||||
|
canvas.set_draw_color(color.clone());
|
||||||
|
canvas
|
||||||
|
.draw_line(start, end)
|
||||||
|
.unwrap_or_else(|_| panic!("Failed to draw a caret"));
|
||||||
|
UpdateResult::NoOp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,3 +99,14 @@ impl Update for Caret {
|
|||||||
UpdateResult::NoOp
|
UpdateResult::NoOp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ClickHandler for Caret {
|
||||||
|
fn on_left_click(&mut self, _point: &Point, _config: &Config) -> UpdateResult {
|
||||||
|
// self.move_caret(Point::new(self.position.x(), self.position.y()));
|
||||||
|
UpdateResult::NoOp
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_left_click_target(&self, point: &Point) -> bool {
|
||||||
|
is_in_rect(point, &self.position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
55
src/ui/menu_bar.rs
Normal file
55
src/ui/menu_bar.rs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
use crate::app::{UpdateResult, WindowCanvas};
|
||||||
|
use crate::config::Config;
|
||||||
|
use crate::renderer::Renderer;
|
||||||
|
use crate::ui::*;
|
||||||
|
use sdl2::pixels::Color;
|
||||||
|
use sdl2::rect::Rect;
|
||||||
|
|
||||||
|
pub struct MenuBar {
|
||||||
|
background_color: Color,
|
||||||
|
dest: Rect,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MenuBar {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
background_color: Color::RGB(10, 10, 10),
|
||||||
|
dest: Rect::new(0, 0, 0, 0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn background_color(&self) -> &Color {
|
||||||
|
&self.background_color
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dest(&self) -> &Rect {
|
||||||
|
&self.dest
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Render for MenuBar {
|
||||||
|
fn render(&mut self, canvas: &mut WindowCanvas, renderer: &mut Renderer) -> UpdateResult {
|
||||||
|
let width = renderer.config().width();
|
||||||
|
let height = renderer.config().menu_height() as u32;
|
||||||
|
self.dest = Rect::new(0, 0, width, height);
|
||||||
|
canvas.set_draw_color(self.background_color.clone());
|
||||||
|
canvas.draw_rect(self.dest.clone()).unwrap();
|
||||||
|
UpdateResult::NoOp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Update for MenuBar {
|
||||||
|
fn update(&mut self, _ticks: i32) -> UpdateResult {
|
||||||
|
UpdateResult::NoOp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClickHandler for MenuBar {
|
||||||
|
fn on_left_click(&mut self, _point: &Point, _config: &Config) -> UpdateResult {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_left_click_target(&self, point: &Point) -> bool {
|
||||||
|
is_in_rect(point, self.dest())
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,20 @@
|
|||||||
|
use crate::app::{UpdateResult, WindowCanvas};
|
||||||
|
use crate::config::Config;
|
||||||
|
use crate::renderer::Renderer;
|
||||||
|
use sdl2::rect::{Point, Rect};
|
||||||
|
|
||||||
pub mod caret;
|
pub mod caret;
|
||||||
|
pub mod menu_bar;
|
||||||
pub mod text_character;
|
pub mod text_character;
|
||||||
|
|
||||||
use crate::renderer::Renderer;
|
pub fn is_in_rect(point: &Point, rect: &Rect) -> bool {
|
||||||
use crate::app::{WindowCanvas,UpdateResult};
|
let start = Point::new(rect.x(), rect.y());
|
||||||
|
let end = Point::new(
|
||||||
|
rect.x() + (rect.width() as i32),
|
||||||
|
rect.y() + (rect.height() as i32),
|
||||||
|
);
|
||||||
|
start.x() <= point.x() && start.y() <= point.y() && end.x() >= point.x() && end.y() >= point.y()
|
||||||
|
}
|
||||||
|
|
||||||
pub trait Render {
|
pub trait Render {
|
||||||
fn render(&mut self, canvas: &mut WindowCanvas, renderer: &mut Renderer) -> UpdateResult;
|
fn render(&mut self, canvas: &mut WindowCanvas, renderer: &mut Renderer) -> UpdateResult;
|
||||||
@ -11,3 +23,9 @@ pub trait Render {
|
|||||||
pub trait Update {
|
pub trait Update {
|
||||||
fn update(&mut self, ticks: i32) -> UpdateResult;
|
fn update(&mut self, ticks: i32) -> UpdateResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait ClickHandler {
|
||||||
|
fn on_left_click(&mut self, point: &Point, config: &Config) -> UpdateResult;
|
||||||
|
|
||||||
|
fn is_left_click_target(&self, point: &Point) -> bool;
|
||||||
|
}
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
use std::rc::Rc;
|
use crate::app::{UpdateResult, WindowCanvas};
|
||||||
|
use crate::config::Config;
|
||||||
|
use crate::lexer::TokenType;
|
||||||
|
use crate::renderer::managers::FontDetails;
|
||||||
|
use crate::renderer::managers::TextDetails;
|
||||||
|
use crate::renderer::Renderer;
|
||||||
|
use crate::ui::*;
|
||||||
|
use sdl2::pixels::Color;
|
||||||
use sdl2::rect::Rect;
|
use sdl2::rect::Rect;
|
||||||
use sdl2::render::Texture;
|
use sdl2::render::Texture;
|
||||||
use sdl2::ttf::Font;
|
use sdl2::ttf::Font;
|
||||||
use sdl2::pixels::Color;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::lexer::TokenType;
|
|
||||||
use crate::renderer::Renderer;
|
|
||||||
use crate::renderer::managers::TextDetails;
|
|
||||||
use crate::app::{UpdateResult, WindowCanvas};
|
|
||||||
use crate::renderer::managers::FontDetails;
|
|
||||||
use crate::ui::*;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct TextCharacter {
|
pub struct TextCharacter {
|
||||||
@ -45,11 +45,11 @@ impl TextCharacter {
|
|||||||
&self.color
|
&self.color
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_position(&mut self, current: &mut Rect) {
|
pub fn update_position(&mut self, current: &mut Rect, config: &Config) {
|
||||||
if self.is_new_line() {
|
if self.is_new_line() {
|
||||||
let y = (self.line * self.source.height() as usize) as i32;
|
let y = self.source.height() as i32;
|
||||||
current.set_x(0);
|
current.set_x(config.editor_left_margin());
|
||||||
current.set_y(y);
|
current.set_y(current.y() + y);
|
||||||
} else {
|
} else {
|
||||||
self.dest.set_x(current.x());
|
self.dest.set_x(current.x());
|
||||||
self.dest.set_y(current.y());
|
self.dest.set_y(current.y());
|
||||||
@ -60,12 +60,11 @@ impl TextCharacter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_view(&mut self, renderer: &mut Renderer) -> UpdateResult {
|
pub fn update_view(&mut self, renderer: &mut Renderer) -> UpdateResult {
|
||||||
let config = &renderer.config.editor_config;
|
let config = renderer.config().editor_config();
|
||||||
let font_details = FontDetails::new(
|
let font_details =
|
||||||
config.font_path.as_str(),
|
FontDetails::new(config.font_path().as_str(), config.character_size().clone());
|
||||||
config.character_size.clone(),
|
let font = renderer
|
||||||
);
|
.font_manager()
|
||||||
let font = renderer.font_manager
|
|
||||||
.load(&font_details)
|
.load(&font_details)
|
||||||
.unwrap_or_else(|_| panic!("Font not found {:?}", font_details));
|
.unwrap_or_else(|_| panic!("Font not found {:?}", font_details));
|
||||||
|
|
||||||
@ -79,10 +78,10 @@ impl TextCharacter {
|
|||||||
color: self.color.clone(),
|
color: self.color.clone(),
|
||||||
font: font_details.clone(),
|
font: font_details.clone(),
|
||||||
};
|
};
|
||||||
renderer.texture_manager
|
renderer
|
||||||
|
.texture_manager()
|
||||||
.load_text(&mut details, &font)
|
.load_text(&mut details, &font)
|
||||||
.unwrap_or_else(|_| panic!("Could not create texture for {:?}", c));
|
.unwrap_or_else(|_| panic!("Could not create texture for {:?}", c));
|
||||||
println!("texture for '{}' created", self.text_character);
|
|
||||||
|
|
||||||
self.pending = false;
|
self.pending = false;
|
||||||
UpdateResult::RefreshPositions
|
UpdateResult::RefreshPositions
|
||||||
@ -94,7 +93,7 @@ impl TextCharacter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_pending(&self) -> bool {
|
pub fn is_pending(&self) -> bool {
|
||||||
self.pending
|
self.pending
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -112,12 +111,11 @@ impl Render for TextCharacter {
|
|||||||
return UpdateResult::NoOp;
|
return UpdateResult::NoOp;
|
||||||
}
|
}
|
||||||
|
|
||||||
let config = &renderer.config.editor_config;
|
let config = renderer.config().editor_config();
|
||||||
let font_details = FontDetails::new(
|
let font_details =
|
||||||
config.font_path.as_str(),
|
FontDetails::new(config.font_path().as_str(), config.character_size().clone());
|
||||||
config.character_size.clone(),
|
let font = renderer
|
||||||
);
|
.font_manager()
|
||||||
let font = renderer.font_manager
|
|
||||||
.load(&font_details)
|
.load(&font_details)
|
||||||
.unwrap_or_else(|_| panic!("Could not load font for {:?}", font_details));
|
.unwrap_or_else(|_| panic!("Could not load font for {:?}", font_details));
|
||||||
|
|
||||||
@ -127,7 +125,7 @@ impl Render for TextCharacter {
|
|||||||
color: self.color.clone(),
|
color: self.color.clone(),
|
||||||
font: font_details.clone(),
|
font: font_details.clone(),
|
||||||
};
|
};
|
||||||
if let Ok(texture) = renderer.texture_manager.load_text(&mut details, &font) {
|
if let Ok(texture) = renderer.texture_manager().load_text(&mut details, &font) {
|
||||||
renderer.render_texture(canvas, &texture, &self.source, &self.dest);
|
renderer.render_texture(canvas, &texture, &self.source, &self.dest);
|
||||||
}
|
}
|
||||||
UpdateResult::NoOp
|
UpdateResult::NoOp
|
||||||
@ -139,3 +137,13 @@ impl Update for TextCharacter {
|
|||||||
UpdateResult::NoOp
|
UpdateResult::NoOp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ClickHandler for TextCharacter {
|
||||||
|
fn on_left_click(&mut self, _point: &Point, _config: &Config) -> UpdateResult {
|
||||||
|
UpdateResult::MoveCaret(self.dest().clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_left_click_target(&self, point: &Point) -> bool {
|
||||||
|
is_in_rect(point, self.dest())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user