-
Notifications
You must be signed in to change notification settings - Fork 0
ui_edit_doc ui_edit_view
Text editing applications require efficient handling of document content and user interaction. Two critical components in this domain are ui_edit_doc and ui_edit_view. These structures and their associated interfaces provide the foundation for document manipulation and user interaction within a text editor. Let's delve into the theory of their operations and examine a sample implementation.
The ui_edit_doc structure represents the document's content and its history of changes. It includes:
- Insert/Delete Transactions: It ensures that all changes (insertions or deletions) are completed fully or not at all, maintaining document integrity.
-
Undo/Redo Semantics:
- All or Nothing: Changes can be reverted or reapplied entirely, ensuring consistent document states.
-
Automation with
replace_text(): This function provides an option to handle transactions on a different basis, which is useful for automated tasks or scripts that may require customized undo/redo functionality.
The ui_edit_str structure maintains UTF-8 strings with several optimizations:
-
Heap or Non-Heap Storage: Strings can either be in heap memory or remain outside, depending on the use case:
- Outside Heap: Efficient for short ASCII strings, common in programming languages, allowing quick indexing and minimal memory usage.
- Inside Heap: Necessary for mutable or long strings, facilitating efficient modifications.
-
UTF-8 Benefits: By using UTF-8, the structure avoids the complexities associated with UTF-16, such as surrogate pairs, and provides a straightforward indexing mechanism for ASCII content.
-
Text Storage: Managed in paragraphs using the
ui_edit_text_tstructure, which stores an array ofui_edit_str_tstructures for each paragraph. -
Undo/Redo Mechanism: Implemented through linked lists of
ui_edit_to_do_tstructures, representing actions that can be undone or redone. -
Listeners: A linked list of
ui_edit_listener_tstructures for notifications on text changes. Theui_edit_listener_tstructures enable a flexible notification system:- Linked List of Listeners: Each listener can be notified before and after text changes, allowing multiple components to react independently.
- Multiple Views: This setup supports multiple views of the same document, such as:
- Vertical/Horizontal Split: Modern editors often have split views for different perspectives on the same document. Each view can update independently while reflecting changes in real-time.
- Collaborative Editing: Multiple users or interfaces can interact with the document simultaneously, with updates broadcast to all listeners.
-
Initialization:
bool init(ui_edit_doc_t* d, const uint8_t* utf8_or_null, int32_t bytes, bool heap);
Initializes the document. The
utf8_or_nullpointer provides initial content, which can be stored on the heap based on theheapflag. -
Text Replacement:
bool replace_text(ui_edit_doc_t* d, const ui_edit_range_t* r, const ui_edit_text_t* t, ui_edit_to_do_t* undo_or_null);
Replaces text in the specified range. If
undo_or_nullis provided, the operation is stored for potential undo. -
Undo/Redo Operations:
bool undo(ui_edit_doc_t* d); bool redo(ui_edit_doc_t* d);
Manage the undo and redo stacks, allowing users to revert or reapply changes.
-
Notification Subscriptions:
bool subscribe(ui_edit_doc_t* d, ui_edit_notify_t* notify); void unsubscribe(ui_edit_doc_t* d, ui_edit_notify_t* notify);
Allows other components to receive notifications before and after text changes, enabling responsive UI updates.
ui_edit_view handles the rendering and interaction aspects of the text editor. It maintains the visual state and manages user input, such as keyboard and mouse actions.
-
Document Reference: Points to the associated
ui_edit_doc_tfor text content. -
Caret and Selection: Managed with
ui_edit_range_tfor selection andui_point_tfor caret position. -
Scrolling and Layout:
ui_edit_pr_tstructures for tracking the view's scrolling state and visible runs. -
User Settings: Flags like
ro(read-only) andsle(single-line edit) to customize behavior.
-
Initialization:
void init(ui_edit_t* e, ui_edit_doc_t* d);
Links the editor view to the document, preparing it for user interactions.
-
Text Manipulation:
void paste(ui_edit_t* e, const char* text, int32_t bytes); void erase(ui_edit_t* e);
Handles pasting new text and erasing selected content.
-
Navigation:
void key_up(ui_edit_t* e); void key_down(ui_edit_t* e); void key_left(ui_edit_t* e); void key_right(ui_edit_t* e);
Responds to user input for moving the caret through the text.
-
Clipboard Operations:
void copy_to_clipboard(ui_edit_t* e); void cut_to_clipboard(ui_edit_t* e); void paste_from_clipboard(ui_edit_t* e);
Facilitates clipboard interactions for text copy, cut, and paste.
Let's examine a sample implementation that utilizes ui_edit_doc and ui_edit_view to create a basic text editor:
static void edit_document_view_sample(ui_view_t* parent) {
static void* text;
static int64_t bytes;
if (text == null) {
if (ut_args.c > 1) {
if (ut_files.exists(ut_args.v[1])) {
errno_t r = ut_mem.map_ro(ut_args.v[1], &text, &bytes);
if (r != 0) {
traceln("ut_mem.map_ro(%s) failed %s", ut_args.v[1], ut_str.error(r));
}
} else {
traceln("file \"%s\" does not exist", ut_args.v[1]);
}
}
}
static ui_view_t list = ui_view(list);
static ui_edit_t edit = {0};
static ui_edit_doc_t doc = {0};
if (doc.text.np == 0) {
swear(ui_edit_doc.init(&doc, text, (int32_t)bytes, false));
ui_edit.init(&edit, &doc);
}
ui_view.add(&test,
ui_view.add(&list,
&edit.view,
null),
null);
list.max_w = ui.infinity;
list.max_h = ui.infinity;
edit.view.debug = true;
edit.view.fm = &ui_app.fm.H1;
edit.view.max_w = ui.infinity;
edit.view.max_h = ui.infinity;
ui_app.focus = &edit.view;
}-
File Mapping:
- The function checks if an external file is provided as an argument and maps its content into memory. This allows the text editor to load and display the file's content.
-
Static Initialization:
-
ui_view_t list: Acts as a container for the editor, setting up the view hierarchy. -
ui_edit_t edit: Represents the text editor, initialized with default values. -
ui_edit_doc_t doc: The document instance, also initialized with default values.
-
-
Document Initialization:
- If the document is not initialized (i.e., no paragraphs), it calls
ui_edit_doc.initto set up the document structure, followed byui_edit.initto link the editor view.
- If the document is not initialized (i.e., no paragraphs), it calls
-
UI Setup:
- Adds the editor view (
edit.view) to the parent view (list), configuring the maximum width and height to support large text content.
- Adds the editor view (
-
Focus and Debugging:
- Sets focus on the editor view and enables debugging for development purposes, assisting in identifying layout and interaction issues.
The ui_edit_doc and ui_edit_view structures provide a comprehensive framework for managing document content and user interactions in a text editor. The separation of document management from user interface handling promotes modularity and ease of maintenance. By leveraging these components, developers can build sophisticated text editing applications with robust undo/redo capabilities and intuitive user interactions.
This example demonstrates the foundational setup, but real-world applications can extend these components to incorporate additional features such as syntax highlighting, search functionalities, and more complex user interfaces.