From 7bfe5f563e48af2c6d28fd209981a6af14cb575b Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Sun, 19 Jun 2022 13:13:25 -0700 Subject: [PATCH] viewer: use popup for text editor --- app/widget/viewer/viewerdisplay.cpp | 102 +++++++++++++++++-------- app/widget/viewer/viewertexteditor.cpp | 49 ++---------- app/widget/viewer/viewertexteditor.h | 6 +- 3 files changed, 77 insertions(+), 80 deletions(-) diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index 1d03c75fb..1efaff97f 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -248,10 +248,15 @@ bool ViewerDisplayWidget::eventFilter(QObject *o, QEvent *e) switch (e->type()) { case QEvent::MouseButtonPress: - if (OnMousePress(static_cast(e))) { - return true; + { + QMouseEvent *mouse = static_cast(e); + if (!(mouse->flags() & Qt::MouseEventCreatedDoubleClick)) { + if (OnMousePress(mouse)) { + return true; + } } break; + } case QEvent::MouseMove: EmitColorAtCursor(static_cast(e)); if (OnMouseMove(static_cast(e))) { @@ -656,61 +661,94 @@ void ViewerDisplayWidget::OpenTextGizmo(TextGizmo *text, QMouseEvent *event) { QTransform gizmo_transform = GenerateDisplayTransform(); - ViewerTextEditor *text_edit = new ViewerTextEditor(gizmo_transform.m11(), this); - - text_edit->setWindowFlags(text_edit->windowFlags() | Qt::Tool | Qt::FramelessWindowHint); - text_edit->setAttribute(Qt::WA_NoSystemBackground); - text_edit->setAttribute(Qt::WA_TranslucentBackground); + // Create popup container for text and toolbar + auto popup = new QWidget(this); + popup->setWindowFlags(Qt::Popup | Qt::FramelessWindowHint); + popup->setAttribute(Qt::WA_DeleteOnClose); + popup->setAttribute(Qt::WA_TranslucentBackground); + // Create text editor + ViewerTextEditor *text_edit = new ViewerTextEditor(gizmo_transform.m11(), popup); Html::HtmlToDoc(text_edit->document(), text->GetHtml()); text_edit->setProperty("gizmo", reinterpret_cast(text)); + connect(text_edit, &ViewerTextEditor::textChanged, this, &ViewerDisplayWidget::TextEditChanged); - QRect transformed_geom = gizmo_transform.map(text->GetRect()).boundingRect().toRect(); + // Get on screen text rect (this will be the text editor's global geometry) + QRect global_text_area = gizmo_transform.map(text->GetRect()).boundingRect().toRect(); + global_text_area = QRect(mapToGlobal(global_text_area.topLeft()), mapToGlobal(global_text_area.bottomRight())); - text_edit->setGeometry(QRect(mapToGlobal(transformed_geom.topLeft()), mapToGlobal(transformed_geom.bottomRight()))); + QRect global_popup_area = global_text_area; - ViewerTextEditorToolBar *toolbar = new ViewerTextEditorToolBar(this); + // Create toolbar + ViewerTextEditorToolBar *toolbar = new ViewerTextEditorToolBar(popup); + text_edit->ConnectToolBar(toolbar); - QPoint pos = mapToGlobal(QPoint(transformed_geom.x(), transformed_geom.y() - toolbar->height())); + // Work out which corner of the text editor to anchor the toolbar to based on screen limitations + bool top = true; + bool left = true; for (QScreen *screen : qApp->screens()) { - if (screen->geometry().contains(pos)) { - if (pos.x() + toolbar->width() > screen->geometry().right()) { - pos.setX(screen->geometry().right() - toolbar->width()); + // Look for screen that contains text area + if (screen->geometry().contains(global_text_area)) { + if (global_text_area.left() + toolbar->width() > screen->geometry().right()) { + left = false; + } + if (global_text_area.top() - toolbar->height() < screen->geometry().top()) { + top = false; } break; } } - toolbar->move(pos); - toolbar->show(); - text_edit->show(); - connect(text_edit, &ViewerTextEditor::textChanged, this, &ViewerDisplayWidget::TextEditChanged); + QPoint toolbar_pos; - text_edit->ConnectToolBar(toolbar); + if (top) { + global_popup_area.adjust(0, -toolbar->height(), 0, 0); + toolbar_pos.setY(0); + } else { + global_popup_area.adjust(0, 0, 0, toolbar->height()); + toolbar_pos.setY(global_text_area.height()); + } - QPoint text_edit_pos; + if (toolbar->width() > global_popup_area.width()) { + int diff = toolbar->width() - global_popup_area.width(); + if (left) { + global_popup_area.adjust(0, 0, diff, 0); + } else { + global_popup_area.adjust(-diff, 0, 0, 0); + } + toolbar_pos.setX(0); + } else { + if (left) { + toolbar_pos.setX(0); + } else { + toolbar_pos.setX(global_popup_area.width() - toolbar->width()); + } + } + + toolbar->move(toolbar_pos); + + popup->setGeometry(global_popup_area); + + text_edit->setGeometry(QRect(text_edit->mapFromGlobal(global_text_area.topLeft()), text_edit->mapFromGlobal(global_text_area.bottomRight()))); + + popup->show(); + + // Store click pos from event so we can use it later to set the initial text cursor position + QPoint click_pos; if (event) { - text_edit_pos = text_edit->mapFrom(this, event->pos()); + click_pos = event->globalPos(); } // Ensure text edit is actually focused rather than the toolbar - connect(toolbar, &ViewerTextEditorToolBar::FirstPaint, this, [this, text_edit, text_edit_pos]{ + connect(toolbar, &ViewerTextEditorToolBar::FirstPaint, this, [text_edit, click_pos]{ // Grab focus back from the toolbar - this->raise(); - this->activateWindow(); text_edit->setFocus(); // Start text cursor where the user clicked - if (!text_edit_pos.isNull()) { - text_edit->setTextCursor(text_edit->cursorForPosition(text_edit_pos)); + if (!click_pos.isNull()) { + text_edit->setTextCursor(text_edit->cursorForPosition(text_edit->mapFromGlobal(click_pos))); } - - // HACK: On macOS, for some reason the QDockWidget receives focus before the - // ViewerTextEditor, causing the editor to close prematurely. However this only - // happens the first time the editor receives focus and not subsequent times, so - // if we get it to only listen after the first one, this solves the problem. - text_edit->SetListenToFocusEvents(true); }); } diff --git a/app/widget/viewer/viewertexteditor.cpp b/app/widget/viewer/viewertexteditor.cpp index 7c56eaa50..6a6c3227a 100644 --- a/app/widget/viewer/viewertexteditor.cpp +++ b/app/widget/viewer/viewertexteditor.cpp @@ -61,7 +61,6 @@ ViewerTextEditor::ViewerTextEditor(double scale, QWidget *parent) : dpi_force_.setDotsPerMeterY(dpm); document()->documentLayout()->setPaintDevice(&dpi_force_); - connect(qApp, &QApplication::focusChanged, this, &ViewerTextEditor::FocusChanged); connect(this, &QTextEdit::currentCharFormatChanged, this, &ViewerTextEditor::FormatChanged); connect(document(), &QTextDocument::contentsChanged, this, &ViewerTextEditor::DocumentChanged, Qt::QueuedConnection); @@ -70,8 +69,6 @@ ViewerTextEditor::ViewerTextEditor(double scale, QWidget *parent) : void ViewerTextEditor::ConnectToolBar(ViewerTextEditorToolBar *toolbar) { - connect(this, &ViewerTextEditor::destroyed, toolbar, &ViewerTextEditorToolBar::deleteLater); - connect(toolbar, &ViewerTextEditorToolBar::FamilyChanged, this, &ViewerTextEditor::SetFamily); connect(toolbar, &ViewerTextEditorToolBar::SizeChanged, this, &ViewerTextEditor::setFontPointSize); connect(toolbar, &ViewerTextEditorToolBar::StyleChanged, this, &ViewerTextEditor::SetStyle); @@ -94,15 +91,6 @@ void ViewerTextEditor::ConnectToolBar(ViewerTextEditorToolBar *toolbar) toolbars_.append(toolbar); } -void ViewerTextEditor::keyPressEvent(QKeyEvent *event) -{ - super::keyPressEvent(event); - - if (event->key() == Qt::Key_Escape) { - deleteLater(); - } -} - void ViewerTextEditor::paintEvent(QPaintEvent *e) { QPainter p(this->viewport()); @@ -178,34 +166,6 @@ void ViewerTextEditor::UpdateToolBar(ViewerTextEditorToolBar *toolbar, const QTe toolbar->SetLineHeight(b.lineHeight() == 0.0 ? 100 : b.lineHeight()); } -void ViewerTextEditor::FocusChanged(QWidget *old, QWidget *now) -{ - if (!listen_to_focus_events_) { - return; - } - - QWidget *test = now; - - if (!test) { - // Ignore null focuses because that could be one of the toolbar widgets simply losing focus - // and that would be undesirable to close the text editor from - return; - } - - while (test) { - if (test == this - || dynamic_cast(test) - || dynamic_cast(test)) { - return; - } - - test = test->parentWidget(); - } - - // If we didn't return in the loop, the user must have focused on something else - deleteLater(); -} - void ViewerTextEditor::FormatChanged(const QTextCharFormat &f) { if (!block_update_toolbar_signal_) { @@ -325,8 +285,9 @@ void ViewerTextEditor::DocumentChanged() } ViewerTextEditorToolBar::ViewerTextEditorToolBar(QWidget *parent) : - QWidget(parent, Qt::Tool | Qt::FramelessWindowHint), - painted_(false) + QWidget(parent), + painted_(false), + drag_enabled_(false) { QVBoxLayout *outer_layout = new QVBoxLayout(this); outer_layout->setSpacing(0); @@ -511,7 +472,7 @@ void ViewerTextEditorToolBar::mousePressEvent(QMouseEvent *event) { QWidget::mousePressEvent(event); - if (event->button() == Qt::LeftButton) { + if (event->button() == Qt::LeftButton && drag_enabled_) { drag_anchor_ = event->pos(); } } @@ -520,7 +481,7 @@ void ViewerTextEditorToolBar::mouseMoveEvent(QMouseEvent *event) { QWidget::mouseMoveEvent(event); - if (event->buttons() & Qt::LeftButton) { + if ((event->buttons() & Qt::LeftButton) && drag_enabled_) { this->move(mapToParent(QPoint(event->pos() - drag_anchor_))); } } diff --git a/app/widget/viewer/viewertexteditor.h b/app/widget/viewer/viewertexteditor.h index 8df6a5285..2731cb710 100644 --- a/app/widget/viewer/viewertexteditor.h +++ b/app/widget/viewer/viewertexteditor.h @@ -126,6 +126,8 @@ private: bool painted_; + bool drag_enabled_; + private slots: void UpdateFontStyleList(const QString &family); @@ -144,8 +146,6 @@ public: void SetListenToFocusEvents(bool e) { listen_to_focus_events_ = e; } protected: - virtual void keyPressEvent(QKeyEvent *event) override; - virtual void paintEvent(QPaintEvent *event) override; private: @@ -166,8 +166,6 @@ private: bool listen_to_focus_events_; private slots: - void FocusChanged(QWidget *old, QWidget *now); - void FormatChanged(const QTextCharFormat &f); void SetFamily(const QString &s);