Re-add contact list and editor support
Signed-off-by: Manos Pitsidianakis <manos@pitsidianak.is>pull/312/head
parent
ba7a97e90b
commit
54d21f25fd
|
@ -24,8 +24,8 @@ use std::collections::HashMap;
|
|||
use melib::Card;
|
||||
|
||||
use crate::{
|
||||
terminal::*, Action::*, CellBuffer, Component, ComponentId, Context, Field, FormWidget, Key,
|
||||
StatusEvent, TabAction, ThemeAttribute, UIDialog, UIEvent,
|
||||
terminal::*, CellBuffer, Component, ComponentId, Context, Field, FormWidget, Key, StatusEvent,
|
||||
ThemeAttribute, UIDialog, UIEvent,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -33,7 +33,6 @@ enum ViewMode {
|
|||
ReadOnly,
|
||||
Discard(Box<UIDialog<char>>),
|
||||
Edit,
|
||||
//New,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -44,11 +43,10 @@ pub struct ContactManager {
|
|||
mode: ViewMode,
|
||||
form: FormWidget<bool>,
|
||||
pub account_pos: usize,
|
||||
content: CellBuffer,
|
||||
content: Screen<Virtual>,
|
||||
theme_default: ThemeAttribute,
|
||||
dirty: bool,
|
||||
has_changes: bool,
|
||||
|
||||
initialized: bool,
|
||||
}
|
||||
|
||||
|
@ -68,7 +66,7 @@ impl ContactManager {
|
|||
mode: ViewMode::Edit,
|
||||
form: FormWidget::default(),
|
||||
account_pos: 0,
|
||||
content: CellBuffer::new_with_context(100, 1, None, context),
|
||||
content: Screen::<Virtual>::new(),
|
||||
theme_default,
|
||||
dirty: true,
|
||||
has_changes: false,
|
||||
|
@ -77,34 +75,38 @@ impl ContactManager {
|
|||
}
|
||||
|
||||
fn initialize(&mut self, context: &Context) {
|
||||
let (width, _) = self.content.size();
|
||||
if !self.content.resize_with_context(100, 1, context) {
|
||||
return;
|
||||
}
|
||||
let mut area = self.content.area();
|
||||
|
||||
let (x, _) = self.content.write_string(
|
||||
let (x, _) = self.content.grid_mut().write_string(
|
||||
"Last edited: ",
|
||||
self.theme_default.fg,
|
||||
self.theme_default.bg,
|
||||
self.theme_default.attrs,
|
||||
((0, 0), (width - 1, 0)),
|
||||
area,
|
||||
None,
|
||||
);
|
||||
let (x, y) = self.content.write_string(
|
||||
area = area.skip_cols(x);
|
||||
let (x, y) = self.content.grid_mut().write_string(
|
||||
&self.card.last_edited(),
|
||||
self.theme_default.fg,
|
||||
self.theme_default.bg,
|
||||
self.theme_default.attrs,
|
||||
((x, 0), (width - 1, 0)),
|
||||
area,
|
||||
None,
|
||||
);
|
||||
area = area.skip(x, y);
|
||||
|
||||
if self.card.external_resource() {
|
||||
self.mode = ViewMode::ReadOnly;
|
||||
_ = self.content.resize(self.content.size().0, 2, None);
|
||||
self.content.write_string(
|
||||
self.content.grid_mut().write_string(
|
||||
"This contact's origin is external and cannot be edited within meli.",
|
||||
self.theme_default.fg,
|
||||
self.theme_default.bg,
|
||||
self.theme_default.attrs,
|
||||
((x, y), (width - 1, y)),
|
||||
area,
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
@ -147,23 +149,15 @@ impl Component for ContactManager {
|
|||
self.initialized = true;
|
||||
}
|
||||
|
||||
let upper_left = area.upper_left();
|
||||
let bottom_right = area.bottom_right();
|
||||
|
||||
if self.dirty {
|
||||
let (width, _height) = self.content.size();
|
||||
|
||||
grid.clear_area(
|
||||
(upper_left, set_y(bottom_right, get_y(upper_left) + 1)),
|
||||
self.theme_default,
|
||||
);
|
||||
grid.copy_area(&self.content, area, ((0, 0), (width - 1, 0)));
|
||||
if self.is_dirty() {
|
||||
grid.clear_area(area, self.theme_default);
|
||||
grid.copy_area(self.content.grid(), area.skip_rows(2), self.content.area());
|
||||
self.dirty = false;
|
||||
}
|
||||
|
||||
self.form.draw(
|
||||
grid,
|
||||
(set_y(upper_left, get_y(upper_left) + 2), bottom_right),
|
||||
area.skip_rows(2 + self.content.area().height()),
|
||||
context,
|
||||
);
|
||||
if let ViewMode::Discard(ref mut selector) = self.mode {
|
||||
|
@ -177,23 +171,27 @@ impl Component for ContactManager {
|
|||
fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool {
|
||||
if let UIEvent::ConfigReload { old_settings: _ } = event {
|
||||
self.theme_default = crate::conf::value(context, "theme_default");
|
||||
self.content = CellBuffer::new_with_context(100, 1, None, context);
|
||||
self.content.grid_mut().empty();
|
||||
self.initialized = false;
|
||||
self.set_dirty(true);
|
||||
}
|
||||
match self.mode {
|
||||
ViewMode::Discard(ref mut selector) => {
|
||||
if matches!(event, UIEvent::ComponentUnrealize(ref id) if *id == selector.id()) {
|
||||
selector.unrealize(context);
|
||||
self.mode = ViewMode::Edit;
|
||||
self.set_dirty(true);
|
||||
return true;
|
||||
}
|
||||
if selector.process_event(event, context) {
|
||||
self.set_dirty(true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
ViewMode::Edit => {
|
||||
if let (Some(parent_id), &UIEvent::Input(Key::Esc)) = (self.parent_id, &event) {
|
||||
if matches!(event, UIEvent::Input(Key::Esc)) {
|
||||
if self.can_quit_cleanly(context) {
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::Action(Tab(TabAction::Kill(parent_id))));
|
||||
self.unrealize(context);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -250,11 +248,7 @@ impl Component for ContactManager {
|
|||
fn is_dirty(&self) -> bool {
|
||||
self.dirty
|
||||
|| self.form.is_dirty()
|
||||
|| if let ViewMode::Discard(ref selector) = self.mode {
|
||||
selector.is_dirty()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|| matches!(self.mode, ViewMode::Discard(ref selector) if selector.is_dirty())
|
||||
}
|
||||
|
||||
fn set_dirty(&mut self, value: bool) {
|
||||
|
@ -274,28 +268,31 @@ impl Component for ContactManager {
|
|||
return true;
|
||||
}
|
||||
|
||||
if let Some(parent_id) = self.parent_id {
|
||||
if matches!(self.mode, ViewMode::Discard(_)) {
|
||||
true
|
||||
} else {
|
||||
let Some(parent_id) = self.parent_id else {
|
||||
return true;
|
||||
};
|
||||
/* Play it safe and ask user for confirmation */
|
||||
self.mode = ViewMode::Discard(Box::new(UIDialog::new(
|
||||
"this contact has unsaved changes",
|
||||
vec![
|
||||
('x', "quit without saving".to_string()),
|
||||
('y', "save draft and quit".to_string()),
|
||||
('y', "quit without saving".to_string()),
|
||||
('n', "cancel".to_string()),
|
||||
],
|
||||
true,
|
||||
Some(Box::new(move |_, results: &[char]| match results[0] {
|
||||
'x' => Some(UIEvent::Action(Tab(TabAction::Kill(parent_id)))),
|
||||
'n' => None,
|
||||
'y' => None,
|
||||
_ => None,
|
||||
Some(Box::new(move |id, results: &[char]| {
|
||||
if matches!(results.first(), Some(&'y')) {
|
||||
Some(UIEvent::ComponentUnrealize(parent_id))
|
||||
} else {
|
||||
Some(UIEvent::ComponentUnrealize(id))
|
||||
}
|
||||
})),
|
||||
context,
|
||||
)));
|
||||
self.set_dirty(true);
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,15 +24,15 @@ use std::cmp;
|
|||
use melib::{backends::AccountHash, text_processing::TextProcessing, Card, CardId, Draft};
|
||||
|
||||
use crate::{
|
||||
conf, /* contacts::editor::ContactManager, */ shortcut, terminal::*, Action::Tab,
|
||||
Component, ComponentId, Composer, Context, DataColumns, PageMovement, ScrollContext,
|
||||
ScrollUpdate, ShortcutMaps, Shortcuts, StatusEvent, TabAction, ThemeAttribute, UIEvent, UIMode,
|
||||
conf, contacts::editor::ContactManager, shortcut, terminal::*, Action::Tab, Component,
|
||||
ComponentId, Composer, Context, DataColumns, PageMovement, ScrollContext, ScrollUpdate,
|
||||
ShortcutMaps, Shortcuts, StatusEvent, TabAction, ThemeAttribute, UIEvent, UIMode,
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[derive(Debug)]
|
||||
enum ViewMode {
|
||||
List,
|
||||
View(ComponentId),
|
||||
View(Box<ContactManager>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -66,7 +66,6 @@ pub struct ContactList {
|
|||
menu_visibility: bool,
|
||||
movement: Option<PageMovement>,
|
||||
cmd_buf: String,
|
||||
//view: Option<ContactManager>,
|
||||
ratio: usize, // right/(container width) * 100
|
||||
id: ComponentId,
|
||||
}
|
||||
|
@ -104,7 +103,6 @@ impl ContactList {
|
|||
dirty: true,
|
||||
movement: None,
|
||||
cmd_buf: String::with_capacity(8),
|
||||
//view: None,
|
||||
ratio: 90,
|
||||
sidebar_divider: context.settings.listing.sidebar_divider,
|
||||
sidebar_divider_theme: conf::value(context, "mail.sidebar_divider"),
|
||||
|
@ -323,9 +321,11 @@ impl ContactList {
|
|||
}
|
||||
|
||||
fn draw_list(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) {
|
||||
let total_area = area;
|
||||
/* reserve top row for column headers */
|
||||
let header_area = area.nth_row(0);
|
||||
let area = area.skip_rows(1);
|
||||
if self.length == 0 {
|
||||
/* reserve top row for column headers */
|
||||
let area = area.skip_rows(1);
|
||||
grid.clear_area(area, self.theme_default);
|
||||
|
||||
grid.copy_area(
|
||||
|
@ -333,7 +333,7 @@ impl ContactList {
|
|||
area,
|
||||
self.data_columns.columns[0].area(),
|
||||
);
|
||||
context.dirty_areas.push_back(area);
|
||||
context.dirty_areas.push_back(total_area);
|
||||
return;
|
||||
}
|
||||
let rows = area.height();
|
||||
|
@ -385,7 +385,7 @@ impl ContactList {
|
|||
ScrollUpdate::Update {
|
||||
id: self.id,
|
||||
context: ScrollContext {
|
||||
shown_lines: top_idx + rows,
|
||||
shown_lines: (top_idx + rows).min(self.length - top_idx),
|
||||
total_lines: self.length,
|
||||
has_more_lines: false,
|
||||
},
|
||||
|
@ -408,7 +408,7 @@ impl ContactList {
|
|||
if *idx >= self.length {
|
||||
continue;
|
||||
}
|
||||
let new_area = area.nth_row(1 + *idx % rows);
|
||||
let new_area = area.nth_row(*idx % rows);
|
||||
self.highlight_line(grid, new_area, *idx);
|
||||
context.dirty_areas.push_back(new_area);
|
||||
}
|
||||
|
@ -422,17 +422,11 @@ impl ContactList {
|
|||
}
|
||||
|
||||
/* Page_no has changed, so draw new page */
|
||||
grid.clear_area(area, self.theme_default);
|
||||
_ = self
|
||||
.data_columns
|
||||
.recalc_widths((area.width(), area.height().saturating_sub(1)), top_idx);
|
||||
grid.clear_area(total_area, self.theme_default);
|
||||
_ = self.data_columns.recalc_widths(area.size(), top_idx);
|
||||
/* copy table columns */
|
||||
self.data_columns.draw(
|
||||
grid,
|
||||
top_idx,
|
||||
self.cursor_pos,
|
||||
grid.bounds_iter(area.skip_rows(1)),
|
||||
);
|
||||
self.data_columns
|
||||
.draw(grid, top_idx, self.cursor_pos, grid.bounds_iter(area));
|
||||
|
||||
let header_attrs = crate::conf::value(context, "widgets.list.header");
|
||||
let mut x = 0;
|
||||
|
@ -451,18 +445,19 @@ impl ContactList {
|
|||
header_attrs.fg,
|
||||
header_attrs.bg,
|
||||
header_attrs.attrs,
|
||||
area.skip_cols(x)
|
||||
header_area
|
||||
.skip_cols(x)
|
||||
.take_cols(x + (self.data_columns.widths[i])),
|
||||
None,
|
||||
);
|
||||
|
||||
x += self.data_columns.widths[i] + 2; // + SEPARATOR
|
||||
if x > area.width() {
|
||||
if x > header_area.width() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
grid.change_theme(area.nth_row(0), header_attrs);
|
||||
grid.change_theme(header_area, header_attrs);
|
||||
|
||||
if top_idx + rows > self.length {
|
||||
grid.clear_area(
|
||||
|
@ -470,21 +465,17 @@ impl ContactList {
|
|||
self.theme_default,
|
||||
);
|
||||
}
|
||||
self.highlight_line(
|
||||
grid,
|
||||
area.nth_row(1 + self.cursor_pos % rows),
|
||||
self.cursor_pos,
|
||||
);
|
||||
context.dirty_areas.push_back(area);
|
||||
self.highlight_line(grid, area.nth_row(self.cursor_pos % rows), self.cursor_pos);
|
||||
context.dirty_areas.push_back(total_area);
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for ContactList {
|
||||
fn draw(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) {
|
||||
//if let Some(mgr) = self.view.as_mut() {
|
||||
// mgr.draw(grid, area, context);
|
||||
// return;
|
||||
//}
|
||||
if let ViewMode::View(ref mut mgr) = self.mode {
|
||||
mgr.draw(grid, area, context);
|
||||
return;
|
||||
}
|
||||
|
||||
if !self.dirty {
|
||||
return;
|
||||
|
@ -531,7 +522,6 @@ impl Component for ContactList {
|
|||
UIEvent::VisibilityChange(true) => {
|
||||
self.initialized = false;
|
||||
self.set_dirty(true);
|
||||
return true;
|
||||
}
|
||||
UIEvent::ConfigReload { old_settings: _ } => {
|
||||
self.theme_default = crate::conf::value(context, "theme_default");
|
||||
|
@ -544,12 +534,6 @@ impl Component for ContactList {
|
|||
self.initialized = false;
|
||||
self.set_dirty(true);
|
||||
}
|
||||
UIEvent::ComponentUnrealize(ref kill_id) if self.mode == ViewMode::View(*kill_id) => {
|
||||
self.mode = ViewMode::List;
|
||||
//self.view.take();
|
||||
self.set_dirty(true);
|
||||
return true;
|
||||
}
|
||||
UIEvent::ChangeMode(UIMode::Normal) => {
|
||||
self.set_dirty(true);
|
||||
}
|
||||
|
@ -559,314 +543,315 @@ impl Component for ContactList {
|
|||
_ => {}
|
||||
}
|
||||
|
||||
//if let Some(ref mut v) = self.view {
|
||||
// if v.process_event(event, context) {
|
||||
// return true;
|
||||
// }
|
||||
//}
|
||||
if let ViewMode::View(ref mut mgr) = self.mode {
|
||||
if matches!(event, UIEvent::ComponentUnrealize(id) if *id == mgr.id()) {
|
||||
mgr.unrealize(context);
|
||||
self.mode = ViewMode::List;
|
||||
self.set_dirty(true);
|
||||
return true;
|
||||
}
|
||||
if mgr.process_event(event, context) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
let shortcuts = self.shortcuts(context);
|
||||
//if self.view.is_none() {
|
||||
match *event {
|
||||
UIEvent::Input(ref key)
|
||||
if shortcut!(key == shortcuts[Shortcuts::CONTACT_LIST]["create_contact"]) =>
|
||||
{
|
||||
/*
|
||||
let mut manager = ContactManager::new(context);
|
||||
manager.set_parent_id(self.id);
|
||||
manager.account_pos = self.account_pos;
|
||||
if matches!(self.mode, ViewMode::List) {
|
||||
match *event {
|
||||
UIEvent::Input(ref key)
|
||||
if shortcut!(key == shortcuts[Shortcuts::CONTACT_LIST]["create_contact"]) =>
|
||||
{
|
||||
let mut manager = Box::new(ContactManager::new(context));
|
||||
manager.set_parent_id(self.id);
|
||||
manager.account_pos = self.account_pos;
|
||||
|
||||
self.mode = ViewMode::View(manager.id());
|
||||
self.view = Some(manager);
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::ScrollUpdate(
|
||||
ScrollUpdate::End(self.id),
|
||||
)));
|
||||
*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
UIEvent::Input(ref key)
|
||||
if shortcut!(key == shortcuts[Shortcuts::CONTACT_LIST]["edit_contact"]) =>
|
||||
{
|
||||
if self.length == 0 {
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
let account = &mut context.accounts[self.account_pos];
|
||||
let book = &mut account.address_book;
|
||||
let card = book[&self.id_positions[self.cursor_pos]].clone();
|
||||
let mut manager = ContactManager::new(context);
|
||||
manager.set_parent_id(self.id);
|
||||
manager.card = card;
|
||||
manager.account_pos = self.account_pos;
|
||||
|
||||
self.mode = ViewMode::View(manager.id());
|
||||
self.view = Some(manager);
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::ScrollUpdate(
|
||||
ScrollUpdate::End(self.id),
|
||||
)));
|
||||
*/
|
||||
|
||||
return true;
|
||||
}
|
||||
UIEvent::Input(ref key)
|
||||
if shortcut!(key == shortcuts[Shortcuts::CONTACT_LIST]["mail_contact"]) =>
|
||||
{
|
||||
if self.length == 0 {
|
||||
return true;
|
||||
}
|
||||
let account = &context.accounts[self.account_pos];
|
||||
let account_hash = account.hash();
|
||||
let book = &account.address_book;
|
||||
let card = &book[&self.id_positions[self.cursor_pos]];
|
||||
let mut draft: Draft = Draft::default();
|
||||
*draft.headers_mut().get_mut("To").unwrap() =
|
||||
format!("{} <{}>", &card.name(), &card.email());
|
||||
let mut composer = Composer::with_account(account_hash, context);
|
||||
composer.set_draft(draft, context);
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::Action(Tab(TabAction::New(Some(Box::new(
|
||||
composer,
|
||||
))))));
|
||||
|
||||
return true;
|
||||
}
|
||||
UIEvent::Input(ref key)
|
||||
if shortcut!(key == shortcuts[Shortcuts::CONTACT_LIST]["delete_contact"]) =>
|
||||
{
|
||||
if self.length == 0 {
|
||||
return true;
|
||||
}
|
||||
// [ref:TODO]: add a confirmation dialog?
|
||||
context.accounts[self.account_pos]
|
||||
.address_book
|
||||
.remove_card(self.id_positions[self.cursor_pos]);
|
||||
self.initialized = false;
|
||||
self.set_dirty(true);
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
||||
|
||||
return true;
|
||||
}
|
||||
UIEvent::Input(ref key)
|
||||
if shortcut!(key == shortcuts[Shortcuts::CONTACT_LIST]["next_account"]) =>
|
||||
{
|
||||
let amount = if self.cmd_buf.is_empty() {
|
||||
1
|
||||
} else if let Ok(amount) = self.cmd_buf.parse::<usize>() {
|
||||
self.cmd_buf.clear();
|
||||
self.mode = ViewMode::View(manager);
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
||||
amount
|
||||
} else {
|
||||
self.cmd_buf.clear();
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
||||
return true;
|
||||
};
|
||||
if self.account_pos + amount < self.accounts.len() {
|
||||
self.account_pos += amount;
|
||||
self.set_dirty(true);
|
||||
self.initialized = false;
|
||||
self.cursor_pos = 0;
|
||||
self.new_cursor_pos = 0;
|
||||
self.length = 0;
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::UpdateStatus(
|
||||
self.status(context),
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::ScrollUpdate(
|
||||
ScrollUpdate::End(self.id),
|
||||
)));
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
UIEvent::Input(ref key)
|
||||
if shortcut!(key == shortcuts[Shortcuts::CONTACT_LIST]["prev_account"]) =>
|
||||
{
|
||||
let amount = if self.cmd_buf.is_empty() {
|
||||
1
|
||||
} else if let Ok(amount) = self.cmd_buf.parse::<usize>() {
|
||||
self.cmd_buf.clear();
|
||||
UIEvent::Input(ref key)
|
||||
if shortcut!(key == shortcuts[Shortcuts::CONTACT_LIST]["edit_contact"]) =>
|
||||
{
|
||||
if self.length == 0 {
|
||||
return true;
|
||||
}
|
||||
let account = &mut context.accounts[self.account_pos];
|
||||
let book = &mut account.address_book;
|
||||
let card = book[&self.id_positions[self.cursor_pos]].clone();
|
||||
let mut manager = Box::new(ContactManager::new(context));
|
||||
manager.set_parent_id(self.id);
|
||||
manager.card = card;
|
||||
manager.account_pos = self.account_pos;
|
||||
|
||||
self.mode = ViewMode::View(manager);
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
||||
amount
|
||||
} else {
|
||||
self.cmd_buf.clear();
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
||||
return true;
|
||||
};
|
||||
if self.accounts.is_empty() {
|
||||
return true;
|
||||
}
|
||||
if self.account_pos >= amount {
|
||||
self.account_pos -= amount;
|
||||
self.set_dirty(true);
|
||||
self.cursor_pos = 0;
|
||||
self.new_cursor_pos = 0;
|
||||
self.length = 0;
|
||||
self.initialized = false;
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::UpdateStatus(
|
||||
self.status(context),
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::ScrollUpdate(
|
||||
ScrollUpdate::End(self.id),
|
||||
)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
UIEvent::Input(ref k)
|
||||
if shortcut!(k == shortcuts[Shortcuts::CONTACT_LIST]["toggle_menu_visibility"]) =>
|
||||
{
|
||||
self.menu_visibility = !self.menu_visibility;
|
||||
self.set_dirty(true);
|
||||
}
|
||||
UIEvent::Input(Key::Esc) | UIEvent::Input(Key::Alt('')) if !self.cmd_buf.is_empty() => {
|
||||
self.cmd_buf.clear();
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
||||
return true;
|
||||
}
|
||||
UIEvent::Input(Key::Char(c)) if c.is_ascii_digit() => {
|
||||
self.cmd_buf.push(c);
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::BufSet(
|
||||
self.cmd_buf.clone(),
|
||||
)));
|
||||
return true;
|
||||
}
|
||||
UIEvent::Input(ref key)
|
||||
if shortcut!(key == shortcuts[Shortcuts::CONTACT_LIST]["scroll_up"]) =>
|
||||
{
|
||||
let amount = if self.cmd_buf.is_empty() {
|
||||
1
|
||||
} else if let Ok(amount) = self.cmd_buf.parse::<usize>() {
|
||||
self.cmd_buf.clear();
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
||||
amount
|
||||
} else {
|
||||
self.cmd_buf.clear();
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
||||
return true;
|
||||
};
|
||||
self.movement = Some(PageMovement::Up(amount));
|
||||
self.set_dirty(true);
|
||||
return true;
|
||||
}
|
||||
UIEvent::Input(ref key)
|
||||
if shortcut!(key == shortcuts[Shortcuts::CONTACT_LIST]["scroll_down"]) =>
|
||||
{
|
||||
if self.cursor_pos >= self.length.saturating_sub(1) {
|
||||
return true;
|
||||
}
|
||||
let amount = if self.cmd_buf.is_empty() {
|
||||
1
|
||||
} else if let Ok(amount) = self.cmd_buf.parse::<usize>() {
|
||||
self.cmd_buf.clear();
|
||||
UIEvent::Input(ref key)
|
||||
if shortcut!(key == shortcuts[Shortcuts::CONTACT_LIST]["mail_contact"]) =>
|
||||
{
|
||||
if self.length == 0 {
|
||||
return true;
|
||||
}
|
||||
let account = &context.accounts[self.account_pos];
|
||||
let account_hash = account.hash();
|
||||
let book = &account.address_book;
|
||||
let card = &book[&self.id_positions[self.cursor_pos]];
|
||||
let mut draft: Draft = Draft::default();
|
||||
*draft.headers_mut().get_mut("To").unwrap() =
|
||||
format!("{} <{}>", &card.name(), &card.email());
|
||||
let mut composer = Composer::with_account(account_hash, context);
|
||||
composer.set_draft(draft, context);
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::Action(Tab(TabAction::New(Some(Box::new(
|
||||
composer,
|
||||
))))));
|
||||
|
||||
return true;
|
||||
}
|
||||
UIEvent::Input(ref key)
|
||||
if shortcut!(key == shortcuts[Shortcuts::CONTACT_LIST]["delete_contact"]) =>
|
||||
{
|
||||
if self.length == 0 {
|
||||
return true;
|
||||
}
|
||||
// [ref:TODO]: add a confirmation dialog?
|
||||
context.accounts[self.account_pos]
|
||||
.address_book
|
||||
.remove_card(self.id_positions[self.cursor_pos]);
|
||||
self.initialized = false;
|
||||
self.set_dirty(true);
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
||||
amount
|
||||
} else {
|
||||
|
||||
return true;
|
||||
}
|
||||
UIEvent::Input(ref key)
|
||||
if shortcut!(key == shortcuts[Shortcuts::CONTACT_LIST]["next_account"]) =>
|
||||
{
|
||||
let amount = if self.cmd_buf.is_empty() {
|
||||
1
|
||||
} else if let Ok(amount) = self.cmd_buf.parse::<usize>() {
|
||||
self.cmd_buf.clear();
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
||||
amount
|
||||
} else {
|
||||
self.cmd_buf.clear();
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
||||
return true;
|
||||
};
|
||||
if self.account_pos + amount < self.accounts.len() {
|
||||
self.account_pos += amount;
|
||||
self.set_dirty(true);
|
||||
self.initialized = false;
|
||||
self.cursor_pos = 0;
|
||||
self.new_cursor_pos = 0;
|
||||
self.length = 0;
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::UpdateStatus(
|
||||
self.status(context),
|
||||
)));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
UIEvent::Input(ref key)
|
||||
if shortcut!(key == shortcuts[Shortcuts::CONTACT_LIST]["prev_account"]) =>
|
||||
{
|
||||
let amount = if self.cmd_buf.is_empty() {
|
||||
1
|
||||
} else if let Ok(amount) = self.cmd_buf.parse::<usize>() {
|
||||
self.cmd_buf.clear();
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
||||
amount
|
||||
} else {
|
||||
self.cmd_buf.clear();
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
||||
return true;
|
||||
};
|
||||
if self.accounts.is_empty() {
|
||||
return true;
|
||||
}
|
||||
if self.account_pos >= amount {
|
||||
self.account_pos -= amount;
|
||||
self.set_dirty(true);
|
||||
self.cursor_pos = 0;
|
||||
self.new_cursor_pos = 0;
|
||||
self.length = 0;
|
||||
self.initialized = false;
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::UpdateStatus(
|
||||
self.status(context),
|
||||
)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
UIEvent::Input(ref k)
|
||||
if shortcut!(
|
||||
k == shortcuts[Shortcuts::CONTACT_LIST]["toggle_menu_visibility"]
|
||||
) =>
|
||||
{
|
||||
self.menu_visibility = !self.menu_visibility;
|
||||
self.set_dirty(true);
|
||||
}
|
||||
UIEvent::Input(Key::Esc) | UIEvent::Input(Key::Alt(''))
|
||||
if !self.cmd_buf.is_empty() =>
|
||||
{
|
||||
self.cmd_buf.clear();
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
||||
return true;
|
||||
};
|
||||
self.set_dirty(true);
|
||||
self.movement = Some(PageMovement::Down(amount));
|
||||
return true;
|
||||
}
|
||||
UIEvent::Input(ref key)
|
||||
if shortcut!(key == shortcuts[Shortcuts::GENERAL]["prev_page"]) =>
|
||||
{
|
||||
let mult = if self.cmd_buf.is_empty() {
|
||||
1
|
||||
} else if let Ok(mult) = self.cmd_buf.parse::<usize>() {
|
||||
self.cmd_buf.clear();
|
||||
}
|
||||
UIEvent::Input(Key::Char(c)) if c.is_ascii_digit() => {
|
||||
self.cmd_buf.push(c);
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
||||
mult
|
||||
} else {
|
||||
self.cmd_buf.clear();
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::BufSet(
|
||||
self.cmd_buf.clone(),
|
||||
)));
|
||||
return true;
|
||||
};
|
||||
self.set_dirty(true);
|
||||
self.movement = Some(PageMovement::PageUp(mult));
|
||||
return true;
|
||||
}
|
||||
UIEvent::Input(ref key)
|
||||
if shortcut!(key == shortcuts[Shortcuts::GENERAL]["next_page"]) =>
|
||||
{
|
||||
let mult = if self.cmd_buf.is_empty() {
|
||||
1
|
||||
} else if let Ok(mult) = self.cmd_buf.parse::<usize>() {
|
||||
self.cmd_buf.clear();
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
||||
mult
|
||||
} else {
|
||||
self.cmd_buf.clear();
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
||||
}
|
||||
UIEvent::Input(ref key)
|
||||
if shortcut!(key == shortcuts[Shortcuts::CONTACT_LIST]["scroll_up"]) =>
|
||||
{
|
||||
let amount = if self.cmd_buf.is_empty() {
|
||||
1
|
||||
} else if let Ok(amount) = self.cmd_buf.parse::<usize>() {
|
||||
self.cmd_buf.clear();
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
||||
amount
|
||||
} else {
|
||||
self.cmd_buf.clear();
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
||||
return true;
|
||||
};
|
||||
self.movement = Some(PageMovement::Up(amount));
|
||||
self.set_dirty(true);
|
||||
return true;
|
||||
};
|
||||
self.set_dirty(true);
|
||||
self.movement = Some(PageMovement::PageDown(mult));
|
||||
return true;
|
||||
}
|
||||
UIEvent::Input(ref key)
|
||||
if shortcut!(key == shortcuts[Shortcuts::CONTACT_LIST]["scroll_down"]) =>
|
||||
{
|
||||
if self.cursor_pos >= self.length.saturating_sub(1) {
|
||||
return true;
|
||||
}
|
||||
let amount = if self.cmd_buf.is_empty() {
|
||||
1
|
||||
} else if let Ok(amount) = self.cmd_buf.parse::<usize>() {
|
||||
self.cmd_buf.clear();
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
||||
amount
|
||||
} else {
|
||||
self.cmd_buf.clear();
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
||||
return true;
|
||||
};
|
||||
self.set_dirty(true);
|
||||
self.movement = Some(PageMovement::Down(amount));
|
||||
return true;
|
||||
}
|
||||
UIEvent::Input(ref key)
|
||||
if shortcut!(key == shortcuts[Shortcuts::GENERAL]["prev_page"]) =>
|
||||
{
|
||||
let mult = if self.cmd_buf.is_empty() {
|
||||
1
|
||||
} else if let Ok(mult) = self.cmd_buf.parse::<usize>() {
|
||||
self.cmd_buf.clear();
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
||||
mult
|
||||
} else {
|
||||
self.cmd_buf.clear();
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
||||
return true;
|
||||
};
|
||||
self.set_dirty(true);
|
||||
self.movement = Some(PageMovement::PageUp(mult));
|
||||
return true;
|
||||
}
|
||||
UIEvent::Input(ref key)
|
||||
if shortcut!(key == shortcuts[Shortcuts::GENERAL]["next_page"]) =>
|
||||
{
|
||||
let mult = if self.cmd_buf.is_empty() {
|
||||
1
|
||||
} else if let Ok(mult) = self.cmd_buf.parse::<usize>() {
|
||||
self.cmd_buf.clear();
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
||||
mult
|
||||
} else {
|
||||
self.cmd_buf.clear();
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
||||
return true;
|
||||
};
|
||||
self.set_dirty(true);
|
||||
self.movement = Some(PageMovement::PageDown(mult));
|
||||
return true;
|
||||
}
|
||||
UIEvent::Input(ref key)
|
||||
if shortcut!(key == shortcuts[Shortcuts::GENERAL]["home_page"]) =>
|
||||
{
|
||||
self.set_dirty(true);
|
||||
self.movement = Some(PageMovement::Home);
|
||||
return true;
|
||||
}
|
||||
UIEvent::Input(ref key)
|
||||
if shortcut!(key == shortcuts[Shortcuts::GENERAL]["end_page"]) =>
|
||||
{
|
||||
self.set_dirty(true);
|
||||
self.movement = Some(PageMovement::End);
|
||||
return true;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
UIEvent::Input(ref key)
|
||||
if shortcut!(key == shortcuts[Shortcuts::GENERAL]["home_page"]) =>
|
||||
{
|
||||
self.set_dirty(true);
|
||||
self.movement = Some(PageMovement::Home);
|
||||
return true;
|
||||
}
|
||||
UIEvent::Input(ref key)
|
||||
if shortcut!(key == shortcuts[Shortcuts::GENERAL]["end_page"]) =>
|
||||
{
|
||||
self.set_dirty(true);
|
||||
self.movement = Some(PageMovement::End);
|
||||
return true;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
//}
|
||||
false
|
||||
}
|
||||
|
||||
fn is_dirty(&self) -> bool {
|
||||
self.dirty //|| self.view.as_ref().map(|v|
|
||||
//|| v.is_dirty()).unwrap_or(false)
|
||||
self.dirty || matches!(self.mode, ViewMode::View(ref mgr) if mgr.is_dirty())
|
||||
}
|
||||
|
||||
fn set_dirty(&mut self, value: bool) {
|
||||
//if let Some(p) = self.view.as_mut() {
|
||||
// p.set_dirty(value);
|
||||
//};
|
||||
if let ViewMode::View(ref mut mgr) = self.mode {
|
||||
mgr.set_dirty(value);
|
||||
}
|
||||
self.dirty = value;
|
||||
}
|
||||
|
||||
|
@ -876,12 +861,13 @@ impl Component for ContactList {
|
|||
.replies
|
||||
.push_back(UIEvent::Action(Tab(TabAction::Kill(uuid))));
|
||||
}
|
||||
|
||||
fn shortcuts(&self, context: &Context) -> ShortcutMaps {
|
||||
let mut map = ShortcutMaps::default(); //self
|
||||
//.view
|
||||
//.as_ref()
|
||||
//.map(|p| p.shortcuts(context))
|
||||
//.unwrap_or_default();
|
||||
let mut map = if let ViewMode::View(ref mgr) = self.mode {
|
||||
mgr.shortcuts(context)
|
||||
} else {
|
||||
ShortcutMaps::default()
|
||||
};
|
||||
|
||||
map.insert(
|
||||
Shortcuts::CONTACT_LIST,
|
||||
|
@ -899,10 +885,11 @@ impl Component for ContactList {
|
|||
self.id
|
||||
}
|
||||
|
||||
fn can_quit_cleanly(&mut self, _context: &Context) -> bool {
|
||||
fn can_quit_cleanly(&mut self, context: &Context) -> bool {
|
||||
if let ViewMode::View(ref mut mgr) = self.mode {
|
||||
return mgr.can_quit_cleanly(context);
|
||||
}
|
||||
true
|
||||
//self.view .as_mut() .map(|p| p.can_quit_cleanly(context))
|
||||
// .unwrap_or(true)
|
||||
}
|
||||
|
||||
fn status(&self, context: &Context) -> String {
|
||||
|
|
|
@ -19,6 +19,5 @@
|
|||
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
pub mod editor;
|
||||
pub mod list;
|
||||
|
||||
//pub mod editor;
|
||||
|
|
|
@ -883,152 +883,139 @@ impl Component for Composer {
|
|||
self.update_form(context);
|
||||
self.initialized = true;
|
||||
}
|
||||
let header_height = self.form.len();
|
||||
|
||||
let theme_default = crate::conf::value(context, "theme_default");
|
||||
if self.dirty {
|
||||
grid.clear_area(area, theme_default);
|
||||
}
|
||||
|
||||
let mid = 0;
|
||||
/*
|
||||
let mid = if width > 80 {
|
||||
let width = width - 80;
|
||||
let mid = width / 2;
|
||||
|
||||
if self.dirty {
|
||||
for i in get_y(upper_left)..=get_y(bottom_right) {
|
||||
//set_and_join_box(grid, (mid, i), VERT_BOUNDARY);
|
||||
grid[(mid, i)]
|
||||
.set_fg(theme_default.fg)
|
||||
.set_bg(theme_default.bg);
|
||||
//set_and_join_box(grid, (mid + 80, i), VERT_BOUNDARY);
|
||||
grid[(mid + 80, i)]
|
||||
.set_fg(theme_default.fg)
|
||||
.set_bg(theme_default.bg);
|
||||
}
|
||||
}
|
||||
mid
|
||||
} else {
|
||||
0
|
||||
};
|
||||
*/
|
||||
let header_height = self.form.len();
|
||||
|
||||
let header_area = area
|
||||
.skip_rows(1)
|
||||
.take_rows(header_height)
|
||||
.skip_cols(mid + 1)
|
||||
.skip_cols_from_end(mid);
|
||||
.skip_cols(1)
|
||||
.skip_cols_from_end(1);
|
||||
let attachments_no = self.draft.attachments().len();
|
||||
let attachment_area = area
|
||||
.skip_rows(header_height)
|
||||
.skip_rows(header_height + 1)
|
||||
.skip_rows(
|
||||
area.height()
|
||||
.saturating_sub(header_area.height() + 4 + attachments_no),
|
||||
)
|
||||
.skip_cols(mid + 1);
|
||||
.skip_cols(1)
|
||||
.skip_cols_from_end(1);
|
||||
|
||||
let body_area = area
|
||||
.skip_rows(header_height)
|
||||
.skip_rows_from_end(attachment_area.height());
|
||||
.skip_rows(header_height + 2)
|
||||
.skip_rows_from_end(attachment_area.height())
|
||||
.skip_cols(1)
|
||||
.skip_cols_from_end(1);
|
||||
|
||||
grid.clear_area(area.nth_row(0), crate::conf::value(context, "highlight"));
|
||||
grid.write_string(
|
||||
if self.reply_context.is_some() {
|
||||
"COMPOSING REPLY"
|
||||
} else {
|
||||
"COMPOSING MESSAGE"
|
||||
},
|
||||
crate::conf::value(context, "highlight").fg,
|
||||
crate::conf::value(context, "highlight").bg,
|
||||
crate::conf::value(context, "highlight").attrs,
|
||||
area.nth_row(0),
|
||||
None,
|
||||
);
|
||||
|
||||
/*
|
||||
grid.change_theme(
|
||||
(
|
||||
set_x(pos_dec(header_area.upper_left(), (0, 1)), x),
|
||||
set_y(header_area.bottom_right(), y),
|
||||
),
|
||||
crate::conf::value(context, "highlight"),
|
||||
);
|
||||
|
||||
grid.clear_area(
|
||||
(
|
||||
pos_dec(upper_left, (0, 1)),
|
||||
set_x(bottom_right, get_x(upper_left) + mid),
|
||||
),
|
||||
theme_default,
|
||||
);
|
||||
|
||||
grid.clear_area(
|
||||
(
|
||||
(
|
||||
get_x(bottom_right).saturating_sub(mid),
|
||||
get_y(upper_left).saturating_sub(1),
|
||||
),
|
||||
bottom_right,
|
||||
),
|
||||
theme_default,
|
||||
);
|
||||
*/
|
||||
if self.dirty {
|
||||
grid.clear_area(area.nth_row(0), crate::conf::value(context, "highlight"));
|
||||
grid.write_string(
|
||||
if self.reply_context.is_some() {
|
||||
"COMPOSING REPLY"
|
||||
} else {
|
||||
"COMPOSING MESSAGE"
|
||||
},
|
||||
crate::conf::value(context, "highlight").fg,
|
||||
crate::conf::value(context, "highlight").bg,
|
||||
crate::conf::value(context, "highlight").attrs,
|
||||
area.nth_row(0),
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
||||
/* Regardless of view mode, do the following */
|
||||
|
||||
if self.dirty {
|
||||
match self.cursor {
|
||||
Cursor::Headers => {
|
||||
grid.change_theme(header_area, theme_default);
|
||||
}
|
||||
Cursor::Body => {
|
||||
grid.change_theme(
|
||||
body_area,
|
||||
ThemeAttribute {
|
||||
fg: theme_default.fg,
|
||||
bg: crate::conf::value(context, "highlight").bg,
|
||||
attrs: if grid.use_color {
|
||||
crate::conf::value(context, "highlight").attrs
|
||||
} else {
|
||||
crate::conf::value(context, "highlight").attrs | Attr::REVERSE
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
Cursor::Sign | Cursor::Encrypt | Cursor::Attachments => {}
|
||||
}
|
||||
}
|
||||
|
||||
self.form.draw(grid, header_area, context);
|
||||
|
||||
if let Some(ref mut embedded) = self.embedded {
|
||||
let embed_pty = &mut embedded.status;
|
||||
let embed_area = area;
|
||||
match embed_pty {
|
||||
EmbedStatus::Running(_, _) => {
|
||||
let mut guard = embed_pty.lock().unwrap();
|
||||
grid.clear_area(embed_area, theme_default);
|
||||
if self.dirty {
|
||||
let mut guard = embed_pty.lock().unwrap();
|
||||
grid.clear_area(embed_area, theme_default);
|
||||
|
||||
grid.copy_area(guard.grid.buffer(), embed_area, guard.grid.area());
|
||||
guard.set_terminal_size((embed_area.width(), embed_area.height()));
|
||||
context.dirty_areas.push_back(area);
|
||||
self.dirty = false;
|
||||
grid.copy_area(guard.grid.buffer(), embed_area, guard.grid.area());
|
||||
guard.set_terminal_size((embed_area.width(), embed_area.height()));
|
||||
context.dirty_areas.push_back(embed_area);
|
||||
self.dirty = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
EmbedStatus::Stopped(_, _) => {
|
||||
let guard = embed_pty.lock().unwrap();
|
||||
if self.dirty {
|
||||
let guard = embed_pty.lock().unwrap();
|
||||
|
||||
grid.copy_area(guard.grid.buffer(), embed_area, guard.grid.buffer().area());
|
||||
grid.change_colors(embed_area, Color::Byte(8), theme_default.bg);
|
||||
let our_map: ShortcutMap =
|
||||
account_settings!(context[self.account_hash].shortcuts.composing)
|
||||
.key_values();
|
||||
let mut shortcuts: ShortcutMaps = Default::default();
|
||||
shortcuts.insert(Shortcuts::COMPOSING, our_map);
|
||||
let stopped_message: String =
|
||||
format!("Process with PID {} has stopped.", guard.child_pid);
|
||||
let stopped_message_2: String = format!(
|
||||
"-press '{}' (edit shortcut) to re-activate.",
|
||||
shortcuts[Shortcuts::COMPOSING]["edit"]
|
||||
);
|
||||
const STOPPED_MESSAGE_3: &str =
|
||||
"-press Ctrl-C to forcefully kill it and return to editor.";
|
||||
let max_len = std::cmp::max(
|
||||
stopped_message.len(),
|
||||
std::cmp::max(stopped_message_2.len(), STOPPED_MESSAGE_3.len()),
|
||||
);
|
||||
let inner_area = create_box(grid, area.center_inside((max_len + 5, 5)));
|
||||
grid.clear_area(inner_area, theme_default);
|
||||
for (i, l) in [
|
||||
stopped_message.as_str(),
|
||||
stopped_message_2.as_str(),
|
||||
STOPPED_MESSAGE_3,
|
||||
]
|
||||
.iter()
|
||||
.enumerate()
|
||||
{
|
||||
grid.write_string(
|
||||
l,
|
||||
theme_default.fg,
|
||||
theme_default.bg,
|
||||
theme_default.attrs,
|
||||
inner_area.skip_rows(i),
|
||||
None, //Some(get_x(inner_area.upper_left())),
|
||||
grid.copy_area(guard.grid.buffer(), embed_area, guard.grid.buffer().area());
|
||||
grid.change_colors(embed_area, Color::Byte(8), theme_default.bg);
|
||||
let our_map: ShortcutMap =
|
||||
account_settings!(context[self.account_hash].shortcuts.composing)
|
||||
.key_values();
|
||||
let mut shortcuts: ShortcutMaps = Default::default();
|
||||
shortcuts.insert(Shortcuts::COMPOSING, our_map);
|
||||
let stopped_message: String =
|
||||
format!("Process with PID {} has stopped.", guard.child_pid);
|
||||
let stopped_message_2: String = format!(
|
||||
"-press '{}' (edit shortcut) to re-activate.",
|
||||
shortcuts[Shortcuts::COMPOSING]["edit"]
|
||||
);
|
||||
const STOPPED_MESSAGE_3: &str =
|
||||
"-press Ctrl-C to forcefully kill it and return to editor.";
|
||||
let max_len = std::cmp::max(
|
||||
stopped_message.len(),
|
||||
std::cmp::max(stopped_message_2.len(), STOPPED_MESSAGE_3.len()),
|
||||
);
|
||||
let inner_area = create_box(grid, area.center_inside((max_len + 5, 5)));
|
||||
grid.clear_area(inner_area, theme_default);
|
||||
for (i, l) in [
|
||||
stopped_message.as_str(),
|
||||
stopped_message_2.as_str(),
|
||||
STOPPED_MESSAGE_3,
|
||||
]
|
||||
.iter()
|
||||
.enumerate()
|
||||
{
|
||||
grid.write_string(
|
||||
l,
|
||||
theme_default.fg,
|
||||
theme_default.bg,
|
||||
theme_default.attrs,
|
||||
inner_area.skip_rows(i),
|
||||
None,
|
||||
);
|
||||
}
|
||||
context.dirty_areas.push_back(area);
|
||||
self.dirty = false;
|
||||
}
|
||||
context.dirty_areas.push_back(area);
|
||||
self.dirty = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1039,51 +1026,13 @@ impl Component for Composer {
|
|||
if self.pager.size().0 > body_area.width() {
|
||||
self.pager.set_initialised(false);
|
||||
}
|
||||
// Force clean pager area, because if body height is less than body_area it will
|
||||
// might leave draw artifacts in the remaining area.
|
||||
grid.clear_area(body_area, theme_default);
|
||||
self.set_dirty(true);
|
||||
self.pager.draw(grid, body_area, context);
|
||||
|
||||
match self.cursor {
|
||||
Cursor::Headers => {
|
||||
/*
|
||||
grid.change_theme(
|
||||
(
|
||||
pos_dec(body_area.upper_left(), (1, 0)),
|
||||
pos_dec(
|
||||
set_y(body_area.upper_left(), get_y(body_area.bottom_right())),
|
||||
(1, 0),
|
||||
),
|
||||
),
|
||||
theme_default,
|
||||
);
|
||||
*/
|
||||
}
|
||||
Cursor::Body => {
|
||||
/*
|
||||
grid.change_theme(
|
||||
(
|
||||
pos_dec(body_area.upper_left(), (1, 0)),
|
||||
pos_dec(
|
||||
set_y(body_area.upper_left(), get_y(body_area.bottom_right())),
|
||||
(1, 0),
|
||||
),
|
||||
),
|
||||
ThemeAttribute {
|
||||
fg: theme_default.fg,
|
||||
bg: crate::conf::value(context, "highlight").bg,
|
||||
attrs: if grid.use_color {
|
||||
crate::conf::value(context, "highlight").attrs
|
||||
} else {
|
||||
crate::conf::value(context, "highlight").attrs | Attr::REVERSE
|
||||
},
|
||||
},
|
||||
);
|
||||
*/
|
||||
}
|
||||
Cursor::Sign | Cursor::Encrypt | Cursor::Attachments => {}
|
||||
if self.dirty {
|
||||
// Force clean pager area, because if body height is less than body_area it will
|
||||
// might leave draw artifacts in the remaining area.
|
||||
grid.clear_area(body_area, theme_default);
|
||||
self.pager.set_dirty(true);
|
||||
}
|
||||
self.pager.draw(grid, body_area, context);
|
||||
|
||||
//if !self.mode.is_edit_attachments() {
|
||||
self.draw_attachments(grid, attachment_area, context);
|
||||
|
@ -1125,8 +1074,11 @@ impl Component for Composer {
|
|||
s.draw(grid, body_area, context);
|
||||
}
|
||||
}
|
||||
self.dirty = false;
|
||||
context.dirty_areas.push_back(area);
|
||||
|
||||
if self.dirty {
|
||||
self.dirty = false;
|
||||
context.dirty_areas.push_back(area);
|
||||
}
|
||||
}
|
||||
|
||||
fn process_event(&mut self, mut event: &mut UIEvent, context: &mut Context) -> bool {
|
||||
|
|
|
@ -154,7 +154,6 @@ pub enum UIEvent {
|
|||
Contacts(ContactEvent),
|
||||
Compose(ComposeEvent),
|
||||
FinishedUIDialog(ComponentId, UIMessage),
|
||||
CanceledUIDialog(ComponentId),
|
||||
IntraComm {
|
||||
from: ComponentId,
|
||||
to: ComponentId,
|
||||
|
|
|
@ -21,11 +21,9 @@
|
|||
|
||||
use super::*;
|
||||
|
||||
const OK_CANCEL: &str = "OK Cancel";
|
||||
const OK_OFFSET: usize = 0;
|
||||
const OK_LENGTH: usize = "OK".len();
|
||||
const OK: &str = "OK";
|
||||
const CANCEL: &str = "Cancel";
|
||||
const CANCEL_OFFSET: usize = "OK ".len();
|
||||
const CANCEL_LENGTH: usize = "Cancel".len();
|
||||
|
||||
#[derive(Debug, Copy, PartialEq, Eq, Clone)]
|
||||
enum SelectorCursor {
|
||||
|
@ -114,10 +112,6 @@ impl<T: 'static + PartialEq + std::fmt::Debug + Clone + Sync + Send> Component f
|
|||
}
|
||||
|
||||
let shortcuts = self.shortcuts(context);
|
||||
let mut highlighted_attrs = crate::conf::value(context, "widgets.options.highlighted");
|
||||
if !context.settings.terminal.use_color() {
|
||||
highlighted_attrs.attrs |= Attr::REVERSE;
|
||||
}
|
||||
match (event, self.cursor) {
|
||||
(UIEvent::Input(Key::Char('\n')), _) if self.single_only => {
|
||||
/* User can only select one entry, so Enter key finalises the selection */
|
||||
|
@ -152,8 +146,8 @@ impl<T: 'static + PartialEq + std::fmt::Debug + Clone + Sync + Send> Component f
|
|||
}
|
||||
self.done = true;
|
||||
_ = self.done();
|
||||
context.replies.push_back(self.cancel());
|
||||
|
||||
self.cancel(context);
|
||||
self.set_dirty(true);
|
||||
return false;
|
||||
}
|
||||
(UIEvent::Input(Key::Char('\n')), SelectorCursor::Cancel) if !self.single_only => {
|
||||
|
@ -211,26 +205,26 @@ impl<T: 'static + PartialEq + std::fmt::Debug + Clone + Sync + Send> Component f
|
|||
self.dirty = true;
|
||||
return true;
|
||||
}
|
||||
(UIEvent::Input(ref key), SelectorCursor::Entry(c))
|
||||
(UIEvent::Input(ref key), SelectorCursor::Entry(_))
|
||||
if !self.single_only
|
||||
&& shortcut!(key == shortcuts[Shortcuts::GENERAL]["scroll_down"]) =>
|
||||
{
|
||||
self.cursor = SelectorCursor::Ok;
|
||||
self.dirty = true;
|
||||
self.set_dirty(true);
|
||||
return true;
|
||||
}
|
||||
(UIEvent::Input(ref key), SelectorCursor::Ok)
|
||||
if shortcut!(key == shortcuts[Shortcuts::GENERAL]["scroll_right"]) =>
|
||||
{
|
||||
self.cursor = SelectorCursor::Cancel;
|
||||
self.dirty = true;
|
||||
self.set_dirty(true);
|
||||
return true;
|
||||
}
|
||||
(UIEvent::Input(ref key), SelectorCursor::Cancel)
|
||||
if shortcut!(key == shortcuts[Shortcuts::GENERAL]["scroll_left"]) =>
|
||||
{
|
||||
self.cursor = SelectorCursor::Ok;
|
||||
self.dirty = true;
|
||||
self.set_dirty(true);
|
||||
return true;
|
||||
}
|
||||
(UIEvent::Input(ref key), _)
|
||||
|
@ -282,10 +276,6 @@ impl Component for UIConfirmationDialog {
|
|||
}
|
||||
|
||||
let shortcuts = self.shortcuts(context);
|
||||
let mut highlighted_attrs = crate::conf::value(context, "widgets.options.highlighted");
|
||||
if !context.settings.terminal.use_color() {
|
||||
highlighted_attrs.attrs |= Attr::REVERSE;
|
||||
}
|
||||
match (event, self.cursor) {
|
||||
(UIEvent::Input(Key::Char('\n')), _) if self.single_only => {
|
||||
/* User can only select one entry, so Enter key finalises the selection */
|
||||
|
@ -294,13 +284,14 @@ impl Component for UIConfirmationDialog {
|
|||
context.replies.push_back(event);
|
||||
self.unrealize(context);
|
||||
}
|
||||
self.set_dirty(true);
|
||||
return true;
|
||||
}
|
||||
(UIEvent::Input(Key::Char('\n')), SelectorCursor::Entry(c)) if !self.single_only => {
|
||||
/* User can select multiple entries, so Enter key toggles the entry under the
|
||||
* cursor */
|
||||
self.entries[c].1 = !self.entries[c].1;
|
||||
self.dirty = true;
|
||||
self.set_dirty(true);
|
||||
return true;
|
||||
}
|
||||
(UIEvent::Input(Key::Char('\n')), SelectorCursor::Ok) if !self.single_only => {
|
||||
|
@ -309,6 +300,7 @@ impl Component for UIConfirmationDialog {
|
|||
context.replies.push_back(event);
|
||||
self.unrealize(context);
|
||||
}
|
||||
self.set_dirty(true);
|
||||
return true;
|
||||
}
|
||||
(UIEvent::Input(Key::Esc), _) => {
|
||||
|
@ -320,8 +312,8 @@ impl Component for UIConfirmationDialog {
|
|||
}
|
||||
self.done = true;
|
||||
_ = self.done();
|
||||
context.replies.push_back(self.cancel());
|
||||
|
||||
self.cancel(context);
|
||||
self.set_dirty(true);
|
||||
return false;
|
||||
}
|
||||
(UIEvent::Input(Key::Char('\n')), SelectorCursor::Cancel) if !self.single_only => {
|
||||
|
@ -333,6 +325,7 @@ impl Component for UIConfirmationDialog {
|
|||
context.replies.push_back(event);
|
||||
self.unrealize(context);
|
||||
}
|
||||
self.set_dirty(true);
|
||||
return true;
|
||||
}
|
||||
(UIEvent::Input(ref key), SelectorCursor::Entry(c))
|
||||
|
@ -344,7 +337,7 @@ impl Component for UIConfirmationDialog {
|
|||
self.entries[c - 1].1 = true;
|
||||
}
|
||||
self.cursor = SelectorCursor::Entry(c - 1);
|
||||
self.dirty = true;
|
||||
self.set_dirty(true);
|
||||
return true;
|
||||
}
|
||||
(UIEvent::Input(ref key), SelectorCursor::Ok)
|
||||
|
@ -353,7 +346,7 @@ impl Component for UIConfirmationDialog {
|
|||
{
|
||||
let c = self.entries.len().saturating_sub(1);
|
||||
self.cursor = SelectorCursor::Entry(c);
|
||||
self.dirty = true;
|
||||
self.set_dirty(true);
|
||||
return true;
|
||||
}
|
||||
(UIEvent::Input(ref key), SelectorCursor::Unfocused)
|
||||
|
@ -363,7 +356,7 @@ impl Component for UIConfirmationDialog {
|
|||
self.entries[0].1 = true;
|
||||
}
|
||||
self.cursor = SelectorCursor::Entry(0);
|
||||
self.dirty = true;
|
||||
self.set_dirty(true);
|
||||
return true;
|
||||
}
|
||||
(UIEvent::Input(ref key), SelectorCursor::Entry(c))
|
||||
|
@ -376,29 +369,29 @@ impl Component for UIConfirmationDialog {
|
|||
self.entries[c + 1].1 = true;
|
||||
}
|
||||
self.cursor = SelectorCursor::Entry(c + 1);
|
||||
self.dirty = true;
|
||||
self.set_dirty(true);
|
||||
return true;
|
||||
}
|
||||
(UIEvent::Input(ref key), SelectorCursor::Entry(c))
|
||||
(UIEvent::Input(ref key), SelectorCursor::Entry(_))
|
||||
if !self.single_only
|
||||
&& shortcut!(key == shortcuts[Shortcuts::GENERAL]["scroll_down"]) =>
|
||||
{
|
||||
self.cursor = SelectorCursor::Ok;
|
||||
self.dirty = true;
|
||||
self.set_dirty(true);
|
||||
return true;
|
||||
}
|
||||
(UIEvent::Input(ref key), SelectorCursor::Ok)
|
||||
if shortcut!(key == shortcuts[Shortcuts::GENERAL]["scroll_right"]) =>
|
||||
{
|
||||
self.cursor = SelectorCursor::Cancel;
|
||||
self.dirty = true;
|
||||
self.set_dirty(true);
|
||||
return true;
|
||||
}
|
||||
(UIEvent::Input(ref key), SelectorCursor::Cancel)
|
||||
if shortcut!(key == shortcuts[Shortcuts::GENERAL]["scroll_left"]) =>
|
||||
{
|
||||
self.cursor = SelectorCursor::Ok;
|
||||
self.dirty = true;
|
||||
self.set_dirty(true);
|
||||
return true;
|
||||
}
|
||||
(UIEvent::Input(ref key), _)
|
||||
|
@ -493,6 +486,11 @@ impl<T: PartialEq + std::fmt::Debug + Clone + Sync + Send, F: 'static + Sync + S
|
|||
}
|
||||
|
||||
fn draw(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) {
|
||||
let mut highlighted_attrs = crate::conf::value(context, "widgets.options.highlighted");
|
||||
if !context.settings.terminal.use_color() {
|
||||
highlighted_attrs.attrs |= Attr::REVERSE;
|
||||
}
|
||||
|
||||
let shortcuts = context.settings.shortcuts.general.key_values();
|
||||
let navigate_help_string = format!(
|
||||
"Navigate options with {} to go down, {} to go up, select with {}",
|
||||
|
@ -504,10 +502,11 @@ impl<T: PartialEq + std::fmt::Debug + Clone + Sync + Send, F: 'static + Sync + S
|
|||
self.entry_titles.iter().map(|e| e.len()).max().unwrap_or(0) + 3,
|
||||
std::cmp::max(self.title.len(), navigate_help_string.len()) + 3,
|
||||
) + 3;
|
||||
let height = self.entries.len() + {
|
||||
/* padding */
|
||||
3
|
||||
};
|
||||
let height = self.entries.len()
|
||||
// padding
|
||||
+ 3
|
||||
// buttons row
|
||||
+ if self.single_only { 1 } else { 5 };
|
||||
let dialog_area = area.align_inside(
|
||||
(width, height),
|
||||
self.horizontal_alignment,
|
||||
|
@ -535,54 +534,57 @@ impl<T: PartialEq + std::fmt::Debug + Clone + Sync + Send, F: 'static + Sync + S
|
|||
);
|
||||
|
||||
let inner_area = inner_area.skip_cols(1).skip_rows(1);
|
||||
let width = std::cmp::max(
|
||||
OK_CANCEL.len(),
|
||||
std::cmp::max(
|
||||
self.entry_titles
|
||||
.iter()
|
||||
.max_by_key(|e| e.len())
|
||||
.map(|v| v.len())
|
||||
.unwrap_or(0),
|
||||
self.title.len(),
|
||||
),
|
||||
) + 5;
|
||||
let height = self.entries.len()
|
||||
+ if self.single_only {
|
||||
0
|
||||
} else {
|
||||
/* Extra room for buttons Okay/Cancel */
|
||||
2
|
||||
};
|
||||
/* Extra room for buttons Okay/Cancel */
|
||||
if self.single_only {
|
||||
for (i, e) in self.entry_titles.iter().enumerate() {
|
||||
grid.write_string(
|
||||
e,
|
||||
self.theme_default.fg,
|
||||
self.theme_default.bg,
|
||||
self.theme_default.attrs,
|
||||
inner_area.nth_row(i),
|
||||
None,
|
||||
);
|
||||
let attr = if matches!(self.cursor, SelectorCursor::Entry(e) if e == i) {
|
||||
highlighted_attrs
|
||||
} else {
|
||||
self.theme_default
|
||||
};
|
||||
grid.write_string(e, attr.fg, attr.bg, attr.attrs, inner_area.nth_row(i), None);
|
||||
}
|
||||
} else {
|
||||
for (i, e) in self.entry_titles.iter().enumerate() {
|
||||
let attr = if matches!(self.cursor, SelectorCursor::Entry(e) if e == i) {
|
||||
highlighted_attrs
|
||||
} else {
|
||||
self.theme_default
|
||||
};
|
||||
grid.write_string(
|
||||
&format!("[{}] {}", if self.entries[i].1 { "x" } else { " " }, e),
|
||||
self.theme_default.fg,
|
||||
self.theme_default.bg,
|
||||
self.theme_default.attrs,
|
||||
attr.fg,
|
||||
attr.bg,
|
||||
attr.attrs,
|
||||
inner_area.nth_row(i),
|
||||
None,
|
||||
);
|
||||
}
|
||||
let inner_area = inner_area.nth_row(self.entry_titles.len() + 2).skip_cols(2);
|
||||
let attr = if matches!(self.cursor, SelectorCursor::Ok) {
|
||||
highlighted_attrs
|
||||
} else {
|
||||
self.theme_default
|
||||
};
|
||||
let (x, y) = grid.write_string(
|
||||
OK,
|
||||
attr.fg,
|
||||
attr.bg,
|
||||
attr.attrs | Attr::BOLD,
|
||||
inner_area,
|
||||
None,
|
||||
);
|
||||
let attr = if matches!(self.cursor, SelectorCursor::Cancel) {
|
||||
highlighted_attrs
|
||||
} else {
|
||||
self.theme_default
|
||||
};
|
||||
grid.write_string(
|
||||
OK_CANCEL,
|
||||
self.theme_default.fg,
|
||||
self.theme_default.bg,
|
||||
self.theme_default.attrs | Attr::BOLD,
|
||||
inner_area
|
||||
.nth_row(height - 1)
|
||||
.skip_cols((width - OK_CANCEL.len()) / 2),
|
||||
CANCEL,
|
||||
attr.fg,
|
||||
attr.bg,
|
||||
attr.attrs,
|
||||
inner_area.skip(CANCEL_OFFSET + x, y),
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
@ -613,9 +615,11 @@ impl<T: 'static + PartialEq + std::fmt::Debug + Clone + Sync + Send> UIDialog<T>
|
|||
})
|
||||
}
|
||||
|
||||
fn cancel(&mut self) -> UIEvent {
|
||||
let Self { ref id, .. } = self;
|
||||
UIEvent::CanceledUIDialog(*id)
|
||||
fn cancel(&mut self, context: &mut Context) {
|
||||
context.unrealized.insert(self.id());
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::ComponentUnrealize(self.id()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -640,8 +644,10 @@ impl UIConfirmationDialog {
|
|||
})
|
||||
}
|
||||
|
||||
fn cancel(&mut self) -> UIEvent {
|
||||
let Self { ref id, .. } = self;
|
||||
UIEvent::CanceledUIDialog(*id)
|
||||
fn cancel(&mut self, context: &mut Context) {
|
||||
context.unrealized.insert(self.id());
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::ComponentUnrealize(self.id()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ use std::{borrow::Cow, collections::HashMap, time::Duration};
|
|||
use super::*;
|
||||
use crate::melib::text_processing::TextProcessing;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Default)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
|
||||
enum FormFocus {
|
||||
#[default]
|
||||
Fields,
|
||||
|
@ -350,17 +350,27 @@ impl<T: 'static + std::fmt::Debug + Copy + Default + Send + Sync> Component for
|
|||
if self.is_dirty() {
|
||||
let theme_default = crate::conf::value(context, "theme_default");
|
||||
|
||||
grid.clear_area(area.take_rows(self.layout.len()), theme_default);
|
||||
grid.clear_area(area, theme_default);
|
||||
let label_attrs = crate::conf::value(context, "widgets.form.label");
|
||||
let mut highlighted = crate::conf::value(context, "highlight");
|
||||
if !context.settings.terminal.use_color() {
|
||||
highlighted.attrs |= Attr::REVERSE;
|
||||
}
|
||||
|
||||
for (i, k) in self.layout.iter().enumerate().rev() {
|
||||
let theme_attr = if i == self.cursor && self.focus == FormFocus::Fields {
|
||||
grid.change_theme(area.nth_row(i), highlighted);
|
||||
highlighted
|
||||
} else {
|
||||
label_attrs
|
||||
};
|
||||
let v = self.fields.get_mut(k).unwrap();
|
||||
/* Write field label */
|
||||
grid.write_string(
|
||||
k.as_ref(),
|
||||
label_attrs.fg,
|
||||
label_attrs.bg,
|
||||
label_attrs.attrs,
|
||||
theme_attr.fg,
|
||||
theme_attr.bg,
|
||||
theme_attr.attrs,
|
||||
area.nth_row(i).skip_cols(1),
|
||||
None,
|
||||
);
|
||||
|
@ -370,47 +380,28 @@ impl<T: 'static + std::fmt::Debug + Copy + Default + Send + Sync> Component for
|
|||
area.nth_row(i).skip_cols(self.field_name_max_length + 3),
|
||||
context,
|
||||
);
|
||||
grid.change_theme(area.nth_row(i), theme_attr);
|
||||
|
||||
/* Highlight if necessary */
|
||||
if i == self.cursor {
|
||||
if self.focus == FormFocus::Fields {
|
||||
let mut field_attrs =
|
||||
crate::conf::value(context, "widgets.form.highlighted");
|
||||
if !context.settings.terminal.use_color() {
|
||||
field_attrs.attrs |= Attr::REVERSE;
|
||||
}
|
||||
for row in grid
|
||||
.bounds_iter(area.nth_row(i).take_cols(area.width().saturating_sub(1)))
|
||||
{
|
||||
for c in row {
|
||||
grid[c]
|
||||
.set_fg(field_attrs.fg)
|
||||
.set_bg(field_attrs.bg)
|
||||
.set_attrs(field_attrs.attrs);
|
||||
}
|
||||
}
|
||||
}
|
||||
if self.focus == FormFocus::TextInput {
|
||||
v.draw_cursor(
|
||||
grid,
|
||||
area.nth_row(i).skip_cols(self.field_name_max_length + 3),
|
||||
area.nth_row(i + 1)
|
||||
.skip_cols(self.field_name_max_length + 3),
|
||||
context,
|
||||
);
|
||||
}
|
||||
if i == self.cursor && self.focus == FormFocus::TextInput {
|
||||
v.draw_cursor(
|
||||
grid,
|
||||
area.nth_row(i).skip_cols(self.field_name_max_length + 3),
|
||||
area.nth_row(i + 1)
|
||||
.skip_cols(self.field_name_max_length + 3),
|
||||
context,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let length = self.layout.len();
|
||||
|
||||
grid.clear_area(area.skip_rows(length).take_rows(length + 2), theme_default);
|
||||
if !self.hide_buttons {
|
||||
self.buttons
|
||||
.draw(grid, area.nth_row(length + 3).skip_cols(1), context);
|
||||
.draw(grid, area.skip_rows(length + 3).skip_cols(1), context);
|
||||
}
|
||||
if length + 4 < area.height() {
|
||||
grid.clear_area(area.skip_rows(length + 3), theme_default);
|
||||
grid.clear_area(area.skip_rows(length + 3 + 1), theme_default);
|
||||
}
|
||||
self.set_dirty(false);
|
||||
context.dirty_areas.push_back(area);
|
||||
|
@ -623,7 +614,7 @@ where
|
|||
theme_default.bg
|
||||
},
|
||||
Attr::BOLD,
|
||||
area.skip_cols(len).take_cols(cur_len + len),
|
||||
area.skip_cols(len),
|
||||
None,
|
||||
);
|
||||
len += cur_len + 3;
|
||||
|
|
Loading…
Reference in New Issue