9G_DEFINE_AUTOPTR_CLEANUP_FUNC(PangoContext, g_object_unref)
12#if !PANGO_VERSION_CHECK(1, 49, 4)
13G_DEFINE_AUTOPTR_CLEANUP_FUNC(PangoLayout, g_object_unref)
31 FlAccessibleTextField,
32 fl_accessible_text_field,
33 fl_accessible_node_get_type(),
35 G_IMPLEMENT_INTERFACE(ATK_TYPE_EDITABLE_TEXT,
38static gchar* get_substring(FlAccessibleTextField*
self,
41 const gchar*
value = gtk_entry_buffer_get_text(
self->buffer);
42 glong
length = g_utf8_strlen(value, -1);
53 PangoFontMap* font_map = pango_cairo_font_map_get_default();
54 PangoContext*
context = pango_font_map_create_context(font_map);
55 pango_context_set_base_dir(
context,
58 : PANGO_DIRECTION_LTR);
64 PangoLayout* layout = pango_layout_new(
context);
65 pango_layout_set_text(layout, gtk_entry_buffer_get_text(
self->buffer), -1);
79 const PangoLogAttr* attrs =
80 pango_layout_get_log_attrs_readonly(layout, &n_attrs);
83 end = CLAMP(
end, 0, MAX(n_attrs - 1, 0));
85 while (
start > 0 && !is_start(&attrs[
start])) {
89 while (
end < n_attrs && !is_end(&attrs[
end])) {
93 if (start_offset !=
nullptr) {
94 *start_offset =
start;
96 if (end_offset !=
nullptr) {
108 self, offset, offset + 1,
109 [](
const PangoLogAttr* attr) ->
bool {
return attr->is_char_break; },
110 [](
const PangoLogAttr* attr) ->
bool {
return attr->is_char_break; },
111 start_offset, end_offset);
119 self, offset, offset,
120 [](
const PangoLogAttr* attr) ->
bool {
return attr->is_word_start; },
121 [](
const PangoLogAttr* attr) ->
bool {
return attr->is_word_end; },
122 start_offset, end_offset);
130 self, offset, offset,
131 [](
const PangoLogAttr* attr) ->
bool {
return attr->is_sentence_start; },
132 [](
const PangoLogAttr* attr) ->
bool {
return attr->is_sentence_end; },
133 start_offset, end_offset);
144 const gchar*
text = gtk_entry_buffer_get_text(
self->buffer);
146 for (GSList* node = pango_layout_get_lines_readonly(layout); node !=
nullptr;
148 PangoLayoutLine* line =
static_cast<PangoLayoutLine*
>(node->data);
151 gint line_start = g_utf8_pointer_to_offset(
text,
text + line->start_index);
153 g_utf8_pointer_to_offset(
text,
text + line->start_index + line->length);
154 if (offset >= line_start && offset <= line_end) {
155 if (start_offset !=
nullptr) {
156 *start_offset = line_start;
158 if (end_offset !=
nullptr) {
159 *end_offset = line_end;
161 return get_substring(
self, line_start, line_end);
177 const gchar*
text = gtk_entry_buffer_get_text(
self->buffer);
179 PangoLayoutLine*
start =
nullptr;
180 PangoLayoutLine*
end =
nullptr;
181 gint n_lines = pango_layout_get_line_count(layout);
182 for (gint
i = 0;
i < n_lines; ++
i) {
183 PangoLayoutLine* line = pango_layout_get_line(layout,
i);
184 if (line->is_paragraph_start) {
187 if (
start !=
nullptr &&
end !=
nullptr) {
193 g_utf8_pointer_to_offset(
text,
text +
end->start_index +
end->length);
194 if (offset >= para_start && offset <= para_end) {
195 if (start_offset !=
nullptr) {
196 *start_offset = para_start;
198 if (end_offset !=
nullptr) {
199 *end_offset = para_end;
201 return get_substring(
self, para_start, para_end);
204 if (line->is_paragraph_start) {
240 FlAccessibleTextField*
self = FL_ACCESSIBLE_TEXT_FIELD(
object);
242 g_clear_object(&
self->buffer);
244 G_OBJECT_CLASS(fl_accessible_text_field_parent_class)->dispose(
object);
249 const gchar* value) {
250 g_return_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(node));
251 FlAccessibleTextField*
self = FL_ACCESSIBLE_TEXT_FIELD(node);
253 if (g_strcmp0(gtk_entry_buffer_get_text(
self->buffer),
value) == 0) {
257 gtk_entry_buffer_set_text(
self->buffer,
value, -1);
264 g_return_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(node));
265 FlAccessibleTextField*
self = FL_ACCESSIBLE_TEXT_FIELD(node);
267 gboolean caret_moved = extent !=
self->selection_extent;
268 gboolean has_selection =
base != extent;
269 gboolean had_selection =
self->selection_base !=
self->selection_extent;
270 gboolean selection_changed = (has_selection || had_selection) &&
271 (caret_moved ||
base !=
self->selection_base);
274 self->selection_extent = extent;
276 if (selection_changed) {
277 g_signal_emit_by_name(
self,
"text-selection-changed",
nullptr);
281 g_signal_emit_by_name(
self,
"text-caret-moved", extent,
nullptr);
287 FlAccessibleNode* node,
289 g_return_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(node));
290 FlAccessibleTextField*
self = FL_ACCESSIBLE_TEXT_FIELD(node);
292 self->text_direction = direction;
299 FlAccessibleNodeClass* parent_class =
300 FL_ACCESSIBLE_NODE_CLASS(fl_accessible_text_field_parent_class);
312 FL_MESSAGE_CODEC(codec), extend_selection,
nullptr);
317 parent_class->perform_action(
self,
action, data);
324 g_return_val_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(
text), 0);
325 FlAccessibleTextField*
self = FL_ACCESSIBLE_TEXT_FIELD(
text);
327 return gtk_entry_buffer_get_length(
self->buffer);
334 g_return_val_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(
text),
nullptr);
335 FlAccessibleTextField*
self = FL_ACCESSIBLE_TEXT_FIELD(
text);
337 return get_substring(
self, start_offset, end_offset);
344 AtkTextGranularity granularity,
347 g_return_val_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(
text),
nullptr);
348 FlAccessibleTextField*
self = FL_ACCESSIBLE_TEXT_FIELD(
text);
350 switch (granularity) {
351 case ATK_TEXT_GRANULARITY_CHAR:
353 case ATK_TEXT_GRANULARITY_WORD:
355 case ATK_TEXT_GRANULARITY_SENTENCE:
357 case ATK_TEXT_GRANULARITY_LINE:
359 case ATK_TEXT_GRANULARITY_PARAGRAPH:
370 AtkTextBoundary boundary_type,
373 switch (boundary_type) {
374 case ATK_TEXT_BOUNDARY_CHAR:
376 text, offset, ATK_TEXT_GRANULARITY_CHAR, start_offset, end_offset);
378 case ATK_TEXT_BOUNDARY_WORD_START:
379 case ATK_TEXT_BOUNDARY_WORD_END:
381 text, offset, ATK_TEXT_GRANULARITY_WORD, start_offset, end_offset);
383 case ATK_TEXT_BOUNDARY_SENTENCE_START:
384 case ATK_TEXT_BOUNDARY_SENTENCE_END:
386 text, offset, ATK_TEXT_GRANULARITY_SENTENCE, start_offset,
389 case ATK_TEXT_BOUNDARY_LINE_START:
390 case ATK_TEXT_BOUNDARY_LINE_END:
392 text, offset, ATK_TEXT_GRANULARITY_LINE, start_offset, end_offset);
401 g_return_val_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(
text), -1);
402 FlAccessibleTextField*
self = FL_ACCESSIBLE_TEXT_FIELD(
text);
404 return self->selection_extent;
410 g_return_val_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(
text),
false);
411 FlAccessibleTextField*
self = FL_ACCESSIBLE_TEXT_FIELD(
text);
419 g_return_val_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(
text), 0);
420 FlAccessibleTextField*
self = FL_ACCESSIBLE_TEXT_FIELD(
text);
422 if (
self->selection_base ==
self->selection_extent) {
434 g_return_val_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(
text),
nullptr);
435 FlAccessibleTextField*
self = FL_ACCESSIBLE_TEXT_FIELD(
text);
437 if (selection_num != 0 ||
self->selection_base ==
self->selection_extent) {
441 gint
start = MIN(
self->selection_base,
self->selection_extent);
442 gint
end = MAX(
self->selection_base,
self->selection_extent);
444 if (start_offset !=
nullptr) {
445 *start_offset =
start;
447 if (end_offset !=
nullptr) {
458 g_return_val_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(
text),
false);
459 FlAccessibleTextField*
self = FL_ACCESSIBLE_TEXT_FIELD(
text);
461 if (
self->selection_base !=
self->selection_extent) {
471 gint selection_num) {
472 g_return_val_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(
text),
false);
473 FlAccessibleTextField*
self = FL_ACCESSIBLE_TEXT_FIELD(
text);
475 if (selection_num != 0 ||
self->selection_base ==
self->selection_extent) {
480 self->selection_extent);
489 g_return_val_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(
text),
false);
490 FlAccessibleTextField*
self = FL_ACCESSIBLE_TEXT_FIELD(
text);
492 if (selection_num != 0) {
502 AtkEditableText* editable_text,
503 const gchar*
string) {
504 g_return_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(editable_text));
505 FlAccessibleTextField*
self = FL_ACCESSIBLE_TEXT_FIELD(editable_text);
515 g_return_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(editable_text));
516 FlAccessibleTextField*
self = FL_ACCESSIBLE_TEXT_FIELD(editable_text);
519 gtk_entry_buffer_insert_text(
self->buffer, *position,
string,
length);
529 g_return_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(editable_text));
530 FlAccessibleTextField*
self = FL_ACCESSIBLE_TEXT_FIELD(editable_text);
532 gtk_entry_buffer_delete_text(
self->buffer, start_pos, end_pos - start_pos);
542 g_return_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(editable_text));
543 FlAccessibleTextField*
self = FL_ACCESSIBLE_TEXT_FIELD(editable_text);
555 g_return_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(editable_text));
556 FlAccessibleTextField*
self = FL_ACCESSIBLE_TEXT_FIELD(editable_text);
567 g_return_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(editable_text));
568 FlAccessibleTextField*
self = FL_ACCESSIBLE_TEXT_FIELD(editable_text);
577 FlAccessibleTextFieldClass* klass) {
579 FL_ACCESSIBLE_NODE_CLASS(klass)->set_value =
581 FL_ACCESSIBLE_NODE_CLASS(klass)->set_text_selection =
583 FL_ACCESSIBLE_NODE_CLASS(klass)->set_text_direction =
585 FL_ACCESSIBLE_NODE_CLASS(klass)->perform_action =
606 AtkEditableTextIface* iface) {
617 self->selection_base = -1;
618 self->selection_extent = -1;
620 self->buffer = gtk_entry_buffer_new(
"", 0);
622 g_signal_connect_object(
623 self->buffer,
"inserted-text",
624 G_CALLBACK(+[](FlAccessibleTextField*
self, guint position, gchar* chars,
626 g_signal_emit_by_name(
self,
"text-insert", position, n_chars, chars,
629 self, G_CONNECT_SWAPPED);
631 g_signal_connect_object(
self->buffer,
"deleted-text",
632 G_CALLBACK(+[](FlAccessibleTextField*
self,
633 guint position, guint n_chars) {
634 g_autofree gchar* chars = atk_text_get_text(
635 ATK_TEXT(
self), position, position + n_chars);
636 g_signal_emit_by_name(
self,
"text-remove", position,
637 n_chars, chars,
nullptr);
639 self, G_CONNECT_SWAPPED);
645 return FL_ACCESSIBLE_NODE(g_object_new(fl_accessible_text_field_get_type(),
647 "node-id",
id,
nullptr));
@ kFlutterSemanticsActionMoveCursorForwardByCharacter
Move the cursor forward by one character.
@ kFlutterSemanticsActionMoveCursorBackwardByCharacter
Move the cursor backward by one character.
@ kFlutterSemanticsActionMoveCursorForwardByWord
Move the cursor forward by one word.
@ kFlutterSemanticsActionSetSelection
Set the text selection to the given range.
@ kFlutterSemanticsActionPaste
Paste the current content of the clipboard.
@ kFlutterSemanticsActionCut
Cut the current selection and place it in the clipboard.
@ kFlutterSemanticsActionCopy
Copy the current selection to the clipboard.
@ kFlutterSemanticsActionMoveCursorBackwardByWord
Move the cursor backward by one word.
@ kFlutterSemanticsActionSetText
Replace the current text in the text field.
@ kFlutterTextDirectionRTL
Text is read from right to left.
g_autoptr(FlEngine) engine
void fl_accessible_node_perform_action(FlAccessibleNode *self, FlutterSemanticsAction action, GBytes *data)
static void perform_set_selection_action(FlAccessibleTextField *self, gint base, gint extent)
static gint fl_accessible_text_field_get_n_selections(AtkText *text)
static gchar * fl_accessible_text_field_get_string_at_offset(AtkText *text, gint offset, AtkTextGranularity granularity, gint *start_offset, gint *end_offset)
static void fl_accessible_text_field_insert_text(AtkEditableText *editable_text, const gchar *string, gint length, gint *position)
static gchar * fl_accessible_text_field_get_text(AtkText *text, gint start_offset, gint end_offset)
static void fl_accessible_text_field_dispose(GObject *object)
static gchar * fl_accessible_text_field_get_selection(AtkText *text, gint selection_num, gint *start_offset, gint *end_offset)
static void fl_accessible_text_field_paste_text(AtkEditableText *editable_text, gint position)
static gchar * get_line_at_offset(FlAccessibleTextField *self, gint offset, gint *start_offset, gint *end_offset)
static gboolean fl_accessible_text_field_set_selection(AtkText *text, gint selection_num, gint start_offset, gint end_offset)
FlAccessibleNode * fl_accessible_text_field_new(FlEngine *engine, FlutterViewId view_id, int32_t id)
static void fl_accessible_text_field_set_text_contents(AtkEditableText *editable_text, const gchar *string)
static void fl_accessible_text_field_copy_text(AtkEditableText *editable_text, gint start_pos, gint end_pos)
static void fl_accessible_text_field_init(FlAccessibleTextField *self)
static gboolean fl_accessible_text_field_remove_selection(AtkText *text, gint selection_num)
static gchar * get_word_at_offset(FlAccessibleTextField *self, gint offset, gint *start_offset, gint *end_offset)
G_DEFINE_TYPE_WITH_CODE(FlAccessibleTextField, fl_accessible_text_field, fl_accessible_node_get_type(), G_IMPLEMENT_INTERFACE(ATK_TYPE_EDITABLE_TEXT, fl_accessible_editable_text_iface_init)) static gchar *get_substring(FlAccessibleTextField *self
static void fl_accessible_text_field_set_text_direction(FlAccessibleNode *node, FlutterTextDirection direction)
static void fl_accessible_text_field_set_text_selection(FlAccessibleNode *node, gint base, gint extent)
bool(* FlTextBoundaryCallback)(const PangoLogAttr *attr)
static void fl_accessible_text_iface_init(AtkTextIface *iface)
static gchar * fl_accessible_text_field_get_text_at_offset(AtkText *text, gint offset, AtkTextBoundary boundary_type, gint *start_offset, gint *end_offset)
static void fl_accessible_text_field_set_value(FlAccessibleNode *node, const gchar *value)
static void fl_accessible_editable_text_iface_init(AtkEditableTextIface *iface)
static gboolean fl_accessible_text_field_set_caret_offset(AtkText *text, gint offset)
static void fl_accessible_node_delete_text(AtkEditableText *editable_text, gint start_pos, gint end_pos)
static gchar * get_sentence_at_offset(FlAccessibleTextField *self, gint offset, gint *start_offset, gint *end_offset)
static void fl_accessible_text_field_cut_text(AtkEditableText *editable_text, gint start_pos, gint end_pos)
static gchar * get_char_at_offset(FlAccessibleTextField *self, gint offset, gint *start_offset, gint *end_offset)
static PangoContext * get_pango_context(FlAccessibleTextField *self)
static gboolean fl_accessible_text_field_add_selection(AtkText *text, gint start_offset, gint end_offset)
static void perform_set_text_action(FlAccessibleTextField *self, const char *text)
static gchar * get_paragraph_at_offset(FlAccessibleTextField *self, gint offset, gint *start_offset, gint *end_offset)
static gchar * get_string_at_offset(FlAccessibleTextField *self, gint start, gint end, FlTextBoundaryCallback is_start, FlTextBoundaryCallback is_end, gint *start_offset, gint *end_offset)
static void fl_accessible_text_field_class_init(FlAccessibleTextFieldClass *klass)
return g_utf8_substring(value, start, end)
static gint fl_accessible_text_field_get_character_count(AtkText *text)
static gint fl_accessible_text_field_get_caret_offset(AtkText *text)
static PangoLayout * create_pango_layout(FlAccessibleTextField *self)
void fl_accessible_text_field_perform_action(FlAccessibleNode *self, FlutterSemanticsAction action, GBytes *data)
G_MODULE_EXPORT GBytes * fl_message_codec_encode_message(FlMessageCodec *self, FlValue *message, GError **error)
G_MODULE_EXPORT FlStandardMessageCodec * fl_standard_message_codec_new()
G_MODULE_EXPORT FlValue * fl_value_new_map()
G_MODULE_EXPORT void fl_value_set_string_take(FlValue *self, const gchar *key, FlValue *value)
G_MODULE_EXPORT FlValue * fl_value_new_string(const gchar *value)
G_MODULE_EXPORT FlValue * fl_value_new_bool(bool value)
G_MODULE_EXPORT FlValue * fl_value_new_int(int64_t value)
typedefG_BEGIN_DECLS struct _FlValue FlValue
G_BEGIN_DECLS FlutterViewId view_id
std::shared_ptr< ContextGLES > context
FlutterTextDirection text_direction
FlAccessibleNode parent_instance