(C++) QtRoundedEditRectItem
January 25, 2018 · View on GitHub
(C++) QtRoundedEditRectItem



QtRoundedEditRectItem is a Qt QGraphicsItem class that displays a rounded rectangle with editable text.
Technical facts
./CppQtRoundedEditRectItem/CppQtRoundedEditRectItem.pri
INCLUDEPATH += \ ../../Classes/CppQtRoundedEditRectItem SOURCES += \ ../../Classes/CppQtRoundedEditRectItem/qtroundededitrectitem.cpp \ ../../Classes/CppQtRoundedEditRectItem/qtroundededitrectitemdialog.cpp \ ../../Classes/CppQtRoundedEditRectItem/qtroundededitrectitempadding.cpp \ ../../Classes/CppQtRoundedEditRectItem/qtroundededitrectitem_test.cpp HEADERS += \ ../../Classes/CppQtRoundedEditRectItem/qtroundededitrectitem.h \ ../../Classes/CppQtRoundedEditRectItem/qtroundededitrectitemdialog.h \ ../../Classes/CppQtRoundedEditRectItem/qtroundededitrectitempadding.h OTHER_FILES += \ ../../Classes/CppQtRoundedEditRectItem/Licence.txt FORMS += \ ../../Classes/CppQtRoundedEditRectItem/qtroundededitrectitemdialog.ui
./CppQtRoundedEditRectItem/qtroundededitrectitem.h
//--------------------------------------------------------------------------- /* QtRoundedEditRectItem, editable rectangular-shaped QGraphicsItem Copyright 2012-2015 Richel Bilderbeek This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program.If not, see <http://www.gnu.org/licenses/>. */ //--------------------------------------------------------------------------- //From http://www.richelbilderbeek.nl/QtRoundedEditRectItem.htm //--------------------------------------------------------------------------- #ifndef QTROUNDEDEDITRECTITEM_H #define QTROUNDEDEDITRECTITEM_H #include <string> #include <vector> #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Weffc++" #pragma GCC diagnostic ignored "-Wunused-local-typedefs" #pragma GCC diagnostic ignored "-Wunused-but-set-parameter" #include <boost/signals2.hpp> #include <QFont> #include "qtroundedrectitem.h" #include "qtroundededitrectitempadding.h" #pragma GCC diagnostic pop namespace ribi { ///A QtRoundedRectTextItem displaying multiple lines of text ///For a single line of text, use QtRoundedEditRectItem class QtRoundedEditRectItem : public QtRoundedRectItem { //Q_OBJECT //Cannot make this a QObject??? public: typedef QtRoundedRectItem Base; typedef QtRoundedEditRectItemPadding Padding; explicit QtRoundedEditRectItem( const std::vector<std::string>& text = { "..." }, const Padding& padding = Padding(), const QFont& font = QFont("monospace",9), QGraphicsItem* parent = 0 ); virtual ~QtRoundedEditRectItem() noexcept; ///Get the font by which the text is drawn const QFont& GetFont() const noexcept; const Padding& GetPadding() const noexcept { return m_padding; } ///Obtain the text on the item const std::vector<std::string>& GetText() const noexcept; const QPen& GetTextPen() const noexcept { return m_text_pen; } ///Obtain the version of this class static std::string GetVersion() noexcept; ///Obtain the version history of this class static std::vector<std::string> GetVersionHistory() noexcept; ///Set the font by which the text is drawn void SetFont(const QFont& font) noexcept; ///Set the padding between text and rectangle void SetPadding(const Padding& padding) noexcept; ///Set the text displayed void SetText(const std::vector<std::string>& text) noexcept; ///Set the pen by which the text is drawn void SetTextPen(const QPen& pen) noexcept; ///Called when the user wants to edit the text //boost::signals2::signal<void(QtRoundedEditRectItem*)> m_signal_item_requests_edit; boost::signals2::signal<void(QtRoundedEditRectItem*)> m_signal_base_changed; boost::signals2::signal<void(QtRoundedEditRectItem*)> m_signal_font_changed; boost::signals2::signal<void(QtRoundedEditRectItem*)> m_signal_padding_changed; boost::signals2::signal<void(QtRoundedEditRectItem*)> m_signal_text_changed; boost::signals2::signal<void(QtRoundedEditRectItem*)> m_signal_text_pen_changed; protected: virtual void keyPressEvent(QKeyEvent* event) noexcept; virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) noexcept; private: ///The font by which the text is drawn QFont m_font; ///Set the padding between text and rectangle Padding m_padding; ///The text displayed std::vector<std::string> m_text; ///Set the padding around text, so the text will be centered static const Padding m_text_padding; ///The pen by which the text is drawn QPen m_text_pen; ///Obtain the unpadded text rectangle for a single line, ///where the center lies at the origin /* | | +-----+ ---|ABCDE|--- +-----+ | | */ static QRectF GetTextRectAtOrigin(const std::string& s, const QFont& font) noexcept; ///Obtain the unpadded text rectangle for the whole text, ///where the center lies at the origin ///Note: even this rectangle is enlarged by a pixel in both dimensions, so the text will be drawn in full /* | | +-----+ |ABCDE| ---|ABCDE|--- |ABCDE| +-----+ | | */ static QRectF GetTextRectAtOrigin(const std::vector<std::string>& text, const QFont& font) noexcept; ///Obtain the padded text rectangle for a single line ///where the center lies at the origin /* | | +-------+ | | ---| ABCDE |--- | | +-------+ | | */ static QRectF GetPaddedTextRectAtOrigin(const std::string& s, const QFont& font) noexcept; ///Obtain the padded text rectangle for a single line ///where the center lies at the correct location /* | | +-------+ | | | ABCDE | | | +-------+ | | ---| |--- | | +-------+ | | | | | | +-------+ | | Line 0/3 */ static QRectF GetPaddedTextRectAtLine(const std::string& s, const QFont& font, const int line, const int n_lines) noexcept; ///Called whenever a base class item is changed void OnBaseChanged(QtRoundedRectItem * const) noexcept; #ifndef NDEBUG static void Test() noexcept; #endif }; //std::ostream& operator<<(std::ostream& os, const QtRoundedEditRectItem&) noexcept; } //~namespace ribi #endif // QTROUNDEDEDITRECTITEM_H
./CppQtRoundedEditRectItem/qtroundededitrectitem.cpp
//--------------------------------------------------------------------------- /* QtRoundedEditRectItem, editable rectangular-shaped QGraphicsItem Copyright 2012-2015 Richel Bilderbeek This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program.If not, see <http://www.gnu.org/licenses/>. */ //--------------------------------------------------------------------------- //From http://www.richelbilderbeek.nl/QtRoundedEditRectItem.htm //--------------------------------------------------------------------------- #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Weffc++" #pragma GCC diagnostic ignored "-Wunused-local-typedefs" #pragma GCC diagnostic ignored "-Wunused-but-set-parameter" #include "qtroundededitrectitem.h" #include <cassert> #include <boost/lambda/lambda.hpp> #include <QFontMetrics> #include <QKeyEvent> #include <QPainter> #include "container.h" //#include "geometry.h" #include "trace.h" #pragma GCC diagnostic pop const ribi::QtRoundedEditRectItem::Padding ribi::QtRoundedEditRectItem::m_text_padding(3.0,0.0,0.0,3.0); ribi::QtRoundedEditRectItem::QtRoundedEditRectItem( const std::vector<std::string>& text, const Padding& padding, const QFont& font, QGraphicsItem* parent) : QtRoundedRectItem(parent), m_signal_base_changed{}, m_signal_font_changed{}, m_signal_padding_changed{}, m_signal_text_changed{}, m_signal_text_pen_changed{}, m_font(font), m_padding(padding), m_text( {""} ), //Empty std::vector<std::string>, as m_text must be set by SetText m_text_pen{} { #ifndef NDEBUG Test(); #endif this->setFlags( QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable ); this->m_signal_contour_pen_changed.connect( boost::bind(&ribi::QtRoundedEditRectItem::OnBaseChanged,this,boost::lambda::_1) ); this->m_signal_focus_pen_changed.connect( boost::bind(&ribi::QtRoundedEditRectItem::OnBaseChanged,this,boost::lambda::_1) ); this->m_signal_pos_changed.connect( boost::bind(&ribi::QtRoundedEditRectItem::OnBaseChanged,this,boost::lambda::_1) ); this->m_signal_radius_x_changed.connect( boost::bind(&ribi::QtRoundedEditRectItem::OnBaseChanged,this,boost::lambda::_1) ); this->m_signal_radius_y_changed.connect( boost::bind(&ribi::QtRoundedEditRectItem::OnBaseChanged,this,boost::lambda::_1) ); this->m_signal_width_changed.connect( boost::bind(&ribi::QtRoundedEditRectItem::OnBaseChanged,this,boost::lambda::_1) ); this->m_signal_height_changed.connect( boost::bind(&ribi::QtRoundedEditRectItem::OnBaseChanged,this,boost::lambda::_1) ); ///Obtain a white background this->setBrush(QBrush(QColor(255,255,255))); this->SetFont(font); this->SetRadiusX(4.0); this->SetRadiusY(4.0); this->SetPadding(Padding(1.0,1.0,1.0,1.0)); this->SetText(text); this->update(); } ribi::QtRoundedEditRectItem::~QtRoundedEditRectItem() noexcept { //OK } const QFont& ribi::QtRoundedEditRectItem::GetFont() const noexcept { return m_font; } QRectF ribi::QtRoundedEditRectItem::GetPaddedTextRectAtOrigin( const std::string& s, const QFont& font ) noexcept { return GetTextRectAtOrigin(s,font).adjusted( -m_text_padding.left, -m_text_padding.top, m_text_padding.right, m_text_padding.bottom); } QRectF ribi::QtRoundedEditRectItem::GetPaddedTextRectAtLine( const std::string& s, const QFont& font, const int line, const int n_lines ) noexcept { const auto r = GetPaddedTextRectAtOrigin(s,font); const auto line_width = r.width(); const auto line_height = r.height(); const auto total_width = line_width; const auto total_height = line_height * n_lines; const auto total_x1 = -0.5 * total_width; const auto total_y1 = -0.5 * total_height; const auto x1 = total_x1; const auto y1 = total_y1 + (line * line_height); return QRectF(x1,y1,line_width,line_height); } const std::vector<std::string>& ribi::QtRoundedEditRectItem::GetText() const noexcept { return m_text; } QRectF ribi::QtRoundedEditRectItem::GetTextRectAtOrigin( const std::string& s, const QFont& font ) noexcept { const double h = QFontMetricsF(font).height(); const double w = QFontMetricsF(font).width(s.c_str()); assert(h > 0.0); assert(w >= 0.0 && "An empty text can have width 0"); #ifdef _WIN32 //adjusted(0.0,0.0,2.0,0.0) works fine for 50% of the fonts supplied by Wine under native Lubuntu //adjusted(0.0,0.0,3.0,0.0) works fine for 80% of the fonts supplied by Wine under native Lubuntu return QRectF(-0.5 * w, 0.0,w,h).adjusted(0.0,0.0,3.0,0.0); #else //adjusted(0.0,0.0,2.0,-1.0) works fine for 90% of the fonts under native Lubuntu //adjusted(0.0,0.0,3.0,-1.0) works fine for 99% of the fonts under native Lubuntu //adjusted(0.0,0.0,4.0,-1.0) works fine for all the fonts I've tried under native Lubuntu //return QRectF(-0.5 * w,0.0,w,h).adjusted(0.0,0.0,2.0,-1.0); const QRectF result = QRectF(-0.5 * w,-0.5 * h,w,h).adjusted(0.0,0.0,2.0,0.0); assert(result.width() >= 0.0); assert(result.height() > 0.0); return result; #endif } QRectF ribi::QtRoundedEditRectItem::GetTextRectAtOrigin( const std::vector<std::string>& text, const QFont& font) noexcept { std::vector<QRectF> v; std::transform(text.begin(),text.end(),std::back_inserter(v), [font](const std::string& s) { return QtRoundedEditRectItem::GetPaddedTextRectAtOrigin(s,font); } ); const auto width_iter = std::max_element(v.begin(),v.end(), [](const QRectF& lhs, const QRectF& rhs) { return lhs.width() < rhs.width(); } ); const double width = width_iter == v.end() ? 1.0 : width_iter->width(); const double height = std::accumulate(v.begin(),v.end(),0.0, [](double& init, const QRectF& r) { assert(r.height() > 0.0); return init + r.height() + 0.0; } ); assert(width > 0.0); assert(height > 0.0); return QRectF(-0.5 * width,-0.5 * height, width, height).adjusted(-0.0,-0.0,0.0,0.0); } std::string ribi::QtRoundedEditRectItem::GetVersion() noexcept { return "1.1"; } std::vector<std::string> ribi::QtRoundedEditRectItem::GetVersionHistory() noexcept { return { "2012-12-19: version 1.0: initial version", "2014-08-09: version 1.1: increased use of Tdd" }; } void ribi::QtRoundedEditRectItem::keyPressEvent(QKeyEvent* event) noexcept { switch (event->key()) { case Qt::Key_F2: //m_signal_item_requests_edit(this); break; } QtRoundedRectItem::keyPressEvent(event); } void ribi::QtRoundedEditRectItem::OnBaseChanged(QtRoundedRectItem * const) noexcept { m_signal_base_changed(this); } void ribi::QtRoundedEditRectItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) noexcept { //Draws the rounded rectangle QtRoundedRectItem::paint(painter,option,widget); //Draw the text lines at the right spot painter->setFont(m_font); painter->setPen(m_text_pen); const int sz = static_cast<int>(m_text.size()); for (int i=0; i!=sz;++i) { // For this line, work down from // (1) a padded text rectangle at the right location // (2) an (ordinary) text rectangle (where the text will be drawn), at the right location const std::string& s = m_text[i]; // (1) a padded text rectangle at the right location const QRectF padded_rect = GetPaddedTextRectAtLine(s,m_font,i,sz); //TRACE(Geometry().ToStr(padded_rect)); // (2) an (ordinary) text rectangle (where the text will be drawn), at the right location const QRectF text_rect( padded_rect.adjusted( m_text_padding.left, m_text_padding.top, -m_text_padding.right, -m_text_padding.bottom ) ); //TRACE(Geometry().ToStr(text_rect)); painter->drawText(text_rect,s.c_str()); } } #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-but-set-parameter" void ribi::QtRoundedEditRectItem::SetFont(const QFont& font) noexcept { if (m_font != font) { m_font = font; this->update(); //m_signal_request_scene_update(); m_signal_font_changed(this); } } #pragma GCC diagnostic pop void ribi::QtRoundedEditRectItem::SetPadding(const Padding& padding) noexcept { if (padding != m_padding) { m_padding = padding; //Adapt the size const QRectF text_rect = GetTextRectAtOrigin(m_text,m_font); this->SetInnerWidth( text_rect.width() + m_padding.left + m_padding.right ); this->SetInnerHeight( text_rect.height() + m_padding.top + m_padding.bottom ); this->update(); //m_signal_request_scene_update(); m_signal_padding_changed(this); } } void ribi::QtRoundedEditRectItem::SetText(const std::vector<std::string>& text) noexcept { const bool verbose{false}; if (text != m_text) { if (verbose) { std::stringstream s; s << "Text will change from '" << Container().Concatenate(m_text) << "' to '" << Container().Concatenate(text) << "'" ; TRACE(s.str()); } m_text = text; //Adapt the size const QRectF text_rect = GetTextRectAtOrigin(m_text,m_font); this->SetInnerWidth( text_rect.width() + m_padding.left + m_padding.right ); this->SetInnerHeight( text_rect.height() + m_padding.top + m_padding.bottom ); m_signal_text_changed(this); this->update(); } else { if (verbose) { std::stringstream s; s << "Text will remain '" << Container().ToStr(m_text) << "'" ; TRACE(s.str()); } } } void ribi::QtRoundedEditRectItem::SetTextPen(const QPen& pen) noexcept { if (m_text_pen != pen) { m_text_pen = pen; this->update(); m_signal_text_pen_changed(this); } }
./CppQtRoundedEditRectItem/qtroundededitrectitem_test.cpp
//--------------------------------------------------------------------------- /* QtRoundedEditRectItem, editable rectangular-shaped QGraphicsItem Copyright 2012-2015 Richel Bilderbeek This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program.If not, see <http://www.gnu.org/licenses/>. */ //--------------------------------------------------------------------------- //From http://www.richelbilderbeek.nl/QtRoundedEditRectItem.htm //--------------------------------------------------------------------------- #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Weffc++" #pragma GCC diagnostic ignored "-Wunused-local-typedefs" #pragma GCC diagnostic ignored "-Wunused-but-set-parameter" #include "qtroundededitrectitem.h" #include <cassert> #include "testtimer.h" #include "trace.h" #pragma GCC diagnostic pop #ifndef NDEBUG void ribi::QtRoundedEditRectItem::Test() noexcept { { static bool is_tested{false}; if (is_tested) return; is_tested = true; } { QtRoundedRectItem(); } const bool verbose{false}; const TestTimer test_timer(__func__,__FILE__,1.0); QtRoundedEditRectItem item; if (verbose) { TRACE("Set/Get Text must be symmetric"); } { const auto old_text = item.GetText(); auto new_text = old_text; new_text[0] += " (modified)"; item.SetText(new_text); assert(item.GetText() == new_text); } if (verbose) { TRACE("Setting two increasing-length single-line texts should increase the inner width"); } { item.SetText( {"A"} ); const double old_width{item.GetInnerWidth()}; item.SetText( {"AB"} ); assert(old_width < item.GetInnerWidth()); } if (verbose) { TRACE("Setting two decreasing-length single-line texts should decrease the inner width"); } { item.SetText( {"AB"} ); const double old_width{item.GetInnerWidth()}; item.SetText( {"A"} ); assert(old_width > item.GetInnerWidth()); } if (verbose) { TRACE("Setting two increasing-length single-line texts should keep the inner height the same"); } { item.SetText( {"A"} ); const double old_height{item.GetInnerHeight()}; item.SetText( {"AB"} ); assert(old_height == item.GetInnerHeight()); } if (verbose) { TRACE("A text rectangle of a single-line text must have its center at origin"); } { const auto center = QtRoundedEditRectItem::GetTextRectAtOrigin("ABCDEFG",QFont()).center(); assert(center.x() >= -2.0); assert(center.x() <= 2.0); assert(center.y() >= -2.0); assert(center.y() <= 2.0); } if (verbose) { TRACE("A text rectangle of a multi-line text must have its center at origin"); } { const auto center = QtRoundedEditRectItem::GetTextRectAtOrigin( { "ABCDEFG", "ABCDEFG", "ABCDEFG" }, QFont()).center(); assert(center.x() >= -2.0); assert(center.x() <= 2.0); assert(center.y() >= -2.0); assert(center.y() <= 2.0); } if (verbose) { TRACE("A padded text rectangle of a multi-line text, line 1/3 must have its center above origin"); } { const auto center = QtRoundedEditRectItem::GetPaddedTextRectAtLine("ABCDEFG",QFont(),0,3).center(); //TRACE(center.x()); //TRACE(center.y()); assert(center.x() >= -2.0); assert(center.x() <= 2.0); assert(center.y() < 0.0); } if (verbose) { TRACE("A padded text rectangle of a multi-line text, line 3/3 must have its center above origin"); } { const auto center = QtRoundedEditRectItem::GetPaddedTextRectAtLine("ABCDEFG",QFont(),2,3).center(); //TRACE(center.x()); //TRACE(center.y()); assert(center.x() >= -2.0); assert(center.x() <= 2.0); assert(center.y() > 0.0); } if (verbose) { TRACE("A padded text rectangle must at least be as wide as a text rectangle"); } { assert(GetTextRectAtOrigin("X",QFont()).width() > 0.0); assert(GetPaddedTextRectAtOrigin("X",QFont()).width() >= GetTextRectAtOrigin("X",QFont()).width()); } } #endif
./CppQtRoundedEditRectItem/qtroundededitrectitemdialog.h
//--------------------------------------------------------------------------- /* QtRoundedEditRectItem, editable rectangular-shaped QGraphicsItem Copyright 2012-2015 Richel Bilderbeek This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program.If not, see <http://www.gnu.org/licenses/>. */ //--------------------------------------------------------------------------- //From http://www.richelbilderbeek.nl/QtRoundedEditRectItem.htm //--------------------------------------------------------------------------- #ifndef QTROUNDEDEDITRECTITEMDIALOG_H #define QTROUNDEDEDITRECTITEMDIALOG_H #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Weffc++" #pragma GCC diagnostic ignored "-Wunused-local-typedefs" #pragma GCC diagnostic ignored "-Wunused-but-set-parameter" #include <boost/shared_ptr.hpp> #include "qthideandshowdialog.h" #pragma GCC diagnostic pop namespace Ui { class QtRoundedEditRectItemDialog; } namespace ribi { //struct QtRoundedRectItem; //QtRoundedEditRectItem its base class struct QtRoundedEditRectItem; //The item struct QtRoundedRectItemDialog; //its base class display class QtRoundedEditRectItemDialog : public QtHideAndShowDialog { Q_OBJECT public: explicit QtRoundedEditRectItemDialog(QWidget *parent = 0); QtRoundedEditRectItemDialog(const QtRoundedEditRectItemDialog&) = delete; QtRoundedEditRectItemDialog& operator=(const QtRoundedEditRectItemDialog&) = delete; ~QtRoundedEditRectItemDialog() noexcept; boost::shared_ptr<QtRoundedEditRectItem> GetItem() const noexcept { return m_item; } static int GetMinimumHeight(const QtRoundedEditRectItem& /* item */) noexcept { return 276 + 500; } static int GetMinimumHeight( ) noexcept { return 276 + 500; } ///Read the X value directly from GUI double GetUiX() const noexcept; ///Read the Y value directly from GUI double GetUiY() const noexcept; ///Obtain the version of this class static std::string GetVersion() noexcept; ///Obtain the version history of this class static std::vector<std::string> GetVersionHistory() noexcept; void SetItem(const boost::shared_ptr<QtRoundedEditRectItem>& item) noexcept; ///Set the X value directly to GUI void SetUiX(const double x) noexcept; ///Set the Y value directly to GUI void SetUiY(const double y) noexcept; protected: void keyPressEvent(QKeyEvent * event); private slots: void on_button_font_clicked(); void on_text_textChanged(); void on_button_text_pen_clicked(); void on_box_padding_left_valueChanged(double arg1); void on_box_padding_top_valueChanged(double arg1); void on_box_padding_right_valueChanged(double arg1); void on_box_padding_bottom_valueChanged(double arg1); private: Ui::QtRoundedEditRectItemDialog *ui; ///Dialog for its base class const boost::shared_ptr<QtRoundedRectItemDialog> m_dialog; ///The QtRoundedRectItem to work on boost::shared_ptr<QtRoundedEditRectItem> m_item; void OnBaseChanged(QtRoundedEditRectItem * const qtitem) noexcept; void OnFontChanged(QtRoundedEditRectItem * const qtitem) noexcept; void OnPaddingChanged(QtRoundedEditRectItem * const qtitem) noexcept; void OnTextChanged(QtRoundedEditRectItem * const qtitem) noexcept; void OnTextPenChanged(QtRoundedEditRectItem * const qtitem) noexcept; #ifndef NDEBUG static void Test() noexcept; #endif }; } //~namespace ribi #endif // QTROUNDEDEDITRECTITEMDIALOG_H
./CppQtRoundedEditRectItem/qtroundededitrectitemdialog.cpp
//--------------------------------------------------------------------------- /* QtRoundedEditRectItem, editable rectangular-shaped QGraphicsItem Copyright 2012-2015 Richel Bilderbeek This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program.If not, see <http://www.gnu.org/licenses/>. */ //--------------------------------------------------------------------------- //From http://www.richelbilderbeek.nl/QtRoundedEditRectItem.htm //--------------------------------------------------------------------------- #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Weffc++" #pragma GCC diagnostic ignored "-Wunused-local-typedefs" #pragma GCC diagnostic ignored "-Wunused-but-set-parameter" #include "qtroundededitrectitemdialog.h" #include <boost/algorithm/string/trim_all.hpp> #include <boost/make_shared.hpp> #include <boost/lambda/lambda.hpp> #include <QKeyEvent> #include <QFont> #include <QFontDialog> #include <QString> #include "container.h" #include "qtroundedrectitemdialog.h" #include "qtroundededitrectitem.h" #include "testtimer.h" #include "trace.h" #include "ui_qtroundededitrectitemdialog.h" #pragma GCC diagnostic pop ribi::QtRoundedEditRectItemDialog::QtRoundedEditRectItemDialog(QWidget *parent) : QtHideAndShowDialog(parent), ui(new Ui::QtRoundedEditRectItemDialog), m_dialog{boost::make_shared<QtRoundedRectItemDialog>()}, m_item{} { #ifndef NDEBUG Test(); #endif ui->setupUi(this); assert(this->layout()); this->layout()->addWidget(m_dialog.get()); m_dialog->DisableSetSize(); } ribi::QtRoundedEditRectItemDialog::~QtRoundedEditRectItemDialog() noexcept { delete ui; } double ribi::QtRoundedEditRectItemDialog::GetUiX() const noexcept { assert(m_dialog); return m_dialog->GetUiX(); } double ribi::QtRoundedEditRectItemDialog::GetUiY() const noexcept { assert(m_dialog); return m_dialog->GetUiY(); } std::string ribi::QtRoundedEditRectItemDialog::GetVersion() noexcept { return "1.3"; } std::vector<std::string> ribi::QtRoundedEditRectItemDialog::GetVersionHistory() noexcept { return { "2014-06-22: version 1.0: initial version", "2014-07-21: version 1.1: added CheckMe member function", "2014-07-31: version 1.2: fixed bug in SetText" "2014-08-04: version 1.3: removed CheckMe member function in favor of Tdd" }; } void ribi::QtRoundedEditRectItemDialog::keyPressEvent(QKeyEvent * event) { if (event->key() == Qt::Key_Escape) { close(); return; } } void ribi::QtRoundedEditRectItemDialog::on_button_font_clicked() { static QFont font = m_item->GetFont(); bool ok = false; const QFont new_font = QFontDialog::getFont(&ok, font, this); if (ok) { m_item->SetFont(new_font); } } void ribi::QtRoundedEditRectItemDialog::on_text_textChanged() { const auto s = ui->text->toPlainText().toStdString(); const auto text = Container().SeperateString(s,'\n'); m_item->SetText(text); } void ribi::QtRoundedEditRectItemDialog::on_button_text_pen_clicked() { const QPen pen( QBrush(qRgb(std::rand() % 256,std::rand() % 256,std::rand() % 256)), 1.0 + (static_cast<double>(std::rand() % 100) / 10.0) ); m_item->SetTextPen(pen); } void ribi::QtRoundedEditRectItemDialog::OnBaseChanged(QtRoundedEditRectItem * const #ifndef NDEBUG qtitem #endif // NDEBUG ) noexcept { assert(m_item.get() == qtitem); //boost::shared_ptr<QtRoundedRectItem> base(m_item); m_dialog->SetItem(m_item); } void ribi::QtRoundedEditRectItemDialog::OnFontChanged(QtRoundedEditRectItem * const qtitem) noexcept { ui->label_font->setText( qtitem->GetFont().toString() ); } void ribi::QtRoundedEditRectItemDialog::OnPaddingChanged(QtRoundedEditRectItem * const qtitem) noexcept { ui->box_padding_bottom->setValue(qtitem->GetPadding().bottom); ui->box_padding_left->setValue(qtitem->GetPadding().left); ui->box_padding_right->setValue(qtitem->GetPadding().right); ui->box_padding_top->setValue(qtitem->GetPadding().top); } void ribi::QtRoundedEditRectItemDialog::OnTextChanged(QtRoundedEditRectItem * const qtitem) noexcept { const std::string s{Container().Concatenate(qtitem->GetText(),"\n")}; ui->text->setPlainText(s.c_str()); } void ribi::QtRoundedEditRectItemDialog::OnTextPenChanged(QtRoundedEditRectItem * const qtitem) noexcept { std::stringstream s; s << "Text pen: " << qtitem->GetTextPen().widthF(); ui->label_text_pen->setText(s.str().c_str()); } void ribi::QtRoundedEditRectItemDialog::SetItem(const boost::shared_ptr<QtRoundedEditRectItem>& item) noexcept { const bool verbose{false}; assert(item); if (m_item == item) { return; } if (verbose) { std::stringstream s; s << "Setting item '" << (*item) << "'\n"; } const boost::shared_ptr<QtRoundedRectItem> base_after = item; const auto font_after = item->GetFont(); const auto padding_after = item->GetPadding(); const auto text_after = item->GetText(); const auto text_pen_after = item->GetTextPen(); bool base_changed = true; bool font_changed = true; bool padding_changed = true; bool text_changed = true; bool text_pen_changed = true; if (m_item) { const boost::shared_ptr<QtRoundedRectItem> base_before = m_item; const auto font_before = m_item->GetFont(); const auto padding_before = m_item->GetPadding(); const auto text_before = m_item->GetText(); const auto text_pen_before = m_item->GetTextPen(); base_changed = base_before != base_after; font_changed = font_before != font_after; padding_changed = padding_before != padding_after; text_changed = text_before != text_after; text_pen_changed = text_pen_before != text_pen_after; if (verbose) { if (base_changed) { std::stringstream s; s << "Base will change from " << (*base_before) << " to " << (*base_after) << '\n' ; TRACE(s.str()); } if (font_changed) { std::stringstream s; s << "Font will change from " << font_before.toString().toStdString() << " to " << font_after.toString().toStdString() << '\n'; TRACE(s.str()); } if (padding_changed) { std::stringstream s; s << "Padding will change from '" << padding_before << "' to '" << padding_after << "'\n"; TRACE(s.str()); } if (text_changed) { std::stringstream s; s << "Text will change from " << Container().ToStr(text_before) << " to " << Container().ToStr(text_after) << '\n'; TRACE(s.str()); } if (text_pen_changed) { std::stringstream s; s << "Text pen will change from " << text_pen_before.widthF() << " to " << text_pen_after.widthF() << '\n' ; TRACE(s.str()); } } //Disconnect m_item m_item->m_signal_base_changed.disconnect( boost::bind(&ribi::QtRoundedEditRectItemDialog::OnBaseChanged,this,boost::lambda::_1) ); m_item->m_signal_font_changed.disconnect( boost::bind(&ribi::QtRoundedEditRectItemDialog::OnFontChanged,this,boost::lambda::_1) ); m_item->m_signal_padding_changed.disconnect( boost::bind(&ribi::QtRoundedEditRectItemDialog::OnPaddingChanged,this,boost::lambda::_1) ); m_item->m_signal_text_changed.disconnect( boost::bind(&ribi::QtRoundedEditRectItemDialog::OnTextChanged,this,boost::lambda::_1) ); m_item->m_signal_text_pen_changed.disconnect( boost::bind(&ribi::QtRoundedEditRectItemDialog::OnTextPenChanged,this,boost::lambda::_1) ); } //Replace m_item by the new one m_item = item; assert(m_item->GetFont() == font_after); assert(m_item->GetPadding() == padding_after); assert(m_item->GetText() == text_after); assert(m_item->GetTextPen() == text_pen_after); m_item->m_signal_base_changed.connect( boost::bind(&ribi::QtRoundedEditRectItemDialog::OnBaseChanged,this,boost::lambda::_1) ); m_item->m_signal_font_changed.connect( boost::bind(&ribi::QtRoundedEditRectItemDialog::OnFontChanged,this,boost::lambda::_1) ); m_item->m_signal_padding_changed.connect( boost::bind(&ribi::QtRoundedEditRectItemDialog::OnPaddingChanged,this,boost::lambda::_1) ); m_item->m_signal_text_changed.connect( boost::bind(&ribi::QtRoundedEditRectItemDialog::OnTextChanged,this,boost::lambda::_1) ); m_item->m_signal_text_pen_changed.connect( boost::bind(&ribi::QtRoundedEditRectItemDialog::OnTextPenChanged,this,boost::lambda::_1) ); //Emit everything that has changed if (base_changed) { m_item->m_signal_base_changed(m_item.get()); } if (font_changed) { m_item->m_signal_font_changed(m_item.get()); } if (padding_changed) { m_item->m_signal_padding_changed(m_item.get()); } if (text_changed) { m_item->m_signal_text_changed(m_item.get()); } if (text_pen_changed) { m_item->m_signal_text_pen_changed(m_item.get()); } assert( item == m_item); assert(*item == *m_item); } void ribi::QtRoundedEditRectItemDialog::SetUiX(const double x) noexcept { this->m_dialog->SetUiX(x); } void ribi::QtRoundedEditRectItemDialog::SetUiY(const double y) noexcept { this->m_dialog->SetUiY(y); } #ifndef NDEBUG void ribi::QtRoundedEditRectItemDialog::Test() noexcept { { static bool is_tested{false}; if (is_tested) return; is_tested = true; } QtRoundedEditRectItem(); const TestTimer test_timer(__func__,__FILE__,1.0); /* assert(ui->box_padding_top->value() == m_item->GetPadding().top); assert(ui->box_padding_right->value() == m_item->GetPadding().right); assert(ui->box_padding_bottom->value() == m_item->GetPadding().bottom); assert(ui->box_padding_left->value() == m_item->GetPadding().left); assert(m_item->GetText() == Container().SeperateString(ui->text->toPlainText().toStdString(),'\n')); */ } #endif void ribi::QtRoundedEditRectItemDialog::on_box_padding_left_valueChanged(double arg1) { auto padding = m_item->GetPadding(); padding.left = arg1; m_item->SetPadding(padding); } void ribi::QtRoundedEditRectItemDialog::on_box_padding_top_valueChanged(double arg1) { auto padding = m_item->GetPadding(); padding.top = arg1; m_item->SetPadding(padding); } void ribi::QtRoundedEditRectItemDialog::on_box_padding_right_valueChanged(double arg1) { auto padding = m_item->GetPadding(); padding.right = arg1; m_item->SetPadding(padding); } void ribi::QtRoundedEditRectItemDialog::on_box_padding_bottom_valueChanged(double arg1) { auto padding = m_item->GetPadding(); padding.bottom = arg1; m_item->SetPadding(padding); }
./CppQtRoundedEditRectItem/qtroundededitrectitempadding.h
//--------------------------------------------------------------------------- /* QtRoundedEditRectItem, editable rectangular-shaped QGraphicsItem Copyright 2012-2015 Richel Bilderbeek This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program.If not, see <http://www.gnu.org/licenses/>. */ //--------------------------------------------------------------------------- //From http://www.richelbilderbeek.nl/QtRoundedEditRectItem.htm //--------------------------------------------------------------------------- #ifndef QTROUNDEDEDITRECTITEMPADDING_H #define QTROUNDEDEDITRECTITEMPADDING_H #include <iosfwd> namespace ribi { struct QtRoundedEditRectItemPadding { QtRoundedEditRectItemPadding( const double any_top = 0.0, const double any_right = 0.0, const double any_bottom = 0.0, const double any_left = 0.0 ) : bottom(any_bottom), left(any_left), right(any_right), top(any_top) {} double bottom; double left; double right; double top; }; std::ostream& operator<<(std::ostream& os, const QtRoundedEditRectItemPadding &p) noexcept; bool operator==(const QtRoundedEditRectItemPadding& lhs, const QtRoundedEditRectItemPadding& rhs) noexcept; bool operator!=(const QtRoundedEditRectItemPadding& lhs, const QtRoundedEditRectItemPadding& rhs) noexcept; } //~namespace ribi #endif // QTROUNDEDEDITRECTITEMPADDING_H
./CppQtRoundedEditRectItem/qtroundededitrectitempadding.cpp
#include "qtroundededitrectitempadding.h" #include <iostream> bool ribi::operator==( const QtRoundedEditRectItemPadding& lhs, const QtRoundedEditRectItemPadding& rhs ) noexcept { return lhs.bottom == rhs.bottom && lhs.left == rhs.left && lhs.right == rhs.right && lhs.top == rhs.top ; } bool ribi::operator!=( const QtRoundedEditRectItemPadding& lhs, const QtRoundedEditRectItemPadding& rhs ) noexcept { return !(lhs == rhs); } std::ostream& ribi::operator<<(std::ostream& os, const QtRoundedEditRectItemPadding &p) noexcept { os << '(' << p.left << ',' << p.top << ')' << '-' << '(' << p.right << ',' << p.bottom << ')' ; return os; }