--- a/ui/qt/text.cpp Tue Feb 25 21:11:00 2025 +0100 +++ b/ui/qt/text.cpp Sat Apr 05 16:46:11 2025 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2014 Olaf Wintermann. All rights reserved. + * Copyright 2025 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -32,124 +32,203 @@ #include "../common/context.h" #include "../common/document.h" -UIWIDGET ui_textarea(UiObject *obj, UiText *value) { - QTextDocument *txtdoc = value && value->obj ? (QTextDocument*)value->obj : new QTextDocument(); +/* + * Gets or creates a QTextDocument for the UiText value and initializes it + * with the UiText string value + */ +static QTextDocument* get_or_create_doc(UiText *value) { + QTextDocument *document = nullptr; + if(value->data1) { + document = (QTextDocument*)value->data1; + } else { + document = new QTextDocument(); + if(value->value.ptr) { + QString str = QString::fromUtf8(value->value.ptr); + document->setPlainText(str); + } + } + + if(value->value.free) { + value->value.free(value->value.ptr); + } + value->value.ptr = NULL; + value->value.free = NULL; - if(value) { - if(value->value && value->obj) { - QString str = QString::fromUtf8(value->value); - txtdoc->setPlainText(str); - } + return document; +} + +UIWIDGET ui_textarea_create(UiObject *obj, UiTextAreaArgs args) { + UiContainerPrivate *ctn = ui_obj_container(obj); + UI_APPLY_LAYOUT(ctn->layout, args); + + QTextEdit *textarea = new QTextEdit(); + ctn->add(textarea, true); + + QTextDocument *document = nullptr; + + UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args.value, args.varname, UI_VAR_STRING); + if(var) { + UiText *value = (UiText*)var->value; + document = get_or_create_doc(value); + + value->save = ui_textarea_save; + value->restore = ui_textarea_restore; + value->destroy = ui_textarea_text_destroy; value->get = ui_textarea_get; value->set = ui_textarea_set; value->getsubstr = ui_textarea_getsubstr; value->insert = ui_textarea_insert; value->setposition = ui_textarea_setposition; value->position = ui_textarea_position; + value->setselection = ui_textarea_setselection; value->selection = ui_textarea_selection; value->length = ui_textarea_length; value->remove = ui_textarea_remove; - value->obj = txtdoc; - value->value = NULL; + value->obj = textarea; + value->data1 = document; + } else { + document = new QTextDocument(); } - UiContainer *ct = uic_get_current_container(obj); - QTextEdit *textedit = new QTextEdit(); - textedit->setDocument(txtdoc); - ct->add(textedit, true); + textarea->setDocument(document); - return textedit; + return textarea; } -UIWIDGET ui_textarea_nv(UiObject *obj, char *varname) { - UiVar *var = uic_connect_var(obj->ctx, varname, UI_VAR_TEXT); - if(var) { - UiText *value = (UiText*)var->value; - return ui_textarea(obj, value); - } else { - // TODO: error - } - return NULL; +void ui_textarea_save(UiText *text) { + // NOOP } +void ui_textarea_restore(UiText *text) { + QTextEdit *textarea = (QTextEdit*)text->obj; + QTextDocument *document = get_or_create_doc(text); + textarea->setDocument(document); +} + +void ui_textarea_text_destroy(UiText *text) { + QTextDocument *document = (QTextDocument*)text->data1; + if(document) { + delete document; + } +} char* ui_textarea_get(UiText *text) { - if(text->value) { - free(text->value); + // clean previous value + if(text->value.free) { + text->value.free(text->value.ptr); } - QTextDocument *doc = (QTextDocument*)text->obj; + // get string + QTextDocument *doc = (QTextDocument*)text->data1; QString str = doc->toPlainText(); - QByteArray array = str.toLocal8Bit(); + QByteArray array = str.toUtf8(); const char *cstr = array.constData(); - if(text->value) { - free(text->value); - } - text->value = strdup(cstr); - return text->value; + // store a copy of the string in the UiText value + text->value.ptr = strdup(cstr); + text->value.free = free; + return text->value.ptr; } -void ui_textarea_set(UiText *text, char *str) { - // set text - QTextDocument *doc = (QTextDocument*)text->obj; +void ui_textarea_set(UiText *text, const char *str) { + if(text->value.free) { + text->value.free(text->value.ptr); + } + text->value.ptr = NULL; + text->value.free = NULL; + + QTextDocument *doc = (QTextDocument*)text->data1; QString qstr = QString::fromUtf8(str); doc->setPlainText(qstr); - // cleanup - if(text->value) { - free(text->value); - } - text->value = NULL; } char* ui_textarea_getsubstr(UiText *text, int begin, int end) { - QTextDocument *doc = (QTextDocument*)text->obj; - return NULL; // TODO + QTextDocument *doc = (QTextDocument*)text->data1; + QTextCursor cursor(doc); + cursor.setPosition(begin, QTextCursor::MoveAnchor); + cursor.setPosition(end, QTextCursor::KeepAnchor); + QString str = cursor.selectedText(); + QByteArray bytes = str.toUtf8(); + const char *cstr = bytes.constData(); + return cstr ? strdup(cstr) : NULL; } void ui_textarea_insert(UiText *text, int pos, char *str) { - QTextDocument *doc = (QTextDocument*)text->obj; + QTextDocument *doc = (QTextDocument*)text->data1; + QTextCursor cursor(doc); + cursor.setPosition(pos); + cursor.insertText(str); } void ui_textarea_setposition(UiText *text, int pos) { - // TODO + QTextEdit *textview = (QTextEdit*)text->obj; + QTextCursor cursor = textview->textCursor(); + cursor.setPosition(pos); + textview->setTextCursor(cursor); } int ui_textarea_position(UiText *text) { - QTextDocument *doc = (QTextDocument*)text->obj; - return 0; // TODO + QTextEdit *textview = (QTextEdit*)text->obj; + QTextCursor cursor = textview->textCursor(); + return cursor.position(); } void ui_textarea_selection(UiText *text, int *begin, int *end) { - QTextDocument *doc = (QTextDocument*)text->obj; + QTextEdit *textview = (QTextEdit*)text->obj; + QTextCursor cursor = textview->textCursor(); + if(cursor.hasSelection()) { + if(begin) { + *begin = cursor.selectionStart(); + } + if(end) { + *end = cursor.selectionEnd(); + } + } +} + +void ui_textarea_setselection(UiText *text, int begin, int end) { + QTextEdit *textview = (QTextEdit*)text->obj; + QTextCursor cursor = textview->textCursor(); + cursor.setPosition(begin, QTextCursor::MoveAnchor); + cursor.setPosition(end, QTextCursor::KeepAnchor); + textview->setTextCursor(cursor); } int ui_textarea_length(UiText *text) { - QTextDocument *doc = (QTextDocument*)text->obj; - return 0; // TODO + QTextDocument *doc = (QTextDocument*)text->data1; + return doc->characterCount(); } void ui_textarea_remove(UiText *text, int begin, int end) { - QTextDocument *doc = (QTextDocument*)text->obj; + // TODO } - -/* ------------------- TextField ------------------- */ +/* ------------------------------ TextField ------------------------------ */ -UIWIDGET ui_textfield(UiObject *obj, UiString *value) { +static UIWIDGET create_textfield(UiObject *obj, UiTextFieldArgs args, bool password, bool frameless) { + UiContainerPrivate *ctn = ui_obj_container(obj); + UI_APPLY_LAYOUT(ctn->layout, args); + QLineEdit *textfield = new QLineEdit(); + ctn->add(textfield, false); + + if(password) { + textfield->setEchoMode(QLineEdit::Password); + } - UiContainer *ct = uic_get_current_container(obj); - ct->add(textfield, false); - - if(value) { - if(value->value) { - QString str = QString::fromUtf8(value->value); + UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args.value, args.varname, UI_VAR_STRING); + if(var) { + UiString *value = (UiString*)var->value; + if(value->value.ptr) { + QString str = QString::fromUtf8(value->value.ptr); textfield->setText(str); - free(value->value); - value->value = NULL; + if(value->value.free) { + value->value.free(value->value.ptr); + } + value->value.ptr = NULL; } + value->set = ui_textfield_set; value->get = ui_textfield_get; value->obj = textfield; @@ -158,38 +237,40 @@ return textfield; } -UIWIDGET ui_textfield_nv(UiObject *obj, char *varname) { - UiVar *var = uic_connect_var(obj->ctx, varname, UI_VAR_STRING); - if(var) { - UiString *value = (UiString*)var->value; - return ui_textfield(obj, value); - } else { - // TODO: error - } - return NULL; +UIWIDGET ui_textfield_create(UiObject *obj, UiTextFieldArgs args) { + return create_textfield(obj, args, false, false); +} + +UIWIDGET ui_frameless_textfield_create(UiObject* obj, UiTextFieldArgs args) { + return create_textfield(obj, args, false, true); +} + +UIWIDGET ui_passwordfield_create(UiObject* obj, UiTextFieldArgs args) { + return create_textfield(obj, args, true, false); } char* ui_textfield_get(UiString *str) { QLineEdit *textfield = (QLineEdit*)str->obj; QString qstr = textfield->text(); - if(str->value) { - free(str->value); + if(str->value.free) { + str->value.free(str->value.ptr); } - QByteArray array = qstr.toLocal8Bit(); + QByteArray array = qstr.toUtf8(); const char *cstr = array.constData(); - str->value = strdup(cstr); + str->value.ptr = strdup(cstr); + str->value.free = free; - return str->value; + return str->value.ptr; } -void ui_textfield_set(UiString *str, char *value) { +void ui_textfield_set(UiString *str, const char *value) { QLineEdit *textfield = (QLineEdit*)str->obj; QString qstr = QString::fromUtf8(value); textfield->setText(qstr); - if(str->value) { - free(str->value); + if(str->value.free) { + str->value.free(str->value.ptr); } - str->value = NULL; + str->value.ptr = NULL; }