summaryrefslogtreecommitdiff
path: root/libopie2/opieui/big-screen/owidgetstack.cpp
blob: ac46cca7ae3ce33db55c8ba59acaea1483951ea3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
/*
               =.            This file is part of the OPIE Project
             .=l.            Copyright (c)  2003,2004,2005 Holger Hans Peter Freyther <zecke@handhelds.org>
           .>+-=
 _;:,     .>    :=|.         This library is free software; you can
.> <`_,   >  .   <=          redistribute it and/or  modify it under
:`=1 )Y*s>-.--   :           the terms of the GNU Library General Public
.="- .-=="i,     .._         License as published by the Free Software
 - .   .-<_>     .<>         Foundation; either version 2 of the License,
     ._= =}       :          or (at your option) any later version.
    .%`+i>       _;_.
    .i_,=:_.      -<s.       This library 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
..}^=.=       =       ;      Library General Public License for more
++=   -.     .`     .:       details.
 :     =  ...= . :.=-
 -.   .:....=;==+<;          You should have received a copy of the GNU
  -_. . .   )=.  =           Library General Public License along with
    --        :-=`           this library; see the file COPYING.LIB.
                             If not, write to the Free Software Foundation,
                             Inc., 59 Temple Place - Suite 330,
                             Boston, MA 02111-1307, USA.

*/

#include "owidgetstack.h"

/* OPIE */
#include <opie2/odebug.h>

/* QT */
#include <qapplication.h>
#include <qwidgetstack.h>

namespace Opie {
namespace Ui   {
    const int mode_size = 330;



/**
 * This is the standard widget. For simple usage see the example. Normally this widget
 * is the central widget of a QMainWindow.
 * Use removeWidget before you delete a widget yourself. OWidgetStack does not
 * yet recognize removal of children.
 *
 * @param parent The parent widget. It maybe 0 but then you need to take care of deletion.
 *               Or you use QPEApplication::showMainWidget().
 * @param name   Name will be passed on to QObject
 * @param fl     Additional window flags passed to QFrame. see @Qt::WFlags
 */
OWidgetStack::OWidgetStack( QWidget* parent, const char* name, WFlags fl)
    : QFrame( parent, name, fl )
{
    m_last = m_mWidget = 0;
    m_forced = false;

    QApplication::desktop()->installEventFilter( this );
    setFontPropagation   ( AllChildren );
    setPalettePropagation( AllChildren );

    /* sets m_mode and initializes more */
    /* if you change this call change switchTop as well */
    m_stack = 0;
    switchStack();
}

/**
 * The destructor. It deletes also all added widgets.
 *
 */
OWidgetStack::~OWidgetStack() {
    if (m_mode == BigScreen && !m_list.isEmpty() ) {
        QMap<int, QWidget*>::Iterator it = m_list.begin();
        for ( ; it != m_list.end(); ++it )
            delete it.data();
    }
    m_list.clear();

}

/**
 * return the mode of the desktop. There are currently two modes. SmallScreen
 * with a normal PDA resolution and BigScreen with resolutions greater than
 * 330 for width and height.
 * You can also force the mode this widget is in with forceMode()
 * Note that NoForce will be never returned from here
 */
enum OWidgetStack::Mode OWidgetStack::mode()const {
    return m_mode;
}

/**
 *  You can also force one of the modes and then
 *  this widget stops on listening to size changes. You
 *  can revert to the scanning behaviour by setting mode
 *  to NoForce
 */
void OWidgetStack::forceMode( enum Mode mode) {
    m_forced = mode != NoForce;

    /* we need to see which mode we're in */
    if (!m_forced ) {
        if ( QApplication::desktop()->width() >=
             mode_size )
            mode = BigScreen;
        else
            mode = SmallScreen;
    }
    switch( mode ) {
    case NoForce:
    case SmallScreen:
        switchStack();
        break;
    case BigScreen:
        switchTop();
        break;

    }

    m_mode = mode;
}

/**
 * Adds a widget to the stack. The first widget added is considered
 * to be the mainwindow. This is important because if Opie is in
 * BigScreen mode the sizeHint of the MainWindow will be returned.
 * In Small Screen the sizeHint of the QWidgetStack is returned.
 * See QWidgetStack::sizeHint.
 * This widget takes ownership of the widget and may even reparent.
 * All windows will be hidden
 *
 * @param wid The QWidget to be added
 * @param id  An ID for the Widget. If the ID is duplicated the
              last set widget will be related to the id
 *
 */
void OWidgetStack::addWidget( QWidget* wid, int id) {
    if (!wid)
        return;

    /* set our main widget */
    if (!m_mWidget)
        m_mWidget = wid;

    m_list.insert( id, wid );

    /**
     * adding does not raise any widget
     * But for our mainwidget we prepare
     * the right position with the right parent
     */
    if (m_mode == SmallScreen )
        m_stack->addWidget( wid,id );
    else if ( m_mWidget == wid ) {
        wid->reparent(this, 0, contentsRect().topLeft() );
        wid->hide();
    }else {
        wid->reparent(0, WType_TopLevel, QPoint(10, 10) );
        wid->hide();
    }
}


/**
 * Remove the widget from the stack it'll be reparented to 0
 * and ownership is dropped. You need to delete it.
 * If the removed widget was the mainwindow consider
 * to call setMainWindow.
 *
 * @param wid The QWidget to be removed
 */
void OWidgetStack::removeWidget( QWidget* wid) {
    if (!wid)
        return;

    if (m_mode == SmallScreen )
        m_stack->removeWidget( wid );


    wid->reparent(0, 0, QPoint(0, 0) );
    m_list.remove( id(wid) );

    if ( wid == m_mWidget )
        m_mWidget = 0;
}

#if 0
/**
 * @internal_resons
 */
QSizeHint OWidgetStack::sizeHint()const {

}

/**
 * @internal_reasons
 */
QSizeHint OWidgetStack::minimumSizeHint()const {

}
#endif

/**
 * This function tries to find the widget with the id.
 * You supplied a possible id in addWIdget. Note that not
 * QWidget::winId() is used.
 *
 * @param id The id to search for
 *
 * @return The widget or null
 * @see addWidget
 */
QWidget* OWidgetStack::widget( int id) const {
    return m_list[id];
}

/**
 * Tries to find the assigned id for the widget
 * or returns -1 if no widget could be found
 * @param wid The widget to look for
 */
int OWidgetStack::id( QWidget* wid)const{
    if (m_list.isEmpty() )
        return -1;

    QMap<int, QWidget*>::ConstIterator it = m_list.begin();
    for ( ; it != m_list.end(); ++it )
        if ( it.data() == wid )
            break;

    /* if not at the end return the key */
    return it == m_list.end() ? -1 : it.key();
}


/**
 * This function returns the currently visible
 * widget. In BigScreen mode the mainwindow
 * is returned
 */
QWidget* OWidgetStack::visibleWidget()const {
    if (m_mode == SmallScreen )
        return m_stack->visibleWidget();
    else
        return m_mWidget;

}

/**
 * This method raises the widget wit the specefic id.
 * Note that in BigScreen mode the widget is made visible
 * but the other ( previous) visible widget(s) will not
 * be made invisible. If you need this use hideWidget().
 *
 * @param id Raise the widget with id
 */
void OWidgetStack::raiseWidget( int id) {
    return raiseWidget( widget( id ) );
}

/**
 * This is an overloaded function and only differs in its parameters.
 * @see raiseWidget( int )
 */
void OWidgetStack::raiseWidget( QWidget* wid) {
    m_last = wid;
    if (m_mode == SmallScreen )
        m_stack->raiseWidget( wid );
    else {
        int ide;
        emit aboutToShow( wid );
        /* if someone is connected and the widget is actually available */
        if ( receivers( SIGNAL(aboutToShow(int) ) ) &&
             ( (ide = id( wid ) ) != -1 ) )
            emit aboutToShow( ide );

        /* ### FIXME PLACE THE WIDGET right */
        wid->show();
    }
}

/**
 * This will hide the currently visible widget
 * and raise the widget specified by the parameter.
 * Note that this method does not use visibleWIdget but remembers
 * the last raisedWidget
 */
void OWidgetStack::hideWidget( int id) {
    /* hiding our main widget wouldn't be smart */
    if ( m_mode == BigScreen && m_last != m_mWidget )
        m_last->hide();
    raiseWidget( id );
}

/**
 * This is overloaded and only differs in the parameters
 * it takes.
 */
void OWidgetStack::hideWidget( QWidget* wid) {
    /* still not smart */
    if ( m_mode == BigScreen && m_last != m_mWidget )
        m_last->hide();

    raiseWidget( wid );
}


bool OWidgetStack::eventFilter( QObject*, QEvent* e) {
    if ( e->type() == QEvent::Resize && !m_forced ) {
        QResizeEvent *res = static_cast<QResizeEvent*>( e );
        QSize size = res->size();
        if ( size.width() >= mode_size )
            switchTop();
        else
            switchStack();
    }
    return false;
}


/**
 * @internal_resons
 */
void OWidgetStack::resizeEvent( QResizeEvent* ev ) {
    QFrame::resizeEvent( ev );
    if (m_mode == SmallScreen )
        m_stack->setGeometry( frameRect() );
    else
        if (m_mWidget )
            m_mWidget->setGeometry( frameRect() );

}

/**
 * setMainWindow gives the OWidgetStack a hint which
 * window should always stay inside the stack.
 * Normally the first added widget is considered to be
 * the mainwindow but you can change this with this
 * function.
 * If in BigScreen mode the current mainwindow will be reparented
 * and hidden. The position will be taken by the new one.
 * If the old MainWindow was hidden the new window will
 * also be hidden. If the window was visible the new mainwindow
 * will be made visible too and the old one hidden. If there
 * was no mainwindow it will be hidden as well.
 *
 * @param wid The new mainwindow
 */
void OWidgetStack::setMainWindow( QWidget* wid ) {
    if (m_mode == BigScreen ) {
        bool wasVisible = false;
        if (m_mWidget ) {
            wasVisible = !m_mWidget->isHidden();
            /* hidden by default */
            m_mWidget->reparent(0, WType_TopLevel, QPoint(10, 10) );
        }
        wid->reparent(this, 0, frameRect().topLeft() );

        if (wasVisible)
            wid->show();
    }

    m_mWidget = wid;
}

/**
 * this is an overloaded member and only differs
 * in the type of arguments.
 * @see setMainWindow(QWidget*)
 */
void OWidgetStack::setMainWindow( int id) {
    setMainWindow( widget( id ) );
}


/*
 * this function switches to a stack ;)
 */
void OWidgetStack::switchStack() {
    if (m_stack ) {
        m_stack->setGeometry( frameRect() );
        return;
    }

    m_mode = SmallScreen;
    m_stack = new QWidgetStack(this);
    m_stack->setGeometry( frameRect() );
    m_stack->show();

    connect(m_stack, SIGNAL(aboutToShow(QWidget*) ),
            this, SIGNAL(aboutToShow(QWidget*) ) );
    connect(m_stack, SIGNAL(aboutToShow(int) ),
            this, SIGNAL(aboutToShow(int) ) );

    /* now reparent the widgets... luckily QWidgetSatck does most of the work */
    if (m_list.isEmpty() )
        return;

    QMap<int, QWidget*>::Iterator it = m_list.begin();
    for ( ; it != m_list.end(); ++it )
        m_stack->addWidget( it.data(), it.key() );

    if ( m_mWidget )
        m_stack->raiseWidget( m_mWidget );


}

/*
 * we will switch to top level mode
 * reparent the list of widgets and then delete the stack
 */
void OWidgetStack::switchTop() {
    m_mode = BigScreen;
    /* this works because it is guaranteed that switchStack was called at least once*/
    if (!m_stack && m_mWidget) {
        m_mWidget->setGeometry( frameRect() );
        return;
    }else if (!m_stack)
        return;

    if (!m_list.isEmpty() ) {
        QMap<int, QWidget*>::Iterator it = m_list.begin();
        for ( ; it != m_list.end(); ++it ) {
            /* better than reparenting twice */
            if ( it.data() == m_mWidget ) {
                m_mWidget->reparent(this, 0, frameRect().topLeft() );
                m_mWidget->setGeometry( frameRect() );
                m_mWidget->show();
            }else
                /* ### FIXME we need to place the widget better */
                it.data()->reparent(0, WType_TopLevel, QPoint(10, 10) );
        }
    }

    delete m_stack;
    m_stack = 0;
}

}
}