Skip to content

Commit

Permalink
examples: add a custom Entry Buffer
Browse files Browse the repository at this point in the history
  • Loading branch information
bilelmoussaoui committed May 9, 2021
1 parent c176b1a commit 1098c1f
Show file tree
Hide file tree
Showing 6 changed files with 196 additions and 0 deletions.
4 changes: 4 additions & 0 deletions examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ path = "custom_application/main.rs"
name = "custom_editable"
path = "custom_editable/main.rs"

[[bin]]
name = "custom_entry_buffer"
path = "custom_entry_buffer/main.rs"

[[bin]]
name = "custom_layout_manager"
path = "custom_layout_manager/main.rs"
Expand Down
1 change: 1 addition & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Consists of various examples to get familiar with writing GTK applications using
- [CSS](./css/)
- [Custom Application](./custom_application/)
- [Custom Editable](./custom_editable/)
- [Custom Entry Buffer](./custom_entry_buffer/)
- [Custom Layout Manager](./custom_layout_manager/)
- [Custom Orientable](./custom_orientable/)
- [Custom Paintable](./custom_paintable/)
Expand Down
3 changes: 3 additions & 0 deletions examples/custom_entry_buffer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Custom Entry Buffer

The example shows how to create a custom `gtk::EntryBuffer`. A `gtk::EntryBuffer` can be used to fed a `gtk::Text` for example.
128 changes: 128 additions & 0 deletions examples/custom_entry_buffer/entry_buffer/imp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
use glib::{ParamFlags, ParamSpec, Value};
use gtk::glib;
use gtk::prelude::*;
use gtk::subclass::prelude::*;
use once_cell::sync::Lazy;
use std::cell::{Cell, RefCell};
use std::rc::Rc;

#[derive(Debug)]
pub struct CustomEntryBuffer {
text: Rc<RefCell<String>>,
length: Cell<u16>,
max_length: Cell<u16>,
}

impl Default for CustomEntryBuffer {
fn default() -> Self {
Self {
text: Rc::new(RefCell::new(String::new())),
length: Cell::new(0),
max_length: Cell::new(0),
}
}
}

#[glib::object_subclass]
impl ObjectSubclass for CustomEntryBuffer {
const NAME: &'static str = "CustomEntryBuffer";
type Type = super::CustomEntryBuffer;
type ParentType = gtk::EntryBuffer;
}

impl ObjectImpl for CustomEntryBuffer {
fn properties() -> &'static [ParamSpec] {
static PROPERTIES: Lazy<Vec<ParamSpec>> = Lazy::new(|| {
vec![
ParamSpec::new_uint(
"length",
"length",
"Length",
0,
u16::MAX as u32,
0,
ParamFlags::READABLE,
),
ParamSpec::new_uint(
"max-length",
"Maximum length",
"Maximum number of characters for this entry",
0,
u16::MAX as u32,
0,
ParamFlags::READWRITE | ParamFlags::EXPLICIT_NOTIFY,
),
ParamSpec::new_string(
"text",
"Text",
"The contents of the buffer",
Some(""),
ParamFlags::READWRITE,
),
]
});
PROPERTIES.as_ref()
}

fn property(&self, _obj: &Self::Type, _id: usize, pspec: &ParamSpec) -> Value {
match pspec.name() {
"length" => (self.length.get() as u32).to_value(),
"max-length" => (self.max_length.get() as u32).to_value(),
"text" => self.text.borrow().to_value(),
_ => unreachable!(),
}
}

fn set_property(&self, _obj: &Self::Type, _id: usize, value: &Value, pspec: &ParamSpec) {
match pspec.name() {
"length" => {
self.length.set(value.get::<u32>().unwrap() as u16);
}
"max-length" => {
self.max_length.set(value.get::<u32>().unwrap() as u16);
}
"text" => {
self.text.replace(value.get().unwrap());
}
_ => unreachable!(),
}
}
}

impl EntryBufferImpl for CustomEntryBuffer {
fn text(&self, _entry_buffer: &Self::Type) -> glib::GString {
self.text.borrow().clone().into()
}

fn length(&self, _entry_buffer: &Self::Type) -> u16 {
self.text.borrow().chars().count() as u16
}

fn insert_text(&self, entry_buffer: &Self::Type, _position: u16, chars: &str) -> u16 {
self.text.borrow_mut().insert_str(0, chars);
let n_chars = chars.chars().count() as u16;
let new_length = self.length.get() + n_chars;
self.length.set(new_length);

entry_buffer.notify("text");
entry_buffer.notify("length");
n_chars
}

fn delete_text(&self, entry_buffer: &Self::Type, position: u16, n_chars: Option<u16>) -> u16 {
let deleted_chars = n_chars.unwrap_or(u16::MAX);
println!("{}", position);
println!("{:#?}", self.text.borrow());
let text = self.text.borrow().chars().skip(position as usize).collect();
println!("{}", text);
self.text.replace(text);

let length = (self.length.get() - deleted_chars).max(0);
self.length.set(length);

entry_buffer.notify("text");
entry_buffer.notify("length");

deleted_chars
}
}
19 changes: 19 additions & 0 deletions examples/custom_entry_buffer/entry_buffer/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
mod imp;

use gtk::glib;

glib::wrapper! {
pub struct CustomEntryBuffer(ObjectSubclass<imp::CustomEntryBuffer>) @extends gtk::EntryBuffer;
}

impl Default for CustomEntryBuffer {
fn default() -> Self {
Self::new()
}
}

impl CustomEntryBuffer {
pub fn new() -> Self {
glib::Object::new(&[]).expect("Failed to create a CustomEntryBuffer")
}
}
41 changes: 41 additions & 0 deletions examples/custom_entry_buffer/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
mod entry_buffer;

use entry_buffer::CustomEntryBuffer;
use gtk::prelude::*;

fn main() {
let application = gtk::Application::new(
Some("com.github.gtk-rs.examples.entry-buffer"),
Default::default(),
);

application.connect_activate(build_ui);
application.run();
}

fn build_ui(application: &gtk::Application) {
let window = gtk::ApplicationWindow::new(application);
window.set_title(Some("Custom Entry Buffer"));
window.set_default_size(500, 500);

let container = gtk::Box::new(gtk::Orientation::Vertical, 12);
container.set_valign(gtk::Align::Center);
container.set_halign(gtk::Align::Center);

let buffer = CustomEntryBuffer::new();

let text1 = gtk::Text::new();
text1.set_buffer(&buffer);
container.append(&text1);

let text2 = gtk::Text::new();
text2.set_buffer(&buffer);
container.append(&text2);

let entry = gtk::Entry::new();
entry.set_buffer(&buffer);
container.append(&entry);

window.set_child(Some(&container));
window.show();
}

0 comments on commit 1098c1f

Please sign in to comment.