From df37cd4edddd82519232cf96b7fa0e4eb7e339dc Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 21 Dec 2013 02:06:59 +0100 Subject: [PATCH] BCheckBox: Add tri-state support * Add possible control state B_CONTROL_PARTIALLY_ON and support it in BCheckBox and BControlLook. * BCheckBox: Add partialStateToOff property defining whether the partial state should transition to off. Defaults to false (i.e. partial to on). --- headers/os/interface/CheckBox.h | 5 +++ headers/os/interface/Control.h | 3 +- headers/os/interface/ControlLook.h | 15 ++++--- src/kits/interface/CheckBox.cpp | 68 ++++++++++++++++++++++++++---- src/kits/interface/ControlLook.cpp | 19 ++++++--- 5 files changed, 88 insertions(+), 22 deletions(-) diff --git a/headers/os/interface/CheckBox.h b/headers/os/interface/CheckBox.h index 7e7de4241f..340bed2e80 100644 --- a/headers/os/interface/CheckBox.h +++ b/headers/os/interface/CheckBox.h @@ -69,6 +69,9 @@ public: virtual status_t Perform(perform_code code, void* data); + bool IsPartialStateToOff() const; + void SetPartialStateToOff(bool partialToOff); + protected: virtual void LayoutInvalidated(bool descendants = false); @@ -81,6 +84,7 @@ private: private: BRect _CheckBoxFrame() const; BSize _ValidatePreferredSize(); + int32 _NextState() const; private: // Forbidden @@ -89,6 +93,7 @@ private: private: BSize fPreferredSize; bool fOutlined; + bool fPartialToOff; }; #endif // _CHECK_BOX_H diff --git a/headers/os/interface/Control.h b/headers/os/interface/Control.h index b797c1661b..31cd84fd4b 100644 --- a/headers/os/interface/Control.h +++ b/headers/os/interface/Control.h @@ -12,7 +12,8 @@ enum { B_CONTROL_OFF = 0, - B_CONTROL_ON = 1 + B_CONTROL_ON = 1, + B_CONTROL_PARTIALLY_ON = 2 }; class BWindow; diff --git a/headers/os/interface/ControlLook.h b/headers/os/interface/ControlLook.h index 48fee2b6b5..8039f14793 100644 --- a/headers/os/interface/ControlLook.h +++ b/headers/os/interface/ControlLook.h @@ -69,13 +69,14 @@ public: }; enum { - B_FOCUSED = 1 << 0, - B_CLICKED = 1 << 1, // some controls activate on mouse up - B_ACTIVATED = 1 << 2, - B_HOVER = 1 << 3, - B_DISABLED = 1 << 4, - B_DEFAULT_BUTTON = 1 << 5, - B_IGNORE_OUTLINE = 1 << 6, + B_FOCUSED = 1 << 0, + B_CLICKED = 1 << 1, // some controls activate on mouse up + B_ACTIVATED = 1 << 2, + B_HOVER = 1 << 3, + B_DISABLED = 1 << 4, + B_DEFAULT_BUTTON = 1 << 5, + B_IGNORE_OUTLINE = 1 << 6, + B_PARTIALLY_ACTIVATED = 1 << 7, // like B_ACTIVATED, but for tri-state B_BLEND_FRAME = 1 << 16 }; diff --git a/src/kits/interface/CheckBox.cpp b/src/kits/interface/CheckBox.cpp index ea12a208bc..53a498a5ff 100644 --- a/src/kits/interface/CheckBox.cpp +++ b/src/kits/interface/CheckBox.cpp @@ -26,7 +26,8 @@ BCheckBox::BCheckBox(BRect frame, const char *name, const char *label, : BControl(frame, name, label, message, resizingMode, flags), fPreferredSize(), - fOutlined(false) + fOutlined(false), + fPartialToOff(false) { // Resize to minimum height if needed font_height fontHeight; @@ -43,7 +44,8 @@ BCheckBox::BCheckBox(const char *name, const char *label, BMessage *message, : BControl(name, label, message, flags | B_WILL_DRAW | B_NAVIGABLE), fPreferredSize(), - fOutlined(false) + fOutlined(false), + fPartialToOff(false) { } @@ -52,7 +54,8 @@ BCheckBox::BCheckBox(const char *label, BMessage *message) : BControl(NULL, label, message, B_WILL_DRAW | B_NAVIGABLE), fPreferredSize(), - fOutlined(false) + fOutlined(false), + fPartialToOff(false) { } @@ -60,7 +63,8 @@ BCheckBox::BCheckBox(const char *label, BMessage *message) BCheckBox::BCheckBox(BMessage *archive) : BControl(archive), - fOutlined(false) + fOutlined(false), + fPartialToOff(false) { } @@ -322,7 +326,16 @@ BCheckBox::MessageReceived(BMessage *message) void BCheckBox::KeyDown(const char *bytes, int32 numBytes) { - BControl::KeyDown(bytes, numBytes); + if (*bytes == B_ENTER || *bytes == B_SPACE) { + if (!IsEnabled()) + return; + + SetValue(_NextState()); + Invoke(); + } else { + // skip the BControl implementation + BView::KeyDown(bytes, numBytes); + } } @@ -360,7 +373,7 @@ BCheckBox::MouseDown(BPoint point) if (fOutlined) { fOutlined = false; - SetValue(!Value()); + SetValue(_NextState()); Invoke(); } else { Invalidate(); @@ -385,7 +398,7 @@ BCheckBox::MouseUp(BPoint point) if (fOutlined) { fOutlined = false; - SetValue(!Value()); + SetValue(_NextState()); Invoke(); } else { Invalidate(); @@ -485,8 +498,16 @@ BCheckBox::MakeFocus(bool focused) void BCheckBox::SetValue(int32 value) { - value = value ? B_CONTROL_ON : B_CONTROL_OFF; - // we only accept boolean values + // We only accept three possible values. + switch (value) { + case B_CONTROL_OFF: + case B_CONTROL_ON: + case B_CONTROL_PARTIALLY_ON: + break; + default: + value = B_CONTROL_ON; + break; + } if (value != Value()) { BControl::SetValueNoUpdate(value); @@ -582,6 +603,20 @@ BCheckBox::LayoutInvalidated(bool descendants) } +bool +BCheckBox::IsPartialStateToOff() const +{ + return fPartialToOff; +} + + +void +BCheckBox::SetPartialStateToOff(bool partialToOff) +{ + fPartialToOff = partialToOff; +} + + // #pragma mark - FBC padding @@ -625,6 +660,21 @@ BCheckBox::_ValidatePreferredSize() } +int32 +BCheckBox::_NextState() const +{ + switch (Value()) { + case B_CONTROL_OFF: + return B_CONTROL_ON; + case B_CONTROL_PARTIALLY_ON: + return fPartialToOff ? B_CONTROL_OFF : B_CONTROL_ON; + case B_CONTROL_ON: + default: + return B_CONTROL_OFF; + } +} + + BCheckBox & BCheckBox::operator=(const BCheckBox &) { diff --git a/src/kits/interface/ControlLook.cpp b/src/kits/interface/ControlLook.cpp index d50cbc9787..baab42d1c5 100644 --- a/src/kits/interface/ControlLook.cpp +++ b/src/kits/interface/ControlLook.cpp @@ -92,8 +92,14 @@ BControlLook::Flags(BControl* control) const flags |= B_FOCUSED; } - if (control->Value() == B_CONTROL_ON) - flags |= B_ACTIVATED; + switch (control->Value()) { + case B_CONTROL_ON: + flags |= B_ACTIVATED; + break; + case B_CONTROL_PARTIALLY_ON: + flags |= B_PARTIALLY_ACTIVATED; + break; + } if (control->Parent() != NULL && (control->Parent()->Flags() & B_DRAW_ON_CHILDREN) != 0) { @@ -3198,7 +3204,7 @@ bool BControlLook::_RadioButtonAndCheckBoxMarkColor(const rgb_color& base, rgb_color& color, uint32 flags) const { - if ((flags & (B_ACTIVATED | B_CLICKED)) == 0) { + if ((flags & (B_ACTIVATED | B_PARTIALLY_ACTIVATED | B_CLICKED)) == 0) { // no mark to be drawn at all return false; } @@ -3212,12 +3218,15 @@ BControlLook::_RadioButtonAndCheckBoxMarkColor(const rgb_color& base, mix = 0.4; } else if ((flags & B_CLICKED) != 0) { if ((flags & B_ACTIVATED) != 0) { - // loosing activation + // losing activation mix = 0.7; } else { - // becoming activated + // becoming activated (or losing partial activation) mix = 0.3; } + } else if ((flags & B_PARTIALLY_ACTIVATED) != 0) { + // partially activated + mix = 0.5; } else { // simply activated }