Added panel bar width to mask calculation.
[situare] / src / ui / tabbedpanel.cpp
1 /*
2     Situare - A location system for Facebook
3     Copyright (C) 2010  Ixonos Plc. Authors:
4
5         Kaj Wallin - kaj.wallin@ixonos.com
6         Pekka Nissinen - pekka.nissinen@ixonos.com
7
8     Situare is free software; you can redistribute it and/or
9     modify it under the terms of the GNU General Public License
10     version 2 as published by the Free Software Foundation.
11
12     Situare is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16
17     You should have received a copy of the GNU General Public License
18     along with Situare; if not, write to the Free Software
19     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
20     USA.
21 */
22
23 #include <QDebug>
24 #include <QPropertyAnimation>
25 #include <QRegion>
26 #include <QSignalTransition>
27 #include <QStackedWidget>
28 #include <QStateMachine>
29
30 #include "panelbar.h"
31 #include "panelbase.h"
32 #include "panelcontentstack.h"
33 #include "panelcontextbuttonbar.h"
34 #include "paneltabbar.h"
35
36 #include "tabbedpanel.h"
37
38 const int PANEL_CONTEXT_BUTTON_BAR_LEFT_X = 1;
39 const int PANEL_TAB_BAR_TOP_SPACING = 8;
40
41 TabbedPanel::TabbedPanel(QWidget *parent)
42     : QWidget(parent),
43       m_open(false),
44       m_closeRequestPending(false)
45 {
46     qDebug() << __PRETTY_FUNCTION__;
47
48     const int PANEL_LEFT_X = 0;
49     const int PANEL_TOP_Y = 0;
50
51     resize(PANEL_BAR_TABBED_WIDTH + PANEL_WIDTH, PANEL_HEIGHT);
52     move(PANEL_CLOSED_X, PANEL_TOP_PADDING);
53
54     // --- TABS ---
55     m_panelTabBar = new PanelTabBar(this);
56     m_panelTabBar->move(PANEL_LEFT_X, PANEL_TAB_BAR_TOP_SPACING);
57
58     connect(m_panelTabBar, SIGNAL(currentChanged(int)),
59             this, SLOT(setCurrentIndex(int)));
60
61     connect(m_panelTabBar, SIGNAL(sizeChangeRequested()),
62             this, SLOT(calculateMask()));
63
64     connect(m_panelTabBar, SIGNAL(tabCloseRequested(int)),
65              this, SLOT(closePanel()));
66
67     connect(this, SIGNAL(panelClosed()),
68             m_panelTabBar, SLOT(deselectTabs()));
69
70     // --- BAR ---
71     m_panelBar = new PanelBar(this);
72     m_panelBar->move(PANEL_TAB_BAR_WIDTH, PANEL_TOP_Y);
73
74     // --- CONTEXT BUTTON BAR ---
75     m_panelContextButtonBar = new PanelContextButtonBar(this);
76     m_panelContextButtonBar->move(PANEL_CONTEXT_BUTTON_BAR_LEFT_X, PANEL_HEIGHT);
77
78     connect(m_panelContextButtonBar, SIGNAL(barHidden()),
79             this, SLOT(closePanel()));
80
81     connect(m_panelContextButtonBar, SIGNAL(positionChangeRequested()),
82             this, SLOT(repositionContextButtonBar()));
83
84     // --- PANEL CONTENT ---
85     m_panelContentStack = new PanelContentStack(this);
86     m_panelContentStack->move(PANEL_TAB_BAR_WIDTH + PANEL_BAR_WIDTH, PANEL_TOP_Y);
87
88     // --- PANEL ANIMATION ---
89     QStateMachine *panelStateMachine = new QStateMachine(this);
90
91     m_stateClosed = new QState(panelStateMachine);
92     m_stateOpened = new QState(panelStateMachine);
93
94     QPropertyAnimation *panelAnimation = new QPropertyAnimation(this, "pos", this);
95
96     panelStateMachine->setInitialState(m_stateClosed);
97
98     QSignalTransition *panelTransitionOpen = m_stateClosed->addTransition(this,
99                                                                           SIGNAL(toggleState()),
100                                                                           m_stateOpened);
101     panelTransitionOpen->addAnimation(panelAnimation);
102
103     QSignalTransition *panelTransitionClose = m_stateOpened->addTransition(this,
104                                                                            SIGNAL(toggleState()),
105                                                                            m_stateClosed);
106     panelTransitionClose->addAnimation(panelAnimation);
107
108     connect(panelAnimation, SIGNAL(finished()),
109             this, SLOT(stateChanged()));
110
111     QPoint closedPosition(PANEL_CLOSED_X, PANEL_TOP_PADDING);
112     m_stateClosed->assignProperty(this, "pos", closedPosition);
113
114     QPoint openedPosition(PANEL_OPENED_X, PANEL_TOP_PADDING);
115     m_stateOpened->assignProperty(this, "pos", openedPosition);
116
117     panelStateMachine->start();
118 }
119
120 int TabbedPanel::addTab(QWidget *widget, const QIcon& icon)
121 {
122     qDebug() << __PRETTY_FUNCTION__;
123
124     const int APPEND_INDEX = -1;
125
126     return insertTab(APPEND_INDEX, widget, icon);
127 }
128
129 void TabbedPanel::calculateMask()
130 {
131     qDebug() << __PRETTY_FUNCTION__;
132
133     QRect panelTabBarRect = m_panelTabBar->rect();
134     QRect panelContextButtonBarRect = m_panelContextButtonBar->rect();
135     int panelContextButtonBarY = height() - panelContextButtonBarRect.height();
136
137     if (!m_open)
138         panelContextButtonBarY = height();
139
140     QRegion panelTabBarRegion(0, PANEL_TAB_BAR_TOP_SPACING,
141                          panelTabBarRect.width(), panelTabBarRect.height());
142     QRegion panelContextButtonBarRegion(0, panelContextButtonBarY,
143                                       panelContextButtonBarRect.width(),
144                                       panelContextButtonBarRect.height());
145     QRegion panelContentRegion(panelTabBarRect.right() + 1, 0,
146                                PANEL_WIDTH + PANEL_BAR_WIDTH, height());
147     QRegion panelRegion = panelTabBarRegion + panelContentRegion + panelContextButtonBarRegion;
148
149     setMask(panelRegion);
150 }
151
152 void TabbedPanel::closePanel()
153 {
154     qDebug() << __PRETTY_FUNCTION__;
155
156     if (m_open) {
157         m_open = false;
158
159         if (m_panelContextButtonBar->isBarVisible()) {
160             m_closeRequestPending = true;
161             m_panelContextButtonBar->hideContextButtonBar();
162         } else {
163             emit toggleState();
164         }
165     } else if (m_closeRequestPending) {
166         m_closeRequestPending = false;
167         emit toggleState();
168     }
169 }
170
171 int TabbedPanel::insertTab(int index, QWidget *widget, const QIcon& icon)
172 {
173     qDebug() << __PRETTY_FUNCTION__;
174
175     index = m_panelContentStack->insertWidget(index, widget);
176     m_panelTabBar->insertTab(index, icon);
177
178     return index;
179 }
180
181 void TabbedPanel::openPanel(QWidget *widget)
182 {
183     qDebug() << __PRETTY_FUNCTION__;
184
185     if (widget) {
186         m_panelTabBar->selectTab(m_panelContentStack->indexOf(widget));
187     } else if (!m_open) {
188         if (!m_closeRequestPending) {
189             m_open = true;
190             emit toggleState();
191         }
192     }
193 }
194
195 void TabbedPanel::removeTab(int index)
196 {
197     qDebug() << __PRETTY_FUNCTION__;
198
199     if (QWidget *widget = m_panelContentStack->widget(index)) {
200         m_panelContentStack->removeWidget(widget);
201         m_panelTabBar->removeTab(index);
202     }
203 }
204
205 void TabbedPanel::repositionContextButtonBar()
206 {
207     qDebug() << __PRETTY_FUNCTION__;
208
209     m_panelContextButtonBar->move(PANEL_CONTEXT_BUTTON_BAR_LEFT_X, height());
210     
211     calculateMask();
212 }
213
214 void TabbedPanel::resizePanel(const QSize &size)
215 {
216     qDebug() << __PRETTY_FUNCTION__;
217
218     resize(PANEL_BAR_TABBED_WIDTH + PANEL_WIDTH,
219            size.height() - PANEL_TOP_PADDING - PANEL_BOTTOM_PADDING);
220
221     if (!m_open)
222         move(size.width() - PANEL_TAB_BAR_WIDTH - PANEL_BAR_WIDTH, PANEL_TOP_PADDING);
223     else
224         move(size.width() - PANEL_TAB_BAR_WIDTH - PANEL_BAR_WIDTH - PANEL_WIDTH, PANEL_TOP_PADDING);
225
226     m_panelBar->resizeBar(size);
227
228     m_panelContextButtonBar->move(PANEL_CONTEXT_BUTTON_BAR_LEFT_X, size.height());
229
230     m_panelContentStack->resizeContentStack(size);
231
232     QPoint closedPosition(size.width() - PANEL_TAB_BAR_WIDTH - PANEL_BAR_WIDTH, PANEL_TOP_PADDING);
233     m_stateClosed->assignProperty(this, "pos", closedPosition);
234
235     QPoint openedPosition(size.width() - PANEL_TAB_BAR_WIDTH - PANEL_BAR_WIDTH - PANEL_WIDTH,
236                           PANEL_TOP_PADDING);
237     m_stateOpened->assignProperty(this, "pos", openedPosition);
238
239     calculateMask();
240 }
241
242 void TabbedPanel::setCurrentIndex(int index)
243 {
244     qDebug() << __PRETTY_FUNCTION__;
245
246     if ((index < m_panelContentStack->count()) && (index >= 0)) {
247         m_panelContentStack->setCurrentIndex(index);
248
249         if (!m_open)
250             openPanel();
251
252         m_panelContextButtonBar->setContextButtons(
253                 static_cast<PanelBase *>(m_panelContentStack->widget(index))->contextButtons());
254
255         emit currentChanged(index);
256     }
257 }
258
259 void TabbedPanel::stateChanged()
260 {
261     qDebug() << __PRETTY_FUNCTION__;
262
263     calculateMask();
264
265     if (m_open) {
266         m_panelContextButtonBar->showContextButtonBar();
267         emit panelOpened();
268     } else {
269         emit panelClosed();
270     }
271 }