Try out different autosuggestion methods
This commit is contained in:
parent
e0feae0546
commit
c3e5db6889
32
src/ui/autosuggestion_element.rs
Normal file
32
src/ui/autosuggestion_element.rs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
use gtk::prelude::*;
|
||||||
|
use relm4::prelude::*;
|
||||||
|
|
||||||
|
pub struct AutosuggestionElementModel {
|
||||||
|
pub label: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[relm4::factory(pub)]
|
||||||
|
impl FactoryComponent for AutosuggestionElementModel {
|
||||||
|
type Init = String;
|
||||||
|
type ParentWidget = gtk::ListBox;
|
||||||
|
type CommandOutput = ();
|
||||||
|
type Input = ();
|
||||||
|
type Output = ();
|
||||||
|
|
||||||
|
view! {
|
||||||
|
#[root]
|
||||||
|
gtk::ListBoxRow {
|
||||||
|
gtk::Label {
|
||||||
|
set_label: &self.label,
|
||||||
|
set_halign: gtk::Align::Start,
|
||||||
|
set_margin_all: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_model(label: Self::Init, _index: &DynamicIndex, _sender: FactorySender<Self>) -> Self {
|
||||||
|
AutosuggestionElementModel { label }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, msg: Self::Input, _sender: FactorySender<Self>) {}
|
||||||
|
}
|
104
src/ui/autosuggestion_popover.rs
Normal file
104
src/ui/autosuggestion_popover.rs
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
use gtk::prelude::*;
|
||||||
|
|
||||||
|
use relm4::component::{AsyncComponent, AsyncComponentParts};
|
||||||
|
use relm4::factory::FactoryVecDeque;
|
||||||
|
use relm4::gtk;
|
||||||
|
use relm4::{AsyncComponentSender, RelmListBoxExt};
|
||||||
|
|
||||||
|
use super::autosuggestion_element::AutosuggestionElementModel;
|
||||||
|
|
||||||
|
pub struct AutosuggestionPopoverModel {
|
||||||
|
hidden: bool,
|
||||||
|
suggestions: Vec<String>,
|
||||||
|
suggestion_rows: FactoryVecDeque<AutosuggestionElementModel>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum AutosuggestionPopoverInput {
|
||||||
|
Show,
|
||||||
|
Hide,
|
||||||
|
SetSuggestions(Vec<String>),
|
||||||
|
SuggestionIndexSelected(i32),
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum AutosuggestionPopoverOutput {
|
||||||
|
SuggestionSelected(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[relm4::component(pub, async)]
|
||||||
|
impl AsyncComponent for AutosuggestionPopoverModel {
|
||||||
|
type Init = ();
|
||||||
|
type Input = AutosuggestionPopoverInput;
|
||||||
|
type Output = AutosuggestionPopoverOutput;
|
||||||
|
type CommandOutput = ();
|
||||||
|
|
||||||
|
view! {
|
||||||
|
gtk::Popover {
|
||||||
|
#[watch]
|
||||||
|
set_visible: !model.hidden,
|
||||||
|
set_has_arrow: false,
|
||||||
|
model.suggestion_rows.widget() -> &relm4::gtk::ListBox {
|
||||||
|
set_hexpand: true,
|
||||||
|
// set_orientation: gtk::Orientation::Vertical,
|
||||||
|
// set_spacing: 5,
|
||||||
|
connect_row_activated[sender] => move |list_box, row| {
|
||||||
|
let index = list_box.index_of_child(row).unwrap();
|
||||||
|
sender.input(AutosuggestionPopoverInput::SuggestionIndexSelected(index));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn init(
|
||||||
|
_params: Self::Init,
|
||||||
|
root: Self::Root,
|
||||||
|
sender: AsyncComponentSender<Self>,
|
||||||
|
) -> AsyncComponentParts<Self> {
|
||||||
|
let suggestion_rows = FactoryVecDeque::builder()
|
||||||
|
.launch(gtk::ListBox::default())
|
||||||
|
.forward(sender.input_sender(), |_| AutosuggestionPopoverInput::None);
|
||||||
|
|
||||||
|
let model = AutosuggestionPopoverModel {
|
||||||
|
hidden: true,
|
||||||
|
suggestions: Vec::new(),
|
||||||
|
suggestion_rows,
|
||||||
|
};
|
||||||
|
let widgets = view_output!();
|
||||||
|
|
||||||
|
AsyncComponentParts { model, widgets }
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: init_loading_widgets
|
||||||
|
|
||||||
|
async fn update(
|
||||||
|
&mut self,
|
||||||
|
msg: Self::Input,
|
||||||
|
_sender: AsyncComponentSender<Self>,
|
||||||
|
_root: &Self::Root,
|
||||||
|
) {
|
||||||
|
match msg {
|
||||||
|
AutosuggestionPopoverInput::Show => self.hidden = false,
|
||||||
|
AutosuggestionPopoverInput::Hide => self.hidden = true,
|
||||||
|
AutosuggestionPopoverInput::SetSuggestions(suggestions) => {
|
||||||
|
self.suggestion_rows.guard().clear();
|
||||||
|
for suggestion in suggestions.iter() {
|
||||||
|
self.suggestion_rows
|
||||||
|
.guard()
|
||||||
|
.push_back(suggestion.to_string());
|
||||||
|
}
|
||||||
|
self.suggestions = suggestions;
|
||||||
|
}
|
||||||
|
AutosuggestionPopoverInput::None => {}
|
||||||
|
AutosuggestionPopoverInput::SuggestionIndexSelected(index) => {
|
||||||
|
let suggestion = self.suggestions.get(index as usize).unwrap();
|
||||||
|
_sender
|
||||||
|
.output(AutosuggestionPopoverOutput::SuggestionSelected(
|
||||||
|
suggestion.to_string(),
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,6 @@
|
|||||||
pub mod app;
|
pub mod app;
|
||||||
|
pub mod autosuggestion_element;
|
||||||
|
pub mod autosuggestion_popover;
|
||||||
pub mod mcdu;
|
pub mod mcdu;
|
||||||
pub mod sheet_edit_dialog;
|
pub mod sheet_edit_dialog;
|
||||||
pub mod sheet_listing;
|
pub mod sheet_listing;
|
||||||
|
@ -3,7 +3,11 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use relm4::{
|
use relm4::{
|
||||||
component::{AsyncComponent, AsyncComponentParts, Connector},
|
component::{AsyncComponent, AsyncComponentParts, Connector},
|
||||||
gtk::EntryBuffer,
|
gtk::{
|
||||||
|
gio::ListStore,
|
||||||
|
glib::{self, GString, Type, Value},
|
||||||
|
EntryBuffer, EntryCompletion,
|
||||||
|
},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
AsyncComponentSender,
|
AsyncComponentSender,
|
||||||
};
|
};
|
||||||
@ -11,15 +15,19 @@ use relm4_components::alert::{Alert, AlertMsg, AlertSettings};
|
|||||||
|
|
||||||
use crate::{database::Database, sheet::Sheet, sheet_dao};
|
use crate::{database::Database, sheet::Sheet, sheet_dao};
|
||||||
|
|
||||||
|
use super::autosuggestion_popover::{AutosuggestionPopoverInput, AutosuggestionPopoverModel};
|
||||||
|
|
||||||
pub struct SheetEditDialogModel {
|
pub struct SheetEditDialogModel {
|
||||||
database: Arc<Database>,
|
database: Arc<Database>,
|
||||||
hidden: bool,
|
hidden: bool,
|
||||||
sheet: Option<Sheet>,
|
sheet: Option<Sheet>,
|
||||||
name_entry_buffer: EntryBuffer,
|
name_entry_buffer: EntryBuffer,
|
||||||
composer_entry_buffer: EntryBuffer,
|
composer_entry_buffer: EntryBuffer,
|
||||||
|
composer_entry_completion: EntryCompletion,
|
||||||
is_book: bool,
|
is_book: bool,
|
||||||
book_sheets: Vec<(String, String, i64)>,
|
book_sheets: Vec<(String, String, i64)>,
|
||||||
alert_empty_fields: Connector<Alert>,
|
alert_empty_fields: Connector<Alert>,
|
||||||
|
autosuggestion_popover: AsyncController<AutosuggestionPopoverModel>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SheetEditDialogInit {
|
pub struct SheetEditDialogInit {
|
||||||
@ -31,6 +39,8 @@ pub struct SheetEditDialogInit {
|
|||||||
pub enum SheetEditDialogInput {
|
pub enum SheetEditDialogInput {
|
||||||
Accept,
|
Accept,
|
||||||
Cancel,
|
Cancel,
|
||||||
|
ComposerTextChanged(String),
|
||||||
|
ComposerSuggestionSelected(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -74,7 +84,9 @@ impl AsyncComponent for SheetEditDialogModel {
|
|||||||
},
|
},
|
||||||
gtk::Entry {
|
gtk::Entry {
|
||||||
set_buffer: &model.composer_entry_buffer,
|
set_buffer: &model.composer_entry_buffer,
|
||||||
|
set_completion: Some(&model.composer_entry_completion),
|
||||||
set_hexpand: true,
|
set_hexpand: true,
|
||||||
|
connect_changed[sender] => move |entry| sender.input(SheetEditDialogInput::ComposerTextChanged(entry.text().to_string())),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
gtk::Box {
|
gtk::Box {
|
||||||
@ -103,7 +115,8 @@ impl AsyncComponent for SheetEditDialogModel {
|
|||||||
set_label : "Confirm",
|
set_label : "Confirm",
|
||||||
connect_clicked[sender] => move |_| sender.input(SheetEditDialogInput::Accept)
|
connect_clicked[sender] => move |_| sender.input(SheetEditDialogInput::Accept)
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
|
// model.autosuggestion_popover.widget(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -148,12 +161,39 @@ impl AsyncComponent for SheetEditDialogModel {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let composer_entry_completion = EntryCompletion::new();
|
||||||
|
let data = [
|
||||||
|
"France".to_string(),
|
||||||
|
"Italy".to_string(),
|
||||||
|
"Sweden".to_string(),
|
||||||
|
"Switzerland".to_string(),
|
||||||
|
];
|
||||||
|
let store = gtk::ListStore::new(&[glib::Type::STRING]);
|
||||||
|
for d in data.iter() {
|
||||||
|
store.set(&store.append(), &[(0, &d)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
composer_entry_completion.set_model(Some(&store));
|
||||||
|
// Use the first (and only) column available to set the autocompletion text
|
||||||
|
composer_entry_completion.set_text_column(0);
|
||||||
|
// how many keystrokes to wait before attempting to autocomplete?
|
||||||
|
composer_entry_completion.set_minimum_key_length(1);
|
||||||
|
// whether the completions should be presented in a popup window
|
||||||
|
composer_entry_completion.set_popup_completion(true);
|
||||||
|
|
||||||
|
let autosuggestion_popover = AutosuggestionPopoverModel::builder()
|
||||||
|
.launch(())
|
||||||
|
.forward(sender.input_sender(), |output| match output {
|
||||||
|
crate::ui::autosuggestion_popover::AutosuggestionPopoverOutput::SuggestionSelected(suggestion) => SheetEditDialogInput::ComposerSuggestionSelected(suggestion),
|
||||||
|
});
|
||||||
|
|
||||||
let model = SheetEditDialogModel {
|
let model = SheetEditDialogModel {
|
||||||
database: params.database,
|
database: params.database,
|
||||||
hidden: false,
|
hidden: false,
|
||||||
sheet: Some(sheet),
|
sheet: Some(sheet),
|
||||||
name_entry_buffer: EntryBuffer::new(Some(sheet_name)),
|
name_entry_buffer: EntryBuffer::new(Some(sheet_name)),
|
||||||
composer_entry_buffer: EntryBuffer::new(Some(sheet_composer)),
|
composer_entry_buffer: EntryBuffer::new(Some(sheet_composer)),
|
||||||
|
composer_entry_completion,
|
||||||
is_book,
|
is_book,
|
||||||
book_sheets: Vec::new(),
|
book_sheets: Vec::new(),
|
||||||
alert_empty_fields: Alert::builder().transient_for(&root).launch(AlertSettings {
|
alert_empty_fields: Alert::builder().transient_for(&root).launch(AlertSettings {
|
||||||
@ -165,6 +205,7 @@ impl AsyncComponent for SheetEditDialogModel {
|
|||||||
cancel_label: None,
|
cancel_label: None,
|
||||||
option_label: None,
|
option_label: None,
|
||||||
}),
|
}),
|
||||||
|
autosuggestion_popover,
|
||||||
};
|
};
|
||||||
let widgets = view_output!();
|
let widgets = view_output!();
|
||||||
|
|
||||||
@ -224,6 +265,32 @@ impl AsyncComponent for SheetEditDialogModel {
|
|||||||
self.hidden = true;
|
self.hidden = true;
|
||||||
self.sheet = None;
|
self.sheet = None;
|
||||||
}
|
}
|
||||||
|
SheetEditDialogInput::ComposerTextChanged(composer_name) => {
|
||||||
|
// let suggestions = vec![
|
||||||
|
// "Hello".into(),
|
||||||
|
// "World".into(),
|
||||||
|
// "Seattle".into(),
|
||||||
|
// "Salzburg".into(),
|
||||||
|
// ];
|
||||||
|
|
||||||
|
// self.autosuggestion_popover
|
||||||
|
// .emit(AutosuggestionPopoverInput::SetSuggestions(suggestions));
|
||||||
|
// self.autosuggestion_popover
|
||||||
|
// .emit(AutosuggestionPopoverInput::Show);
|
||||||
|
// self.model.filtered_suggestions = self
|
||||||
|
// .model
|
||||||
|
// .suggestions
|
||||||
|
// .iter()
|
||||||
|
// .filter(|suggestion| suggestion.starts_with(&text))
|
||||||
|
// .cloned()
|
||||||
|
// .collect();
|
||||||
|
// self.update_suggestions();
|
||||||
|
}
|
||||||
|
SheetEditDialogInput::ComposerSuggestionSelected(composer_name) => {
|
||||||
|
self.composer_entry_buffer.set_text(composer_name);
|
||||||
|
self.autosuggestion_popover
|
||||||
|
.emit(AutosuggestionPopoverInput::Hide);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user