From b60e73d93bb27ffc36e67f25dead05a7d3d9d95e Mon Sep 17 00:00:00 2001 From: ispyisail Date: Thu, 30 Jul 2026 19:11:25 +1200 Subject: [PATCH] Fix #487: drag-selecting dynamic text fields silently converts their text source updateForm() called on_m_text_from_cb_activated() directly, intending only to enable the sibling widget matching the combo box's current index ("For enable the good widget"). But that slot also loops over every currently selected part and pushes an undo command overwriting textFrom on any part that doesn't match, since it's normally only reached via the combo box's own activated(int) signal (real user interaction, never fired by programmatic setCurrentIndex()). updateForm() runs on every selection change, so during a rubber-band drag over dynamic text fields with different sources, each time a new field enters the selection, the representative part's textFrom gets force-applied to every other selected part - converting e.g. a UserText field to ElementInfo mid-drag, before the user has released the mouse or interacted with the combo box at all. Split the cosmetic widget-enable logic into updateTextFromWidgetsEnabled(), called from updateForm(). on_m_text_from_cb_activated() keeps the part-mutating loop, now only reached from real user activation. Co-Authored-By: Claude Sonnet 5 --- sources/editor/ui/dynamictextfieldeditor.cpp | 17 +++++++++++++++-- sources/editor/ui/dynamictextfieldeditor.h | 1 + 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/sources/editor/ui/dynamictextfieldeditor.cpp b/sources/editor/ui/dynamictextfieldeditor.cpp index 84f4db772..33d572f2a 100644 --- a/sources/editor/ui/dynamictextfieldeditor.cpp +++ b/sources/editor/ui/dynamictextfieldeditor.cpp @@ -163,7 +163,7 @@ void DynamicTextFieldEditor::updateForm() } } - on_m_text_from_cb_activated(ui -> m_text_from_cb -> currentIndex()); //For enable the good widget + updateTextFromWidgetsEnabled(ui -> m_text_from_cb -> currentIndex()); //For enable the good widget } } @@ -327,7 +327,16 @@ void DynamicTextFieldEditor::on_m_elmt_info_cb_activated(const QString &arg1) { } } -void DynamicTextFieldEditor::on_m_text_from_cb_activated(int index) { +/** + @brief DynamicTextFieldEditor::updateTextFromWidgetsEnabled + Enable the widget matching @p index (the "text from" combo box's current + index) and disable the other two. Purely cosmetic: called both from the + real user-activated slot below and from updateForm() when the form is + (re)filled for a part/selection, so it must never touch m_parts's data — + see on_m_text_from_cb_activated() for the part-mutating counterpart. +*/ +void DynamicTextFieldEditor::updateTextFromWidgetsEnabled(int index) +{ ui -> m_user_text_le -> setDisabled(true); ui -> m_elmt_info_cb -> setDisabled(true); ui -> m_composite_text_pb -> setDisabled(true); @@ -341,6 +350,10 @@ void DynamicTextFieldEditor::on_m_text_from_cb_activated(int index) { else { ui->m_composite_text_pb->setEnabled(true); } +} + +void DynamicTextFieldEditor::on_m_text_from_cb_activated(int index) { + updateTextFromWidgetsEnabled(index); DynamicElementTextItem::TextFrom tf; if(index == 0) { diff --git a/sources/editor/ui/dynamictextfieldeditor.h b/sources/editor/ui/dynamictextfieldeditor.h index b4fd3ed8d..5e5464222 100644 --- a/sources/editor/ui/dynamictextfieldeditor.h +++ b/sources/editor/ui/dynamictextfieldeditor.h @@ -52,6 +52,7 @@ class DynamicTextFieldEditor : public ElementItemEditor { void fillInfoComboBox(); void setUpConnections(); void disconnectConnections(); + void updateTextFromWidgetsEnabled(int index); private slots: void on_m_x_sb_editingFinished();