24
24
#include < QMouseEvent>
25
25
#include < QStyleOptionGroupBox>
26
26
#include < QSettings>
27
+ #include < QScrollArea>
27
28
28
29
QIcon QgsCollapsibleGroupBox::mCollapseIcon ;
29
30
QIcon QgsCollapsibleGroupBox::mExpandIcon ;
30
31
31
32
QgsCollapsibleGroupBox::QgsCollapsibleGroupBox ( QWidget *parent )
32
- : QGroupBox( parent ), mCollapsed( false ), mSaveState( true )
33
+ : QGroupBox( parent )
33
34
{
34
35
init ();
35
36
}
36
37
37
38
QgsCollapsibleGroupBox::QgsCollapsibleGroupBox ( const QString &title,
38
39
QWidget *parent )
39
- : QGroupBox( title, parent ), mCollapsed( false ), mSaveState( true )
40
+ : QGroupBox( title, parent )
40
41
{
41
42
init ();
42
43
}
@@ -48,6 +49,14 @@ QgsCollapsibleGroupBox::~QgsCollapsibleGroupBox()
48
49
49
50
void QgsCollapsibleGroupBox::init ()
50
51
{
52
+ // variables
53
+ mCollapsed = false ;
54
+ mSaveState = true ;
55
+ mInitFlat = false ;
56
+ mScrollOnExpand = true ;
57
+ mShown = false ;
58
+ mParentScrollArea = 0 ;
59
+
51
60
// init icons
52
61
if ( mCollapseIcon .isNull () )
53
62
{
@@ -70,11 +79,32 @@ void QgsCollapsibleGroupBox::init()
70
79
71
80
void QgsCollapsibleGroupBox::showEvent ( QShowEvent * event )
72
81
{
82
+ // initialise widget on first show event only
83
+ if ( mShown )
84
+ {
85
+ event->accept ();
86
+ return ;
87
+ }
88
+ mShown = true ;
89
+
90
+ // check if groupbox was set to flat in Designer or in code
91
+ mInitFlat = isFlat ();
92
+
93
+ // find parent QScrollArea - this might not work in complex layouts - should we look deeper?
94
+ if ( parent () && parent ()->parent () )
95
+ mParentScrollArea = dynamic_cast <QScrollArea*>( parent ()->parent ()->parent () );
96
+ else
97
+ mParentScrollArea = 0 ;
98
+ if ( mParentScrollArea )
99
+ QgsDebugMsg ( " found a QScrollArea parent: " + mParentScrollArea ->objectName () );
100
+ else
101
+ QgsDebugMsg ( " did not find a QScrollArea parent" );
102
+
73
103
loadState ();
74
104
75
105
updateStyle ();
76
106
77
- // expand if needed - any calls to setCollapsed() before only set mCollapsed
107
+ // expand if needed - any calls to setCollapsed() before only set mCollapsed, but have UI effect
78
108
if ( mCollapsed )
79
109
{
80
110
setCollapsed ( mCollapsed );
@@ -85,6 +115,7 @@ void QgsCollapsibleGroupBox::showEvent( QShowEvent * event )
85
115
still emit signal for connections using expanded state */
86
116
emit collapsedStateChanged ( this );
87
117
}
118
+
88
119
event->accept ();
89
120
}
90
121
@@ -152,7 +183,6 @@ void QgsCollapsibleGroupBox::saveState()
152
183
{
153
184
if ( ! mSaveState )
154
185
return ;
155
- QgsDebugMsg ( " key = " + saveKey () + " objectName = " + objectName () );
156
186
QSettings settings;
157
187
QString key = saveKey ();
158
188
settings.setValue ( key + " /checked" , isChecked () );
@@ -178,24 +208,66 @@ void QgsCollapsibleGroupBox::updateStyle()
178
208
{
179
209
setUpdatesEnabled ( false );
180
210
181
- // customize style sheet
211
+ // margin/offset defaults
212
+ int marginLeft = 20 ; // title margin for disclosure triangle
213
+ int marginRight = 5 ; // a little bit of space on the right, to match space on the left
214
+ int offsetLeft = 0 ; // offset for oxygen theme
215
+ int offsetTop = 0 ;
216
+ int offsetTop2 = 0 ; // offset for triangle
217
+
218
+ // calculate offset if frame overlaps triangle (oxygen theme)
219
+ // using an offset of 6 pixels from frame border
220
+ if ( QApplication::style ()->objectName ().toLower () == " oxygen" )
221
+ {
222
+ QStyleOptionGroupBox box;
223
+ initStyleOption ( &box );
224
+ QRect rectFrame = style ()->subControlRect ( QStyle::CC_GroupBox, &box,
225
+ QStyle::SC_GroupBoxFrame, this );
226
+ QRect rectCheckBox = style ()->subControlRect ( QStyle::CC_GroupBox, &box,
227
+ QStyle::SC_GroupBoxCheckBox, this );
228
+ if ( rectFrame.left () <= 0 )
229
+ offsetLeft = 6 + rectFrame.left ();
230
+ if ( rectFrame.top () <= 0 )
231
+ {
232
+ if ( isCheckable () )
233
+ {
234
+ // if is checkable align with checkbox
235
+ offsetTop = ( rectCheckBox.height () / 2 ) -
236
+ ( mCollapseButton ->height () / 2 ) + rectCheckBox.top ();
237
+ offsetTop2 = offsetTop + 1 ;
238
+ }
239
+ else
240
+ {
241
+ offsetTop = 6 + rectFrame.top ();
242
+ offsetTop2 = offsetTop;
243
+ }
244
+ }
245
+ }
246
+
247
+ QgsDebugMsg ( QString ( " groupbox: %1 style: %2 offset: left=%3 top=%4 top2=%5" ).arg (
248
+ objectName () ).arg ( QApplication::style ()->objectName () ).arg ( offsetLeft ).arg ( offsetTop ).arg ( offsetTop2 ) );
249
+
250
+ // customize style sheet for collapse/expand button and force left-aligned title
182
251
// TODO: move to app stylesheet system, when appropriate
183
252
QString ss;
184
253
ss += " QgsCollapsibleGroupBox::title {" ;
185
254
ss += " subcontrol-origin: margin;" ;
186
255
ss += " subcontrol-position: top left;" ;
187
- ss += " margin-left: 20px;" ; // offset for disclosure triangle
188
- ss += " margin-right: 5px;" ; // a little bit of space on the right, to match space on the left
256
+ ss += QString ( " margin-left: %1px;" ).arg ( marginLeft );
257
+ ss += QString ( " margin-right: %1px;" ).arg ( marginRight );
258
+ ss += QString ( " left: %1px;" ).arg ( offsetLeft );
259
+ ss += QString ( " top: %1px;" ).arg ( offsetTop );
189
260
ss += " }" ;
190
261
setStyleSheet ( ss );
191
262
192
- // clear toolbutton default background and border
193
- // TODO: move to app stylesheet system, when appropriate
263
+ // clear toolbutton default background and border and apply offset
194
264
QString ssd;
195
265
ssd = QString ( " QgsCollapsibleGroupBox > QToolButton#%1 {" ).arg ( mCollapseButton ->objectName () );
196
266
ssd += " background-color: rgba(255, 255, 255, 0); border: none;" ;
197
267
ssd += " }" ;
198
268
mCollapseButton ->setStyleSheet ( ssd );
269
+ if ( offsetLeft != 0 || offsetTop2 != 0 )
270
+ mCollapseButton ->move ( offsetLeft, offsetTop2 );
199
271
200
272
setUpdatesEnabled ( true );
201
273
}
@@ -208,14 +280,24 @@ void QgsCollapsibleGroupBox::setCollapsed( bool collapse )
208
280
return ;
209
281
210
282
// for consistent look/spacing across platforms when collapsed
211
- setFlat ( collapse );
283
+ if ( ! mInitFlat ) // skip if initially set to flat in Designer
284
+ setFlat ( collapse );
285
+
212
286
// avoid flicker in X11
213
287
QApplication::processEvents ();
288
+
214
289
// set maximum height to hide contents - does this work in all envs?
215
290
// setMaximumHeight( collapse ? 25 : 16777215 );
216
291
setMaximumHeight ( collapse ? titleRect ().bottom () + 6 : 16777215 );
217
292
mCollapseButton ->setIcon ( collapse ? mExpandIcon : mCollapseIcon );
218
293
294
+ // if expanding and is in a QScrollArea, scroll down to make entire widget visible
295
+ if ( mScrollOnExpand && !collapse && mParentScrollArea )
296
+ {
297
+ // process events so entire widget is shown
298
+ QApplication::processEvents ();
299
+ mParentScrollArea ->ensureWidgetVisible ( this );
300
+ }
219
301
emit collapsedStateChanged ( this );
220
302
}
221
303
0 commit comments