// This file is part of VSTGUI. It is subject to the license terms // in the LICENSE file found in the top-level directory of this // distribution and at http://github.com/steinbergmedia/vstgui/LICENSE #include "cbuttons.h" #include "../cdrawcontext.h" #include "../cbitmap.h" #include "../cframe.h" #include "../cgraphicspath.h" #include "../events.h" #include "../platform/iplatformfont.h" #include namespace VSTGUI { //------------------------------------------------------------------------ // COnOffButton //------------------------------------------------------------------------ /*! @class COnOffButton Define a button with 2 positions. The bitmap includes the 2 subbitmaps (i.e the rectangle used for the display of this button is half-height of the bitmap). When its value changes, the listener is called. */ //------------------------------------------------------------------------ /** * COnOffButton constructor. * @param size the size of this view * @param listener the listener * @param tag the control tag * @param background bitmap of the on/off button * @param style style, currently not used */ //------------------------------------------------------------------------ COnOffButton::COnOffButton (const CRect& size, IControlListener* listener, int32_t tag, CBitmap* background, int32_t style) : CControl (size, listener, tag, background) , style (style) { setWantsFocus (true); } //------------------------------------------------------------------------ COnOffButton::COnOffButton (const COnOffButton& v) : CControl (v) , style (v.style) { setWantsFocus (true); } //------------------------------------------------------------------------ void COnOffButton::draw (CDrawContext *pContext) { if (getDrawBackground ()) { CCoord off; if (value == getMax ()) off = getDrawBackground ()->getHeight () / 2; else off = 0; getDrawBackground ()->draw (pContext, getViewSize (), CPoint (0, off)); } setDirty (false); } //------------------------------------------------------------------------ CMouseEventResult COnOffButton::onMouseDown (CPoint& where, const CButtonState& buttons) { if (!(buttons & kLButton)) return kMouseEventNotHandled; beginEdit (); return kMouseEventHandled; } //------------------------------------------------------------------------ CMouseEventResult COnOffButton::onMouseMoved (CPoint& where, const CButtonState& buttons) { return kMouseEventHandled; } //------------------------------------------------------------------------ CMouseEventResult COnOffButton::onMouseUp (CPoint& where, const CButtonState& buttons) { if (isEditing ()) { if (getViewSize ().pointInside (where)) { value = (value == getMax ()) ? getMin () : getMax (); invalid (); valueChanged (); } endEdit (); } return kMouseEventHandled; } //------------------------------------------------------------------------ CMouseEventResult COnOffButton::onMouseCancel () { if (isEditing ()) endEdit (); return kMouseEventHandled; } //------------------------------------------------------------------------ void COnOffButton::onKeyboardEvent (KeyboardEvent& event) { if (event.type != EventType::KeyDown) return; if (event.virt == VirtualKey::Return && event.modifiers.empty ()) { value = (value == getMax ()) ? getMin () : getMax (); invalid (); beginEdit (); valueChanged (); endEdit (); event.consumed = true; } } //------------------------------------------------------------------------ bool COnOffButton::sizeToFit () { if (getDrawBackground ()) { CRect vs (getViewSize ()); vs.setWidth (getDrawBackground ()->getWidth ()); vs.setHeight (getDrawBackground ()->getHeight () / 2.); setViewSize (vs, true); setMouseableArea (vs); return true; } return false; } //------------------------------------------------------------------------ // CKickButton //------------------------------------------------------------------------ /*! @class CKickButton Define a button with 2 states using 2 subbitmaps. One click on it, then the second subbitmap is displayed. When the mouse button is relaxed, the first subbitmap is framed. Use a CMultiFrameBitmap for its background bitmap. */ //------------------------------------------------------------------------ /** * CKickButton constructor. * @param size the size of this view * @param listener the listener * @param tag the control tag * @param background the bitmap */ //------------------------------------------------------------------------ CKickButton::CKickButton (const CRect& size, IControlListener* listener, int32_t tag, CBitmap* background) : CControl (size, listener, tag, background) { #if VSTGUI_ENABLE_DEPRECATED_METHODS if (dynamic_cast (background) == nullptr) { heightOfOneImage = size.getHeight (); } #endif setWantsFocus (true); } #if VSTGUI_ENABLE_DEPRECATED_METHODS //------------------------------------------------------------------------ /** * CKickButton constructor. * @param size the size of this view * @param listener the listener * @param tag the control tag * @param heightOfOneImage height of one sub bitmap in background * @param background the bitmap * @param offset of background */ //------------------------------------------------------------------------ CKickButton::CKickButton (const CRect& size, IControlListener* listener, int32_t tag, CCoord heightOfOneImage, CBitmap* background, const CPoint& offset) : CControl (size, listener, tag, background) , offset (offset) { setHeightOfOneImage (heightOfOneImage); setWantsFocus (true); } #endif //------------------------------------------------------------------------ CKickButton::CKickButton (const CKickButton& v) : CControl (v) { #if VSTGUI_ENABLE_DEPRECATED_METHODS offset = v.offset; setHeightOfOneImage (v.heightOfOneImage); #endif setWantsFocus (true); } //------------------------------------------------------------------------ void CKickButton::draw (CDrawContext *pContext) { bounceValue (); if (auto bitmap = getDrawBackground ()) { if (auto mfb = dynamic_cast (bitmap)) { auto index = getMultiFrameBitmapIndex (*mfb, getValueNormalized ()); mfb->drawFrame (pContext, index, getViewSize ().getTopLeft ()); } else { #if VSTGUI_ENABLE_DEPRECATED_METHODS CPoint where (offset.x, offset.y); if (value == getMax ()) where.y += heightOfOneImage; bitmap->draw (pContext, getViewSize (), where); #else bitmap->draw (pContext, getViewSize ()); #endif } } setDirty (false); } //------------------------------------------------------------------------ CMouseEventResult CKickButton::onMouseDown (CPoint& where, const CButtonState& buttons) { if (!(buttons & kLButton)) return kMouseEventNotHandled; beginEdit (); return onMouseMoved (where, buttons); } //------------------------------------------------------------------------ CMouseEventResult CKickButton::onMouseCancel () { if (isEditing ()) { value = getMin (); if (isDirty ()) { valueChanged (); invalid (); } endEdit (); } return kMouseEventHandled; } //------------------------------------------------------------------------ CMouseEventResult CKickButton::onMouseUp (CPoint& where, const CButtonState& buttons) { if (isEditing ()) { if (value > 0.f) valueChanged (); value = getMin (); valueChanged (); if (isDirty ()) invalid (); endEdit (); } return kMouseEventHandled; } //------------------------------------------------------------------------ CMouseEventResult CKickButton::onMouseMoved (CPoint& where, const CButtonState& buttons) { if (isEditing ()) { if (where.x >= getViewSize ().left && where.y >= getViewSize ().top && where.x <= getViewSize ().right && where.y <= getViewSize ().bottom) value = getMax (); else value = getMin (); if (isDirty ()) invalid (); return kMouseEventHandled; } return kMouseEventNotHandled; } //------------------------------------------------------------------------ void CKickButton::onKeyboardEvent (KeyboardEvent& event) { if (event.modifiers.empty () && event.virt == VirtualKey::Return) { if (event.type == EventType::KeyDown) { if (value != getMax ()) { beginEdit (); value = getMax (); invalid (); valueChanged (); } event.consumed = true; } else if (event.type == EventType::KeyUp && isEditing ()) { value = getMin (); invalid (); valueChanged (); endEdit (); event.consumed = true; } } } //------------------------------------------------------------------------ bool CKickButton::sizeToFit () { if (auto bitmap = getDrawBackground ()) { CRect vs (getViewSize ()); if (auto mfb = dynamic_cast (bitmap)) { vs.setSize (mfb->getFrameSize ()); } else { #if VSTGUI_ENABLE_DEPRECATED_METHODS vs.setHeight (heightOfOneImage); #else vs.setHeight (bitmap->getHeight ()); #endif vs.setWidth (bitmap->getWidth ()); } setViewSize (vs, true); setMouseableArea (vs); return true; } return false; } //------------------------------------------------------------------------ // CCheckBox //------------------------------------------------------------------------ /*! @class CCheckBox A checkbox control with a title and 3 states : checked, half checked, not checked - if value is < 0.5 the checkbox is not checked - if value is 0.5 the checkbox is half checked - if value is > 0.5 the checkbox is checked the user can only switch between checked and not checked state. If the bitmap is set, the bitmap must contain 6 states of the checkbox in the following order: - not checked - half checked - checked - not checked hilighted - half checked hilighted - checked hilighted */ //------------------------------------------------------------------------ //------------------------------------------------------------------------ CCheckBox::CCheckBox (const CRect& size, IControlListener* listener, int32_t tag, UTF8StringPtr title, CBitmap* bitmap, int32_t style) : CControl (size, listener, tag, bitmap) , style (style) , fontColor (kWhiteCColor) , font (kSystemFont) { setTitle (title); setBoxFillColor (kWhiteCColor); setBoxFrameColor (kBlackCColor); setCheckMarkColor (kRedCColor); setWantsFocus (true); if (style & kAutoSizeToFit) sizeToFit (); } //------------------------------------------------------------------------ CCheckBox::CCheckBox (const CCheckBox& checkbox) : CControl (checkbox) , style (checkbox.style) , fontColor (checkbox.fontColor) , font (checkbox.font) { setTitle (checkbox.title); setBoxFillColor (checkbox.boxFillColor); setBoxFrameColor (checkbox.boxFrameColor); setCheckMarkColor (checkbox.checkMarkColor); setWantsFocus (true); } //------------------------------------------------------------------------ void CCheckBox::setTitle (const UTF8String& newTitle) { title = newTitle; if (style & kAutoSizeToFit) sizeToFit (); } //------------------------------------------------------------------------ void CCheckBox::setFont (CFontRef newFont) { font = newFont; if (font && style & kAutoSizeToFit) sizeToFit (); } //------------------------------------------------------------------------ void CCheckBox::setBackground (CBitmap *background) { CView::setBackground (background); if (style & kAutoSizeToFit) sizeToFit (); } //------------------------------------------------------------------------ void CCheckBox::setStyle (int32_t newStyle) { if (style != newStyle) { style = newStyle; if (style & kAutoSizeToFit) sizeToFit (); invalid (); } } //------------------------------------------------------------------------ void CCheckBox::setFrameWidth (CCoord width) { if (frameWidth != width) { frameWidth = width; invalid (); } } //------------------------------------------------------------------------ void CCheckBox::setRoundRectRadius (CCoord radius) { if (roundRectRadius != radius) { roundRectRadius = radius; invalid (); } } /// @cond ignore //------------------------------------------------------------------------ static CCoord getFontCapHeight (CFontRef font) { CCoord c = font->getSize (); IPlatformFont* pf = font->getPlatformFont (); if (pf) { CCoord capHeight = pf->getCapHeight (); if (capHeight <= 0) capHeight = pf->getAscent (); if (capHeight > 0) c = capHeight; } return c; } /// @endcond //------------------------------------------------------------------------ static CCoord kCheckBoxTitleMargin = 5; //------------------------------------------------------------------------ bool CCheckBox::sizeToFit () { if (title.empty ()) return false; if (auto painter = font->getFontPainter ()) { CRect fitSize (getViewSize ()); if (getDrawBackground ()) { fitSize.setWidth (getDrawBackground ()->getWidth ()); fitSize.setHeight (getDrawBackground ()->getHeight () / 6); } else { fitSize.setWidth (fitSize.getHeight ()); } fitSize.right += kCheckBoxTitleMargin; fitSize.right += painter->getStringWidth (nullptr, UTF8String (title).getPlatformString (), true); setViewSize (fitSize); setMouseableArea (fitSize); return true; } return false; } //------------------------------------------------------------------------ void CCheckBox::draw (CDrawContext* context) { float norm = getValueNormalized (); CRect checkBoxSize (getViewSize ()); if (getDrawBackground ()) { CPoint off; checkBoxSize.setWidth (getDrawBackground ()->getWidth ()); checkBoxSize.setHeight (getDrawBackground ()->getHeight () / 6); if (norm == 0.5) off.y = checkBoxSize.getHeight (); else if (norm > 0.5) off.y = checkBoxSize.getHeight () * 2; else off.y = 0; if (hilight) off.y += getDrawBackground ()->getHeight () / 2.; getDrawBackground ()->draw (context, checkBoxSize, off); } else { auto lineWidth = frameWidth; if (lineWidth < 0) lineWidth = context->getHairlineSize (); if (!(style & kIgnoreCapHeightOnDraw)) checkBoxSize.setHeight (std::floor (getFontCapHeight (font) + 2.5)); else checkBoxSize.bottom -= 2.; checkBoxSize.setWidth (checkBoxSize.getHeight ()); checkBoxSize.offset (1., std::ceil ((getViewSize ().getHeight () - checkBoxSize.getHeight ()) / 2.)); context->setLineWidth (lineWidth); context->setLineStyle (kLineSolid); context->setDrawMode (kAntiAliasing); context->setFrameColor (boxFrameColor); context->setFillColor (boxFillColor); if (auto path = owned (context->createRoundRectGraphicsPath (checkBoxSize, roundRectRadius))) { context->drawGraphicsPath (path, CDrawContext::kPathFilled); context->drawGraphicsPath (path, CDrawContext::kPathStroked); } else { context->drawRect (checkBoxSize, kDrawFilledAndStroked); } if (hilight) { CColor hilightColor = boxFrameColor; hilightColor.alpha /= 2; context->setFrameColor (hilightColor); CRect r (checkBoxSize); r.inset (lineWidth, lineWidth); if (auto path = owned (context->createRoundRectGraphicsPath (r, roundRectRadius))) { context->drawGraphicsPath (path, CDrawContext::kPathStroked); } else { context->drawRect (r, kDrawStroked); } } context->setDrawMode (kAntiAliasing); context->setFrameColor (checkMarkColor); context->setLineWidth (2.); const CCoord cbInset = 2.; if (style & kDrawCrossBox) { if (norm == 0.5f) { context->drawLine (CPoint (checkBoxSize.left + cbInset, checkBoxSize.top + checkBoxSize.getHeight () / 2.), CPoint (checkBoxSize.right - cbInset, checkBoxSize.top + checkBoxSize.getHeight () / 2)); } else if (norm > 0.5f) { context->drawLine (CPoint (checkBoxSize.left + cbInset, checkBoxSize.top + cbInset), CPoint (checkBoxSize.right - cbInset, checkBoxSize.bottom - cbInset)); context->drawLine (CPoint (checkBoxSize.left + cbInset, checkBoxSize.bottom - cbInset), CPoint (checkBoxSize.right - cbInset, checkBoxSize.top + cbInset)); } } else { if (norm == 0.5f) { context->drawLine (CPoint (checkBoxSize.left + cbInset, checkBoxSize.top + checkBoxSize.getHeight () / 2.), CPoint (checkBoxSize.right - cbInset, checkBoxSize.top + checkBoxSize.getHeight () / 2)); } else if (norm > 0.5f) { SharedPointer path = owned (context->createGraphicsPath ()); if (path) { path->beginSubpath (CPoint (checkBoxSize.left + cbInset, checkBoxSize.top + checkBoxSize.getHeight () / 2.)); path->addLine (CPoint (checkBoxSize.left + checkBoxSize.getWidth () / 2, checkBoxSize.bottom - cbInset)); path->addLine (CPoint (checkBoxSize.right + 1, checkBoxSize.top - 1)); context->drawGraphicsPath (path, CDrawContext::kPathStroked); } else { context->drawLine (CPoint (checkBoxSize.left + cbInset, checkBoxSize.top + checkBoxSize.getHeight () / 2.), CPoint (checkBoxSize.left + checkBoxSize.getWidth () / 2, checkBoxSize.bottom - cbInset)); context->drawLine (CPoint (checkBoxSize.left + checkBoxSize.getWidth () / 2., checkBoxSize.bottom - cbInset), CPoint (checkBoxSize.right + 1, checkBoxSize.top - 1)); } } } } if (title.empty() == false) { CPoint p (checkBoxSize.getBottomRight ()); p.offset (kCheckBoxTitleMargin, -1.); context->setFont (font); context->setFontColor (fontColor); context->setDrawMode (kAntiAliasing); context->drawString (title.getPlatformString (), p, true); } setDirty (false); } //------------------------------------------------------------------------ bool CCheckBox::getFocusPath (CGraphicsPath& outPath) { if (wantsFocus ()) { CCoord focusWidth = getFrame ()->getFocusWidth (); CRect checkBoxSize (getViewSize ()); if (getDrawBackground ()) { checkBoxSize.setWidth (getDrawBackground ()->getWidth ()); checkBoxSize.setHeight (getDrawBackground ()->getHeight () / 6); } else { if (!(style & kIgnoreCapHeightOnDraw)) checkBoxSize.setHeight (std::floor (getFontCapHeight (font) + 2.5)); else checkBoxSize.bottom -= 2.; checkBoxSize.setWidth (checkBoxSize.getHeight ()); checkBoxSize.offset (1, std::ceil ((getViewSize ().getHeight () - checkBoxSize.getHeight ()) / 2)); } outPath.addRoundRect (checkBoxSize, roundRectRadius); checkBoxSize.extend (focusWidth, focusWidth); outPath.addRoundRect (checkBoxSize, roundRectRadius); } return true; } //------------------------------------------------------------------------ CMouseEventResult CCheckBox::onMouseDown (CPoint& where, const CButtonState& buttons) { if (buttons.isLeftButton ()) { beginEdit (); previousValue = value; return onMouseMoved (where, buttons); } return kMouseDownEventHandledButDontNeedMovedOrUpEvents; } //------------------------------------------------------------------------ CMouseEventResult CCheckBox::onMouseMoved (CPoint& where, const CButtonState& buttons) { if (isEditing ()) { bool wasHilighted = hilight; if (getViewSize ().pointInside (where)) hilight = true; else hilight = false; if (wasHilighted != hilight) invalid (); return kMouseEventHandled; } return kMouseEventNotHandled; } //------------------------------------------------------------------------ CMouseEventResult CCheckBox::onMouseCancel () { if (isEditing ()) { hilight = false; value = previousValue; if (isDirty ()) valueChanged (); invalid (); endEdit (); } return kMouseEventHandled; } //------------------------------------------------------------------------ CMouseEventResult CCheckBox::onMouseUp (CPoint& where, const CButtonState& buttons) { hilight = false; if (getViewSize ().pointInside (where)) value = (previousValue < getMax ()) ? getMax () : getMin (); else value = previousValue; if (isDirty ()) { valueChanged (); invalid (); } endEdit (); return kMouseEventHandled; } //------------------------------------------------------------------------ void CCheckBox::onKeyboardEvent (KeyboardEvent& event) { if (event.type == EventType::KeyDown && event.virt == VirtualKey::Return && event.modifiers.empty ()) { value = (value < getMax ()) ? getMax () : getMin (); invalid (); beginEdit (); valueChanged (); endEdit (); event.consumed = true; } } //------------------------------------------------------------------------ //------------------------------------------------------------------------ //------------------------------------------------------------------------ CTextButton::CTextButton (const CRect& size, IControlListener* listener, int32_t tag, UTF8StringPtr title, Style style) : CControl (size, listener, tag, nullptr) , font (kSystemFont) , frameWidth (1.) , roundRadius (6.) , textMargin (0.) , horiTxtAlign (kCenterText) , iconPosition (CDrawMethods::kIconLeft) , style (style) , title (title) { setTextColor (kBlackCColor); setTextColorHighlighted (kWhiteCColor); gradient = owned (CGradient::create (0, 1, CColor (220, 220, 220, 255), CColor (180, 180, 180, 255))); gradientHighlighted = owned (CGradient::create (0, 1, CColor (180, 180, 180, 255), CColor (100, 100, 100, 255))); setFrameColor (kBlackCColor); setFrameColorHighlighted (kBlackCColor); setWantsFocus (true); } //------------------------------------------------------------------------ bool CTextButton::removed (CView* parent) { invalidPath (); return CControl::removed (parent); } //------------------------------------------------------------------------ void CTextButton::setViewSize (const CRect& rect, bool invalid) { invalidPath (); CControl::setViewSize (rect, invalid); } //------------------------------------------------------------------------ CGradient* CTextButton::getGradient () const { return gradient; } //------------------------------------------------------------------------ CGradient* CTextButton::getGradientHighlighted () const { return gradientHighlighted; } //------------------------------------------------------------------------ CBitmap* CTextButton::getIcon () const { return icon; } //------------------------------------------------------------------------ CBitmap* CTextButton::getIconHighlighted () const { return iconHighlighted; } //------------------------------------------------------------------------ void CTextButton::setTitle (const UTF8String& newTitle) { title = newTitle; invalid (); } //------------------------------------------------------------------------ void CTextButton::setFont (CFontRef newFont) { font = newFont; invalid (); } //------------------------------------------------------------------------ void CTextButton::setTextColor (const CColor& color) { textColor = color; invalid (); } //------------------------------------------------------------------------ void CTextButton::setGradient (CGradient* newGradient) { gradient = newGradient; invalid (); } //------------------------------------------------------------------------ void CTextButton::setGradientHighlighted (CGradient* newGradient) { gradientHighlighted = newGradient; invalid (); } //------------------------------------------------------------------------ void CTextButton::setFrameColor (const CColor& color) { frameColor = color; invalid (); } //------------------------------------------------------------------------ void CTextButton::setTextColorHighlighted (const CColor& color) { textColorHighlighted = color; invalid (); } //------------------------------------------------------------------------ void CTextButton::setFrameColorHighlighted (const CColor& color) { frameColorHighlighted = color; invalid (); } //------------------------------------------------------------------------ void CTextButton::setFrameWidth (CCoord width) { frameWidth = width; invalid (); } //------------------------------------------------------------------------ void CTextButton::setRoundRadius (CCoord radius) { roundRadius = radius; invalidPath (); invalid (); } //------------------------------------------------------------------------ void CTextButton::setStyle (Style _style) { style = _style; } //------------------------------------------------------------------------ void CTextButton::setIcon (CBitmap* bitmap) { if (icon != bitmap) { icon = bitmap; invalid (); } } //------------------------------------------------------------------------ void CTextButton::setIconHighlighted (CBitmap* bitmap) { if (iconHighlighted != bitmap) { iconHighlighted = bitmap; invalid (); } } //------------------------------------------------------------------------ void CTextButton::setIconPosition (CDrawMethods::IconPosition pos) { if (iconPosition != pos) { iconPosition = pos; invalid (); } } //------------------------------------------------------------------------ void CTextButton::setTextMargin (CCoord margin) { if (textMargin != margin) { textMargin = margin; invalid (); } } //------------------------------------------------------------------------ void CTextButton::setTextAlignment (CHoriTxtAlign hAlign) { // to force the redraw if (horiTxtAlign != hAlign) { horiTxtAlign = hAlign; invalid (); } } //------------------------------------------------------------------------ bool CTextButton::sizeToFit () { if (title.empty ()) return false; if (auto painter = font->getFontPainter ()) { CRect fitSize (getViewSize ()); fitSize.right = fitSize.left + (roundRadius + 1.) * 4.; fitSize.right += painter->getStringWidth (nullptr, title.getPlatformString (), true); setViewSize (fitSize); setMouseableArea (fitSize); return true; } return false; } //------------------------------------------------------------------------ void CTextButton::draw (CDrawContext* context) { bool highlight = value == getMax () ? true : false; auto lineWidth = getFrameWidth (); if (lineWidth < 0.) lineWidth = context->getHairlineSize (); context->setDrawMode (kAntiAliasing); context->setLineWidth (lineWidth); context->setLineStyle (CLineStyle (CLineStyle::kLineCapRound, CLineStyle::kLineJoinRound)); context->setFrameColor (highlight ? frameColorHighlighted : frameColor); CRect r (getViewSize ()); r.inset (lineWidth / 2., lineWidth / 2.); if (gradient && gradientHighlighted) { CGraphicsPath* path = getPath (context, lineWidth); if (path) { CGradient* drawGradient = highlight ? gradientHighlighted : gradient; if (drawGradient) context->fillLinearGradient (path, *drawGradient, r.getTopLeft (), r.getBottomLeft (), false); context->drawGraphicsPath (path, CDrawContext::kPathStroked); } } CRect titleRect = getViewSize (); titleRect.inset (lineWidth / 2., lineWidth / 2.); CBitmap* iconToDraw = nullptr; if (!getMouseEnabled () && getDisabledBackground ()) iconToDraw = getDisabledBackground (); else iconToDraw = highlight ? (iconHighlighted ? iconHighlighted : icon) : (icon ? icon : iconHighlighted); CDrawMethods::drawIconAndText (context, iconToDraw, iconPosition, getTextAlignment (), getTextMargin (), titleRect, title, getFont (), highlight ? getTextColorHighlighted () : getTextColor ()); setDirty (false); } //------------------------------------------------------------------------ bool CTextButton::getFocusPath (CGraphicsPath& outPath) { CRect r (getViewSize ()); CCoord focusWidth = getFrame ()->getFocusWidth (); r.inset (-focusWidth, -focusWidth); outPath.addRoundRect (r, roundRadius); outPath.closeSubpath (); r = getViewSize (); outPath.addRoundRect (r, roundRadius); return true; } //------------------------------------------------------------------------ bool CTextButton::drawFocusOnTop () { return false; } //------------------------------------------------------------------------ CGraphicsPath* CTextButton::getPath (CDrawContext* context, CCoord lineWidth) { if (_path == nullptr) { CRect r (getViewSize ()); r.inset (lineWidth / 2., lineWidth / 2.); _path = owned (context->createRoundRectGraphicsPath (r, roundRadius)); } return _path; } //------------------------------------------------------------------------ void CTextButton::invalidPath () { _path = nullptr; } //------------------------------------------------------------------------ CMouseEventResult CTextButton::onMouseDown (CPoint& where, const CButtonState& buttons) { if (!(buttons & kLButton)) return kMouseEventNotHandled; fEntryState = value; beginEdit (); return onMouseMoved (where, buttons); } //------------------------------------------------------------------------ CMouseEventResult CTextButton::onMouseCancel () { if (isEditing ()) { value = fEntryState; if (isDirty ()) invalid (); endEdit (); } return kMouseEventHandled; } //------------------------------------------------------------------------ CMouseEventResult CTextButton::onMouseUp (CPoint& where, const CButtonState& buttons) { if (isEditing ()) { if (value != fEntryState) { valueChanged (); if (style == kKickStyle) { value = getMin (); // set button to UNSELECTED state valueChanged (); } if (isDirty ()) invalid (); } endEdit (); } return kMouseEventHandled; } //------------------------------------------------------------------------ CMouseEventResult CTextButton::onMouseMoved (CPoint& where, const CButtonState& buttons) { if (isEditing ()) { if (where.x >= getViewSize ().left && where.y >= getViewSize ().top && where.x <= getViewSize ().right && where.y <= getViewSize ().bottom) value = fEntryState == getMin () ? getMax () : getMin (); else value = fEntryState == getMin () ? getMin () : getMax (); if (isDirty ()) invalid (); return kMouseEventHandled; } return kMouseEventNotHandled; } //------------------------------------------------------------------------ void CTextButton::onKeyboardEvent (KeyboardEvent& event) { if (event.type != EventType::KeyDown) return; if (event.modifiers.empty () && event.virt == VirtualKey::Return) { if (style == kKickStyle) { if (value != getMax ()) { beginEdit (); value = getMax (); invalid (); valueChanged (); value = getMin (); invalid (); valueChanged (); endEdit (); } } else { beginEdit (); if (value == getMin ()) value = getMax (); else value = getMin (); invalid (); valueChanged (); endEdit (); } event.consumed = true; } } } // VSTGUI