Implement structured desktop entry viewer
This commit is contained in:
@@ -12,14 +12,25 @@ use ironstorage::{
|
||||
pub struct EntryEditor {
|
||||
document: EntryDocument,
|
||||
revealed: BTreeSet<EntryFieldId>,
|
||||
focused: Option<EntryFieldId>,
|
||||
dirty: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum FieldNavigation {
|
||||
First,
|
||||
Last,
|
||||
Next,
|
||||
Previous,
|
||||
}
|
||||
|
||||
impl EntryEditor {
|
||||
pub fn new(document: EntryDocument) -> Self {
|
||||
let focused = document.fields().first().map(EntryField::id);
|
||||
Self {
|
||||
document,
|
||||
revealed: BTreeSet::new(),
|
||||
focused,
|
||||
dirty: false,
|
||||
}
|
||||
}
|
||||
@@ -44,6 +55,44 @@ impl EntryEditor {
|
||||
self.revealed.contains(&id)
|
||||
}
|
||||
|
||||
pub fn focused(&self) -> Option<EntryFieldId> {
|
||||
self.focused
|
||||
}
|
||||
|
||||
pub fn focused_ratio(&self) -> f32 {
|
||||
let fields = self.document.fields();
|
||||
self.focused
|
||||
.and_then(|id| fields.iter().position(|field| field.id() == id))
|
||||
.map_or(0.0, |index| {
|
||||
index as f32 / fields.len().saturating_sub(1).max(1) as f32
|
||||
})
|
||||
}
|
||||
|
||||
pub fn select(&mut self, id: EntryFieldId) {
|
||||
if self.document.field(id).is_some() {
|
||||
self.focused = Some(id);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn navigate(&mut self, navigation: FieldNavigation) {
|
||||
let fields = self.document.fields();
|
||||
if fields.is_empty() {
|
||||
self.focused = None;
|
||||
return;
|
||||
}
|
||||
let current = self
|
||||
.focused
|
||||
.and_then(|id| fields.iter().position(|field| field.id() == id))
|
||||
.unwrap_or(0);
|
||||
let index = match navigation {
|
||||
FieldNavigation::First => 0,
|
||||
FieldNavigation::Last => fields.len() - 1,
|
||||
FieldNavigation::Next => (current + 1).min(fields.len() - 1),
|
||||
FieldNavigation::Previous => current.saturating_sub(1),
|
||||
};
|
||||
self.focused = Some(fields[index].id());
|
||||
}
|
||||
|
||||
pub fn toggle_reveal(&mut self, id: EntryFieldId) -> Result<(), DocumentError> {
|
||||
let field = self
|
||||
.document
|
||||
@@ -81,14 +130,27 @@ impl EntryEditor {
|
||||
.position(|field| field.id() == id)
|
||||
})
|
||||
.map_or(self.document.fields().len(), |index| index + 1);
|
||||
self.document.add(index, EntryFieldDraft::blank())?;
|
||||
self.focused = Some(self.document.add(index, EntryFieldDraft::blank())?);
|
||||
self.dirty = true;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, id: EntryFieldId) -> Result<(), DocumentError> {
|
||||
let index = self
|
||||
.document
|
||||
.fields()
|
||||
.iter()
|
||||
.position(|field| field.id() == id)
|
||||
.ok_or(DocumentError::UnknownField { id })?;
|
||||
self.document.remove(id)?;
|
||||
self.revealed.remove(&id);
|
||||
if self.focused == Some(id) {
|
||||
self.focused = self
|
||||
.document
|
||||
.fields()
|
||||
.get(index.min(self.document.fields().len().saturating_sub(1)))
|
||||
.map(EntryField::id);
|
||||
}
|
||||
self.dirty = true;
|
||||
Ok(())
|
||||
}
|
||||
@@ -148,6 +210,7 @@ impl fmt::Debug for EntryEditor {
|
||||
.debug_struct("EntryEditor")
|
||||
.field("document", &self.document)
|
||||
.field("revealed", &self.revealed)
|
||||
.field("focused", &self.focused)
|
||||
.field("dirty", &self.dirty)
|
||||
.finish()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user