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