Update libcosmic/iced

This commit is contained in:
Jeremy Soller 2024-10-22 11:55:58 -06:00
parent bd80ac7e09
commit 5b0d05d2cb
No known key found for this signature in database
GPG key ID: D02FD439211AF56F
6 changed files with 840 additions and 881 deletions

1335
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -34,7 +34,6 @@ rust-embed = "8"
[dependencies.cosmic-files]
git = "https://github.com/pop-os/cosmic-files.git"
default-features = false
features = ["winit"]
[dependencies.cosmic-syntax-theme]
git = "https://github.com/pop-os/cosmic-syntax-theme.git"
@ -63,11 +62,7 @@ wgpu = ["libcosmic/wgpu", "cosmic-files/wgpu"]
inherits = "release"
debug = true
[patch.crates-io]
# https://github.com/alexcrichton/filetime/pull/104
filetime = { git = "https://github.com/jackpot51/filetime" }
# [patch.'https://github.com/pop-os/libcosmic']
# libcosmic = { path = "../libcosmic" }
# cosmic-config = { path = "../libcosmic/cosmic-config" }
# cosmic-theme = { path = "../libcosmic/cosmic-theme" }
# cosmic-theme = { path = "../libcosmic/cosmic-theme" }

View file

@ -1,6 +1,5 @@
use cosmic_text::{
Align, Attrs, AttrsList, BufferLine, Family, FontSystem, LayoutLine, LineEnding, ShapeBuffer,
Shaping, Wrap,
Align, Attrs, AttrsList, BufferLine, Family, FontSystem, LayoutLine, LineEnding, Shaping, Wrap,
};
use std::collections::HashMap;

View file

@ -4,7 +4,7 @@ use cosmic::widget::menu::action::MenuAction;
use cosmic::widget::menu::key_bind::KeyBind;
use cosmic::widget::segmented_button::Entity;
use cosmic::{
app::{message, Command, Core, Settings},
app::{message, Core, Settings, Task},
cosmic_config::{self, CosmicConfigEntry},
cosmic_theme, executor,
font::Font,
@ -13,9 +13,7 @@ use cosmic::{
clipboard, event,
futures::{self, SinkExt},
keyboard::{self, Modifiers},
subscription,
widget::text,
window, Alignment, Background, Color, Length, Limits, Point,
stream, window, Alignment, Background, Color, Length, Limits, Point, Subscription,
},
style, theme,
widget::{self, button, icon, nav_bar, segmented_button},
@ -322,6 +320,7 @@ pub enum Message {
ConfigState(ConfigState),
CloseFile,
CloseProject(usize),
CloseWindow(window::Id),
Copy,
Cut,
DefaultFont(usize),
@ -338,7 +337,7 @@ pub enum Message {
FindSearchValueChanged(String),
FindUseRegex(bool),
FindWrapAround(bool),
Focus,
Focus(window::Id),
GitProjectStatus(Vec<(String, PathBuf, Vec<GitStatus>)>),
GitStage(PathBuf, PathBuf),
GitUnstage(PathBuf, PathBuf),
@ -670,7 +669,7 @@ impl App {
}
}
fn update_config(&mut self) -> Command<Message> {
fn update_config(&mut self) -> Task<Message> {
//TODO: provide iterator over data
let entities: Vec<_> = self.tab_model.iter().collect();
for entity in entities {
@ -681,7 +680,7 @@ impl App {
cosmic::app::command::set_theme(self.config.app_theme.theme())
}
fn save_config(&mut self) -> Command<Message> {
fn save_config(&mut self) -> Task<Message> {
if let Some(ref config_handler) = self.config_handler {
if let Err(err) = self.config.write_entry(config_handler) {
log::error!("failed to save config: {}", err);
@ -698,7 +697,7 @@ impl App {
}
}
fn update_dialogs(&mut self) -> Command<Message> {
fn update_dialogs(&mut self) -> Task<Message> {
match self.dialog_page_opt {
Some(DialogPage::PromptSaveClose(entity)) => {
if let Some(Tab::Editor(tab)) = self.tab_model.data::<Tab>(entity) {
@ -730,16 +729,16 @@ impl App {
}
None => {}
}
Command::none()
Task::none()
}
fn update_focus(&self) -> Command<Message> {
fn update_focus(&self) -> Task<Message> {
if self.core.window.show_context {
match self.context_page {
ContextPage::ProjectSearch => {
widget::text_input::focus(self.project_search_id.clone())
}
_ => Command::none(),
_ => Task::none(),
}
} else if self.find_opt.is_some() {
widget::text_input::focus(self.find_search_id.clone())
@ -783,7 +782,7 @@ impl App {
match expand_opt {
Some(id) => {
//TODO: can this be optimized?
// Command not used becuase opening a folder just returns Command::none
// Task not used becuase opening a folder just returns Task::none
let _ = self.on_nav_select(id);
}
None => {
@ -796,7 +795,7 @@ impl App {
}
// Call this any time the tab changes
pub fn update_tab(&mut self) -> Command<Message> {
pub fn update_tab(&mut self) -> Task<Message> {
self.update_nav_bar_active();
let title = match self.active_tab() {
@ -811,8 +810,12 @@ impl App {
};
let window_title = format!("{title} - {}", fl!("cosmic-text-editor"));
Command::batch([
self.set_window_title(window_title, self.main_window_id()),
Task::batch([
if let Some(window_id) = self.core.main_window_id() {
self.set_window_title(window_title, window_id)
} else {
Task::none()
},
self.update_focus(),
])
}
@ -844,7 +847,7 @@ impl App {
.padding(0)
.into(),
])
.align_items(Alignment::Center)
.align_x(Alignment::Center)
.spacing(space_xxs)
.into()
}
@ -878,7 +881,7 @@ impl App {
});
}
widget::settings::view_column(vec![widget::settings::view_section("")
widget::settings::view_column(vec![widget::settings::section()
.add(
widget::settings::item::builder(fl!("word-count"))
.control(widget::text(word_count.to_string())),
@ -911,10 +914,10 @@ impl App {
cosmic_theme.warning_color(),
)
};
let added = || widget::text("[+]").style(theme::Text::Color(success_color.into()));
let added = || widget::text("[+]").class(theme::Text::Color(success_color.into()));
let deleted =
|| widget::text("[-]").style(theme::Text::Color(destructive_color.into()));
let modified = || widget::text("[*]").style(theme::Text::Color(warning_color.into()));
|| widget::text("[-]").class(theme::Text::Color(destructive_color.into()));
let modified = || widget::text("[*]").class(theme::Text::Color(warning_color.into()));
let mut items =
Vec::with_capacity(project_status.len().saturating_mul(3).saturating_add(1));
@ -979,7 +982,7 @@ impl App {
widget::row::with_children(vec![
icon.into(),
widget::text(text.clone()).into(),
widget::horizontal_space(Length::Fill).into(),
widget::horizontal_space().into(),
widget::button::standard(fl!("stage"))
.on_press(Message::GitStage(
project_path.clone(),
@ -987,7 +990,7 @@ impl App {
))
.into(),
])
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(spacing.space_xs),
)
.on_press(Message::PrepareGitDiff(
@ -995,7 +998,7 @@ impl App {
item.path.clone(),
false,
))
.style(theme::Button::AppletMenu)
.class(theme::Button::AppletMenu)
.width(Length::Fill)
.into(),
);
@ -1020,7 +1023,7 @@ impl App {
widget::row::with_children(vec![
icon.into(),
widget::text(text.clone()).into(),
widget::horizontal_space(Length::Fill).into(),
widget::horizontal_space().into(),
widget::button::standard(fl!("unstage"))
.on_press(Message::GitUnstage(
project_path.clone(),
@ -1028,7 +1031,7 @@ impl App {
))
.into(),
])
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.spacing(spacing.space_xs),
)
.on_press(Message::PrepareGitDiff(
@ -1036,7 +1039,7 @@ impl App {
item.path.clone(),
true,
))
.style(theme::Button::AppletMenu)
.class(theme::Button::AppletMenu)
.width(Length::Fill)
.into(),
);
@ -1047,7 +1050,8 @@ impl App {
if !unstaged_items.is_empty() {
items.push(
widget::settings::view_section(fl!("unstaged-changes"))
widget::settings::section()
.title(fl!("unstaged-changes"))
.add(widget::column::with_children(unstaged_items))
.into(),
);
@ -1055,7 +1059,8 @@ impl App {
if !staged_items.is_empty() {
items.push(
widget::settings::view_section(fl!("staged-changes"))
widget::settings::section()
.title(fl!("staged-changes"))
.add(widget::column::with_children(staged_items))
.into(),
);
@ -1132,17 +1137,15 @@ impl App {
)
.on_press(Message::OpenSearchResult(file_i, line_i))
.width(Length::Fill)
.style(theme::Button::AppletMenu),
.class(theme::Button::AppletMenu),
);
}
items.push(
widget::settings::view_section(format!(
"{}",
file_search_result.path.display(),
))
.add(column)
.into(),
widget::settings::section()
.title(format!("{}", file_search_result.path.display(),))
.add(column)
.into(),
);
}
@ -1188,7 +1191,8 @@ impl App {
.iter()
.position(|font_size| font_size == &self.config.font_size);
widget::settings::view_column(vec![
widget::settings::view_section(fl!("appearance"))
widget::settings::section()
.title(fl!("appearance"))
.add(
widget::settings::item::builder(fl!("theme")).control(widget::dropdown(
&self.app_themes,
@ -1231,7 +1235,8 @@ impl App {
),
)
.into(),
widget::settings::view_section(fl!("keyboard-shortcuts"))
widget::settings::section()
.title(fl!("keyboard-shortcuts"))
.add(
widget::settings::item::builder(fl!("enable-vim-bindings"))
.toggler(self.config.vim_bindings, Message::VimBindings),
@ -1265,7 +1270,7 @@ impl Application for App {
}
/// Creates the application, and optionally emits command on initialize.
fn init(core: Core, flags: Self::Flags) -> (Self, Command<Self::Message>) {
fn init(core: Core, flags: Self::Flags) -> (Self, Task<Self::Message>) {
// Update font name from config
{
let mut font_system = font_system().write().unwrap();
@ -1396,7 +1401,7 @@ impl Application for App {
.style(theme::SegmentedButton::TabBar)
.apply(widget::container)
.padding(space_s)
.width(Length::Fill);
.width(Length::Shrink);
if !self.core().is_condensed() {
nav = nav.max_width(280);
@ -1406,7 +1411,7 @@ impl Application for App {
nav.apply(widget::scrollable)
.apply(widget::container)
.height(Length::Fill)
.style(theme::Container::custom(nav_bar::nav_bar_style))
.class(theme::Container::custom(nav_bar::nav_bar_style))
.into(),
)
}
@ -1419,13 +1424,13 @@ impl Application for App {
Some(Message::Quit)
}
fn on_context_drawer(&mut self) -> Command<Message> {
fn on_context_drawer(&mut self) -> Task<Message> {
// Focus correct widget
self.update_focus()
}
//TODO: currently the first escape unfocuses, and the second calls this function
fn on_escape(&mut self) -> Command<Message> {
fn on_escape(&mut self) -> Task<Message> {
if self.core.window.show_context {
// Close context drawer if open
self.core.window.show_context = false;
@ -1438,7 +1443,7 @@ impl Application for App {
self.update_focus()
}
fn on_nav_select(&mut self, id: nav_bar::Id) -> Command<Message> {
fn on_nav_select(&mut self, id: nav_bar::Id) -> Task<Message> {
// Toggle open state and get clone of node data
let node_opt = match self.nav_model.data_mut::<ProjectNode>(id) {
Some(node) => {
@ -1477,7 +1482,7 @@ impl Application for App {
// folder in condensed mode.
self.core_mut().nav_bar_set_toggled(true);
Command::none()
Task::none()
}
ProjectNode::File { path, .. } => {
//TODO: go to already open file if possible
@ -1520,9 +1525,9 @@ impl Application for App {
let mut column = widget::column::with_capacity(entities.len()).spacing(space_xxs);
for entity in entities.iter() {
if let Some(Tab::Editor(tab)) = self.tab_model.data::<Tab>(*entity) {
let mut row = widget::row::with_capacity(3).align_items(Alignment::Center);
let mut row = widget::row::with_capacity(3).align_y(Alignment::Center);
row = row.push(widget::text(tab.title()));
row = row.push(widget::horizontal_space(Length::Fill));
row = row.push(widget::horizontal_space());
if let Some(_path) = &tab.path_opt {
row = row.push(
widget::button::standard(fl!("save"))
@ -1562,7 +1567,7 @@ impl Application for App {
}
}
fn update(&mut self, message: Message) -> Command<Message> {
fn update(&mut self, message: Message) -> Task<Message> {
match message {
Message::AppTheme(app_theme) => {
self.config.app_theme = app_theme;
@ -1613,6 +1618,11 @@ impl Application for App {
}
}
}
Message::CloseWindow(window_id) => {
if Some(window_id) == self.core.main_window_id() {
return self.update(Message::Quit);
}
}
Message::Copy => {
if let Some(Tab::Editor(tab)) = self.active_tab() {
let editor = tab.editor.lock().unwrap();
@ -1633,7 +1643,7 @@ impl Application for App {
selection_opt
};
if let Some(selection) = selection_opt {
return Command::batch([
return Task::batch([
clipboard::write(selection),
self.update(Message::TabChanged(self.tab_model.active())),
]);
@ -1830,7 +1840,7 @@ impl Application for App {
self.git_project_status = Some(project_status);
}
Message::GitStage(project_path, path) => {
return Command::perform(
return Task::perform(
async move {
//TODO: send errors to UI
match GitRepository::new(&project_path) {
@ -1861,7 +1871,7 @@ impl Application for App {
);
}
Message::GitUnstage(project_path, path) => {
return Command::perform(
return Task::perform(
async move {
//TODO: send errors to UI
match GitRepository::new(&project_path) {
@ -2107,9 +2117,9 @@ impl Application for App {
if let Some((path, cursor)) = path_cursor_opt {
if let Some(entity) = self.open_tab(Some(path)) {
return Command::batch([
return Task::batch([
//TODO: why must this be done in a command?
Command::perform(
Task::perform(
async move { message::app(Message::TabSetCursor(entity, cursor)) },
|x| x,
),
@ -2119,7 +2129,7 @@ impl Application for App {
}
}
Message::Paste => {
return clipboard::read(|value_opt| match value_opt {
return clipboard::read().map(|value_opt| match value_opt {
Some(value) => message::app(Message::PasteValue(value)),
None => message::none(),
});
@ -2136,7 +2146,7 @@ impl Application for App {
}
}
Message::PrepareGitDiff(project_path, path, staged) => {
return Command::perform(
return Task::perform(
async move {
//TODO: send errors to UI
match GitRepository::new(&project_path) {
@ -2183,7 +2193,7 @@ impl Application for App {
files: Vec::new(),
};
self.project_search_result = Some(project_search_result.clone());
return Command::perform(
return Task::perform(
async move {
let task_res = tokio::task::spawn_blocking(move || {
project_search_result.search_projects(projects);
@ -2378,7 +2388,7 @@ impl Application for App {
// Ex. If tab 2 and 3 both have unsaved changes and `PromptSaveClose` is
// emitted for tab 2, closing tab 3 should open the dialog for tab 3 in
// order for `Message::Save` to save the correct tab.
return Command::batch([
return Task::batch([
// Focus the tab in case the user is closing an unfocussed tab
// Otherwise, closing an unfocussed tab would be very confusing
self.update(Message::TabActivate(entity)),
@ -2542,7 +2552,7 @@ impl Application for App {
Message::UpdateGitProjectStatus => {
self.git_project_status = None;
let projects = self.projects.clone();
return Command::perform(
return Task::perform(
async move {
let mut project_status = Vec::new();
for (project_name, project_path) in projects.iter() {
@ -2584,15 +2594,17 @@ impl Application for App {
self.config.vim_bindings = vim_bindings;
return self.save_config();
}
Message::Focus => {
// focus the text box if context page is not shown
if !self.core.window.show_context {
return self.update_focus();
Message::Focus(window_id) => {
if Some(window_id) == self.core.main_window_id() {
// focus the text box if context page is not shown
if !self.core.window.show_context {
return self.update_focus();
}
}
}
}
Command::none()
Task::none()
}
fn context_drawer(&self) -> Option<Element<Message>> {
@ -2629,7 +2641,7 @@ impl Application for App {
tab_column = tab_column.push(
widget::row::with_capacity(2)
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.push(
widget::tab_bar::horizontal(&self.tab_model)
.button_height(32)
@ -2644,43 +2656,13 @@ impl Application for App {
button::custom(icon_cache_get("list-add-symbolic", 16))
.on_press(Message::NewFile)
.padding(space_xxs)
.style(style::Button::Icon),
.class(style::Button::Icon),
),
);
let tab_id = self.tab_model.active();
match self.tab_model.data::<Tab>(tab_id) {
Some(Tab::Editor(tab)) => {
let status = {
let editor = tab.editor.lock().unwrap();
let parser = editor.parser();
match &parser.mode {
ViMode::Normal => {
format!("{}", parser.cmd)
}
ViMode::Insert => "-- INSERT --".to_string(),
ViMode::Extra(extra) => {
format!("{}{}", parser.cmd, extra)
}
ViMode::Replace => "-- REPLACE --".to_string(),
ViMode::Visual => {
format!("-- VISUAL -- {}", parser.cmd)
}
ViMode::VisualLine => {
format!("-- VISUAL LINE -- {}", parser.cmd)
}
ViMode::Command { value } => {
format!(":{value}|")
}
ViMode::Search { value, forwards } => {
if *forwards {
format!("/{value}|")
} else {
format!("?{value}|")
}
}
}
};
let mut text_box = text_box(&tab.editor, self.config.metrics())
.id(self.text_box_id.clone())
.on_changed(Message::TabChanged(tab_id))
@ -2701,11 +2683,39 @@ impl Application for App {
.position(widget::popover::Position::Point(point));
}
tab_column = tab_column.push(popover);
/*TODO: the status area breaks text box focus
if !status.is_empty() {
tab_column = tab_column.push(text(status).font(Font::MONOSPACE));
if self.config.vim_bindings {
let status = {
let editor = tab.editor.lock().unwrap();
let parser = editor.parser();
match &parser.mode {
ViMode::Normal => {
format!("{}", parser.cmd)
}
ViMode::Insert => "-- INSERT --".to_string(),
ViMode::Extra(extra) => {
format!("{}{}", parser.cmd, extra)
}
ViMode::Replace => "-- REPLACE --".to_string(),
ViMode::Visual => {
format!("-- VISUAL -- {}", parser.cmd)
}
ViMode::VisualLine => {
format!("-- VISUAL LINE -- {}", parser.cmd)
}
ViMode::Command { value } => {
format!(":{value}|")
}
ViMode::Search { value, forwards } => {
if *forwards {
format!("/{value}|")
} else {
format!("?{value}|")
}
}
}
};
tab_column = tab_column.push(widget::text(status).font(Font::MONOSPACE));
}
*/
}
Some(Tab::GitDiff(tab)) => {
let mut diff_widget = widget::column::with_capacity(tab.diff.hunks.len());
@ -2721,36 +2731,36 @@ impl Application for App {
"{:4} {:4} {}",
old_line, new_line, text
))),
GitDiffLine::Added { new_line, text } => widget::container(
widget::text::monotext(format!(
GitDiffLine::Added { new_line, text } => {
widget::container(widget::text::monotext(format!(
"{:4} {:4} + {}",
"", new_line, text
)),
)
.style(theme::Container::Custom(Box::new(|_theme| {
//TODO: theme this color
widget::container::Appearance {
background: Some(Background::Color(Color::from_rgb8(
0x00, 0x40, 0x00,
))),
..Default::default()
}
}))),
GitDiffLine::Deleted { old_line, text } => widget::container(
widget::text::monotext(format!(
)))
.style(|_theme| {
//TODO: theme this color
widget::container::Style {
background: Some(Background::Color(Color::from_rgb8(
0x00, 0x40, 0x00,
))),
..Default::default()
}
})
}
GitDiffLine::Deleted { old_line, text } => {
widget::container(widget::text::monotext(format!(
"{:4} {:4} - {}",
old_line, "", text
)),
)
.style(theme::Container::Custom(Box::new(|_theme| {
//TODO: theme this color
widget::container::Appearance {
background: Some(Background::Color(Color::from_rgb8(
0x40, 0x00, 0x00,
))),
..Default::default()
}
}))),
)))
.style(|_theme| {
//TODO: theme this color
widget::container::Style {
background: Some(Background::Color(Color::from_rgb8(
0x40, 0x00, 0x00,
))),
..Default::default()
}
})
}
};
hunk_widget = hunk_widget.push(line_widget.width(Length::Fill));
}
@ -2777,7 +2787,7 @@ impl Application for App {
.trailing_icon(
button::custom(icon_cache_get("edit-clear-symbolic", 16))
.on_press(Message::FindSearchValueChanged(String::new()))
.style(style::Button::Icon)
.class(style::Button::Icon)
.into(),
);
let find_widget = widget::row::with_children(vec![
@ -2786,8 +2796,8 @@ impl Application for App {
button::custom(icon_cache_get("go-up-symbolic", 16))
.on_press(Message::FindPrevious)
.padding(space_xxs)
.style(style::Button::Icon),
fl!("find-previous"),
.class(style::Button::Icon),
widget::text::body(fl!("find-previous")),
widget::tooltip::Position::Top,
)
.into(),
@ -2795,19 +2805,19 @@ impl Application for App {
button::custom(icon_cache_get("go-down-symbolic", 16))
.on_press(Message::FindNext)
.padding(space_xxs)
.style(style::Button::Icon),
fl!("find-next"),
.class(style::Button::Icon),
widget::text::body(fl!("find-next")),
widget::tooltip::Position::Top,
)
.into(),
widget::horizontal_space(Length::Fill).into(),
widget::horizontal_space().into(),
button::custom(icon_cache_get("window-close-symbolic", 16))
.on_press(Message::Find(None))
.padding(space_xxs)
.style(style::Button::Icon)
.class(style::Button::Icon)
.into(),
])
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.padding(space_xxs)
.spacing(space_xxs);
@ -2824,7 +2834,7 @@ impl Application for App {
.trailing_icon(
button::custom(icon_cache_get("edit-clear-symbolic", 16))
.on_press(Message::FindReplaceValueChanged(String::new()))
.style(style::Button::Icon)
.class(style::Button::Icon)
.into(),
);
let replace_widget = widget::row::with_children(vec![
@ -2833,8 +2843,8 @@ impl Application for App {
button::custom(icon_cache_get("replace-symbolic", 16))
.on_press(Message::FindReplace)
.padding(space_xxs)
.style(style::Button::Icon),
fl!("replace"),
.class(style::Button::Icon),
widget::text::body(fl!("replace")),
widget::tooltip::Position::Top,
)
.into(),
@ -2842,13 +2852,13 @@ impl Application for App {
button::custom(icon_cache_get("replace-all-symbolic", 16))
.on_press(Message::FindReplaceAll)
.padding(space_xxs)
.style(style::Button::Icon),
fl!("replace-all"),
.class(style::Button::Icon),
widget::text::body(fl!("replace-all")),
widget::tooltip::Position::Top,
)
.into(),
])
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.padding(space_xxs)
.spacing(space_xxs);
@ -2857,26 +2867,17 @@ impl Application for App {
column = column.push(
widget::row::with_children(vec![
widget::checkbox(
fl!("case-sensitive"),
self.config.find_case_sensitive,
Message::FindCaseSensitive,
)
.into(),
widget::checkbox(
fl!("use-regex"),
self.config.find_use_regex,
Message::FindUseRegex,
)
.into(),
widget::checkbox(
fl!("wrap-around"),
self.config.find_wrap_around,
Message::FindWrapAround,
)
.into(),
widget::checkbox(fl!("case-sensitive"), self.config.find_case_sensitive)
.on_toggle(Message::FindCaseSensitive)
.into(),
widget::checkbox(fl!("use-regex"), self.config.find_use_regex)
.on_toggle(Message::FindUseRegex)
.into(),
widget::checkbox(fl!("wrap-around"), self.config.find_wrap_around)
.on_toggle(Message::FindWrapAround)
.into(),
])
.align_items(Alignment::Center)
.align_y(Alignment::Center)
.padding(space_xxs)
.spacing(space_xxs),
);
@ -2899,14 +2900,14 @@ impl Application for App {
}
}
fn subscription(&self) -> subscription::Subscription<Message> {
fn subscription(&self) -> Subscription<Message> {
struct WatcherSubscription;
struct ConfigSubscription;
struct ConfigStateSubscription;
struct ThemeSubscription;
subscription::Subscription::batch([
event::listen_with(|event, status| match event {
Subscription::batch([
event::listen_with(|event, status, window_id| match event {
event::Event::Keyboard(keyboard::Event::KeyPressed { modifiers, key, .. }) => {
match status {
event::Status::Ignored => Some(Message::Key(modifiers, key)),
@ -2916,20 +2917,15 @@ impl Application for App {
event::Event::Keyboard(keyboard::Event::ModifiersChanged(modifiers)) => {
Some(Message::Modifiers(modifiers))
}
event::Event::Window(id, window::Event::Focused) if id == window::Id::MAIN => {
Some(Message::Focus)
}
event::Event::Window(id, window::Event::CloseRequested)
if id == window::Id::MAIN =>
{
Some(Message::Quit)
event::Event::Window(window::Event::Focused) => Some(Message::Focus(window_id)),
event::Event::Window(window::Event::CloseRequested) => {
Some(Message::CloseWindow(window_id))
}
_ => None,
}),
subscription::channel(
Subscription::run_with_id(
TypeId::of::<WatcherSubscription>(),
100,
|mut output| async move {
stream::channel(100, |mut output| async move {
let watcher_res = {
let mut output = output.clone();
//TODO: debounce
@ -2986,7 +2982,7 @@ impl Application for App {
loop {
time::sleep(time::Duration::new(1, 0)).await;
}
},
}),
),
cosmic_config::config_subscription(
TypeId::of::<ConfigSubscription>(),
@ -3026,7 +3022,7 @@ impl Application for App {
}),
match &self.dialog_opt {
Some(dialog) => dialog.subscription(),
None => subscription::Subscription::none(),
None => Subscription::none(),
},
])
}

View file

@ -5,7 +5,6 @@ use cosmic::widget::menu::{items as menu_items, root as menu_root, Item as MenuI
use cosmic::{
iced::{widget::column, widget::horizontal_rule, Background, Length},
iced_core::Border,
theme,
widget::{
self, horizontal_space,
menu::{menu_button, ItemHeight, ItemWidth, MenuBar, Tree as MenuTree},
@ -31,7 +30,7 @@ pub fn context_menu<'a>(
}
menu_button(vec![
widget::text(menu_label).into(),
horizontal_space(Length::Fill).into(),
horizontal_space().into(),
widget::text(key).into(),
])
.on_press(Message::TabContextAction(entity, menu_action))
@ -48,10 +47,10 @@ pub fn context_menu<'a>(
))
.padding(1)
//TODO: move style to libcosmic
.style(theme::Container::custom(|theme| {
.style(|theme| {
let cosmic = theme.cosmic();
let component = &cosmic.background.component;
widget::container::Appearance {
widget::container::Style {
icon_color: Some(component.on.into()),
text_color: Some(component.on.into()),
background: Some(Background::Color(component.base.into())),
@ -62,7 +61,7 @@ pub fn context_menu<'a>(
},
..Default::default()
}
}))
})
.width(Length::Fixed(240.0))
.into()
}

View file

@ -17,10 +17,10 @@ use cosmic::{
renderer::{self, Quad, Renderer as _},
widget::{
self,
operation::{self, Operation, OperationOutputWrapper},
operation::{self, Operation},
tree, Id, Widget,
},
Border, Shell,
Border, Radians, Shell,
},
theme::Theme,
Renderer,
@ -265,7 +265,7 @@ where
tree: &mut widget::Tree,
_layout: Layout<'_>,
_renderer: &Renderer,
operation: &mut dyn Operation<OperationOutputWrapper<Message>>,
operation: &mut dyn Operation,
) {
let state = tree.state.downcast_mut::<State>();
@ -653,7 +653,7 @@ where
editor.set_redraw(false);
state.scale_factor.set(scale_factor);
*handle_opt = Some(image::Handle::from_pixels(
*handle_opt = Some(image::Handle::from_rgba(
image_w as u32,
image_h as u32,
pixels_u8,
@ -662,7 +662,7 @@ where
let image_position = layout.position() + [self.padding.left, self.padding.top].into();
if let Some(ref handle) = *handle_opt {
let image_size = image::Renderer::dimensions(renderer, handle);
let image_size = image::Renderer::measure_image(renderer, handle);
let scaled_size = Size::new(scaled_w as f32, scaled_h as f32);
log::debug!(
"text_box image {:?} scaled {:?} position {:?}",
@ -670,11 +670,13 @@ where
scaled_size,
image_position
);
image::Renderer::draw(
image::Renderer::draw_image(
renderer,
handle.clone(),
image::FilterMethod::Nearest,
Rectangle::new(image_position, scaled_size),
Radians(0.0),
1.0,
[0.0; 4],
);
}
@ -884,6 +886,11 @@ where
let (buffer_size, buffer_scroll) =
editor.with_buffer(|buffer| (buffer.size(), buffer.scroll()));
let last_changed = editor.changed();
//TODO: better handling of status line update
let (last_parser_mode, last_parser_cmd) = {
let parser = editor.parser();
(parser.mode.clone(), parser.cmd)
};
let mut font_system = font_system().write().unwrap();
let mut editor = editor.borrow_with(font_system.raw());
@ -1191,8 +1198,12 @@ where
_ => (),
}
if editor.changed() != last_changed {
if let Some(on_changed) = &self.on_changed {
if let Some(on_changed) = &self.on_changed {
//TODO: better handling of status line update
let parser = editor.parser();
if editor.changed() != last_changed
|| (&parser.mode, &parser.cmd) != (&last_parser_mode, &last_parser_cmd)
{
shell.publish(on_changed.clone());
}
}