Go back to Richel Bilderbeek's homepage.

Go back to Richel Bilderbeek's C++ page.

 

 

 

 

 

(C++) QtRoundedEditRectItem

 

QtQt CreatorLubuntu

 

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 (C) 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 (C) 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 (C) 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 (C) 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 (C) 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 (C) 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;
}

 

 

 

 

 

Go back to Richel Bilderbeek's C++ page.

Go back to Richel Bilderbeek's homepage.

 

Valid XHTML 1.0 Strict

This page has been created by the tool CodeToHtml