Salome HOME
Copyright update 2022
[modules/gui.git] / src / Qtx / QtxMenu.cxx
1 // Copyright (C) 2007-2022  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 // File:      QtxMenu.cxx
21 // Author:    Sergey TELKOV
22 //
23 #include "QtxMenu.h"
24
25 #include <QLabel>
26 #include <QLayout>
27 #include <QPainter>
28 #include <QPaintEvent>
29 #include <QTextDocument>
30 #include <QWidgetAction>
31 #include <QLinearGradient>
32 #include <QAbstractTextDocumentLayout>
33
34 /*!
35   \class QtxMenu::Title
36   \brief Popup menu title item.
37   \internal
38 */
39
40 class QtxMenu::Title : public QWidget
41 {
42 public:
43   Title( QWidget* = 0 );
44   virtual ~Title();
45
46   QIcon            icon() const;
47   void             setIcon( const QIcon& );
48
49   QString          text() const;
50   void             setText( const QString& );
51
52   Qt::Alignment    alignment() const;
53   void             setAlignment( const Qt::Alignment );
54
55   virtual QSize    sizeHint() const;
56   virtual QSize    minimumSizeHint() const;
57
58 protected:
59   virtual void     paintEvent( QPaintEvent* );
60
61 private:
62   QIcon            myIcon;
63   QString          myText;
64   Qt::Alignment    myAlignment;
65 };
66
67 /*!
68   \brief Constructor.
69   \param parent parent widget
70   \internal
71 */
72 QtxMenu::Title::Title( QWidget* parent )
73 : QWidget( parent ),
74   myAlignment( 0 )
75 {
76 }
77
78 /*!
79   \brief Destructor.
80   \internal
81 */
82 QtxMenu::Title::~Title()
83 {
84 }
85
86 /*!
87   \brief Get title icon.
88   \return title item icon
89   \internal
90 */
91 QIcon QtxMenu::Title::icon() const
92 {
93   return myIcon;
94 }
95
96 /*!
97   \brief Set title icon.
98   \param ico title item icon
99   \internal
100 */
101 void QtxMenu::Title::setIcon( const QIcon& ico )
102 {
103   myIcon = ico;
104 }
105
106 /*!
107   \brief Get title menu text.
108   \return menu text for the title item
109   \internal
110 */
111 QString QtxMenu::Title::text() const
112 {
113   return myText;
114 }
115
116 /*!
117   \brief Set title menu text.
118   \param txt menu text to be used for the title item
119   \internal
120 */
121 void QtxMenu::Title::setText( const QString& txt )
122 {
123   myText = txt;
124 }
125
126 /*!
127   \brief Get title alignment flags.
128   \return title alignment flags
129   \internal
130 */
131 Qt::Alignment QtxMenu::Title::alignment() const
132 {
133   return myAlignment;
134 }
135
136 /*!
137   \brief Set title alignment flags.
138   \param a title alignment flags
139   \internal
140 */
141 void QtxMenu::Title::setAlignment( const Qt::Alignment a )
142 {
143   myAlignment = a;
144 }
145
146 /*!
147   \brief Get recommended size for the title item widget.
148   \return title item widget size
149   \internal
150 */
151 QSize QtxMenu::Title::sizeHint() const
152 {
153   int m = 5;
154   QTextDocument doc;
155   doc.setHtml( text() );
156
157   QSize sz = icon().isNull() ? QSize( 0, 0 ) : icon().actualSize( QSize( 16, 16 ) );
158   sz.setWidth( 2 * m + sz.width() + (int)doc.size().width() );
159   sz.setHeight( 2 * m + qMax( sz.height(), (int)doc.size().height() ) );
160   return sz;
161 }
162
163 /*!
164   \brief Get recommended minimum size for the title item widget.
165   \return title item widget minimum size
166   \internal
167 */
168 QSize QtxMenu::Title::minimumSizeHint() const
169 {
170   return sizeHint();
171 }
172
173 /*!
174   \brief Paint the title item widget.
175   \param e paint event (not used)
176   \internal
177 */
178 void QtxMenu::Title::paintEvent( QPaintEvent* /*e*/ )
179 {
180   int m = 5;
181   QIcon ico = icon();
182   QString txt = text();
183   Qt::Alignment align = alignment();
184
185   QRect base = rect();
186   base.setTop( base.top() + 1 );
187   base.setLeft( base.left() + 1 );
188   base.setRight( base.right() -1 );
189   base.setBottom( base.bottom() - 1 );
190
191   QTextDocument doc;
192   doc.setHtml( txt );
193
194   QSize isz = ico.isNull() ? QSize( 0, 0 ) : ico.actualSize( QSize( 16, 16 ) );
195   QSize sz( (int)doc.size().width(), (int)doc.size().height() );
196
197   QPainter p( this );
198   QAbstractTextDocumentLayout::PaintContext ctx;
199   ctx.palette.setColor( QPalette::Text, palette().color( QPalette::Light ) );
200
201   QLinearGradient linearGrad( base.topLeft(), base.topRight() );
202   linearGrad.setColorAt( 0, palette().color( QPalette::Highlight ) );
203   linearGrad.setColorAt( 1, palette().color( QPalette::Window ) );
204
205   p.fillRect( base, linearGrad );
206
207   QPoint start = base.topLeft() + QPoint( m, m );
208   if ( align & Qt::AlignLeft )
209     start.setX( base.left() + m );
210   else if ( align & Qt::AlignRight )
211     start.setX( base.right() - m - isz.width() - sz.width() );
212   else if ( align & Qt::AlignHCenter )
213     start.setX( base.left() + ( base.width() - isz.width() - sz.width() ) / 2 );
214
215   if ( align & Qt::AlignTop )
216     start.setY( base.top() + m );
217   else if ( align & Qt::AlignBottom )
218     start.setY( base.bottom() - m - qMax( isz.height(), - sz.height() ) );
219   else if ( align & Qt::AlignVCenter )
220     start.setY( base.top() + ( base.height() - qMax( isz.height(), sz.height() ) ) / 2 );
221
222   if ( !ico.isNull() )
223   {
224     ico.paint( &p, QRect( start, isz ) );
225     start.setX( start.x() + isz.width() );
226   }
227
228   p.save();
229   p.translate( start );
230   doc.documentLayout()->draw( &p, ctx );
231   p.restore();
232 }
233
234 /*!
235   \class QtxMenu
236   \brief The class QtxMenu represents the popup menu with the title.
237
238   The title for the popup menu can be set via setTitleText() method.
239   In addition, title item can contain the icon, which can be set using
240   setTitleIcon() method. Current title text and icon can be retrieved with
241   titleText() and titleIcon() methods.
242
243   The title text alignment flags can be changed using setTitleAlignment()
244   method and retrieved with titleAlignment() method.
245
246   By default, QtxMenu::TitleAuto mode is used. In this mode, the title item
247   is shown only if it is not empty. To show title always (even empty), pass
248   QtxMenu::TitleOn to the setTitleMode() method. To hide the title, use 
249   setTitleMode() method with QtxMenu::TitleOff parameter.
250 */
251
252 /*!
253   \brief Constructor.
254   \param parent parent widget
255 */
256 QtxMenu::QtxMenu( QWidget* parent )
257 : QMenu( parent ),
258   myMode( TitleAuto )
259 {
260   myTitle = new Title( this );
261   myAction = new QWidgetAction( this );
262   myAction->setDefaultWidget( myTitle );
263 }
264
265 /*!
266   \brief Destructor.
267 */
268 QtxMenu::~QtxMenu()
269 {
270 }
271
272 /*!
273   \brief Get title menu text.
274   \return menu text for the title item
275 */
276 QString QtxMenu::titleText() const
277 {
278   return myTitle->text();
279 }
280
281 /*!
282   \brief Get title icon.
283   \return title item icon
284 */
285 QIcon QtxMenu::titleIcon() const
286 {
287   return myTitle->icon();
288 }
289
290 /*!
291   \brief Get title item display mode.
292   \return popup menu title display mode (QtxMenu::TitleMode)
293 */
294 QtxMenu::TitleMode QtxMenu::titleMode() const
295 {
296   return myMode;
297 }
298
299 /*!
300   \brief Get title alignment flags.
301   \return title alignment flags
302 */
303 Qt::Alignment QtxMenu::titleAlignment() const
304 {
305   return myTitle->alignment();
306 }
307
308 /*!
309   \brief Set title menu text.
310   \param txt menu text to be used for the title item
311 */
312 void QtxMenu::setTitleText( const QString& txt )
313 {
314   if ( titleText() == txt )
315     return;
316
317   myTitle->setText( txt );
318
319   updateTitle();
320 }
321
322 /*!
323   \brief Set title icon.
324   \param ico title item icon
325 */
326 void QtxMenu::setTitleIcon( const QIcon& ico )
327 {
328   myTitle->setIcon( ico );
329
330   updateTitle();
331 }
332
333 /*!
334   \brief Set title item display mode.
335   \param m popup menu title display mode (QtxMenu::TitleMode)
336 */
337 void QtxMenu::setTitleMode( const QtxMenu::TitleMode m )
338 {
339   if ( myMode == m )
340     return;
341
342   myMode = m;
343
344   updateTitle();
345 }
346
347 /*!
348   \brief Set title alignment flags.
349   \param a title alignment flags
350 */
351 void QtxMenu::setTitleAlignment( const Qt::Alignment a )
352 {
353   if ( titleAlignment() == a )
354     return;
355
356   myTitle->setAlignment( a );
357
358   updateTitle();
359 }
360
361 /*!
362   \brief Append group title to the end of the menu.
363   \param text group title's text
364 */
365 void QtxMenu::addGroup( const QString& text )
366 {
367   Title* aTitle = new Title( this );
368   aTitle->setText( text );
369
370   QWidgetAction* anAction = new QWidgetAction( this );
371   anAction->setDefaultWidget( aTitle );
372
373   addAction( anAction );
374 }
375
376 /*!
377   \brief Append group title to the end of the menu.
378   \param icon group title's icon
379   \param text group title's text
380 */
381 void QtxMenu::addGroup( const QIcon& icon, const QString& text )
382 {
383   Title* aTitle = new Title( this );
384   aTitle->setText( text );
385   aTitle->setIcon( icon );
386
387   QWidgetAction* anAction = new QWidgetAction( this );
388   anAction->setDefaultWidget( aTitle );
389
390   addAction( anAction );
391 }
392
393 /*!
394   \brief Customize show/hide menu operation.
395   \param on new popup menu visibility state
396 */
397 void QtxMenu::setVisible( bool on )
398 {
399   if ( on )
400     insertTitle();
401
402   QMenu::setVisible( on );
403
404   if ( !on )
405     removeTitle();
406 }
407
408 /*!
409   \brief Insert title item to the popup menu.
410 */
411 void QtxMenu::insertTitle()
412 {
413   if ( titleMode() == TitleOff || ( titleMode() == TitleAuto && titleText().trimmed().isEmpty() ) )
414     return;
415
416   if ( actions().isEmpty() )
417     addAction( myAction );
418   else
419     insertAction( actions().first(), myAction );
420 }
421
422 /*!
423   \brief Remove title item from the popup menu.
424 */
425 void QtxMenu::removeTitle()
426 {
427   if ( actions().contains( myAction ) )
428     removeAction( myAction );
429 }
430
431 /*!
432   \brief Update title item.
433 */
434 void QtxMenu::updateTitle()
435 {
436   if ( !actions().contains( myAction ) )
437     return;
438
439   removeTitle();
440   insertTitle();
441 }