xref: /haiku/src/apps/icon-o-matic/generic/gui/IconButton.cpp (revision 128277c969aa806add78941cd2972754c37a1572)
1 /*
2  * Copyright 2006, Haiku.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Stephan Aßmus <superstippi@gmx.de>
7  */
8 
9 #include "IconButton.h"
10 
11 #include <new>
12 #include <stdio.h>
13 
14 #include <Application.h>
15 #include <Bitmap.h>
16 #include <Control.h>
17 #include <Entry.h>
18 #include <Looper.h>
19 #include <Message.h>
20 #include <Mime.h>
21 #include <Path.h>
22 #include <Region.h>
23 #include <Roster.h>
24 #include <TranslationUtils.h>
25 #include <Window.h>
26 
27 using std::nothrow;
28 
29 // constructor
IconButton(const char * name,uint32 id,const char * label,BMessage * message,BHandler * target)30 IconButton::IconButton(const char* name, uint32 id, const char* label,
31 					   BMessage* message, BHandler* target)
32 	: BView(BRect(0.0, 0.0, 10.0, 10.0), name, B_FOLLOW_NONE, B_WILL_DRAW),
33 	  BInvoker(message, target),
34 	  fButtonState(STATE_ENABLED),
35 	  fID(id),
36 	  fNormalBitmap(NULL),
37 	  fDisabledBitmap(NULL),
38 	  fClickedBitmap(NULL),
39 	  fDisabledClickedBitmap(NULL),
40 	  fLabel(label),
41 	  fTargetCache(target)
42 {
43 	SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
44 	SetViewColor(B_TRANSPARENT_32_BIT);
45 }
46 
47 // destructor
~IconButton()48 IconButton::~IconButton()
49 {
50 	_DeleteBitmaps();
51 }
52 
53 // MessageReceived
54 void
MessageReceived(BMessage * message)55 IconButton::MessageReceived(BMessage* message)
56 {
57 	switch (message->what) {
58 		default:
59 			BView::MessageReceived(message);
60 			break;
61 	}
62 }
63 
64 // AttachedToWindow
65 void
AttachedToWindow()66 IconButton::AttachedToWindow()
67 {
68 	SetTarget(fTargetCache);
69 	if (!Target()) {
70 		SetTarget(Window());
71 	}
72 }
73 
74 // Draw
75 void
Draw(BRect area)76 IconButton::Draw(BRect area)
77 {
78 	rgb_color background = LowColor();
79 	if (MView* parent = dynamic_cast<MView*>(Parent()))
80 		background = parent->getcolor();
81 	rgb_color lightShadow, shadow, darkShadow, light;
82 	BRect r(Bounds());
83 	BBitmap* bitmap = fNormalBitmap;
84 	// adjust colors and bitmap according to flags
85 	if (IsEnabled()) {
86 		lightShadow = tint_color(background, B_DARKEN_1_TINT);
87 		shadow = tint_color(background, B_DARKEN_2_TINT);
88 		darkShadow = tint_color(background, B_DARKEN_4_TINT);
89 		light = tint_color(background, B_LIGHTEN_MAX_TINT);
90 		SetHighColor(0, 0, 0, 255);
91 	} else {
92 		lightShadow = tint_color(background, 1.11);
93 		shadow = tint_color(background, B_DARKEN_1_TINT);
94 		darkShadow = tint_color(background, B_DARKEN_2_TINT);
95 		light = tint_color(background, B_LIGHTEN_2_TINT);
96 		bitmap = fDisabledBitmap;
97 		SetHighColor(tint_color(background, B_DISABLED_LABEL_TINT));
98 	}
99 	if (_HasFlags(STATE_PRESSED) || _HasFlags(STATE_FORCE_PRESSED)) {
100 		if (IsEnabled())  {
101 //			background = tint_color(background, B_DARKEN_2_TINT);
102 //			background = tint_color(background, B_LIGHTEN_1_TINT);
103 			background = tint_color(background, B_DARKEN_1_TINT);
104 			bitmap = fClickedBitmap;
105 		} else {
106 //			background = tint_color(background, B_DARKEN_1_TINT);
107 //			background = tint_color(background, (B_NO_TINT + B_LIGHTEN_1_TINT) / 2.0);
108 			background = tint_color(background, (B_NO_TINT + B_DARKEN_1_TINT) / 2.0);
109 			bitmap = fDisabledClickedBitmap;
110 		}
111 		// background
112 		SetLowColor(background);
113 		r.InsetBy(2.0, 2.0);
114 		StrokeLine(r.LeftBottom(), r.LeftTop(), B_SOLID_LOW);
115 		StrokeLine(r.LeftTop(), r.RightTop(), B_SOLID_LOW);
116 		r.InsetBy(-2.0, -2.0);
117 	}
118 	// draw frame only if tracking
119 	if (DrawBorder()) {
120 		if (_HasFlags(STATE_PRESSED) || _HasFlags(STATE_FORCE_PRESSED))
121 			DrawPressedBorder(r, background, shadow, darkShadow, lightShadow, light);
122 		else
123 			DrawNormalBorder(r, background, shadow, darkShadow, lightShadow, light);
124 		r.InsetBy(2.0, 2.0);
125 	} else
126 		_DrawFrame(r, background, background, background, background);
127 	float width = Bounds().Width();
128 	float height = Bounds().Height();
129 	// bitmap
130 	BRegion originalClippingRegion;
131 	if (bitmap && bitmap->IsValid()) {
132 		float x = floorf((width - bitmap->Bounds().Width()) / 2.0 + 0.5);
133 		float y = floorf((height - bitmap->Bounds().Height()) / 2.0 + 0.5);
134 		BPoint point(x, y);
135 		if (_HasFlags(STATE_PRESSED) || _HasFlags(STATE_FORCE_PRESSED))
136 			point += BPoint(1.0, 1.0);
137 		if (bitmap->ColorSpace() == B_RGBA32 || bitmap->ColorSpace() == B_RGBA32_BIG) {
138 			FillRect(r, B_SOLID_LOW);
139 			SetDrawingMode(B_OP_ALPHA);
140 			SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
141 		}
142 		DrawBitmap(bitmap, point);
143 		// constrain clipping region
144 		BRegion region= originalClippingRegion;
145 		GetClippingRegion(&region);
146 		region.Exclude(bitmap->Bounds().OffsetByCopy(point));
147 		ConstrainClippingRegion(&region);
148 	}
149 	// background
150 	SetDrawingMode(B_OP_COPY);
151 	FillRect(r, B_SOLID_LOW);
152 	ConstrainClippingRegion(&originalClippingRegion);
153 	// label
154 	if (fLabel.CountChars() > 0) {
155 		SetDrawingMode(B_OP_COPY);
156 		font_height fh;
157 		GetFontHeight(&fh);
158 		float y = Bounds().bottom - 4.0;
159 		y -= fh.descent;
160 		float x = (width - StringWidth(fLabel.String())) / 2.0;
161 		DrawString(fLabel.String(), BPoint(x, y));
162 	}
163 }
164 
165 // MouseDown
166 void
MouseDown(BPoint where)167 IconButton::MouseDown(BPoint where)
168 {
169 	if (IsValid()) {
170 		if (_HasFlags(STATE_ENABLED)/* && !_HasFlags(STATE_FORCE_PRESSED)*/) {
171 			if (Bounds().Contains(where)) {
172 				SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
173 				_AddFlags(STATE_PRESSED | STATE_TRACKING);
174 			} else {
175 				_ClearFlags(STATE_PRESSED | STATE_TRACKING);
176 			}
177 		}
178 	}
179 }
180 
181 // MouseUp
182 void
MouseUp(BPoint where)183 IconButton::MouseUp(BPoint where)
184 {
185 	if (IsValid()) {
186 //		if (!_HasFlags(STATE_FORCE_PRESSED)) {
187 			if (_HasFlags(STATE_ENABLED) && _HasFlags(STATE_PRESSED) && Bounds().Contains(where))
188 				Invoke();
189 			else if (Bounds().Contains(where))
190 				_AddFlags(STATE_INSIDE);
191 			_ClearFlags(STATE_PRESSED | STATE_TRACKING);
192 //		}
193 	}
194 }
195 
196 // MouseMoved
197 void
MouseMoved(BPoint where,uint32 transit,const BMessage * message)198 IconButton::MouseMoved(BPoint where, uint32 transit, const BMessage* message)
199 {
200 	if (IsValid()) {
201 		uint32 buttons = 0;
202 		Window()->CurrentMessage()->FindInt32("buttons", (int32*)&buttons);
203 		// catch a mouse up event that we might have missed
204 		if (!buttons && _HasFlags(STATE_PRESSED)) {
205 			MouseUp(where);
206 			return;
207 		}
208 		if (buttons && !_HasFlags(STATE_TRACKING))
209 			return;
210 		if ((transit == B_INSIDE_VIEW || transit == B_ENTERED_VIEW)
211 			&& _HasFlags(STATE_ENABLED))
212 			_AddFlags(STATE_INSIDE);
213 		else
214 			_ClearFlags(STATE_INSIDE);
215 		if (_HasFlags(STATE_TRACKING)) {
216 			if (Bounds().Contains(where))
217 				_AddFlags(STATE_PRESSED);
218 			else
219 				_ClearFlags(STATE_PRESSED);
220 		}
221 	}
222 }
223 
224 // GetPreferredSize
225 void
GetPreferredSize(float * width,float * height)226 IconButton::GetPreferredSize(float* width, float* height)
227 {
228 	layoutprefs();
229 
230 	if (width)
231 		*width = mpm.mini.x;
232 	if (height)
233 		*height = mpm.mini.y;
234 }
235 
236 // Invoke
237 status_t
Invoke(BMessage * message)238 IconButton::Invoke(BMessage* message)
239 {
240 	if (!message)
241 		message = Message();
242 	if (message) {
243 		BMessage clone(*message);
244 		clone.AddInt64("be:when", system_time());
245 		clone.AddPointer("be:source", (BView*)this);
246 		clone.AddInt32("be:value", Value());
247 		clone.AddInt32("id", ID());
248 		return BInvoker::Invoke(&clone);
249 	}
250 	return BInvoker::Invoke(message);
251 }
252 
253 #define MIN_SPACE 15.0
254 
255 // layoutprefs
256 minimax
layoutprefs()257 IconButton::layoutprefs()
258 {
259 	float minWidth = 0.0;
260 	float minHeight = 0.0;
261 	if (IsValid()) {
262 		minWidth += fNormalBitmap->Bounds().IntegerWidth() + 1.0;
263 		minHeight += fNormalBitmap->Bounds().IntegerHeight() + 1.0;
264 	} else {
265 		minWidth += MIN_SPACE;
266 		minHeight += MIN_SPACE;
267 	}
268 	if (minWidth < MIN_SPACE)
269 		minWidth = MIN_SPACE;
270 	if (minHeight < MIN_SPACE)
271 		minHeight = MIN_SPACE;
272 	if (fLabel.CountChars() > 0) {
273 		font_height fh;
274 		GetFontHeight(&fh);
275 		minHeight += ceilf(fh.ascent + fh.descent) + 4.0;
276 		minWidth += StringWidth(fLabel.String()) + 4.0;
277 	}
278 	mpm.mini.x = minWidth + 4.0;
279 //	mpm.maxi.x = 10000.0 + 4.0;
280 	mpm.maxi.x = minWidth + 4.0;
281 	mpm.mini.y = minHeight + 4.0;
282 //	mpm.maxi.y = 10000.0 + 4.0;
283 	mpm.maxi.y = minHeight + 4.0;
284 	mpm.weight = 0.0;
285 	return mpm;
286 }
287 
288 // layout
289 BRect
layout(BRect rect)290 IconButton::layout(BRect rect)
291 {
292 	MoveTo(rect.LeftTop());
293 	ResizeTo(rect.Width(), rect.Height());
294 	return Frame();
295 }
296 
297 // SetPressed
298 void
SetPressed(bool pressed)299 IconButton::SetPressed(bool pressed)
300 {
301 	if (pressed)
302 		_AddFlags(STATE_FORCE_PRESSED);
303 	else
304 		_ClearFlags(STATE_FORCE_PRESSED);
305 }
306 
307 // IsPressed
308 bool
IsPressed() const309 IconButton::IsPressed() const
310 {
311 	return _HasFlags(STATE_FORCE_PRESSED);
312 }
313 
314 // SetIcon
315 status_t
SetIcon(const char * pathToBitmap)316 IconButton::SetIcon(const char* pathToBitmap)
317 {
318 	status_t status = B_BAD_VALUE;
319 	if (pathToBitmap) {
320 		BBitmap* fileBitmap = NULL;
321 		// try to load bitmap from either relative or absolute path
322 		BEntry entry(pathToBitmap, true);
323 		if (!entry.Exists()) {
324 			app_info info;
325 			status = be_app->GetAppInfo(&info);
326 			if (status == B_OK) {
327 				BEntry app_entry(&info.ref, true);
328 				BPath path;
329 				app_entry.GetPath(&path);
330 				status = path.InitCheck();
331 				if (status == B_OK) {
332 					status = path.GetParent(&path);
333 					if (status == B_OK) {
334 						status = path.Append(pathToBitmap, true);
335 						if (status == B_OK)
336 							fileBitmap = BTranslationUtils::GetBitmap(path.Path());
337 						else
338 							printf("IconButton::SetIcon() - path.Append() failed: %s\n", strerror(status));
339 					} else
340 						printf("IconButton::SetIcon() - path.GetParent() failed: %s\n", strerror(status));
341 				} else
342 					printf("IconButton::SetIcon() - path.InitCheck() failed: %s\n", strerror(status));
343 			} else
344 				printf("IconButton::SetIcon() - be_app->GetAppInfo() failed: %s\n", strerror(status));
345 		} else
346 			fileBitmap = BTranslationUtils::GetBitmap(pathToBitmap);
347 		if (fileBitmap) {
348 			status = _MakeBitmaps(fileBitmap);
349 			delete fileBitmap;
350 		} else
351 			status = B_ERROR;
352 	}
353 	return status;
354 }
355 
356 // SetIcon
357 status_t
SetIcon(const BBitmap * bitmap)358 IconButton::SetIcon(const BBitmap* bitmap)
359 {
360 	if (bitmap && bitmap->ColorSpace() == B_CMAP8) {
361 		status_t status = bitmap->InitCheck();
362 		if (status >= B_OK) {
363 			if (BBitmap* rgb32Bitmap = _ConvertToRGB32(bitmap)) {
364 				status = _MakeBitmaps(rgb32Bitmap);
365 				delete rgb32Bitmap;
366 			} else
367 				status = B_NO_MEMORY;
368 		}
369 		return status;
370 	} else
371 		return _MakeBitmaps(bitmap);
372 }
373 
374 // SetIcon
375 status_t
SetIcon(const BMimeType * fileType,bool small)376 IconButton::SetIcon(const BMimeType* fileType, bool small)
377 {
378 	status_t status = fileType ? fileType->InitCheck() : B_BAD_VALUE;
379 	if (status >= B_OK) {
380 		BBitmap* mimeBitmap = new(nothrow) BBitmap(BRect(0.0, 0.0, 15.0, 15.0), B_CMAP8);
381 		if (mimeBitmap && mimeBitmap->IsValid()) {
382 			status = fileType->GetIcon(mimeBitmap, small ? B_MINI_ICON : B_LARGE_ICON);
383 			if (status >= B_OK) {
384 				if (BBitmap* bitmap = _ConvertToRGB32(mimeBitmap)) {
385 					status = _MakeBitmaps(bitmap);
386 					delete bitmap;
387 				} else
388 					printf("IconButton::SetIcon() - B_RGB32 bitmap is not valid\n");
389 			} else
390 				printf("IconButton::SetIcon() - fileType->GetIcon() failed: %s\n", strerror(status));
391 		} else
392 			printf("IconButton::SetIcon() - B_CMAP8 bitmap is not valid\n");
393 		delete mimeBitmap;
394 	} else
395 		printf("IconButton::SetIcon() - fileType is not valid: %s\n", strerror(status));
396 	return status;
397 }
398 
399 // SetIcon
400 status_t
SetIcon(const unsigned char * bitsFromQuickRes,uint32 width,uint32 height,color_space format,bool convertToBW)401 IconButton::SetIcon(const unsigned char* bitsFromQuickRes,
402 					uint32 width, uint32 height, color_space format, bool convertToBW)
403 {
404 	status_t status = B_BAD_VALUE;
405 	if (bitsFromQuickRes && width > 0 && height > 0) {
406 		BBitmap* quickResBitmap = new(nothrow) BBitmap(BRect(0.0, 0.0, width - 1.0, height - 1.0), format);
407 		status = quickResBitmap ? quickResBitmap->InitCheck() : B_ERROR;
408 		if (status >= B_OK) {
409 			// It doesn't look right to copy BitsLength() bytes, but bitmaps
410 			// exported from QuickRes still contain their padding, so it is alright.
411 			memcpy(quickResBitmap->Bits(), bitsFromQuickRes, quickResBitmap->BitsLength());
412 			if (format != B_RGB32 && format != B_RGBA32 && format != B_RGB32_BIG && format != B_RGBA32_BIG) {
413 				// colorspace needs conversion
414 				BBitmap* bitmap = new(nothrow) BBitmap(quickResBitmap->Bounds(), B_RGB32, true);
415 				if (bitmap && bitmap->IsValid()) {
416 					BView* helper = new BView(bitmap->Bounds(), "helper",
417 											  B_FOLLOW_NONE, B_WILL_DRAW);
418 					if (bitmap->Lock()) {
419 						bitmap->AddChild(helper);
420 						helper->SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR));
421 						helper->FillRect(helper->Bounds());
422 						helper->SetDrawingMode(B_OP_OVER);
423 						helper->DrawBitmap(quickResBitmap, BPoint(0.0, 0.0));
424 						helper->Sync();
425 						bitmap->Unlock();
426 					}
427 					status = _MakeBitmaps(bitmap);
428 				} else
429 					printf("IconButton::SetIcon() - B_RGB32 bitmap is not valid\n");
430 				delete bitmap;
431 			} else {
432 				// native colorspace (32 bits)
433 				if (convertToBW) {
434 					// convert to gray scale icon
435 					uint8* bits = (uint8*)quickResBitmap->Bits();
436 					uint32 bpr = quickResBitmap->BytesPerRow();
437 					for (uint32 y = 0; y < height; y++) {
438 						uint8* handle = bits;
439 						uint8 gray;
440 						for (uint32 x = 0; x < width; x++) {
441 							gray = uint8((116 * handle[0] + 600 * handle[1] + 308 * handle[2]) / 1024);
442 							handle[0] = gray;
443 							handle[1] = gray;
444 							handle[2] = gray;
445 							handle += 4;
446 						}
447 						bits += bpr;
448 					}
449 				}
450 				status = _MakeBitmaps(quickResBitmap);
451 			}
452 		} else
453 			printf("IconButton::SetIcon() - error allocating bitmap: %s\n", strerror(status));
454 		delete quickResBitmap;
455 	}
456 	return status;
457 }
458 
459 // ClearIcon
460 void
ClearIcon()461 IconButton::ClearIcon()
462 {
463 	_DeleteBitmaps();
464 	_Update();
465 }
466 
467 // Bitmap
468 BBitmap*
Bitmap() const469 IconButton::Bitmap() const
470 {
471 	BBitmap* bitmap = NULL;
472 	if (fNormalBitmap && fNormalBitmap->IsValid()) {
473 		bitmap = new(nothrow) BBitmap(fNormalBitmap);
474 		if (bitmap->IsValid()) {
475 			// TODO: remove this functionality when we use real transparent bitmaps
476 			uint8* bits = (uint8*)bitmap->Bits();
477 			uint32 bpr = bitmap->BytesPerRow();
478 			uint32 width = bitmap->Bounds().IntegerWidth() + 1;
479 			uint32 height = bitmap->Bounds().IntegerHeight() + 1;
480 			color_space format = bitmap->ColorSpace();
481 			if (format == B_CMAP8) {
482 				// replace gray with magic transparent index
483 			} else if (format == B_RGB32) {
484 				for (uint32 y = 0; y < height; y++) {
485 					uint8* bitsHandle = bits;
486 					for (uint32 x = 0; x < width; x++) {
487 						if (bitsHandle[0] == 216
488 							&& bitsHandle[1] == 216
489 							&& bitsHandle[2] == 216) {
490 							bitsHandle[3] = 0;	// make this pixel completely transparent
491 						}
492 						bitsHandle += 4;
493 					}
494 					bits += bpr;
495 				}
496 			}
497 		} else {
498 			delete bitmap;
499 			bitmap = NULL;
500 		}
501 	}
502 	return bitmap;
503 }
504 
505 // DrawBorder
506 bool
DrawBorder() const507 IconButton::DrawBorder() const
508 {
509 	return (IsEnabled() && (_HasFlags(STATE_INSIDE) || _HasFlags(STATE_TRACKING))
510 			|| _HasFlags(STATE_FORCE_PRESSED));
511 }
512 
513 // DrawNormalBorder
514 void
DrawNormalBorder(BRect r,rgb_color background,rgb_color shadow,rgb_color darkShadow,rgb_color lightShadow,rgb_color light)515 IconButton::DrawNormalBorder(BRect r, rgb_color background,
516 							 rgb_color shadow, rgb_color darkShadow,
517 							 rgb_color lightShadow, rgb_color light)
518 {
519 	_DrawFrame(r, shadow, darkShadow, light, lightShadow);
520 }
521 
522 // DrawPressedBorder
523 void
DrawPressedBorder(BRect r,rgb_color background,rgb_color shadow,rgb_color darkShadow,rgb_color lightShadow,rgb_color light)524 IconButton::DrawPressedBorder(BRect r, rgb_color background,
525 							rgb_color shadow, rgb_color darkShadow,
526 							rgb_color lightShadow, rgb_color light)
527 {
528 	_DrawFrame(r, shadow, light, darkShadow, background);
529 }
530 
531 // IsValid
532 bool
IsValid() const533 IconButton::IsValid() const
534 {
535 	return (fNormalBitmap && fDisabledBitmap && fClickedBitmap && fDisabledClickedBitmap
536 		&& fNormalBitmap->IsValid()
537 		&& fDisabledBitmap->IsValid()
538 		&& fClickedBitmap->IsValid()
539 		&& fDisabledClickedBitmap->IsValid());
540 }
541 
542 // Value
543 int32
Value() const544 IconButton::Value() const
545 {
546 	return _HasFlags(STATE_PRESSED) ? B_CONTROL_ON : B_CONTROL_OFF;
547 }
548 
549 // SetValue
550 void
SetValue(int32 value)551 IconButton::SetValue(int32 value)
552 {
553 	if (value)
554 		_AddFlags(STATE_PRESSED);
555 	else
556 		_ClearFlags(STATE_PRESSED);
557 }
558 
559 // IsEnabled
560 bool
IsEnabled() const561 IconButton::IsEnabled() const
562 {
563 	return _HasFlags(STATE_ENABLED) ? B_CONTROL_ON : B_CONTROL_OFF;
564 }
565 
566 // SetEnabled
567 void
SetEnabled(bool enabled)568 IconButton::SetEnabled(bool enabled)
569 {
570 	if (enabled)
571 		_AddFlags(STATE_ENABLED);
572 	else
573 		_ClearFlags(STATE_ENABLED | STATE_TRACKING | STATE_INSIDE);
574 }
575 
576 // _ConvertToRGB32
577 BBitmap*
_ConvertToRGB32(const BBitmap * bitmap) const578 IconButton::_ConvertToRGB32(const BBitmap* bitmap) const
579 {
580 	BBitmap* convertedBitmap = new(nothrow) BBitmap(bitmap->Bounds(), B_BITMAP_ACCEPTS_VIEWS, B_RGBA32);
581 	if (convertedBitmap && convertedBitmap->IsValid()) {
582 		memset(convertedBitmap->Bits(), 0, convertedBitmap->BitsLength());
583 		BView* helper = new BView(bitmap->Bounds(), "helper",
584 								  B_FOLLOW_NONE, B_WILL_DRAW);
585 		if (convertedBitmap->Lock()) {
586 			convertedBitmap->AddChild(helper);
587 			helper->SetDrawingMode(B_OP_OVER);
588 			helper->DrawBitmap(bitmap, BPoint(0.0, 0.0));
589 			helper->Sync();
590 			convertedBitmap->Unlock();
591 		}
592 	} else {
593 		delete convertedBitmap;
594 		convertedBitmap = NULL;
595 	}
596 	return convertedBitmap;
597 }
598 
599 // _MakeBitmaps
600 status_t
_MakeBitmaps(const BBitmap * bitmap)601 IconButton::_MakeBitmaps(const BBitmap* bitmap)
602 {
603 	status_t status = bitmap ? bitmap->InitCheck() : B_BAD_VALUE;
604 	if (status >= B_OK) {
605 		// make our own versions of the bitmap
606 		BRect b(bitmap->Bounds());
607 		_DeleteBitmaps();
608 		color_space format = bitmap->ColorSpace();
609 		fNormalBitmap = new(nothrow) BBitmap(b, format);
610 		fDisabledBitmap = new(nothrow) BBitmap(b, format);
611 		fClickedBitmap = new(nothrow) BBitmap(b, format);
612 		fDisabledClickedBitmap = new(nothrow) BBitmap(b, format);
613 		if (IsValid()) {
614 			// copy bitmaps from file bitmap
615 			uint8* nBits = (uint8*)fNormalBitmap->Bits();
616 			uint8* dBits = (uint8*)fDisabledBitmap->Bits();
617 			uint8* cBits = (uint8*)fClickedBitmap->Bits();
618 			uint8* dcBits = (uint8*)fDisabledClickedBitmap->Bits();
619 			uint8* fBits = (uint8*)bitmap->Bits();
620 			int32 nbpr = fNormalBitmap->BytesPerRow();
621 			int32 fbpr = bitmap->BytesPerRow();
622 			int32 pixels = b.IntegerWidth() + 1;
623 			int32 lines = b.IntegerHeight() + 1;
624 			// nontransparent version:
625 			if (format == B_RGB32 || format == B_RGB32_BIG) {
626 				// iterate over color components
627 				for (int32 y = 0; y < lines; y++) {
628 					for (int32 x = 0; x < pixels; x++) {
629 						int32 nOffset = 4 * x;
630 						int32 fOffset = 4 * x;
631 						nBits[nOffset + 0] = fBits[fOffset + 0];
632 						nBits[nOffset + 1] = fBits[fOffset + 1];
633 						nBits[nOffset + 2] = fBits[fOffset + 2];
634 						nBits[nOffset + 3] = 255;
635 						// clicked bits are darker (lame method...)
636 						cBits[nOffset + 0] = (uint8)((float)nBits[nOffset + 0] * 0.8);
637 						cBits[nOffset + 1] = (uint8)((float)nBits[nOffset + 1] * 0.8);
638 						cBits[nOffset + 2] = (uint8)((float)nBits[nOffset + 2] * 0.8);
639 						cBits[nOffset + 3] = 255;
640 						// disabled bits have less contrast (lame method...)
641 						uint8 grey = 216;
642 						float dist = (nBits[nOffset + 0] - grey) * 0.4;
643 						dBits[nOffset + 0] = (uint8)(grey + dist);
644 						dist = (nBits[nOffset + 1] - grey) * 0.4;
645 						dBits[nOffset + 1] = (uint8)(grey + dist);
646 						dist = (nBits[nOffset + 2] - grey) * 0.4;
647 						dBits[nOffset + 2] = (uint8)(grey + dist);
648 						dBits[nOffset + 3] = 255;
649 						// disabled bits have less contrast (lame method...)
650 						grey = 188;
651 						dist = (nBits[nOffset + 0] - grey) * 0.4;
652 						dcBits[nOffset + 0] = (uint8)(grey + dist);
653 						dist = (nBits[nOffset + 1] - grey) * 0.4;
654 						dcBits[nOffset + 1] = (uint8)(grey + dist);
655 						dist = (nBits[nOffset + 2] - grey) * 0.4;
656 						dcBits[nOffset + 2] = (uint8)(grey + dist);
657 						dcBits[nOffset + 3] = 255;
658 					}
659 					nBits += nbpr;
660 					dBits += nbpr;
661 					cBits += nbpr;
662 					dcBits += nbpr;
663 					fBits += fbpr;
664 				}
665 			// transparent version:
666 			} else if (format == B_RGBA32 || format == B_RGBA32_BIG) {
667 				// iterate over color components
668 				for (int32 y = 0; y < lines; y++) {
669 					for (int32 x = 0; x < pixels; x++) {
670 						int32 nOffset = 4 * x;
671 						int32 fOffset = 4 * x;
672 						nBits[nOffset + 0] = fBits[fOffset + 0];
673 						nBits[nOffset + 1] = fBits[fOffset + 1];
674 						nBits[nOffset + 2] = fBits[fOffset + 2];
675 						nBits[nOffset + 3] = fBits[fOffset + 3];
676 						// clicked bits are darker (lame method...)
677 						cBits[nOffset + 0] = (uint8)(nBits[nOffset + 0] * 0.8);
678 						cBits[nOffset + 1] = (uint8)(nBits[nOffset + 1] * 0.8);
679 						cBits[nOffset + 2] = (uint8)(nBits[nOffset + 2] * 0.8);
680 						cBits[nOffset + 3] = fBits[fOffset + 3];
681 						// disabled bits have less opacity
682 						dBits[nOffset + 0] = fBits[fOffset + 0];
683 						dBits[nOffset + 1] = fBits[fOffset + 1];
684 						dBits[nOffset + 2] = fBits[fOffset + 2];
685 						dBits[nOffset + 3] = (uint8)(fBits[fOffset + 3] * 0.5);
686 						// disabled bits have less contrast (lame method...)
687 						dcBits[nOffset + 0] = (uint8)(nBits[nOffset + 0] * 0.8);
688 						dcBits[nOffset + 1] = (uint8)(nBits[nOffset + 1] * 0.8);
689 						dcBits[nOffset + 2] = (uint8)(nBits[nOffset + 2] * 0.8);
690 						dcBits[nOffset + 3] = (uint8)(fBits[fOffset + 3] * 0.5);
691 					}
692 					nBits += nbpr;
693 					dBits += nbpr;
694 					cBits += nbpr;
695 					dcBits += nbpr;
696 					fBits += fbpr;
697 				}
698 			// unsupported format
699 			} else {
700 				printf("IconButton::_MakeBitmaps() - bitmap has unsupported colorspace\n");
701 				status = B_MISMATCHED_VALUES;
702 				_DeleteBitmaps();
703 			}
704 		} else {
705 			printf("IconButton::_MakeBitmaps() - error allocating local bitmaps\n");
706 			status = B_NO_MEMORY;
707 			_DeleteBitmaps();
708 		}
709 	} else
710 		printf("IconButton::_MakeBitmaps() - bitmap is not valid\n");
711 	return status;
712 }
713 
714 // _DeleteBitmaps
715 void
_DeleteBitmaps()716 IconButton::_DeleteBitmaps()
717 {
718 	delete fNormalBitmap;
719 	fNormalBitmap = NULL;
720 	delete fDisabledBitmap;
721 	fDisabledBitmap = NULL;
722 	delete fClickedBitmap;
723 	fClickedBitmap = NULL;
724 	delete fDisabledClickedBitmap;
725 	fDisabledClickedBitmap = NULL;
726 }
727 
728 // _Update
729 void
_Update()730 IconButton::_Update()
731 {
732 	if (LockLooper()) {
733 		Invalidate();
734 		UnlockLooper();
735 	}
736 }
737 
738 // _AddFlags
739 void
_AddFlags(uint32 flags)740 IconButton::_AddFlags(uint32 flags)
741 {
742 	if (!(fButtonState & flags)) {
743 		fButtonState |= flags;
744 		_Update();
745 	}
746 }
747 
748 // _ClearFlags
749 void
_ClearFlags(uint32 flags)750 IconButton::_ClearFlags(uint32 flags)
751 {
752 	if (fButtonState & flags) {
753 		fButtonState &= ~flags;
754 		_Update();
755 	}
756 }
757 
758 // _HasFlags
759 bool
_HasFlags(uint32 flags) const760 IconButton::_HasFlags(uint32 flags) const
761 {
762 	return (fButtonState & flags);
763 }
764 
765 // _DrawFrame
766 void
_DrawFrame(BRect r,rgb_color col1,rgb_color col2,rgb_color col3,rgb_color col4)767 IconButton::_DrawFrame(BRect r, rgb_color col1, rgb_color col2,
768 					   rgb_color col3, rgb_color col4)
769 {
770 	BeginLineArray(8);
771 		AddLine(BPoint(r.left, r.bottom), BPoint(r.left, r.top), col1);
772 		AddLine(BPoint(r.left + 1.0, r.top), BPoint(r.right, r.top), col1);
773 		AddLine(BPoint(r.right, r.top + 1.0), BPoint(r.right, r.bottom), col2);
774 		AddLine(BPoint(r.right - 1.0, r.bottom), BPoint(r.left + 1.0, r.bottom), col2);
775 		r.InsetBy(1.0, 1.0);
776 		AddLine(BPoint(r.left, r.bottom), BPoint(r.left, r.top), col3);
777 		AddLine(BPoint(r.left + 1.0, r.top), BPoint(r.right, r.top), col3);
778 		AddLine(BPoint(r.right, r.top + 1.0), BPoint(r.right, r.bottom), col4);
779 		AddLine(BPoint(r.right - 1.0, r.bottom), BPoint(r.left + 1.0, r.bottom), col4);
780 	EndLineArray();
781 }
782