| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163 |
- /* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2025 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
- use crate::{
- android,
- gfx::Point,
- mesh::Color,
- prop::{PropertyColor, PropertyFloat32},
- text2::{TextContext, TEXT_CTX},
- };
- macro_rules! t { ($($arg:tt)*) => { trace!(target: "text::editor::android", $($arg)*); } }
- // You must be careful working with string indexes in Java. They are UTF16 string indexs, not UTF8
- fn char16_to_byte_index(s: &str, char_idx: usize) -> Option<usize> {
- let utf16_data: Vec<_> = s.encode_utf16().take(char_idx).collect();
- let prestr = String::from_utf16(&utf16_data).ok()?;
- Some(prestr.len())
- }
- fn byte_to_char16_index(s: &str, byte_idx: usize) -> Option<usize> {
- if byte_idx > s.len() || !s.is_char_boundary(byte_idx) {
- return None
- }
- Some(s[..byte_idx].encode_utf16().count())
- }
- pub struct Editor {
- pub composer_id: usize,
- is_init: bool,
- layout: parley::Layout<Color>,
- width: Option<f32>,
- font_size: PropertyFloat32,
- text_color: PropertyColor,
- window_scale: PropertyFloat32,
- lineheight: PropertyFloat32,
- }
- impl Editor {
- pub async fn new(
- font_size: PropertyFloat32,
- text_color: PropertyColor,
- window_scale: PropertyFloat32,
- lineheight: PropertyFloat32,
- ) -> Self {
- Self {
- composer_id: usize::MAX,
- is_init: false,
- layout: Default::default(),
- width: None,
- font_size,
- text_color,
- window_scale,
- lineheight,
- }
- }
- pub fn init(&mut self) {
- android::focus(self.composer_id).unwrap();
- }
- pub fn setup(&mut self) {
- assert!(self.composer_id != usize::MAX);
- t!("Initialized composer [{}]", self.composer_id);
- let atxt = "A berry is small 😊 and pulpy.";
- android::set_text(self.composer_id, atxt).unwrap();
- self.is_init = true;
- }
- pub async fn refresh(&mut self) {
- let font_size = self.font_size.get();
- let text_color = self.text_color.get();
- let window_scale = self.window_scale.get();
- let lineheight = self.lineheight.get();
- let edit = android::get_editable(self.composer_id).unwrap();
- t!("refesh buffer = {}", edit.buffer);
- let mut txt_ctx = TEXT_CTX.get().await;
- self.layout = txt_ctx.make_layout(
- &edit.buffer,
- text_color,
- font_size,
- lineheight,
- window_scale,
- self.width,
- );
- }
- pub fn layout(&self) -> &parley::Layout<Color> {
- &self.layout
- }
- pub fn move_to_pos(&self, pos: Point) {
- let cursor = parley::Cursor::from_point(&self.layout, pos.x, pos.y);
- let edit = android::get_editable(self.composer_id).unwrap();
- let cursor_idx = cursor.index();
- let pos = byte_to_char16_index(&edit.buffer, cursor_idx).unwrap();
- android::set_selection(self.composer_id, pos, pos);
- t!(" {cursor_idx} => {pos}");
- }
- pub fn get_cursor_pos(&self) -> Option<Point> {
- if !self.is_init {
- return None
- }
- let lineheight = self.lineheight.get();
- let edit = android::get_editable(self.composer_id).unwrap();
- let cursor_byte_idx = char16_to_byte_index(&edit.buffer, edit.select_start).unwrap();
- let cursor = if cursor_byte_idx >= edit.buffer.len() {
- parley::Cursor::from_byte_index(
- &self.layout,
- edit.buffer.len(),
- parley::Affinity::Upstream,
- )
- } else {
- parley::Cursor::from_byte_index(
- &self.layout,
- cursor_byte_idx,
- parley::Affinity::Downstream,
- )
- };
- let cursor_rect = cursor.geometry(&self.layout, lineheight);
- let cursor_pos = Point::new(cursor_rect.x0 as f32, cursor_rect.y0 as f32);
- Some(cursor_pos)
- }
- pub async fn driver<'a>(
- &'a mut self,
- txt_ctx: &'a mut TextContext,
- ) -> Option<parley::PlainEditorDriver<'a, Color>> {
- None
- }
- pub fn set_width(&mut self, w: f32) {
- self.width = Some(w);
- }
- pub fn height(&self) -> f32 {
- self.layout().height()
- }
- }
|