From 67d934194fd84a447324dc0c9f56c001e23ba9fe Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 19 Oct 2023 01:58:38 +0200 Subject: [PATCH] Added line style selection widget --- src/laybasic/laybasic/layLineStyles.cc | 39 +++-- src/laybasic/laybasic/layLineStyles.h | 3 +- src/layui/layui/layWidgets.cc | 194 +++++++++++++++++++++++++ src/layui/layui/layWidgets.h | 62 ++++++++ 4 files changed, 281 insertions(+), 17 deletions(-) diff --git a/src/laybasic/laybasic/layLineStyles.cc b/src/laybasic/laybasic/layLineStyles.cc index a4a3856f8..06667092b 100644 --- a/src/laybasic/laybasic/layLineStyles.cc +++ b/src/laybasic/laybasic/layLineStyles.cc @@ -175,31 +175,38 @@ LineStyleInfo::is_bit_set (unsigned int n) const #if defined(HAVE_QT) QBitmap -LineStyleInfo::get_bitmap (int width, int height) const +LineStyleInfo::get_bitmap (int w, int h, int fw) const { - if (height < 0) { - height = 5; - } - if (width < 0) { - width = 34; - } - + unsigned int height = h < 0 ? 5 : (unsigned int) h; + unsigned int width = w < 0 ? 34 : (unsigned int) w; + unsigned int frame_width = fw <= 0 ? 1 : (unsigned int) fw; unsigned int stride = (width + 7) / 8; unsigned char *data = new unsigned char[stride * height]; memset (data, 0x00, size_t (stride * height)); - for (unsigned int i = 0; i < (unsigned int)(height - 2); ++i) { - if (is_bit_set (i)) { - data [(height - 2 - i) * stride] |= 0x01; - data [(height - 2 - i) * stride + (width - 1) / 8] |= (1 << ((width - 1) % 8)); + unsigned int hv = height - 2 * frame_width; + + for (unsigned int i = 0; i < hv; ++i) { + if (is_bit_set (i / frame_width + 1)) { + unsigned int y = height - 1 - frame_width - i; + for (unsigned int x = 0; x < frame_width; ++x) { + data [y * stride + x / 8] |= (1 << (x % 8)); + } + for (unsigned int x = width - frame_width; x < width; ++x) { + data [y * stride + x / 8] |= (1 << (x % 8)); + } } } - for (unsigned int i = 1; i < (unsigned int)(width - 1); ++i) { - if (is_bit_set (i)) { - data [stride + i / 8] |= (1 << (i % 8)); - data [(height - 2) * stride + i / 8] |= (1 << (i % 8)); + for (unsigned int i = 0; i < width; ++i) { + if (is_bit_set (i / frame_width)) { + for (unsigned int y = 0; y < frame_width; ++y) { + data [y * stride + i / 8] |= (1 << (i % 8)); + } + for (unsigned int y = height - frame_width; y < height; ++y) { + data [y * stride + i / 8] |= (1 << (i % 8)); + } } } diff --git a/src/laybasic/laybasic/layLineStyles.h b/src/laybasic/laybasic/layLineStyles.h index b29dbcb6e..b2317d574 100644 --- a/src/laybasic/laybasic/layLineStyles.h +++ b/src/laybasic/laybasic/layLineStyles.h @@ -150,8 +150,9 @@ public: * * @param width The desired width (-1 for default) * @param height The desired height (-1 for default) + * @param The intended frame width in pixels */ - QBitmap get_bitmap (int width = -1, int height = -1) const; + QBitmap get_bitmap (int width = -1, int height = -1, int frame_width = 1) const; #endif /** diff --git a/src/layui/layui/layWidgets.cc b/src/layui/layui/layWidgets.cc index 2a9272412..06c6807dc 100644 --- a/src/layui/layui/layWidgets.cc +++ b/src/layui/layui/layWidgets.cc @@ -46,6 +46,7 @@ #include "tlInternational.h" #include "laySelectStippleForm.h" +#include "laySelectLineStyleForm.h" #include @@ -246,6 +247,199 @@ DitherPatternSelectionButton::update_menu () } catch (...) { } } +// ------------------------------------------------------------- +// LineStyleSelectionButton implementation + +LineStyleSelectionButton::LineStyleSelectionButton (QWidget *parent) + : QPushButton (parent), mp_view (0), m_line_style (-1) +{ + setMenu (new QMenu (this)); + update_pattern (); + connect (menu (), SIGNAL (aboutToShow ()), this, SLOT (menu_about_to_show ())); +} + +LineStyleSelectionButton::~LineStyleSelectionButton () +{ + // .. nothing yet .. +} + +void +LineStyleSelectionButton::set_view (lay::LayoutViewBase *view) +{ + if (view != mp_view) { + mp_view = view; + update_menu (); + } +} + +void +LineStyleSelectionButton::set_line_style (int ls) +{ + if (ls != m_line_style) { + m_line_style = ls; + update_pattern (); + } +} + +int +LineStyleSelectionButton::line_style () const +{ + return m_line_style; +} + +void +LineStyleSelectionButton::menu_selected () +{ + QAction *action = dynamic_cast (sender ()); + if (action) { + + m_line_style = action->data ().toInt (); + update_pattern (); + emit (line_style_changed (m_line_style)); + + } +} + +void +LineStyleSelectionButton::browse_selected () +{ + if (mp_view) { + + SelectLineStyleForm styles_form (0, mp_view->line_styles (), true); + styles_form.set_selected (m_line_style); + + if (styles_form.exec ()) { + + m_line_style = styles_form.selected (); + update_pattern (); + emit (line_style_changed (m_line_style)); + + } + + } else { + + // Use the default (non-custom) pattern if no view is set. + lay::LineStyles default_pattern; + + SelectLineStyleForm styles_form (0, default_pattern, true); + styles_form.set_selected (m_line_style); + + if (styles_form.exec ()) { + + m_line_style = styles_form.selected (); + update_pattern (); + emit (line_style_changed (m_line_style)); + + } + + } +} + +void +LineStyleSelectionButton::update_pattern () +{ + QPushButton::setText (QString::fromUtf8 (" ")); + + QString text = QString::fromUtf8 ("XXXXXXX"); + QFontMetrics fm (font (), this); + QRect rt (fm.boundingRect (text)); // dummy text to be compliant with the other color button + + QPushButton::setIconSize (QSize (rt.width (), rt.height ())); + +#if QT_VERSION >= 0x050000 + double dpr = devicePixelRatio (); +#else + double dpr = 1.0; +#endif + + if (m_line_style < 0) { + + QPixmap pixmap (rt.width () * dpr, rt.height () * dpr); +#if QT_VERSION >= 0x050000 + pixmap.setDevicePixelRatio (dpr); +#endif + pixmap.fill (QColor (0, 0, 0, 0)); + + QPainter pxpainter (&pixmap); + pxpainter.setFont (font ()); + QColor text_color = palette ().color (QPalette::Active, QPalette::Text); + pxpainter.setPen (QPen (text_color)); + + QRectF r (0, 0, rt.width () - pxpainter.pen ().widthF (), rt.height () - pxpainter.pen ().widthF ()); + pxpainter.drawText (r, Qt::AlignHCenter | Qt::AlignVCenter | Qt::TextSingleLine, QObject::tr ("None")); + + QPushButton::setIcon (QIcon (pixmap)); + + } else { + + const lay::LineStyleInfo *dp_info; + if (mp_view) { + dp_info = & mp_view->line_styles ().style ((unsigned int) m_line_style); + } else { + static lay::LineStyles default_pattern; + dp_info = & default_pattern.style ((unsigned int) m_line_style); + } + + QPushButton::setIcon (dp_info->get_bitmap (rt.width () * dpr, rt.height () * dpr, dpr)); + + } +} + +void +LineStyleSelectionButton::menu_about_to_show () +{ + update_menu (); +} + +void +LineStyleSelectionButton::update_menu () +{ + menu ()->clear (); + menu ()->addAction (QObject::tr ("None"), this, SLOT (menu_selected ()))->setData (-1); + menu ()->addAction (QObject::tr ("Choose ..."), this, SLOT (browse_selected ())); + menu ()->addSeparator (); + + // from_string might throw an exception ... + try { + + lay::LineStyles patterns; + + std::string s; + if (lay::Dispatcher::instance ()) { + lay::Dispatcher::instance ()->config_get (cfg_line_style_palette, s); + } + lay::LineStylePalette palette = lay::LineStylePalette::default_palette (); + if (! s.empty ()) { + palette.from_string (s); + } + + // fill the list of stipple palette items + for (unsigned int i = 0; i < palette.styles (); ++i) { + + unsigned int n = palette.style_by_index (i); + if (int (n) < std::distance (patterns.begin (), patterns.end ())) { + +#if QT_VERSION > 0x050000 + double dpr = devicePixelRatio (); +#else + double dpr = 1.0; +#endif + + lay::LineStyleInfo info = patterns.begin () [n]; + + std::string name (info.name ()); + if (name.empty ()) { + name = tl::sprintf ("#%d", n); + } + + menu ()->addAction (QIcon (info.get_bitmap (16, 8)), tl::to_qstring (name), this, SLOT (menu_selected ()))->setData (n); + + } + } + + } catch (...) { } +} + // ------------------------------------------------------------- // CellViewSelectionComboBox implementation diff --git a/src/layui/layui/layWidgets.h b/src/layui/layui/layWidgets.h index adfa708b6..787d171e5 100644 --- a/src/layui/layui/layWidgets.h +++ b/src/layui/layui/layWidgets.h @@ -115,6 +115,68 @@ private: void update_menu (); }; +/** + * @brief A selection button for dither pattern + */ +class LAYUI_PUBLIC LineStyleSelectionButton + : public QPushButton +{ +Q_OBJECT + +public: + /** + * @brief Constructor + */ + LineStyleSelectionButton (QWidget *parent); + + /** + * @brief Destructor + */ + ~LineStyleSelectionButton (); + + /** + * @brief Associate with a view + * + * This method is required to select the proper dither pattern + */ + void set_view (lay::LayoutViewBase *view); + + /** + * @brief Set the line style index + */ + void set_line_style (int ls); + + /** + * @brief Get the line style index + */ + int line_style () const; + + /** + * @brief Override setText + */ + void setText (const QString &) { } + + /** + * @brief Override setPixmap + */ + void setPixmap (const QPixmap &) { } + +signals: + void line_style_changed (int); + +private slots: + void browse_selected (); + void menu_selected (); + void menu_about_to_show (); + +private: + lay::LayoutViewBase *mp_view; + int m_line_style; + + void update_pattern (); + void update_menu (); +}; + /** * @brief A library selection combo box *