fixing up the presenter and editor more
This commit is contained in:
parent
d27e12d9f8
commit
74ae0e8a17
4 changed files with 148 additions and 35 deletions
146
src/main.rs
146
src/main.rs
|
|
@ -9,26 +9,30 @@ use cosmic::app::{Core, Settings, Task};
|
||||||
use cosmic::iced::alignment::Vertical;
|
use cosmic::iced::alignment::Vertical;
|
||||||
use cosmic::iced::keyboard::{Key, Modifiers};
|
use cosmic::iced::keyboard::{Key, Modifiers};
|
||||||
use cosmic::iced::window::{Mode, Position};
|
use cosmic::iced::window::{Mode, Position};
|
||||||
use cosmic::iced::{self, event, window, Length, Point};
|
use cosmic::iced::{self, event, window, Color, Length, Point};
|
||||||
use cosmic::iced_futures::Subscription;
|
use cosmic::iced_futures::Subscription;
|
||||||
|
use cosmic::iced_runtime::dnd::DndAction;
|
||||||
use cosmic::iced_widget::{column, row, stack};
|
use cosmic::iced_widget::{column, row, stack};
|
||||||
use cosmic::theme;
|
use cosmic::theme;
|
||||||
use cosmic::widget::dnd_destination::dnd_destination;
|
use cosmic::widget::dnd_destination::dnd_destination;
|
||||||
|
use cosmic::widget::menu::key_bind::Modifier;
|
||||||
|
use cosmic::widget::menu::{ItemWidth, KeyBind};
|
||||||
use cosmic::widget::nav_bar::nav_bar_style;
|
use cosmic::widget::nav_bar::nav_bar_style;
|
||||||
use cosmic::widget::tooltip::Position as TPosition;
|
use cosmic::widget::tooltip::Position as TPosition;
|
||||||
use cosmic::widget::Container;
|
|
||||||
use cosmic::widget::{
|
use cosmic::widget::{
|
||||||
button, horizontal_space, mouse_area, nav_bar, search_input,
|
button, dnd_source, horizontal_space, mouse_area, nav_bar,
|
||||||
tooltip, vertical_space, Space,
|
search_input, tooltip, vertical_space, RcElementWrapper, Space,
|
||||||
};
|
};
|
||||||
use cosmic::widget::{container, text};
|
use cosmic::widget::{container, text};
|
||||||
use cosmic::widget::{icon, slider};
|
use cosmic::widget::{icon, slider};
|
||||||
|
use cosmic::widget::{menu, Container};
|
||||||
use cosmic::{executor, Application, ApplicationExt, Element};
|
use cosmic::{executor, Application, ApplicationExt, Element};
|
||||||
use crisp::types::Value;
|
use crisp::types::Value;
|
||||||
use lisp::parse_lisp;
|
use lisp::parse_lisp;
|
||||||
use miette::{miette, Result};
|
use miette::{miette, Result};
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use resvg::usvg::fontdb;
|
use resvg::usvg::fontdb;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::fs::read_to_string;
|
use std::fs::read_to_string;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
@ -119,6 +123,7 @@ struct App {
|
||||||
search_id: cosmic::widget::Id,
|
search_id: cosmic::widget::Id,
|
||||||
library_dragged_item: Option<ServiceItem>,
|
library_dragged_item: Option<ServiceItem>,
|
||||||
fontdb: Arc<fontdb::Database>,
|
fontdb: Arc<fontdb::Database>,
|
||||||
|
menu_keys: HashMap<KeyBind, MenuAction>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
@ -147,6 +152,35 @@ enum Message {
|
||||||
CloseSearch,
|
CloseSearch,
|
||||||
UpdateSearchResults(Vec<ServiceItem>),
|
UpdateSearchResults(Vec<ServiceItem>),
|
||||||
OpenEditor(ServiceItem),
|
OpenEditor(ServiceItem),
|
||||||
|
New,
|
||||||
|
Open,
|
||||||
|
OpenFile(PathBuf),
|
||||||
|
Save(Option<PathBuf>),
|
||||||
|
SaveAs,
|
||||||
|
OpenSettings,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
enum MenuAction {
|
||||||
|
New,
|
||||||
|
Save,
|
||||||
|
SaveAs,
|
||||||
|
Open,
|
||||||
|
OpenSettings,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl menu::Action for MenuAction {
|
||||||
|
type Message = Message;
|
||||||
|
|
||||||
|
fn message(&self) -> Self::Message {
|
||||||
|
match self {
|
||||||
|
MenuAction::New => Message::New,
|
||||||
|
MenuAction::Save => Message::Save(None),
|
||||||
|
MenuAction::SaveAs => Message::SaveAs,
|
||||||
|
MenuAction::Open => Message::Open,
|
||||||
|
MenuAction::OpenSettings => Message::OpenSettings,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const HEADER_SPACE: u16 = 6;
|
const HEADER_SPACE: u16 = 6;
|
||||||
|
|
@ -230,6 +264,28 @@ impl cosmic::Application for App {
|
||||||
// nav_model.insert().text(item.title()).data(item.clone());
|
// nav_model.insert().text(item.title()).data(item.clone());
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
let mut menu_keys = HashMap::new();
|
||||||
|
menu_keys.insert(
|
||||||
|
KeyBind {
|
||||||
|
modifiers: vec![Modifier::Ctrl],
|
||||||
|
key: Key::Character("s".into()),
|
||||||
|
},
|
||||||
|
MenuAction::Save,
|
||||||
|
);
|
||||||
|
menu_keys.insert(
|
||||||
|
KeyBind {
|
||||||
|
modifiers: vec![Modifier::Ctrl],
|
||||||
|
key: Key::Character("o".into()),
|
||||||
|
},
|
||||||
|
MenuAction::Open,
|
||||||
|
);
|
||||||
|
menu_keys.insert(
|
||||||
|
KeyBind {
|
||||||
|
modifiers: vec![Modifier::Ctrl],
|
||||||
|
key: Key::Character(".".into()),
|
||||||
|
},
|
||||||
|
MenuAction::OpenSettings,
|
||||||
|
);
|
||||||
// nav_model.activate_position(0);
|
// nav_model.activate_position(0);
|
||||||
let mut app = Self {
|
let mut app = Self {
|
||||||
presenter,
|
presenter,
|
||||||
|
|
@ -251,6 +307,7 @@ impl cosmic::Application for App {
|
||||||
current_item: (0, 0),
|
current_item: (0, 0),
|
||||||
library_dragged_item: None,
|
library_dragged_item: None,
|
||||||
fontdb: Arc::clone(&fontdb),
|
fontdb: Arc::clone(&fontdb),
|
||||||
|
menu_keys,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut batch = vec![];
|
let mut batch = vec![];
|
||||||
|
|
@ -270,7 +327,46 @@ impl cosmic::Application for App {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn header_start(&self) -> Vec<Element<Self::Message>> {
|
fn header_start(&self) -> Vec<Element<Self::Message>> {
|
||||||
vec![]
|
let file_menu = menu::Tree::with_children(
|
||||||
|
Into::<Element<Message>>::into(menu::root("File")),
|
||||||
|
menu::items(
|
||||||
|
&self.menu_keys,
|
||||||
|
vec![
|
||||||
|
menu::Item::Button("New", None, MenuAction::New),
|
||||||
|
menu::Item::Button(
|
||||||
|
"Open",
|
||||||
|
None,
|
||||||
|
MenuAction::Open,
|
||||||
|
),
|
||||||
|
menu::Item::Button(
|
||||||
|
"Save",
|
||||||
|
None,
|
||||||
|
MenuAction::Save,
|
||||||
|
),
|
||||||
|
menu::Item::Button(
|
||||||
|
"Save As",
|
||||||
|
None,
|
||||||
|
MenuAction::SaveAs,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
let settings_menu = menu::Tree::with_children(
|
||||||
|
Into::<Element<Message>>::into(menu::root("Settings")),
|
||||||
|
menu::items(
|
||||||
|
&self.menu_keys,
|
||||||
|
vec![menu::Item::Button(
|
||||||
|
"Open Settings",
|
||||||
|
None,
|
||||||
|
MenuAction::OpenSettings,
|
||||||
|
)],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
let menu_bar =
|
||||||
|
menu::bar::<Message>(vec![file_menu, settings_menu])
|
||||||
|
.item_width(ItemWidth::Static(250))
|
||||||
|
.main_offset(10);
|
||||||
|
vec![menu_bar.into()]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn header_center(&self) -> Vec<Element<Self::Message>> {
|
fn header_center(&self) -> Vec<Element<Self::Message>> {
|
||||||
|
|
@ -978,6 +1074,34 @@ impl cosmic::Application for App {
|
||||||
ServiceItemKind::Content(_slide) => todo!(),
|
ServiceItemKind::Content(_slide) => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Message::New => {
|
||||||
|
debug!("new file");
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
|
Message::Open => {
|
||||||
|
debug!("Open file");
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
|
Message::OpenFile(file) => {
|
||||||
|
debug!(?file, "opening file");
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
|
Message::Save(file) => {
|
||||||
|
let Some(file) = file else {
|
||||||
|
debug!("saving current");
|
||||||
|
return Task::none();
|
||||||
|
};
|
||||||
|
debug!(?file, "saving new file");
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
|
Message::SaveAs => {
|
||||||
|
debug!("saving as a file");
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
|
Message::OpenSettings => {
|
||||||
|
debug!("Opening settings");
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1237,6 +1361,15 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match (key, modifiers) {
|
match (key, modifiers) {
|
||||||
|
(Key::Character(k), Modifiers::CTRL) if k == *"s" => {
|
||||||
|
self.update(Message::Save(None))
|
||||||
|
}
|
||||||
|
(Key::Character(k), Modifiers::CTRL) if k == *"o" => {
|
||||||
|
self.update(Message::Open)
|
||||||
|
}
|
||||||
|
(Key::Character(k), Modifiers::CTRL) if k == *"." => {
|
||||||
|
self.update(Message::OpenSettings)
|
||||||
|
}
|
||||||
(Key::Character(k), Modifiers::CTRL)
|
(Key::Character(k), Modifiers::CTRL)
|
||||||
if k == *"k" || k == *"f" =>
|
if k == *"k" || k == *"f" =>
|
||||||
{
|
{
|
||||||
|
|
@ -1306,8 +1439,7 @@ where
|
||||||
// .icon_size(cosmic::theme::spacing().space_l)
|
// .icon_size(cosmic::theme::spacing().space_l)
|
||||||
.class(cosmic::theme::style::Button::HeaderBar)
|
.class(cosmic::theme::style::Button::HeaderBar)
|
||||||
// .spacing(cosmic::theme::spacing().space_l)
|
// .spacing(cosmic::theme::spacing().space_l)
|
||||||
// .padding(cosmic::theme::spacing().space_m)
|
.height(cosmic::theme::spacing().space_xl)
|
||||||
// .height(cosmic::theme::spacing().space_xxxl)
|
|
||||||
.width(Length::Fill)
|
.width(Length::Fill)
|
||||||
.on_press(Message::ChangeServiceItem(index));
|
.on_press(Message::ChangeServiceItem(index));
|
||||||
let tooltip = tooltip(button,
|
let tooltip = tooltip(button,
|
||||||
|
|
|
||||||
|
|
@ -399,21 +399,11 @@ impl Presenter {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn view(&self) -> Element<Message> {
|
pub fn view(&self) -> Element<Message> {
|
||||||
slide_view(
|
slide_view(&self.current_slide, &self.video, false, true)
|
||||||
self.current_slide.clone(),
|
|
||||||
&self.video,
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn view_preview(&self) -> Element<Message> {
|
pub fn view_preview(&self) -> Element<Message> {
|
||||||
slide_view(
|
slide_view(&self.current_slide, &self.video, false, false)
|
||||||
self.current_slide.clone(),
|
|
||||||
&self.video,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn preview_bar(&self) -> Element<Message> {
|
pub fn preview_bar(&self) -> Element<Message> {
|
||||||
|
|
@ -423,19 +413,6 @@ impl Presenter {
|
||||||
let mut slides = vec![];
|
let mut slides = vec![];
|
||||||
item.slides.iter().enumerate().for_each(
|
item.slides.iter().enumerate().for_each(
|
||||||
|(slide_index, slide)| {
|
|(slide_index, slide)| {
|
||||||
let font_name = slide.font().into_boxed_str();
|
|
||||||
let family =
|
|
||||||
Family::Name(Box::leak(font_name));
|
|
||||||
let weight = Weight::Normal;
|
|
||||||
let stretch = Stretch::Normal;
|
|
||||||
let style = Style::Normal;
|
|
||||||
let font = Font {
|
|
||||||
family,
|
|
||||||
weight,
|
|
||||||
stretch,
|
|
||||||
style,
|
|
||||||
};
|
|
||||||
|
|
||||||
let is_current_slide =
|
let is_current_slide =
|
||||||
(item_index, slide_index)
|
(item_index, slide_index)
|
||||||
== (
|
== (
|
||||||
|
|
@ -444,7 +421,7 @@ impl Presenter {
|
||||||
);
|
);
|
||||||
|
|
||||||
let container = slide_view(
|
let container = slide_view(
|
||||||
slide.clone(),
|
&slide,
|
||||||
&self.video,
|
&self.video,
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
|
|
@ -705,7 +682,7 @@ fn scale_font(font_size: f32, width: f32) -> f32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn slide_view<'a>(
|
pub(crate) fn slide_view<'a>(
|
||||||
slide: Slide,
|
slide: &'a Slide,
|
||||||
video: &'a Option<Video>,
|
video: &'a Option<Video>,
|
||||||
delegate: bool,
|
delegate: bool,
|
||||||
hide_mouse: bool,
|
hide_mouse: bool,
|
||||||
|
|
|
||||||
|
|
@ -314,7 +314,7 @@ impl SongEditor {
|
||||||
.map(|(index, slide)| {
|
.map(|(index, slide)| {
|
||||||
container(
|
container(
|
||||||
slide_view(
|
slide_view(
|
||||||
slide.clone(),
|
&slide,
|
||||||
if index == 0 {
|
if index == 0 {
|
||||||
&self.video
|
&self.video
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
4
todo.org
4
todo.org
|
|
@ -1,6 +1,9 @@
|
||||||
#+TITLE: The Task list for Lumina
|
#+TITLE: The Task list for Lumina
|
||||||
|
|
||||||
|
|
||||||
|
* TODO [#A] Add removal and reordering of service_items
|
||||||
|
* TODO Add OBS integration
|
||||||
|
This will be based on each slide having the ability to activate an OBS scene when it is active.
|
||||||
* TODO Move text_generation function to be asynchronous so that UI doesn't lock up during song editing.
|
* TODO Move text_generation function to be asynchronous so that UI doesn't lock up during song editing.
|
||||||
* TODO Build a video editor
|
* TODO Build a video editor
|
||||||
* TODO Build an image editor
|
* TODO Build an image editor
|
||||||
|
|
@ -73,6 +76,7 @@ This needs lots more attention
|
||||||
This will make it so that we can add styling to the text like borders and backgrounds or highlights. Maybe in the future it'll add shadows too.
|
This will make it so that we can add styling to the text like borders and backgrounds or highlights. Maybe in the future it'll add shadows too.
|
||||||
* DONE Check into =mupdf-rs= for loading PDF's.
|
* DONE Check into =mupdf-rs= for loading PDF's.
|
||||||
|
|
||||||
|
* DONE Build Menu
|
||||||
* DONE Find a way for text to pass through a service item to a slide i.e. content piece
|
* DONE Find a way for text to pass through a service item to a slide i.e. content piece
|
||||||
This proved easier by just creating the =Slide= first and inserting it into the =ServiceItem=.
|
This proved easier by just creating the =Slide= first and inserting it into the =ServiceItem=.
|
||||||
* DONE [#A] Change return type of all components to an Action enum instead of the Task<Message> type [0%] [0/0]
|
* DONE [#A] Change return type of all components to an Action enum instead of the Task<Message> type [0%] [0/0]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue