hrev46580 adds 5 changesets to branch 'master' old head: d3e73d457e74feb381f5984f060595a2a60e835d new head: fe8787698c2a7ddc1f79d3bf645303ab7052e553 overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=fe87876+%5Ed3e73d4 ---------------------------------------------------------------------------- 8719e0d: BControlLook: Add methods for getting insets * Update the previously unused frame_type and background_type enums. * Add methods GetFrameInsets(), GetBackgroundInsets(), GetInsets() to get the insets for a given frame type, background type, or both respectively. 1b848ee: BControlLook: Add DrawLabel() variants with icon A label, a bitmap, or both can be specified. be26037: BControl: Add icon support The icon is meant as an addition to or replacement of the label. Icon bitmaps for various states of the control (off, on, partially on, each enabled or disabled, plus up to 125 custom states) can be set individually via SetIconBitmap() (getter IconBitmap()). The convenience method SetIcon() can be used to set the bitmaps for the standard states from a single bitmap; it also supports cropping the icon to its non-transparent area. Code borrowed from BIconButton. be43674: BControl subclasses: Override SetIcon() ... and implement Perform() action for potential later use. fe87876: BButton: Add icon support * Remove non-BControlLook drawing code. It's just an annoyance to maintain. * Update Draw() and _ValidatePreferredSize() to add icon support. [ Ingo Weinhold <ingo_weinhold@xxxxxx> ] ---------------------------------------------------------------------------- 22 files changed, 931 insertions(+), 315 deletions(-) headers/os/interface/Button.h | 2 + headers/os/interface/CheckBox.h | 2 + headers/os/interface/ColorControl.h | 2 + headers/os/interface/Control.h | 59 ++- headers/os/interface/ControlLook.h | 37 +- headers/os/interface/PictureButton.h | 2 + headers/os/interface/RadioButton.h | 2 + headers/os/interface/Slider.h | 2 + headers/os/interface/TextControl.h | 2 + headers/private/binary_compatibility/Global.h | 8 +- headers/private/binary_compatibility/Interface.h | 6 + headers/private/shared/IconButton.h | 3 +- src/kits/interface/Button.cpp | 322 +++--------- src/kits/interface/CheckBox.cpp | 12 + src/kits/interface/ColorControl.cpp | 12 + src/kits/interface/Control.cpp | 507 ++++++++++++++++++- src/kits/interface/ControlLook.cpp | 215 ++++++-- src/kits/interface/PictureButton.cpp | 12 + src/kits/interface/RadioButton.cpp | 11 + src/kits/interface/Slider.cpp | 12 + src/kits/interface/TextControl.cpp | 14 +- src/kits/shared/IconButton.cpp | 2 +- ############################################################################ Commit: 8719e0dc4bf8495cd70c2dc3d25a5165f7ea3d16 URL: http://cgit.haiku-os.org/haiku/commit/?id=8719e0d Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Sun Dec 22 00:57:36 2013 UTC BControlLook: Add methods for getting insets * Update the previously unused frame_type and background_type enums. * Add methods GetFrameInsets(), GetBackgroundInsets(), GetInsets() to get the insets for a given frame type, background type, or both respectively. ---------------------------------------------------------------------------- diff --git a/headers/os/interface/ControlLook.h b/headers/os/interface/ControlLook.h index 8039f14..3db12f7 100644 --- a/headers/os/interface/ControlLook.h +++ b/headers/os/interface/ControlLook.h @@ -35,16 +35,20 @@ public: enum frame_type { B_BUTTON_FRAME, - B_MENU_FRAME, - B_LISTVIEW_FRAME, - B_INPUT_FRAME + B_GROUP_FRAME, + B_MENU_FIELD_FRAME, + B_SCROLL_VIEW_FRAME, + B_TEXT_CONTROL_FRAME, }; enum background_type { B_BUTTON_BACKGROUND, B_MENU_BACKGROUND, - B_LISTVIEW_BACKGROUND, - B_INPUT_BACKGROUND + B_MENU_BAR_BACKGROUND, + B_MENU_FIELD_BACKGROUND, + B_MENU_ITEM_BACKGROUND, + B_HORIZONTAL_SCROLL_BAR_BACKGROUND, + B_VERTICAL_SCROLL_BAR_BACKGROUND, }; enum { @@ -332,6 +336,18 @@ public: const rgb_color& base, uint32 flags, const BPoint& where); + virtual void GetFrameInsets(frame_type frameType, + uint32 flags, float& _left, float& _top, + float& _right, float& _bottom); + virtual void GetBackgroundInsets( + background_type backgroundType, + uint32 flags, float& _left, float& _top, + float& _right, float& _bottom); + void GetInsets(frame_type frameType, + background_type backgroundType, + uint32 flags, float& _left, float& _top, + float& _right, float& _bottom); + void SetBackgroundInfo( const BMessage& backgroundInfo); diff --git a/src/kits/interface/ControlLook.cpp b/src/kits/interface/ControlLook.cpp index baab42d..e4e0292 100644 --- a/src/kits/interface/ControlLook.cpp +++ b/src/kits/interface/ControlLook.cpp @@ -1902,6 +1902,86 @@ BControlLook::DrawLabel(BView* view, const char* label, const rgb_color& base, void +BControlLook::GetFrameInsets(frame_type frameType, uint32 flags, float& _left, + float& _top, float& _right, float& _bottom) +{ + // All frames have the same inset on each side. + float inset = 0; + + switch (frameType) { + case B_BUTTON_FRAME: + inset = (flags & B_DEFAULT_BUTTON) != 0 ? 6 : 3; + break; + case B_GROUP_FRAME: + case B_MENU_FIELD_FRAME: + inset = 3; + break; + case B_SCROLL_VIEW_FRAME: + case B_TEXT_CONTROL_FRAME: + inset = 2; + break; + } + + _left = inset; + _top = inset; + _right = inset; + _bottom = inset; +} + + +void +BControlLook::GetBackgroundInsets(background_type backgroundType, + uint32 flags, float& _left, float& _top, float& _right, float& _bottom) +{ + // Most backgrounds have the same inset on each side. + float inset = 0; + + switch (backgroundType) { + case B_BUTTON_BACKGROUND: + case B_MENU_BACKGROUND: + case B_MENU_BAR_BACKGROUND: + case B_MENU_FIELD_BACKGROUND: + case B_MENU_ITEM_BACKGROUND: + inset = 1; + break; + case B_HORIZONTAL_SCROLL_BAR_BACKGROUND: + _left = 2; + _top = 0; + _right = 1; + _bottom = 0; + return; + case B_VERTICAL_SCROLL_BAR_BACKGROUND: + _left = 0; + _top = 2; + _right = 0; + _bottom = 1; + return; + } + + _left = inset; + _top = inset; + _right = inset; + _bottom = inset; +} + + +void +BControlLook::GetInsets(frame_type frameType, background_type backgroundType, + uint32 flags, float& _left, float& _top, float& _right, float& _bottom) +{ + GetFrameInsets(frameType, flags, _left, _top, _right, _bottom); + + float left, top, right, bottom; + GetBackgroundInsets(backgroundType, flags, left, top, right, bottom); + + _left += left; + _top += top; + _right += right; + _bottom += bottom; +} + + +void BControlLook::SetBackgroundInfo(const BMessage& backgroundInfo) { fBackgroundInfo = backgroundInfo; ############################################################################ Commit: 1b848ee7f2943f00b95a8657494592e2d0f15898 URL: http://cgit.haiku-os.org/haiku/commit/?id=1b848ee Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Sun Dec 22 01:01:13 2013 UTC BControlLook: Add DrawLabel() variants with icon A label, a bitmap, or both can be specified. ---------------------------------------------------------------------------- diff --git a/headers/os/interface/ControlLook.h b/headers/os/interface/ControlLook.h index 3db12f7..8222ae2 100644 --- a/headers/os/interface/ControlLook.h +++ b/headers/os/interface/ControlLook.h @@ -12,6 +12,7 @@ #include <Slider.h> +class BBitmap; class BControl; class BGradientLinear; class BView; @@ -336,6 +337,16 @@ public: const rgb_color& base, uint32 flags, const BPoint& where); + void DrawLabel(BView* view, const char* label, + const BBitmap* icon, BRect rect, + const BRect& updateRect, + const rgb_color& base, uint32 flags); + virtual void DrawLabel(BView* view, const char* label, + const BBitmap* icon, BRect rect, + const BRect& updateRect, + const rgb_color& base, uint32 flags, + const BAlignment& alignment); + virtual void GetFrameInsets(frame_type frameType, uint32 flags, float& _left, float& _top, float& _right, float& _bottom); diff --git a/src/kits/interface/ControlLook.cpp b/src/kits/interface/ControlLook.cpp index e4e0292..6af7778 100644 --- a/src/kits/interface/ControlLook.cpp +++ b/src/kits/interface/ControlLook.cpp @@ -10,8 +10,11 @@ #include <ControlLook.h> +#include <algorithm> + #include <Control.h> #include <GradientLinear.h> +#include <LayoutUtils.h> #include <Region.h> #include <Shape.h> #include <String.h> @@ -1730,7 +1733,7 @@ void BControlLook::DrawLabel(BView* view, const char* label, BRect rect, const BRect& updateRect, const rgb_color& base, uint32 flags) { - DrawLabel(view, label, rect, updateRect, base, flags, + DrawLabel(view, label, NULL, rect, updateRect, base, flags, DefaultLabelAlignment()); } @@ -1740,54 +1743,7 @@ BControlLook::DrawLabel(BView* view, const char* label, BRect rect, const BRect& updateRect, const rgb_color& base, uint32 flags, const BAlignment& alignment) { - if (!rect.Intersects(updateRect)) - return; - - // truncate the label if necessary and get the width and height - BString truncatedLabel(label); - - BFont font; - view->GetFont(&font); - - float width = rect.Width(); - font.TruncateString(&truncatedLabel, B_TRUNCATE_END, width); - width = font.StringWidth(truncatedLabel.String()); - - font_height fontHeight; - font.GetHeight(&fontHeight); - float height = ceilf(fontHeight.ascent) + ceilf(fontHeight.descent); - - // handle alignment - BPoint location; - - switch (alignment.horizontal) { - default: - case B_ALIGN_LEFT: - location.x = rect.left; - break; - case B_ALIGN_RIGHT: - location.x = rect.right - width; - break; - case B_ALIGN_CENTER: - location.x = (rect.left + rect.right - width) / 2.0f; - break; - } - - switch (alignment.vertical) { - case B_ALIGN_TOP: - location.y = rect.top + ceilf(fontHeight.ascent); - break; - default: - case B_ALIGN_MIDDLE: - location.y = floorf((rect.top + rect.bottom - height) / 2.0f + 0.5f) - + ceilf(fontHeight.ascent); - break; - case B_ALIGN_BOTTOM: - location.y = rect.bottom - ceilf(fontHeight.descent); - break; - } - - DrawLabel(view, truncatedLabel.String(), base, flags, location); + DrawLabel(view, label, NULL, rect, updateRect, base, flags, alignment); } @@ -1902,6 +1858,87 @@ BControlLook::DrawLabel(BView* view, const char* label, const rgb_color& base, void +BControlLook::DrawLabel(BView* view, const char* label, const BBitmap* icon, + BRect rect, const BRect& updateRect, const rgb_color& base, uint32 flags) +{ + DrawLabel(view, label, icon, rect, updateRect, base, flags, + DefaultLabelAlignment()); +} + + +void +BControlLook::DrawLabel(BView* view, const char* label, const BBitmap* icon, + BRect rect, const BRect& updateRect, const rgb_color& base, uint32 flags, + const BAlignment& alignment) +{ + if (!rect.Intersects(updateRect)) + return; + + if (label == NULL && icon == NULL) + return; + + if (label == NULL) { + // icon only + BRect alignedRect = BLayoutUtils::AlignInFrame(rect, + icon->Bounds().Size(), alignment); + drawing_mode oldMode = view->DrawingMode(); + view->SetDrawingMode(B_OP_OVER); + view->DrawBitmap(icon, alignedRect.LeftTop()); + view->SetDrawingMode(oldMode); + return; + } + + // label, possibly with icon + float availableWidth = rect.Width(); + float width = 0; + float textOffset = 0; + float height = 0; + + if (icon != NULL) { + width = icon->Bounds().Width() + DefaultLabelSpacing() + 1; + height = icon->Bounds().Height() + 1; + textOffset = width; + availableWidth -= textOffset; + } + + // truncate the label if necessary and get the width and height + BString truncatedLabel(label); + + BFont font; + view->GetFont(&font); + + font.TruncateString(&truncatedLabel, B_TRUNCATE_END, availableWidth); + width += font.StringWidth(truncatedLabel.String()); + + font_height fontHeight; + font.GetHeight(&fontHeight); + float textHeight = ceilf(fontHeight.ascent) + ceilf(fontHeight.descent); + height = std::max(height, textHeight); + + // handle alignment + BRect alignedRect = BLayoutUtils::AlignInFrame(rect, + BSize(width - 1, height - 1), alignment); + + if (icon != NULL) { + BPoint location = alignedRect.LeftTop(); + if (icon->Bounds().Height() + 1 < height) + location.y += ceilf((height - icon->Bounds().Height() - 1) / 2); + + drawing_mode oldMode = view->DrawingMode(); + view->SetDrawingMode(B_OP_OVER); + view->DrawBitmap(icon, location); + view->SetDrawingMode(oldMode); + } + + BPoint location(alignedRect.left + textOffset, + alignedRect.top + ceilf(fontHeight.ascent)); + if (textHeight < height) + location.y += ceilf((height - textHeight) / 2); + DrawLabel(view, truncatedLabel.String(), base, flags, location); +} + + +void BControlLook::GetFrameInsets(frame_type frameType, uint32 flags, float& _left, float& _top, float& _right, float& _bottom) { ############################################################################ Commit: be260374d58f6eae120320ac1ca1ba50783e8c4b URL: http://cgit.haiku-os.org/haiku/commit/?id=be26037 Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Sun Dec 22 01:18:39 2013 UTC BControl: Add icon support The icon is meant as an addition to or replacement of the label. Icon bitmaps for various states of the control (off, on, partially on, each enabled or disabled, plus up to 125 custom states) can be set individually via SetIconBitmap() (getter IconBitmap()). The convenience method SetIcon() can be used to set the bitmaps for the standard states from a single bitmap; it also supports cropping the icon to its non-transparent area. Code borrowed from BIconButton. ---------------------------------------------------------------------------- diff --git a/headers/os/interface/Control.h b/headers/os/interface/Control.h index 31cd84f..0db157d 100644 --- a/headers/os/interface/Control.h +++ b/headers/os/interface/Control.h @@ -1,5 +1,5 @@ /* - * Copyright 2001-2009, Haiku, Inc. All rights reserved. + * Copyright 2001-2013, Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. */ #ifndef _CONTROL_H @@ -16,11 +16,43 @@ enum { B_CONTROL_PARTIALLY_ON = 2 }; +class BBitmap; class BWindow; class BControl : public BView, public BInvoker { public: + // Values for [Set]IconBitmap(). Not all types are applicable for + // all controls. + enum { + B_OFF_BITMAP = 0x00, + B_ON_BITMAP = 0x01, + B_PARTIALLY_ON_BITMAP = 0x02, + + // flag, can be combined with any of the above + B_DISABLED_BITMAP = 0x80, + // disabled version of the specified bitmap + }; + + // flags for SetIconBitmap() + enum { + B_KEEP_BITMAP = 0x0001, + // transfer bitmap ownership to BControl object + }; + + // flags for SetIcon() + enum { + B_TRIM_BITMAP = 0x0100, + // crop the bitmap to the not fully transparent area, may + // change the icon size + B_TRIM_BITMAP_KEEP_ASPECT = 0x0200, + // like B_TRIM_BITMAP, but keeps the aspect ratio + B_CREATE_ON_BITMAP = 0x0400, + B_CREATE_PARTIALLY_ON_BITMAP = 0x0800, + B_CREATE_DISABLED_BITMAPS = 0x1000, + }; + +public: BControl(BRect frame, const char* name, const char* label, BMessage* message, uint32 resizingMode, uint32 flags); @@ -70,6 +102,12 @@ public: virtual status_t Perform(perform_code d, void* arg); + virtual status_t SetIcon(const BBitmap* bitmap, + uint32 flags = 0); + status_t SetIconBitmap(const BBitmap* bitmap, + uint32 which, uint32 flags = 0); + const BBitmap* IconBitmap(uint32 which) const; + protected: bool IsFocusChanging() const; bool IsTracking() const; @@ -78,7 +116,16 @@ protected: void SetValueNoUpdate(int32 value); private: - virtual void _ReservedControl1(); + struct IconData; + +private: + static BBitmap* _ConvertToRGB32(const BBitmap* bitmap, + bool noAppServerLink = false); + static status_t _TrimBitmap(const BBitmap* bitmap, + bool keepAspect, BBitmap*& _trimmedBitmap); + status_t _MakeBitmaps(const BBitmap* bitmap, + uint32 flags); + virtual void _ReservedControl2(); virtual void _ReservedControl3(); virtual void _ReservedControl4(); @@ -87,14 +134,20 @@ private: void InitData(BMessage* data = NULL); +private: char* fLabel; int32 fValue; bool fEnabled; bool fFocusChanging; bool fTracking; bool fWantsNav; + IconData* fIconData; - uint32 _reserved[4]; +#ifdef B_HAIKU_64_BIT + uint32 _reserved[2]; +#else + uint32 _reserved[3]; +#endif }; #endif // _CONTROL_H diff --git a/headers/private/binary_compatibility/Global.h b/headers/private/binary_compatibility/Global.h index 6ba9693..94e468d 100644 --- a/headers/private/binary_compatibility/Global.h +++ b/headers/private/binary_compatibility/Global.h @@ -29,12 +29,12 @@ enum { PERFORM_CODE_LAYOUT_INVALIDATED = 1007, PERFORM_CODE_DO_LAYOUT = 1008, PERFORM_CODE_GET_TOOL_TIP_AT = 1009, + PERFORM_CODE_LAYOUT_CHANGED = 1010, + PERFORM_CODE_SET_ICON = 1011, // support kit - PERFORM_CODE_ALL_ARCHIVED = 1010, - PERFORM_CODE_ALL_UNARCHIVED = 1011, - - PERFORM_CODE_LAYOUT_CHANGED = 1012 + PERFORM_CODE_ALL_ARCHIVED = 2000, + PERFORM_CODE_ALL_UNARCHIVED = 2001, }; diff --git a/headers/private/binary_compatibility/Interface.h b/headers/private/binary_compatibility/Interface.h index 5653583..6255b5e 100644 --- a/headers/private/binary_compatibility/Interface.h +++ b/headers/private/binary_compatibility/Interface.h @@ -51,4 +51,10 @@ struct perform_data_get_tool_tip_at { bool return_value; }; +struct perform_data_set_icon { + const BBitmap* icon; + uint32 flags; +}; + + #endif /* _BINARY_COMPATIBILITY_INTERFACE_H_ */ diff --git a/src/kits/interface/Control.cpp b/src/kits/interface/Control.cpp index 8fd92bd..42dbc2f 100644 --- a/src/kits/interface/Control.cpp +++ b/src/kits/interface/Control.cpp @@ -1,9 +1,11 @@ /* - * Copyright 2001-2006, Haiku Inc. + * Copyright 2001-2013, Haiku, Inc. * Distributed under the terms of the MIT License. * * Authors: - * Marc Flerackers (mflerackers@xxxxxxxxxx) + * Marc Flerackers, mflerackers@xxxxxxxxxx + * Stephan Aßmus, superstippi@xxxxxx + * Ingo Weinhold, ingo_weinhold@xxxxxx */ /*! BControl is the base class for user-event handling objects. */ @@ -12,10 +14,13 @@ #include <stdlib.h> #include <string.h> +#include <Bitmap.h> #include <Control.h> +#include <ObjectList.h> #include <PropertyInfo.h> #include <Window.h> +#include <AutoDeleter.h> #include <binary_compatibility/Interface.h> @@ -45,6 +50,85 @@ static property_info sPropertyList[] = { }; +struct BControl::IconData { +public: + IconData() + : + fEnabledBitmaps(8, true), + fDisabledBitmaps(8, true) + { + } + + ~IconData() + { + DeleteBitmaps(); + } + + BBitmap* CreateBitmap(const BRect& bounds, color_space colorSpace, + uint32 which) + { + BBitmap* bitmap = new(std::nothrow) BBitmap(bounds, colorSpace); + if (bitmap == NULL || !bitmap->IsValid() || !SetBitmap(bitmap, which)) { + delete bitmap; + return NULL; + } + + return bitmap; + } + + BBitmap* CopyBitmap(const BBitmap& bitmapToClone, uint32 which) + { + BBitmap* bitmap = new(std::nothrow) BBitmap(bitmapToClone); + if (bitmap == NULL || !bitmap->IsValid() || !SetBitmap(bitmap, which)) { + delete bitmap; + return NULL; + } + + return bitmap; + } + + bool SetBitmap(BBitmap* bitmap, uint32 which) + { + IconList& list = (which & B_DISABLED_BITMAP) == 0 + ? fEnabledBitmaps : fDisabledBitmaps; + which &= ~uint32(B_DISABLED_BITMAP); + + int32 count = list.CountItems(); + if ((int32)which < count) { + list.ReplaceItem(which, bitmap); + return true; + } + + while (list.CountItems() < (int32)which) { + if (!list.AddItem((BBitmap*)NULL)) + return false; + } + + return list.AddItem(bitmap); + } + + BBitmap* Bitmap(uint32 which) const + { + const IconList& list = (which & B_DISABLED_BITMAP) == 0 + ? fEnabledBitmaps : fDisabledBitmaps; + return list.ItemAt(which & ~uint32(B_DISABLED_BITMAP)); + } + + void DeleteBitmaps() + { + fEnabledBitmaps.MakeEmpty(true); + fDisabledBitmaps.MakeEmpty(true); + } + +private: + typedef BObjectList<BBitmap> IconList; + +private: + IconList fEnabledBitmaps; + IconList fDisabledBitmaps; +}; + + BControl::BControl(BRect frame, const char *name, const char *label, BMessage *message, uint32 resizingMode, uint32 flags) : BView(frame, name, resizingMode, flags) @@ -70,6 +154,7 @@ BControl::BControl(const char *name, const char *label, BMessage *message, BControl::~BControl() { free(fLabel); + delete fIconData; SetMessage(NULL); } @@ -509,12 +594,148 @@ BControl::Perform(perform_code code, void* _data) BControl::DoLayout(); return B_OK; } + case PERFORM_CODE_SET_ICON: + { + perform_data_set_icon* data = (perform_data_set_icon*)_data; + return BControl::SetIcon(data->icon, data->flags); + } } return BView::Perform(code, _data); } +status_t +BControl::SetIcon(const BBitmap* bitmap, uint32 flags) +{ + if (bitmap == NULL) { + delete fIconData; + fIconData = NULL; + return B_OK; + } + + if (!bitmap->IsValid()) + return B_BAD_VALUE; + + // check the color space + bool hasAlpha = false; + bool canUseForMakeBitmaps = false; + + switch (bitmap->ColorSpace()) { + case B_RGBA32: + case B_RGBA32_BIG: + hasAlpha = true; + // fall through + case B_RGB32: + case B_RGB32_BIG: + canUseForMakeBitmaps = true; + break; + + case B_UVLA32: + case B_LABA32: + case B_HSIA32: + case B_HSVA32: + case B_HLSA32: + case B_CMYA32: + case B_RGBA15: + case B_RGBA15_BIG: + case B_CMAP8: + hasAlpha = true; + break; + + default: + break; + } + + BBitmap* trimmedBitmap = NULL; + + // trim the bitmap, if requested and the bitmap actually has alpha + status_t error; + if ((flags & (B_TRIM_BITMAP | B_TRIM_BITMAP_KEEP_ASPECT)) != 0 + && hasAlpha) { + if (bitmap->ColorSpace() == B_RGBA32) { + error = _TrimBitmap(bitmap, + (flags & B_TRIM_BITMAP_KEEP_ASPECT) != 0, trimmedBitmap); + } else { + BBitmap* rgb32Bitmap = _ConvertToRGB32(bitmap, true); + if (rgb32Bitmap != NULL) { + error = _TrimBitmap(rgb32Bitmap, + (flags & B_TRIM_BITMAP_KEEP_ASPECT) != 0, trimmedBitmap); + delete rgb32Bitmap; + } else + error = B_NO_MEMORY; + } + + if (error != B_OK) + return error; + + bitmap = trimmedBitmap; + canUseForMakeBitmaps = true; + } + + // create the bitmaps + if (canUseForMakeBitmaps) { + error = _MakeBitmaps(bitmap, flags); + } else { + if (BBitmap* rgb32Bitmap = _ConvertToRGB32(bitmap, true)) { + error = _MakeBitmaps(rgb32Bitmap, flags); + delete rgb32Bitmap; + } else + error = B_NO_MEMORY; + } + + delete trimmedBitmap; + + InvalidateLayout(); + Invalidate(); + + return error; +} + + +status_t +BControl::SetIconBitmap(const BBitmap* bitmap, uint32 which, uint32 flags) +{ + if (fIconData == NULL) { + fIconData = new(std::nothrow) IconData; + if (fIconData == NULL) + return B_NO_MEMORY; + } + + BBitmap* ourBitmap = NULL; + if (bitmap != NULL) { + if (!bitmap->IsValid()) + return B_BAD_VALUE; + + if ((flags & B_KEEP_BITMAP) != 0) { + ourBitmap = const_cast<BBitmap*>(bitmap); + } else { + ourBitmap = _ConvertToRGB32(bitmap); + if (ourBitmap == NULL) + return B_NO_MEMORY; + } + } + + if (!fIconData->SetBitmap(ourBitmap, which)) { + if (ourBitmap != bitmap) + delete ourBitmap; + return B_NO_MEMORY; + } + + InvalidateLayout(); + Invalidate(); + + return B_OK; +} + + +const BBitmap* +BControl::IconBitmap(uint32 which) const +{ + return fIconData != NULL ? fIconData->Bitmap(which) : NULL; +} + + bool BControl::IsFocusChanging() const { @@ -536,7 +757,286 @@ BControl::SetTracking(bool state) } -void BControl::_ReservedControl1() {} +extern "C" status_t +B_IF_GCC_2(_ReservedControl1__8BControl, _ZN8BControl17_ReservedControl1Ev)( + BControl* control, const BBitmap* icon, uint32 flags) +{ + // SetIcon() + perform_data_set_icon data; + data.icon = icon; + data.flags = flags; + return control->Perform(PERFORM_CODE_SET_ICON, &data); +} + + +/*static*/ BBitmap* +BControl::_ConvertToRGB32(const BBitmap* bitmap, bool noAppServerLink) +{ + BBitmap* rgb32Bitmap = new(std::nothrow) BBitmap(bitmap->Bounds(), + noAppServerLink ? B_BITMAP_NO_SERVER_LINK : 0, B_RGBA32); + if (rgb32Bitmap == NULL) + return NULL; + + if (!rgb32Bitmap->IsValid() || rgb32Bitmap->ImportBits(bitmap)!= B_OK) { + delete rgb32Bitmap; + return NULL; + } + + return rgb32Bitmap; +} + + +/*static*/ status_t +BControl::_TrimBitmap(const BBitmap* bitmap, bool keepAspect, + BBitmap*& _trimmedBitmap) +{ + if (bitmap == NULL || !bitmap->IsValid() + || bitmap->ColorSpace() != B_RGBA32) { + return B_BAD_VALUE; + } + + uint8* bits = (uint8*)bitmap->Bits(); + uint32 bpr = bitmap->BytesPerRow(); + uint32 width = bitmap->Bounds().IntegerWidth() + 1; + uint32 height = bitmap->Bounds().IntegerHeight() + 1; + BRect trimmed(INT32_MAX, INT32_MAX, INT32_MIN, INT32_MIN); + + for (uint32 y = 0; y < height; y++) { + uint8* b = bits + 3; + bool rowHasAlpha = false; + for (uint32 x = 0; x < width; x++) { + if (*b) { + rowHasAlpha = true; + if (x < trimmed.left) + trimmed.left = x; + if (x > trimmed.right) + trimmed.right = x; + } + b += 4; + } + if (rowHasAlpha) { + if (y < trimmed.top) + trimmed.top = y; + if (y > trimmed.bottom) + trimmed.bottom = y; + } + bits += bpr; + } + + if (!trimmed.IsValid()) + return B_BAD_VALUE; + + if (keepAspect) { + float minInset = trimmed.left; + minInset = min_c(minInset, trimmed.top); + minInset = min_c(minInset, bitmap->Bounds().right - trimmed.right); + minInset = min_c(minInset, bitmap->Bounds().bottom - trimmed.bottom); + trimmed = bitmap->Bounds().InsetByCopy(minInset, minInset); + } + trimmed = trimmed & bitmap->Bounds(); + + BBitmap* trimmedBitmap = new(std::nothrow) BBitmap( + trimmed.OffsetToCopy(B_ORIGIN), B_BITMAP_NO_SERVER_LINK, B_RGBA32); + if (trimmedBitmap == NULL) + return B_NO_MEMORY; + + bits = (uint8*)bitmap->Bits(); + bits += 4 * (int32)trimmed.left + bpr * (int32)trimmed.top; + uint8* dst = (uint8*)trimmedBitmap->Bits(); + uint32 trimmedWidth = trimmedBitmap->Bounds().IntegerWidth() + 1; + uint32 trimmedHeight = trimmedBitmap->Bounds().IntegerHeight() + 1; + uint32 trimmedBPR = trimmedBitmap->BytesPerRow(); + for (uint32 y = 0; y < trimmedHeight; y++) { + memcpy(dst, bits, trimmedWidth * 4); + dst += trimmedBPR; + bits += bpr; + } + + _trimmedBitmap = trimmedBitmap; + return B_OK; +} + + +status_t +BControl::_MakeBitmaps(const BBitmap* bitmap, uint32 flags) +{ + // make our own versions of the bitmap + BRect b(bitmap->Bounds()); + + IconData* iconData = new(std::nothrow) IconData; + if (iconData == NULL) + return B_NO_MEMORY; + ObjectDeleter<IconData> iconDataDeleter(iconData); + + color_space format = bitmap->ColorSpace(); + BBitmap* normalBitmap = iconData->CreateBitmap(b, format, B_OFF_BITMAP); + if (normalBitmap == NULL) + return B_NO_MEMORY; + + BBitmap* disabledBitmap = NULL; + if ((flags & B_CREATE_DISABLED_BITMAPS) != 0) { + disabledBitmap = iconData->CreateBitmap(b, format, + B_OFF_BITMAP | B_DISABLED_BITMAP); + if (disabledBitmap == NULL) + return B_NO_MEMORY; + } + + BBitmap* clickedBitmap = NULL; + if ((flags & (B_CREATE_ON_BITMAP | B_CREATE_PARTIALLY_ON_BITMAP)) != 0) { + clickedBitmap = iconData->CreateBitmap(b, format, B_ON_BITMAP); + if (clickedBitmap == NULL) + return B_NO_MEMORY; + } + + BBitmap* disabledClickedBitmap = NULL; + if (disabledBitmap != NULL && clickedBitmap != NULL) { + disabledClickedBitmap = iconData->CreateBitmap(b, format, + B_ON_BITMAP | B_DISABLED_BITMAP); + if (disabledClickedBitmap == NULL) + return B_NO_MEMORY; + } + + // copy bitmaps from file bitmap + uint8* nBits = normalBitmap != NULL ? (uint8*)normalBitmap->Bits() : NULL; + uint8* dBits = disabledBitmap != NULL + ? (uint8*)disabledBitmap->Bits() : NULL; + uint8* cBits = clickedBitmap != NULL ? (uint8*)clickedBitmap->Bits() : NULL; + uint8* dcBits = disabledClickedBitmap != NULL + ? (uint8*)disabledClickedBitmap->Bits() : NULL; + uint8* fBits = (uint8*)bitmap->Bits(); + int32 nbpr = normalBitmap->BytesPerRow(); + int32 fbpr = bitmap->BytesPerRow(); + int32 pixels = b.IntegerWidth() + 1; + int32 lines = b.IntegerHeight() + 1; + if (format == B_RGB32 || format == B_RGB32_BIG) { + // nontransparent version + + // iterate over color components + for (int32 y = 0; y < lines; y++) { + for (int32 x = 0; x < pixels; x++) { + int32 nOffset = 4 * x; + int32 fOffset = 4 * x; + nBits[nOffset + 0] = fBits[fOffset + 0]; + nBits[nOffset + 1] = fBits[fOffset + 1]; + nBits[nOffset + 2] = fBits[fOffset + 2]; + nBits[nOffset + 3] = 255; + + // clicked bits are darker (lame method...) + if (cBits != NULL) { + cBits[nOffset + 0] = uint8((float)nBits[nOffset + 0] * 0.8); + cBits[nOffset + 1] = uint8((float)nBits[nOffset + 1] * 0.8); + cBits[nOffset + 2] = uint8((float)nBits[nOffset + 2] * 0.8); + cBits[nOffset + 3] = 255; + } + + // disabled bits have less contrast (lame method...) + if (dBits != NULL) { + uint8 grey = 216; + float dist = (nBits[nOffset + 0] - grey) * 0.4; + dBits[nOffset + 0] = (uint8)(grey + dist); + dist = (nBits[nOffset + 1] - grey) * 0.4; + dBits[nOffset + 1] = (uint8)(grey + dist); + dist = (nBits[nOffset + 2] - grey) * 0.4; + dBits[nOffset + 2] = (uint8)(grey + dist); + dBits[nOffset + 3] = 255; + } + + // disabled bits have less contrast (lame method...) + if (dcBits != NULL) { + uint8 grey = 188; + float dist = (nBits[nOffset + 0] - grey) * 0.4; + dcBits[nOffset + 0] = (uint8)(grey + dist); + dist = (nBits[nOffset + 1] - grey) * 0.4; + dcBits[nOffset + 1] = (uint8)(grey + dist); + dist = (nBits[nOffset + 2] - grey) * 0.4; + dcBits[nOffset + 2] = (uint8)(grey + dist); + dcBits[nOffset + 3] = 255; + } + } + fBits += fbpr; + nBits += nbpr; + if (cBits != NULL) + cBits += nbpr; + if (dBits != NULL) + dBits += nbpr; + if (dcBits != NULL) + dcBits += nbpr; + } + } else if (format == B_RGBA32 || format == B_RGBA32_BIG) { + // transparent version + + // iterate over color components + for (int32 y = 0; y < lines; y++) { + for (int32 x = 0; x < pixels; x++) { + int32 nOffset = 4 * x; + int32 fOffset = 4 * x; + nBits[nOffset + 0] = fBits[fOffset + 0]; + nBits[nOffset + 1] = fBits[fOffset + 1]; + nBits[nOffset + 2] = fBits[fOffset + 2]; + nBits[nOffset + 3] = fBits[fOffset + 3]; + + // clicked bits are darker (lame method...) + if (cBits != NULL) { + cBits[nOffset + 0] = (uint8)(nBits[nOffset + 0] * 0.8); + cBits[nOffset + 1] = (uint8)(nBits[nOffset + 1] * 0.8); + cBits[nOffset + 2] = (uint8)(nBits[nOffset + 2] * 0.8); + cBits[nOffset + 3] = fBits[fOffset + 3]; + } + + // disabled bits have less opacity + if (dBits != NULL) { + uint8 grey = ((uint16)nBits[nOffset + 0] * 10 + + nBits[nOffset + 1] * 60 + + nBits[nOffset + 2] * 30) / 100; + float dist = (nBits[nOffset + 0] - grey) * 0.3; + dBits[nOffset + 0] = (uint8)(grey + dist); + dist = (nBits[nOffset + 1] - grey) * 0.3; + dBits[nOffset + 1] = (uint8)(grey + dist); + dist = (nBits[nOffset + 2] - grey) * 0.3; + dBits[nOffset + 2] = (uint8)(grey + dist); + dBits[nOffset + 3] = (uint8)(fBits[fOffset + 3] * 0.3); + } + + // disabled bits have less contrast (lame method...) + if (dcBits != NULL) { + dcBits[nOffset + 0] = (uint8)(dBits[nOffset + 0] * 0.8); + dcBits[nOffset + 1] = (uint8)(dBits[nOffset + 1] * 0.8); + dcBits[nOffset + 2] = (uint8)(dBits[nOffset + 2] * 0.8); + dcBits[nOffset + 3] = (uint8)(fBits[fOffset + 3] * 0.3); + } + } + fBits += fbpr; + nBits += nbpr; + if (cBits != NULL) + cBits += nbpr; + if (dBits != NULL) + dBits += nbpr; + if (dcBits != NULL) + dcBits += nbpr; + } + } else { + // unsupported format + return B_BAD_VALUE; + } + + // make the partially-on bitmaps a copy of the on bitmaps + if ((flags & B_CREATE_PARTIALLY_ON_BITMAP) != 0) { + if (iconData->CopyBitmap(clickedBitmap, B_PARTIALLY_ON_BITMAP) == NULL) + return B_NO_MEMORY; + if ((flags & B_CREATE_DISABLED_BITMAPS) != 0) { + if (iconData->CopyBitmap(disabledClickedBitmap, + B_PARTIALLY_ON_BITMAP | B_DISABLED_BITMAP) == NULL) { + return B_NO_MEMORY; + } + } + } + + delete fIconData; + fIconData = iconDataDeleter.Detach(); + return B_OK; +} + + void BControl::_ReservedControl2() {} void BControl::_ReservedControl3() {} void BControl::_ReservedControl4() {} @@ -559,6 +1059,7 @@ BControl::InitData(BMessage *data) fFocusChanging = false; fTracking = false; fWantsNav = Flags() & B_NAVIGABLE; + fIconData = NULL; if (data && data->HasString("_fname")) SetFont(be_plain_font, B_FONT_FAMILY_AND_STYLE); ############################################################################ Commit: be4367428b6478ae059614d7a9b6f6dc721e5dcb URL: http://cgit.haiku-os.org/haiku/commit/?id=be43674 Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Sun Dec 22 01:31:47 2013 UTC BControl subclasses: Override SetIcon() ... and implement Perform() action for potential later use. ---------------------------------------------------------------------------- diff --git a/headers/os/interface/Button.h b/headers/os/interface/Button.h index 240b928..304bd64 100644 --- a/headers/os/interface/Button.h +++ b/headers/os/interface/Button.h @@ -68,6 +68,8 @@ public: virtual BSize MaxSize(); virtual BSize PreferredSize(); + virtual status_t SetIcon(const BBitmap* icon, uint32 flags = 0); + protected: virtual void LayoutInvalidated(bool descendants = false); diff --git a/headers/os/interface/CheckBox.h b/headers/os/interface/CheckBox.h index 340bed2..70f89a8 100644 --- a/headers/os/interface/CheckBox.h +++ b/headers/os/interface/CheckBox.h @@ -69,6 +69,8 @@ public: virtual status_t Perform(perform_code code, void* data); + virtual status_t SetIcon(const BBitmap* icon, uint32 flags = 0); + bool IsPartialStateToOff() const; void SetPartialStateToOff(bool partialToOff); diff --git a/headers/os/interface/ColorControl.h b/headers/os/interface/ColorControl.h index ca6171b..b686177 100644 --- a/headers/os/interface/ColorControl.h +++ b/headers/os/interface/ColorControl.h @@ -76,6 +76,8 @@ public: virtual void AllAttached(); virtual void AllDetached(); + virtual status_t SetIcon(const BBitmap* icon, uint32 flags = 0); + private: virtual status_t Perform(perform_code d, void *arg); // this can be made public again if needed diff --git a/headers/os/interface/PictureButton.h b/headers/os/interface/PictureButton.h index 10cfa10..e457db8 100644 --- a/headers/os/interface/PictureButton.h +++ b/headers/os/interface/PictureButton.h @@ -79,6 +79,8 @@ public: virtual status_t Perform(perform_code code, void* data); + virtual status_t SetIcon(const BBitmap* icon, uint32 flags = 0); + private: // FBC padding and forbidden methods virtual void _ReservedPictureButton1(); diff --git a/headers/os/interface/RadioButton.h b/headers/os/interface/RadioButton.h index 48da018..040f6ee 100644 --- a/headers/os/interface/RadioButton.h +++ b/headers/os/interface/RadioButton.h @@ -63,6 +63,8 @@ public: virtual BSize MaxSize(); virtual BAlignment LayoutAlignment(); + virtual status_t SetIcon(const BBitmap* icon, uint32 flags = 0); + private: friend status_t _init_interface_kit_(); diff --git a/headers/os/interface/Slider.h b/headers/os/interface/Slider.h index 8b76dfa..42e8148 100644 --- a/headers/os/interface/Slider.h +++ b/headers/os/interface/Slider.h @@ -159,6 +159,8 @@ public: virtual BSize MaxSize(); virtual BSize PreferredSize(); + virtual status_t SetIcon(const BBitmap* icon, uint32 flags = 0); + protected: virtual void LayoutInvalidated(bool descendants); diff --git a/headers/os/interface/TextControl.h b/headers/os/interface/TextControl.h index 77d36d9..05bf6de 100644 --- a/headers/os/interface/TextControl.h +++ b/headers/os/interface/TextControl.h @@ -98,6 +98,8 @@ protected: virtual void LayoutInvalidated(bool descendants); virtual void DoLayout(); + virtual status_t SetIcon(const BBitmap* icon, uint32 flags = 0); + private: // FBC padding and forbidden methods virtual status_t Perform(perform_code d, void* arg); diff --git a/headers/private/shared/IconButton.h b/headers/private/shared/IconButton.h index 0b5a5f2..29f7535 100644 --- a/headers/private/shared/IconButton.h +++ b/headers/private/shared/IconButton.h @@ -71,7 +71,8 @@ public: status_t SetIcon(int32 resourceID); status_t SetIcon(const char* pathToBitmap); - status_t SetIcon(const BBitmap* bitmap); + virtual status_t SetIcon(const BBitmap* bitmap, + uint32 flags = 0); status_t SetIcon(const BMimeType* fileType, bool small = true); status_t SetIcon(const unsigned char* bitsFromQuickRes, diff --git a/src/kits/interface/Button.cpp b/src/kits/interface/Button.cpp index 87f85a3..99364fa 100644 --- a/src/kits/interface/Button.cpp +++ b/src/kits/interface/Button.cpp @@ -661,6 +661,11 @@ BButton::Perform(perform_code code, void* _data) BButton::DoLayout(); return B_OK; } + case PERFORM_CODE_SET_ICON: + { + perform_data_set_icon* data = (perform_data_set_icon*)_data; + return BButton::SetIcon(data->icon, data->flags); + } } return BControl::Perform(code, _data); @@ -691,6 +696,13 @@ BButton::PreferredSize() } +status_t +BButton::SetIcon(const BBitmap* icon, uint32 flags) +{ + return BControl::SetIcon(icon, flags); +} + + void BButton::LayoutInvalidated(bool descendants) { diff --git a/src/kits/interface/CheckBox.cpp b/src/kits/interface/CheckBox.cpp index 53a498a..d991bd0 100644 --- a/src/kits/interface/CheckBox.cpp +++ b/src/kits/interface/CheckBox.cpp @@ -589,12 +589,24 @@ BCheckBox::Perform(perform_code code, void* _data) BCheckBox::DoLayout(); return B_OK; } + case PERFORM_CODE_SET_ICON: + { + perform_data_set_icon* data = (perform_data_set_icon*)_data; + return BCheckBox::SetIcon(data->icon, data->flags); + } } return BControl::Perform(code, _data); } +status_t +BCheckBox::SetIcon(const BBitmap* icon, uint32 flags) +{ + return BControl::SetIcon(icon, flags); +} + + void BCheckBox::LayoutInvalidated(bool descendants) { diff --git a/src/kits/interface/ColorControl.cpp b/src/kits/interface/ColorControl.cpp index 1fbd4fc..245bb91 100644 --- a/src/kits/interface/ColorControl.cpp +++ b/src/kits/interface/ColorControl.cpp @@ -1037,6 +1037,13 @@ BColorControl::AllDetached() status_t +BColorControl::SetIcon(const BBitmap* icon, uint32 flags) +{ + return BControl::SetIcon(icon, flags); +} + + +status_t BColorControl::Perform(perform_code code, void* _data) { switch (code) { @@ -1086,6 +1093,11 @@ BColorControl::Perform(perform_code code, void* _data) BColorControl::DoLayout(); return B_OK; } + case PERFORM_CODE_SET_ICON: + { + perform_data_set_icon* data = (perform_data_set_icon*)_data; + return BColorControl::SetIcon(data->icon, data->flags); + } } return BControl::Perform(code, _data); diff --git a/src/kits/interface/PictureButton.cpp b/src/kits/interface/PictureButton.cpp index 2b3b554..ee0c79f 100644 --- a/src/kits/interface/PictureButton.cpp +++ b/src/kits/interface/PictureButton.cpp @@ -470,12 +470,24 @@ BPictureButton::Perform(perform_code code, void* _data) BPictureButton::DoLayout(); return B_OK; } + case PERFORM_CODE_SET_ICON: + { + perform_data_set_icon* data = (perform_data_set_icon*)_data; + return BPictureButton::SetIcon(data->icon, data->flags); + } } return BControl::Perform(code, _data); } +status_t +BPictureButton::SetIcon(const BBitmap* icon, uint32 flags) +{ + return BControl::SetIcon(icon, flags); +} + + // #pragma mark - diff --git a/src/kits/interface/RadioButton.cpp b/src/kits/interface/RadioButton.cpp index 8918095..2230c49 100644 --- a/src/kits/interface/RadioButton.cpp +++ b/src/kits/interface/RadioButton.cpp @@ -555,6 +555,11 @@ BRadioButton::Perform(perform_code code, void* _data) BRadioButton::DoLayout(); return B_OK; } + case PERFORM_CODE_SET_ICON: + { + perform_data_set_icon* data = (perform_data_set_icon*)_data; + return BRadioButton::SetIcon(data->icon, data->flags); + } } return BControl::Perform(code, _data); @@ -580,6 +585,12 @@ BRadioButton::LayoutAlignment() } +status_t +BRadioButton::SetIcon(const BBitmap* icon, uint32 flags) +{ + return BControl::SetIcon(icon, flags); +} + void BRadioButton::_ReservedRadioButton1() {} void BRadioButton::_ReservedRadioButton2() {} diff --git a/src/kits/interface/Slider.cpp b/src/kits/interface/Slider.cpp index 6d654d8..1748594 100644 --- a/src/kits/interface/Slider.cpp +++ b/src/kits/interface/Slider.cpp @@ -345,6 +345,11 @@ BSlider::Perform(perform_code code, void* _data) BSlider::DoLayout(); return B_OK; } + case PERFORM_CODE_SET_ICON: + { + perform_data_set_icon* data = (perform_data_set_icon*)_data; + return BSlider::SetIcon(data->icon, data->flags); + } } return BControl::Perform(code, _data); @@ -1768,6 +1773,13 @@ BSlider::PreferredSize() } +status_t +BSlider::SetIcon(const BBitmap* icon, uint32 flags) +{ + return BControl::SetIcon(icon, flags); +} + + void BSlider::LayoutInvalidated(bool descendants) { diff --git a/src/kits/interface/TextControl.cpp b/src/kits/interface/TextControl.cpp index ee77dec..9863ecd 100644 --- a/src/kits/interface/TextControl.cpp +++ b/src/kits/interface/TextControl.cpp @@ -947,6 +947,13 @@ BTextControl::DoLayout() } +status_t +BTextControl::SetIcon(const BBitmap* icon, uint32 flags) +{ + return BControl::SetIcon(icon, flags); +} + + // #pragma mark - @@ -981,7 +988,7 @@ BTextControl::Perform(perform_code code, void* _data) BTextControl::GetHeightForWidth(data->width, &data->min, &data->max, &data->preferred); return B_OK; -} + } case PERFORM_CODE_SET_LAYOUT: { perform_data_set_layout* data = (perform_data_set_layout*)_data; @@ -1000,6 +1007,11 @@ BTextControl::Perform(perform_code code, void* _data) BTextControl::DoLayout(); return B_OK; } + case PERFORM_CODE_SET_ICON: + { + perform_data_set_icon* data = (perform_data_set_icon*)_data; + return BTextControl::SetIcon(data->icon, data->flags); + } case PERFORM_CODE_ALL_UNARCHIVED: { perform_data_all_unarchived* data diff --git a/src/kits/shared/IconButton.cpp b/src/kits/shared/IconButton.cpp index fb55ff0..2bf8ea5 100644 --- a/src/kits/shared/IconButton.cpp +++ b/src/kits/shared/IconButton.cpp @@ -382,7 +382,7 @@ BIconButton::SetIcon(const char* pathToBitmap) status_t -BIconButton::SetIcon(const BBitmap* bitmap) +BIconButton::SetIcon(const BBitmap* bitmap, uint32 flags) { if (bitmap && bitmap->ColorSpace() == B_CMAP8) { status_t status = bitmap->InitCheck(); ############################################################################ Revision: hrev46580 Commit: fe8787698c2a7ddc1f79d3bf645303ab7052e553 URL: http://cgit.haiku-os.org/haiku/commit/?id=fe87876 Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Sun Dec 22 01:46:27 2013 UTC BButton: Add icon support * Remove non-BControlLook drawing code. It's just an annoyance to maintain. * Update Draw() and _ValidatePreferredSize() to add icon support. ---------------------------------------------------------------------------- diff --git a/src/kits/interface/Button.cpp b/src/kits/interface/Button.cpp index 99364fa..d8db09c 100644 --- a/src/kits/interface/Button.cpp +++ b/src/kits/interface/Button.cpp @@ -13,8 +13,10 @@ #include <Button.h> +#include <algorithm> #include <new> +#include <Bitmap.h> #include <ControlLook.h> #include <Font.h> #include <LayoutUtils.h> @@ -24,6 +26,9 @@ #include <binary_compatibility/Interface.h> +static const float kLabelMargin = 3; + + BButton::BButton(BRect frame, const char* name, const char* label, BMessage* message, uint32 resizingMode, uint32 flags) : BControl(frame, name, label, message, resizingMode, @@ -103,246 +108,25 @@ BButton::Archive(BMessage* archive, bool deep) const void BButton::Draw(BRect updateRect) { - if (be_control_look != NULL) { - BRect rect(Bounds()); - rgb_color background = LowColor(); - rgb_color base = background; - uint32 flags = be_control_look->Flags(this); - if (IsDefault()) - flags |= BControlLook::B_DEFAULT_BUTTON; - be_control_look->DrawButtonFrame(this, rect, updateRect, - base, background, flags); - be_control_look->DrawButtonBackground(this, rect, updateRect, - base, flags); - - // always leave some room around the label - rect.InsetBy(3.0, 3.0); - be_control_look->DrawLabel(this, Label(), rect, updateRect, - base, flags, BAlignment(B_ALIGN_CENTER, B_ALIGN_MIDDLE)); - return; - } - - font_height fh; - GetFontHeight(&fh); - - const BRect bounds = Bounds(); - BRect rect = bounds; - - const bool enabled = IsEnabled(); - const bool pushed = Value() == B_CONTROL_ON; - // Default indicator + BRect rect(Bounds()); + rgb_color background = LowColor(); + rgb_color base = background; + uint32 flags = be_control_look->Flags(this); if (IsDefault()) - rect = _DrawDefault(rect, enabled); - - BRect fillArea = rect; - fillArea.InsetBy(3.0, 3.0); - - BString text = Label(); - -#if 1 - // Label truncation - BFont font; - GetFont(&font); - font.TruncateString(&text, B_TRUNCATE_END, fillArea.Width() - 4); -#endif - - // Label position - const float stringWidth = StringWidth(text.String()); - const float x = (rect.right - stringWidth) / 2.0; - const float labelY = bounds.top - + ((bounds.Height() - fh.ascent - fh.descent) / 2.0) - + fh.ascent + 1.0; - const float focusLineY = labelY + fh.descent; - - /* speed trick: - if the focus changes but the button is not pressed then we can - redraw only the focus line, - if the focus changes and the button is pressed invert the internal rect - this block takes care of all the focus changes - */ - if (IsFocusChanging()) { - if (pushed) { - rect.InsetBy(2.0, 2.0); - InvertRect(rect); - } else { - _DrawFocusLine(x, focusLineY, stringWidth, IsFocus() - && Window()->IsActive()); - } - - return; - } - - // colors - rgb_color panelBgColor = ui_color(B_PANEL_BACKGROUND_COLOR); - rgb_color buttonBgColor = tint_color(panelBgColor, B_LIGHTEN_1_TINT); - rgb_color lightColor; - rgb_color maxLightColor; - - rgb_color dark1BorderColor; - rgb_color dark2BorderColor; - - rgb_color bevelColor1; - rgb_color bevelColor2; - rgb_color bevelColorRBCorner; - - rgb_color borderBevelShadow; - rgb_color borderBevelLight; - - if (enabled) { - lightColor = tint_color(panelBgColor, B_LIGHTEN_2_TINT); - maxLightColor = tint_color(panelBgColor, B_LIGHTEN_MAX_TINT); + flags |= BControlLook::B_DEFAULT_BUTTON; + be_control_look->DrawButtonFrame(this, rect, updateRect, + base, background, flags); + be_control_look->DrawButtonBackground(this, rect, updateRect, + base, flags); - dark1BorderColor = tint_color(panelBgColor, B_DARKEN_3_TINT); - dark2BorderColor = tint_color(panelBgColor, B_DARKEN_4_TINT); + // always leave some room around the label + rect.InsetBy(kLabelMargin, kLabelMargin); - bevelColor1 = tint_color(panelBgColor, B_DARKEN_2_TINT); - bevelColor2 = panelBgColor; - - if (IsDefault()) { - borderBevelShadow = tint_color(dark1BorderColor, - (B_NO_TINT + B_DARKEN_1_TINT) / 2); - borderBevelLight = tint_color(dark1BorderColor, B_LIGHTEN_1_TINT); - - borderBevelLight.red = (borderBevelLight.red + panelBgColor.red) - / 2; - borderBevelLight.green = (borderBevelLight.green - + panelBgColor.green) / 2; - borderBevelLight.blue = (borderBevelLight.blue - + panelBgColor.blue) / 2; - - dark1BorderColor = tint_color(dark1BorderColor, B_DARKEN_3_TINT); - dark2BorderColor = tint_color(dark1BorderColor, B_DARKEN_4_TINT); - - bevelColorRBCorner = borderBevelShadow; - } else { - borderBevelShadow = tint_color(panelBgColor, - (B_NO_TINT + B_DARKEN_1_TINT) / 2); - borderBevelLight = buttonBgColor; - - bevelColorRBCorner = dark1BorderColor; - } - } else { - lightColor = tint_color(panelBgColor, B_LIGHTEN_2_TINT); - maxLightColor = tint_color(panelBgColor, B_LIGHTEN_1_TINT); - - dark1BorderColor = tint_color(panelBgColor, B_DARKEN_1_TINT); - dark2BorderColor = tint_color(panelBgColor, B_DARKEN_2_TINT); - - bevelColor1 = panelBgColor; - bevelColor2 = buttonBgColor; - - if (IsDefault()) { - borderBevelShadow = dark1BorderColor; - borderBevelLight = panelBgColor; - dark1BorderColor = tint_color(dark1BorderColor, B_DARKEN_1_TINT); - dark2BorderColor = tint_color(dark1BorderColor, 1.16); - - } else { - borderBevelShadow = panelBgColor; - borderBevelLight = panelBgColor; - } - - bevelColorRBCorner = tint_color(panelBgColor, 1.08);; - } - - // fill the button area - SetHighColor(buttonBgColor); - FillRect(fillArea); - - BeginLineArray(22); - // bevel around external border - AddLine(BPoint(rect.left, rect.bottom), - BPoint(rect.left, rect.top), borderBevelShadow); - AddLine(BPoint(rect.left + 1, rect.top), - BPoint(rect.right, rect.top), borderBevelShadow); - - AddLine(BPoint(rect.right, rect.top + 1), - BPoint(rect.right, rect.bottom), borderBevelLight); - AddLine(BPoint(rect.left + 1, rect.bottom), - BPoint(rect.right - 1, rect.bottom), borderBevelLight); - - rect.InsetBy(1.0, 1.0); - - // external border - AddLine(BPoint(rect.left, rect.bottom), - BPoint(rect.left, rect.top), dark1BorderColor); - AddLine(BPoint(rect.left + 1, rect.top), - BPoint(rect.right, rect.top), dark1BorderColor); - AddLine(BPoint(rect.right, rect.top + 1), - BPoint(rect.right, rect.bottom), dark2BorderColor); - AddLine(BPoint(rect.right - 1, rect.bottom), - BPoint(rect.left + 1, rect.bottom), dark2BorderColor); - - rect.InsetBy(1.0, 1.0); - - // Light - AddLine(BPoint(rect.left, rect.top), - BPoint(rect.left, rect.top), buttonBgColor); - AddLine(BPoint(rect.left, rect.top + 1), - BPoint(rect.left, rect.bottom - 1), lightColor); - AddLine(BPoint(rect.left, rect.bottom), - BPoint(rect.left, rect.bottom), bevelColor2); - AddLine(BPoint(rect.left + 1, rect.top), - BPoint(rect.right - 1, rect.top), lightColor); - AddLine(BPoint(rect.right, rect.top), - BPoint(rect.right, rect.top), bevelColor2); - // Shadow - AddLine(BPoint(rect.left + 1, rect.bottom), - BPoint(rect.right - 1, rect.bottom), bevelColor1); - AddLine(BPoint(rect.right, rect.bottom), - BPoint(rect.right, rect.bottom), bevelColorRBCorner); - AddLine(BPoint(rect.right, rect.bottom - 1), - BPoint(rect.right, rect.top + 1), bevelColor1); - - rect.InsetBy(1.0, 1.0); - - // Light - AddLine(BPoint(rect.left, rect.top), - BPoint(rect.left, rect.bottom - 1), maxLightColor); - AddLine(BPoint(rect.left, rect.bottom), - BPoint(rect.left, rect.bottom), buttonBgColor); - AddLine(BPoint(rect.left + 1, rect.top), - BPoint(rect.right - 1, rect.top), maxLightColor); - AddLine(BPoint(rect.right, rect.top), - BPoint(rect.right, rect.top), buttonBgColor); - // Shadow - AddLine(BPoint(rect.left + 1, rect.bottom), - BPoint(rect.right, rect.bottom), bevelColor2); - AddLine(BPoint(rect.right, rect.bottom - 1), - BPoint(rect.right, rect.top + 1), bevelColor2); - - rect.InsetBy(1.0,1.0); - - EndLineArray(); - - // Invert if clicked - if (enabled && pushed) { - rect.InsetBy(-2.0, -2.0); - InvertRect(rect); - } - - // Label color - if (enabled) { - if (pushed) { - SetHighColor(maxLightColor); - SetLowColor(255 - buttonBgColor.red, - 255 - buttonBgColor.green, - 255 - buttonBgColor.blue); - } else { - SetHighColor(ui_color(B_CONTROL_TEXT_COLOR)); - SetLowColor(buttonBgColor); - } - } else { - SetHighColor(tint_color(panelBgColor, B_DISABLED_LABEL_TINT)); - SetLowColor(buttonBgColor); - } - - // Draw the label - DrawString(text.String(), BPoint(x, labelY)); - - // Focus line - if (enabled && IsFocus() && Window()->IsActive() && !pushed) - _DrawFocusLine(x, focusLineY, stringWidth, true); + const BBitmap* icon = IconBitmap( + (Value() == B_CONTROL_OFF ? B_OFF_BITMAP : B_ON_BITMAP) + | (IsEnabled() ? 0 : B_DISABLED_BITMAP)); + be_control_look->DrawLabel(this, Label(), icon, rect, updateRect, + base, flags, BAlignment(B_ALIGN_CENTER, B_ALIGN_MIDDLE)); } @@ -699,7 +483,8 @@ BButton::PreferredSize() status_t BButton::SetIcon(const BBitmap* icon, uint32 flags) { - return BControl::SetIcon(icon, flags); + return BControl::SetIcon(icon, + flags | B_CREATE_ON_BITMAP | B_CREATE_DISABLED_BITMAPS); } @@ -727,23 +512,52 @@ BSize BButton::_ValidatePreferredSize() { if (fPreferredSize.width < 0) { + float left, top, right, bottom; + be_control_look->GetInsets(BControlLook::B_BUTTON_FRAME, + BControlLook::B_BUTTON_BACKGROUND, + fDrawAsDefault ? BControlLook::B_DEFAULT_BUTTON : 0, + left, top, right, bottom); + // width - float width = 20.0f + (float)ceil(StringWidth(Label())); - if (width < 75.0f) - width = 75.0f; + float width = left + right + 2 * kLabelMargin - 1; - if (fDrawAsDefault) - width += 6.0f; + const char* label = Label(); + if (label != NULL) { + width = std::max(width, 20.0f); + width += (float)ceil(StringWidth(label)); + } - fPreferredSize.width = width; + const BBitmap* icon = IconBitmap(B_OFF_BITMAP); + if (icon != NULL) + width += icon->Bounds().Width() + 1; + + if (label != NULL && icon != NULL) + width += be_control_look->DefaultLabelSpacing(); // height - font_height fontHeight; - GetFontHeight(&fontHeight); + float minHorizontalMargins = top + bottom + 2 * kLabelMargin; + float height = -1; + + if (label != NULL) { + font_height fontHeight; + GetFontHeight(&fontHeight); + float textHeight = fontHeight.ascent + fontHeight.descent; + height = ceilf(textHeight * 1.8); + float margins = height - ceilf(textHeight); + if (margins < minHorizontalMargins) + height += minHorizontalMargins - margins; + } + + if (icon != NULL) { + height = std::max(height, + icon->Bounds().Height() + minHorizontalMargins); + } + + // force some minimum width/height values + width = std::max(width, label != NULL ? 75.0f : 5.0f); + height = std::max(height, 5.0f); - fPreferredSize.height - = ceilf((fontHeight.ascent + fontHeight.descent) * 1.8) - + (fDrawAsDefault ? 6.0f : 0); + fPreferredSize.Set(width, height); ResetLayoutInvalidation(); }