1 /*
2 * tracker/TabHeaderControl.cpp
3 *
4 * Copyright 2009 Peter Barth
5 *
6 * This file is part of Milkytracker.
7 *
8 * Milkytracker is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * Milkytracker is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with Milkytracker. If not, see <http://www.gnu.org/licenses/>.
20 *
21 */
22
23 /*
24 * TabHeaderControl.cpp
25 * MilkyTracker
26 *
27 * Created by Peter Barth on 09.12.07.
28 *
29 */
30
31 #include "TabHeaderControl.h"
32 #include "Event.h"
33 #include "Screen.h"
34 #include "Button.h"
35 #include "Font.h"
36 #include "PPUIConfig.h"
37 #include "GlobalColorConfig.h"
38
handleTabClick(const PPPoint & p)39 void TabHeaderControl::handleTabClick(const PPPoint& p)
40 {
41 pp_int32 hitIndex = -1;
42 for (pp_int32 i = 0; i < tabButtons.size(); i++)
43 {
44 if (tabButtons.get(i)->hit(p))
45 {
46 hitIndex = i;
47 }
48 }
49
50 if (hitIndex != -1)
51 {
52 for (pp_int32 i = 0; i < tabButtons.size(); i++)
53 {
54 PPButton* button = tabButtons.get(i);
55 button->setPressed(i == hitIndex);
56 }
57
58 parentScreen->paintControl(this);
59
60 this->hitIndex = hitIndex + startIndex;
61 }
62 }
63
TabHeaderControl(pp_int32 id,PPScreen * parentScreen,EventListenerInterface * eventListener,const PPPoint & location,const PPSize & size)64 TabHeaderControl::TabHeaderControl(pp_int32 id, PPScreen* parentScreen, EventListenerInterface* eventListener,
65 const PPPoint& location, const PPSize& size) :
66 PPControl(id, parentScreen, eventListener, location, size),
67 color(&PPUIConfig::getInstance()->getColor(PPUIConfig::ColorContainer)),
68 leftButton(NULL),
69 rightButton(NULL),
70 minSize(60),
71 maxSize(200),
72 caughtControl(NULL),
73 startIndex(0)
74 {
75 backgroundButton = new PPButton(0, parentScreen, NULL, location, size, false, false);
76 backgroundButton->setColor(*color);
77 }
78
~TabHeaderControl()79 TabHeaderControl::~TabHeaderControl()
80 {
81 delete backgroundButton;
82 delete leftButton;
83 delete rightButton;
84 }
85
paint(PPGraphicsAbstract * g)86 void TabHeaderControl::paint(PPGraphicsAbstract* g)
87 {
88 if (!isVisible())
89 return;
90
91 backgroundButton->paint(g);
92
93 if (leftButton != NULL)
94 {
95 leftButton->enable(startIndex > 0);
96 leftButton->paint(g);
97 }
98
99 if (rightButton != NULL)
100 {
101 rightButton->enable(startIndex + tabButtons.size() < tabHeaders.size());
102 rightButton->paint(g);
103 }
104
105 paintControls(g);
106 }
107
dispatchEvent(PPEvent * event)108 pp_int32 TabHeaderControl::dispatchEvent(PPEvent* event)
109 {
110 switch (event->getID())
111 {
112 case eLMouseDown:
113 {
114 PPPoint* p = (PPPoint*)event->getDataPtr();
115
116 if (leftButton && leftButton->isEnabled() && leftButton->isVisible() && leftButton->hit(*p))
117 {
118 caughtControl = leftButton;
119 caughtControl->dispatchEvent(event);
120 }
121 else if (rightButton && rightButton->isEnabled() && rightButton->isVisible() && rightButton->hit(*p))
122 {
123 caughtControl = rightButton;
124 caughtControl->dispatchEvent(event);
125 }
126 else
127 {
128 oldHitIndex = hitIndex;
129 handleTabClick(*p);
130 }
131 break;
132 }
133
134 case eLMouseUp:
135 if (caughtControl == NULL)
136 {
137 if (hitIndex != oldHitIndex)
138 {
139 PPEvent e(eSelection, &hitIndex, sizeof(hitIndex));
140 eventListener->handleEvent(reinterpret_cast<PPObject*>(this), &e);
141 }
142 break;
143 }
144
145 caughtControl->dispatchEvent(event);
146 caughtControl = NULL;
147 break;
148
149 default:
150 if (caughtControl != NULL)
151 caughtControl->dispatchEvent(event);
152 }
153
154 return 0;
155 }
156
handleEvent(PPObject * sender,PPEvent * event)157 pp_int32 TabHeaderControl::handleEvent(PPObject* sender, PPEvent* event)
158 {
159 if (event->getID() == eCommand || event->getID() == eCommandRepeat)
160 {
161
162 switch (reinterpret_cast<PPControl*>(sender)->getID())
163 {
164 case 0:
165 {
166 shiftTabs(-1);
167 break;
168 }
169
170 case 1:
171 {
172 shiftTabs();
173 break;
174 }
175 }
176 }
177 return 0;
178 }
179
setSize(const PPSize & size)180 void TabHeaderControl::setSize(const PPSize& size)
181 {
182 this->size = size;
183 backgroundButton->setSize(size);
184 }
185
setLocation(const PPPoint & location)186 void TabHeaderControl::setLocation(const PPPoint& location)
187 {
188 this->location = location;
189 backgroundButton->setLocation(location);
190 }
191
addTab(const TabHeader & tabHeader)192 void TabHeaderControl::addTab(const TabHeader& tabHeader)
193 {
194 tabHeaders.add(new TabHeader(tabHeader));
195 setNumTabs(tabHeaders.size());
196 setSelectedTab(tabHeaders.size()-1);
197 adjustLabels();
198 }
199
getTab(pp_int32 index) const200 const TabHeaderControl::TabHeader* TabHeaderControl::getTab(pp_int32 index) const
201 {
202 return (index >= 0 && index < tabHeaders.size()) ? tabHeaders.get(index) : NULL;
203 }
204
removeTab(pp_int32 index)205 bool TabHeaderControl::removeTab(pp_int32 index)
206 {
207 if (index < 0 || index >= tabHeaders.size())
208 return false;
209
210 return tabHeaders.remove(index);
211 }
212
setNumTabs(pp_uint32 numTabs)213 void TabHeaderControl::setNumTabs(pp_uint32 numTabs)
214 {
215 pp_int32 width = (size.width - 4) / numTabs;
216 pp_int32 height = size.height - 4;
217
218 if (minSize && width < minSize)
219 width = minSize;
220 if (maxSize && width > maxSize)
221 width = maxSize;
222
223 tabButtons.clear();
224
225 if ((signed)numTabs*width > size.width - 4)
226 {
227 numTabs = (size.width - (4+12+12)) / minSize;
228 width = (size.width - (4+12+12)) / numTabs;
229
230 delete leftButton;
231 leftButton = new PPButton(0, parentScreen, this,
232 PPPoint(location.x + size.width - (4+12+12) + 2, location.y + 2), PPSize(12, height), false);
233 leftButton->setText("<");
234
235 delete rightButton;
236 rightButton = new PPButton(1, parentScreen, this,
237 PPPoint(location.x + size.width - (4+13) + 3, location.y + 2), PPSize(12, height), false);
238 rightButton->setText(">");
239 }
240 else
241 {
242 delete rightButton;
243 rightButton = NULL;
244 delete leftButton;
245 leftButton = NULL;
246 }
247
248 PPPoint location = this->location;
249 location.x += 2;
250 location. y+= 2;
251 for (pp_int32 i = 0; i < (signed)numTabs; i++)
252 {
253 PPButton* button = new PPButton(i+0x1000, parentScreen, this, location, PPSize(width, height), false, true, false);
254 button->setText("Blabla");
255 button->setColor(*color);
256 button->setAutoSizeFont(false);
257 tabButtons.add(button);
258 location.x+=width;
259 }
260 }
261
adjustLabels()262 void TabHeaderControl::adjustLabels()
263 {
264 for (pp_int32 i = 0; i < tabButtons.size(); i++)
265 {
266 PPButton* button = tabButtons.get(i);
267 PPFont* font = button->getFont();
268 pp_int32 shrinkWidth = button->getSize().width - 4;
269 if (shrinkWidth < 1)
270 shrinkWidth = 1;
271
272 PPString text = tabHeaders.get(i + startIndex)->text;
273 if (text.charAt(text.length()-1) == '*')
274 {
275 text = font->shrinkString(text, shrinkWidth - font->getCharWidth(), PPFont::ShrinkTypeEnd);
276 if (text.charAt(text.length()-1) != '*')
277 text.append("*");
278 }
279 else
280 text = font->shrinkString(text, shrinkWidth, PPFont::ShrinkTypeEnd);
281
282 button->setText(text);
283 if ((i + startIndex) & 1)
284 button->setTextColor(GlobalColorConfig::getInstance()->getColor(GlobalColorConfig::ColorTextHighlited));
285 else
286 button->setTextColor(GlobalColorConfig::getInstance()->getColor(GlobalColorConfig::ColorForegroundText));
287 }
288 }
289
shiftTabs(pp_int32 offset,bool repaint)290 void TabHeaderControl::shiftTabs(pp_int32 offset/* = 1*/, bool repaint/* = true*/)
291 {
292 pp_int32 startIndex = this->startIndex + offset;
293
294 if (startIndex + tabButtons.size() > tabHeaders.size())
295 startIndex-= (startIndex + tabButtons.size()) - tabHeaders.size();
296
297 if (startIndex < 0)
298 startIndex = 0;
299
300 if (startIndex != this->startIndex)
301 {
302
303 for (pp_int32 i = 0; i < tabButtons.size(); i++)
304 tabButtons.get(i)->setPressed(false);
305
306 pp_int32 newIndex = (signed)hitIndex - startIndex;
307 if (newIndex >= 0 && newIndex < tabButtons.size())
308 {
309 tabButtons.get(newIndex)->setPressed(true);
310 }
311
312 this->startIndex = startIndex;
313 adjustLabels();
314 if (repaint)
315 parentScreen->paintControl(this);
316 }
317 }
318
assureTabVisible(pp_uint32 index)319 void TabHeaderControl::assureTabVisible(pp_uint32 index)
320 {
321 pp_int32 newIndex = (signed)index - startIndex;
322
323 if (newIndex >= 0 && newIndex < tabButtons.size())
324 return;
325
326 if (newIndex < 0)
327 {
328 while (newIndex < 0)
329 {
330 startIndex--;
331 newIndex = (signed)index - startIndex;
332 }
333 return;
334 }
335
336 if (newIndex >= tabButtons.size())
337 {
338 while (newIndex >= tabButtons.size())
339 {
340 startIndex++;
341 newIndex = (signed)index - startIndex;
342 }
343 return;
344 }
345 }
346
setSelectedTab(pp_uint32 index)347 void TabHeaderControl::setSelectedTab(pp_uint32 index)
348 {
349 hitIndex = index;
350
351 assureTabVisible(index);
352
353 for (pp_int32 i = 0; i < tabButtons.size(); i++)
354 tabButtons.get(i)->setPressed(false);
355
356 pp_int32 newIndex = (signed)index - startIndex;
357 if (newIndex >= 0 && newIndex < tabButtons.size())
358 {
359 tabButtons.get(newIndex)->setPressed(true);
360 }
361 }
362
setTabHeaderText(pp_int32 index,const PPString & text)363 void TabHeaderControl::setTabHeaderText(pp_int32 index, const PPString& text)
364 {
365 if (index < 0 || index >= tabHeaders.size())
366 return;
367
368 tabHeaders.get(index)->text = text;
369 adjustLabels();
370 }
371
372
373