2121#include " qgslogger.h"
2222
2323#include < QToolButton>
24- #include < QLayout>
25- #include < QStyle>
2624
2725
26+ QIcon QgsCollapsibleGroupBox::mCollapseIcon ;
27+ QIcon QgsCollapsibleGroupBox::mExpandIcon ;
28+
2829QgsCollapsibleGroupBox::QgsCollapsibleGroupBox ( QWidget *parent )
29- : QGroupBox( parent ), mCollapsed( false )
30+ : QGroupBox( parent ), mCollapsed( true ), mMarginOffset( 0 )
3031{
3132 init ();
3233}
3334
3435QgsCollapsibleGroupBox::QgsCollapsibleGroupBox ( const QString &title,
3536 QWidget *parent )
36- : QGroupBox( title, parent ), mCollapsed( false )
37+ : QGroupBox( title, parent ), mCollapsed( true ), mMarginOffset( 0 )
3738{
3839 init ();
3940}
4041
4142void QgsCollapsibleGroupBox::init ()
4243{
44+ /* Top margin fix is to increase the vertical default spacing
45+ between multiple groupboxes, especially ones without title checkboxes
46+ may not be necessary on certain platforms */
47+ mMarginOffset = 0 ; // in pixels; for temporary testing across platforms
4348
44- connect ( this , SIGNAL ( toggled ( bool ) ), this , SLOT ( checkboxToggled () ) );
49+ // init icons
50+ if ( mCollapseIcon .isNull () )
51+ {
52+ mCollapseIcon = QgsApplication::getThemeIcon ( " /mIconCollapse.png" );
53+ mExpandIcon = QgsApplication::getThemeIcon ( " /mIconExpand.png" );
54+ }
4555
56+ // customize style sheet
57+ // TODO: move to app stylesheet system, when appropriate
4658 QString ss;
47- ss += " QGroupBox {" ;
48- ss += " margin-top: 28px;" ; // fix for non-checkbox-groupbox spacing
49- ss += " }" ;
50- ss += " QGroupBox::title {" ;
59+ if ( mMarginOffset > 0 )
60+ {
61+ ss += " QgsCollapsibleGroupBox {" ;
62+ ss += QString ( " margin-top: %1px;" ).arg ( mMarginOffset + 8 );
63+ ss += " }" ;
64+ }
65+ ss += " QgsCollapsibleGroupBox::title {" ;
5166 ss += " subcontrol-origin: margin;" ;
5267 ss += " subcontrol-position: top left;" ;
68+ // ss += QString( " font-size: %1";).arg( appFontSize );
5369 ss += " margin-left: 24px;" ; // offset for disclosure triangle
54- ss += " margin-top: 10px;" ; // offset to match extra top margin
70+ if ( mMarginOffset > 0 )
71+ ss += QString ( " margin-top: %1px;" ).arg ( mMarginOffset );
5572 ss += " }" ;
5673 setStyleSheet ( ss );
5774
58- mDisclosure = new QToolButton ( this );
59- mDisclosureName = QString ( " grpboxDisclosure" );
60- mDisclosure ->setObjectName ( mDisclosureName );
61- mDisclosure ->setFixedSize ( 16 , 16 );
62- mDisclosure ->move ( 0 , 10 ); // match title offset
63- mDisclosure ->setIconSize ( QSize ( 16 , 16 ) );
64-
65- // get rid of toolbutton background
75+ // collapse button
76+ mCollapseButton = new QToolButton ( this );
77+ mCollapseButton ->setObjectName ( " collapseButton" );
78+ mCollapseButton ->setAutoRaise ( true );
79+ mCollapseButton ->setFixedSize ( 16 , 16 );
80+ // TODO set size (as well as margins) depending on theme
81+ mCollapseButton ->setIconSize ( QSize ( 12 , 12 ) );
82+ mCollapseButton ->setIcon ( mExpandIcon );
83+ if ( mMarginOffset > 0 )
84+ mCollapseButton ->move ( 0 , mMarginOffset ); // match title offset
85+
86+ // clear toolbutton default background and border
87+ // TODO: move to app stylesheet system, when appropriate
6688 QString ssd;
67- ssd + = QString ( " QToolButton#%1 {" ).arg ( mDisclosureName );
68- ssd += " background-color: rgba(255, 255, 255, 0);" ;
89+ ssd = QString ( " QgsCollapsibleGroupBox > QToolButton#%1 {" ).arg ( mCollapseButton -> objectName () );
90+ ssd += " background-color: rgba(255, 255, 255, 0); border: none; " ;
6991 ssd += " }" ;
70- mDisclosure ->setStyleSheet ( ssd );
92+ mCollapseButton ->setStyleSheet ( ssd );
7193
72- connect ( mDisclosure , SIGNAL ( clicked () ), this , SLOT ( toggleCollapsed () ) );
94+ connect ( mCollapseButton , SIGNAL ( clicked () ), this , SLOT ( toggleCollapsed () ) );
95+ connect ( this , SIGNAL ( clicked ( bool ) ), this , SLOT ( checkClicked () ) );
96+ connect ( this , SIGNAL ( toggled ( bool ) ), this , SLOT ( checkToggled () ) );
7397}
7498
75-
7699void QgsCollapsibleGroupBox::showEvent ( QShowEvent * event )
77100{
78101 QGroupBox::showEvent ( event );
79- // collapse if needed - any calls to setCollapsed() before have no effect
80- setCollapsed ( true );
102+ // expand if needed - any calls to setCollapsed() before have no effect
103+ if ( mCollapsed )
104+ {
105+ setCollapsed ( mCollapsed );
106+ }
107+ else
108+ {
109+ /* manually uncollapsing (already default) on show may scroll scroll areas
110+ still emit signal for connections using uncollapsed state */
111+ emit collapsedStateChanged ( this );
112+ }
81113}
82114
83- void QgsCollapsibleGroupBox::checkboxToggled ()
115+ void QgsCollapsibleGroupBox::checkClicked ()
84116{
85- mDisclosure ->setEnabled ( true ); // always keep enabled
117+ mCollapseButton ->setEnabled ( true ); // always keep enabled
118+ // expand/collapse when clicked
119+ if ( isChecked () && isCollapsed () )
120+ setCollapsed ( false );
121+ else if ( ! isChecked () && ! isCollapsed () )
122+ setCollapsed ( true );
123+ }
124+
125+ void QgsCollapsibleGroupBox::checkToggled ()
126+ {
127+ mCollapseButton ->setEnabled ( true ); // always keep enabled
86128}
87129
88130void QgsCollapsibleGroupBox::toggleCollapsed ()
@@ -92,44 +134,42 @@ void QgsCollapsibleGroupBox::toggleCollapsed()
92134
93135void QgsCollapsibleGroupBox::setCollapsed ( bool collapse )
94136{
95- if ( ! isVisible () )
137+ if ( !isVisible () )
96138 return ;
97139
98140 mCollapsed = collapse;
99141
142+ // for consistent look/spacing across platforms when collapsed
100143 setFlat ( collapse );
101144 setMaximumHeight ( collapse ? 36 : 16777215 );
102145
103146 // if we are collapsing, save hidden widgets in a list
104147 if ( collapse )
105148 {
106- mDisclosure ->setIcon ( QgsApplication::getThemeIcon ( " /mIconExpand.png " ) );
149+ mCollapseButton ->setIcon ( mExpandIcon );
107150 mHiddenWidgets .clear ();
108151 foreach ( QWidget *widget, findChildren<QWidget*>() )
109152 {
110- if ( widget->isHidden () && widget->objectName () != mDisclosureName )
153+ if ( widget->isHidden () && widget->objectName () != mCollapseButton -> objectName () )
111154 mHiddenWidgets << widget;
112155 }
113156 }
114157
115158 // show/hide widgets
116159 foreach ( QWidget *widget, findChildren<QWidget*>() )
117- if ( widget->objectName () != mDisclosureName )
160+ if ( widget->objectName () != mCollapseButton -> objectName () )
118161 widget->setHidden ( collapse );
119162
120163 // if we are expanding, re-hide saved hidden widgets
121164 if ( ! collapse )
122165 {
123- mDisclosure ->setIcon ( QgsApplication::getThemeIcon ( " /mIconCollapse.png " ) );
166+ mCollapseButton ->setIcon ( mCollapseIcon );
124167 foreach ( QWidget *widget, mHiddenWidgets )
125168 {
126169 widget->setHidden ( true );
127170 }
128171 }
129172
130- if ( mCollapsed )
131- emit collapsed ( this );
132- else
133- emit expanded ( this );
173+ emit collapsedStateChanged ( this );
134174}
135175
0 commit comments