BButton: Add icon support

* Remove non-BControlLook drawing code. It's just an annoyance to
  maintain.
* Update Draw() and _ValidatePreferredSize() to add icon support.
This commit is contained in:
Ingo Weinhold
2013-12-22 02:48:28 +01:00
parent be4367428b
commit fe8787698c
+51 -237
View File
@@ -13,8 +13,10 @@
#include <Button.h> #include <Button.h>
#include <algorithm>
#include <new> #include <new>
#include <Bitmap.h>
#include <ControlLook.h> #include <ControlLook.h>
#include <Font.h> #include <Font.h>
#include <LayoutUtils.h> #include <LayoutUtils.h>
@@ -24,6 +26,9 @@
#include <binary_compatibility/Interface.h> #include <binary_compatibility/Interface.h>
static const float kLabelMargin = 3;
BButton::BButton(BRect frame, const char* name, const char* label, BButton::BButton(BRect frame, const char* name, const char* label,
BMessage* message, uint32 resizingMode, uint32 flags) BMessage* message, uint32 resizingMode, uint32 flags)
: BControl(frame, name, label, message, resizingMode, : BControl(frame, name, label, message, resizingMode,
@@ -103,7 +108,6 @@ BButton::Archive(BMessage* archive, bool deep) const
void void
BButton::Draw(BRect updateRect) BButton::Draw(BRect updateRect)
{ {
if (be_control_look != NULL) {
BRect rect(Bounds()); BRect rect(Bounds());
rgb_color background = LowColor(); rgb_color background = LowColor();
rgb_color base = background; rgb_color base = background;
@@ -116,233 +120,13 @@ BButton::Draw(BRect updateRect)
base, flags); base, flags);
// always leave some room around the label // always leave some room around the label
rect.InsetBy(3.0, 3.0); rect.InsetBy(kLabelMargin, kLabelMargin);
be_control_look->DrawLabel(this, Label(), rect, updateRect,
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)); 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
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);
dark1BorderColor = tint_color(panelBgColor, B_DARKEN_3_TINT);
dark2BorderColor = tint_color(panelBgColor, B_DARKEN_4_TINT);
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);
} }
@@ -699,7 +483,8 @@ BButton::PreferredSize()
status_t status_t
BButton::SetIcon(const BBitmap* icon, uint32 flags) 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() BButton::_ValidatePreferredSize()
{ {
if (fPreferredSize.width < 0) { 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 // width
float width = 20.0f + (float)ceil(StringWidth(Label())); float width = left + right + 2 * kLabelMargin - 1;
if (width < 75.0f)
width = 75.0f;
if (fDrawAsDefault) const char* label = Label();
width += 6.0f; 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 // height
float minHorizontalMargins = top + bottom + 2 * kLabelMargin;
float height = -1;
if (label != NULL) {
font_height fontHeight; font_height fontHeight;
GetFontHeight(&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;
}
fPreferredSize.height if (icon != NULL) {
= ceilf((fontHeight.ascent + fontHeight.descent) * 1.8) height = std::max(height,
+ (fDrawAsDefault ? 6.0f : 0); 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.Set(width, height);
ResetLayoutInvalidation(); ResetLayoutInvalidation();
} }