Refactored panel context button bar animation and now it is implemented in a lot...
[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 <QSignalTransition>
26 #include <QStackedWidget>
27 #include <QStateMachine>
28
29 #include "panelbar.h"
30 #include "panelbase.h"
31 #include "panelcontentstack.h"
32 #include "panelcontextbuttonbar.h"
33 #include "paneltabbar.h"
34
35 #include "tabbedpanel.h"
36
37 const int PANEL_CONTEXT_BUTTON_BAR_LEFT_X = 1;
38
39 TabbedPanel::TabbedPanel(QWidget *parent)
40     : QWidget(parent),
41       m_open(false),
42       m_closeRequestPending(false)
43 {
44     qDebug() << __PRETTY_FUNCTION__;
45
46     const int PANEL_LEFT_X = 0;
47     const int PANEL_TOP_Y = 0;
48     const int PANEL_TAB_BAR_TOP_SPACING = 8;
49
50     resize(PANEL_BAR_TABBED_WIDTH + PANEL_WIDTH, PANEL_HEIGHT);
51     move(PANEL_CLOSED_X, PANEL_TOP_PADDING);
52
53     // --- TABS ---
54     m_panelTabBar = new PanelTabBar(this);
55     m_panelTabBar->move(PANEL_LEFT_X, PANEL_TAB_BAR_TOP_SPACING);
56
57     connect(m_panelTabBar, SIGNAL(currentChanged(int)),
58             this, SLOT(setCurrentIndex(int)));
59
60     connect(m_panelTabBar, SIGNAL(tabCloseRequested(int)),
61              this, SLOT(closePanel()));
62
63     connect(this, SIGNAL(panelClosed()),
64             m_panelTabBar, SLOT(deselectTabs()));
65
66     // --- BAR ---
67     m_panelBar = new PanelBar(this);
68     m_panelBar->move(PANEL_TAB_WIDTH, PANEL_TOP_Y);
69
70     // --- CONTEXT BUTTON BAR ---
71     m_panelContextButtonBar = new PanelContextButtonBar(this);
72     m_panelContextButtonBar->move(PANEL_CONTEXT_BUTTON_BAR_LEFT_X, PANEL_HEIGHT);
73
74     connect(m_panelContextButtonBar, SIGNAL(barHidden()),
75             this, SLOT(closePanel()));
76
77     // --- PANEL CONTENT ---
78     m_panelContentStack = new PanelContentStack(this);
79     m_panelContentStack->move(PANEL_TAB_WIDTH + PANEL_BAR_WIDTH, PANEL_TOP_Y);
80
81     // --- PANEL ANIMATION ---
82     QStateMachine *panelStateMachine = new QStateMachine(this);
83
84     m_stateClosed = new QState(panelStateMachine);
85     m_stateOpened = new QState(panelStateMachine);
86
87     QPropertyAnimation *panelAnimation = new QPropertyAnimation(this, "pos", this);
88
89     panelStateMachine->setInitialState(m_stateClosed);
90
91     QSignalTransition *panelTransitionOpen = m_stateClosed->addTransition(this,
92                                                                           SIGNAL(toggleState()),
93                                                                           m_stateOpened);
94     panelTransitionOpen->addAnimation(panelAnimation);
95
96     QSignalTransition *panelTransitionClose = m_stateOpened->addTransition(this,
97                                                                            SIGNAL(toggleState()),
98                                                                            m_stateClosed);
99     panelTransitionClose->addAnimation(panelAnimation);
100
101     connect(panelAnimation, SIGNAL(finished()),
102             this, SLOT(stateChanged()));
103
104     QPoint closedPosition(PANEL_CLOSED_X, PANEL_TOP_PADDING);
105     m_stateClosed->assignProperty(this, "pos", closedPosition);
106
107     QPoint openedPosition(PANEL_OPENED_X, PANEL_TOP_PADDING);
108     m_stateOpened->assignProperty(this, "pos", openedPosition);
109
110     panelStateMachine->start();
111 }
112
113 int TabbedPanel::addTab(QWidget *widget, const QIcon& icon)
114 {
115     qDebug() << __PRETTY_FUNCTION__;
116
117     const int APPEND_INDEX = -1;
118
119     return insertTab(APPEND_INDEX, widget, icon);
120 }
121
122 void TabbedPanel::closePanel()
123 {
124     qDebug() << __PRETTY_FUNCTION__;
125
126     if (m_open) {
127         m_open = false;
128
129         if (m_panelContextButtonBar->isBarVisible()) {
130             m_closeRequestPending = true;
131             m_panelContextButtonBar->hideContextButtonBar();
132         } else {
133             emit toggleState();
134         }
135     } else if (m_closeRequestPending) {
136         m_closeRequestPending = false;
137         emit toggleState();
138     }
139 }
140
141 int TabbedPanel::insertTab(int index, QWidget *widget, const QIcon& icon)
142 {
143     qDebug() << __PRETTY_FUNCTION__;
144
145     index = m_panelContentStack->insertWidget(index, widget);
146     m_panelTabBar->insertTab(index, icon);
147
148     return index;
149 }
150
151 void TabbedPanel::openPanel(QWidget *widget)
152 {
153     qDebug() << __PRETTY_FUNCTION__;
154
155     if (widget) {
156         m_panelTabBar->selectTab(m_panelContentStack->indexOf(widget));
157     } else if (!m_open) {
158         if (!m_closeRequestPending) {
159             m_open = true;
160             emit toggleState();
161         }
162     }
163 }
164
165 void TabbedPanel::removeTab(int index)
166 {
167     qDebug() << __PRETTY_FUNCTION__;
168
169     if (QWidget *widget = m_panelContentStack->widget(index)) {
170         m_panelContentStack->removeWidget(widget);
171         m_panelTabBar->removeTab(index);
172     }
173 }
174
175 void TabbedPanel::resizePanel(const QSize &size)
176 {
177     qDebug() << __PRETTY_FUNCTION__;
178
179     resize(PANEL_BAR_TABBED_WIDTH + PANEL_WIDTH,
180            size.height() - PANEL_TOP_PADDING - PANEL_BOTTOM_PADDING);
181
182     if (!m_open)
183         move(size.width() - PANEL_TAB_WIDTH - PANEL_BAR_WIDTH, PANEL_TOP_PADDING);
184     else
185         move(size.width() - PANEL_TAB_WIDTH - PANEL_BAR_WIDTH - PANEL_WIDTH, PANEL_TOP_PADDING);
186
187     m_panelBar->resizeBar(size);
188
189     m_panelContextButtonBar->move(PANEL_CONTEXT_BUTTON_BAR_LEFT_X, size.height());
190
191     m_panelContentStack->resizeContentStack(size);
192
193     QPoint closedPosition(size.width() - PANEL_TAB_WIDTH - PANEL_BAR_WIDTH, PANEL_TOP_PADDING);
194     m_stateClosed->assignProperty(this, "pos", closedPosition);
195
196     QPoint openedPosition(size.width() - PANEL_TAB_WIDTH - PANEL_BAR_WIDTH - PANEL_WIDTH,
197                           PANEL_TOP_PADDING);
198     m_stateOpened->assignProperty(this, "pos", openedPosition);
199 }
200
201 void TabbedPanel::setCurrentIndex(int index)
202 {
203     qDebug() << __PRETTY_FUNCTION__;
204
205     if ((index < m_panelContentStack->count()) && (index >= 0)) {
206         m_panelContentStack->setCurrentIndex(index);
207
208         if (!m_open)
209             openPanel();
210
211         m_panelContextButtonBar->setContextButtons(
212                 static_cast<PanelBase *>(m_panelContentStack->widget(index))->contextButtons());
213
214         emit currentChanged(index);
215     }
216 }
217
218 void TabbedPanel::stateChanged()
219 {
220     qDebug() << __PRETTY_FUNCTION__;
221
222     if (m_open) {
223         m_panelContextButtonBar->showContextButtonBar();
224         emit panelOpened();
225     } else {
226         emit panelClosed();
227     }
228 }