422 lines
11 KiB
C++
422 lines
11 KiB
C++
// 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 "ctextedit.h"
|
|
#include "itexteditlistener.h"
|
|
#include "../cframe.h"
|
|
#include "../cdrawcontext.h"
|
|
#include "../events.h"
|
|
#include "../platform/iplatformframe.h"
|
|
#include <cassert>
|
|
|
|
namespace VSTGUI {
|
|
|
|
//------------------------------------------------------------------------
|
|
// CTextEdit
|
|
//------------------------------------------------------------------------
|
|
/*! @class CTextEdit
|
|
Define a rectangle view where a text-value can be displayed and edited with a given font and color.
|
|
The user can specify its convert function (from char to char). The text-value is centered in the given rect.
|
|
A bitmap can be used as background.
|
|
*/
|
|
//------------------------------------------------------------------------
|
|
/**
|
|
* CTextEdit constructor.
|
|
* @param size the size of this view
|
|
* @param listener the listener
|
|
* @param tag the control tag
|
|
* @param txt the initial text as c string (UTF-8 encoded)
|
|
* @param background the background bitmap
|
|
* @param style the display style (see CParamDisplay for styles)
|
|
*/
|
|
//------------------------------------------------------------------------
|
|
CTextEdit::CTextEdit (const CRect& size, IControlListener* listener, int32_t tag, UTF8StringPtr txt,
|
|
CBitmap* background, const int32_t style)
|
|
: CTextLabel (size, txt, background, style)
|
|
{
|
|
this->listener = listener;
|
|
this->tag = tag;
|
|
|
|
setWantsFocus (true);
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
CTextEdit::CTextEdit (const CTextEdit& v)
|
|
: CTextLabel (v)
|
|
, bWasReturnPressed (false)
|
|
, stringToValueFunction (v.stringToValueFunction)
|
|
, immediateTextChange (v.immediateTextChange)
|
|
, secureStyle (v.secureStyle)
|
|
, platformFont (v.platformFont)
|
|
, placeholderString (v.placeholderString)
|
|
{
|
|
setWantsFocus (true);
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
CTextEdit::~CTextEdit () noexcept
|
|
{
|
|
listener = nullptr;
|
|
vstgui_assert (platformControl == nullptr);
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CTextEdit::setStringToValueFunction (const StringToValueFunction& stringToValueFunc)
|
|
{
|
|
stringToValueFunction = stringToValueFunc;
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CTextEdit::setStringToValueFunction (StringToValueFunction&& stringToValueFunc)
|
|
{
|
|
stringToValueFunction = std::move (stringToValueFunc);
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CTextEdit::setImmediateTextChange (bool state)
|
|
{
|
|
immediateTextChange = state;
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CTextEdit::setSecureStyle (bool state)
|
|
{
|
|
if (secureStyle != state)
|
|
{
|
|
secureStyle = state;
|
|
if (platformControl)
|
|
{
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
bool CTextEdit::getSecureStyle () const
|
|
{
|
|
return secureStyle;
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CTextEdit::registerTextEditListener (ITextEditListener* listener)
|
|
{
|
|
textEditListeners.add (listener);
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CTextEdit::unregisterTextEditListener (ITextEditListener* listener)
|
|
{
|
|
textEditListeners.remove (listener);
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CTextEdit::setValue (float val)
|
|
{
|
|
CTextLabel::setValue (val);
|
|
bool converted = false;
|
|
std::string string;
|
|
if (valueToStringFunction)
|
|
converted = valueToStringFunction (getValue (), string, this);
|
|
if (!converted)
|
|
{
|
|
char tmp[255];
|
|
char precisionStr[10];
|
|
snprintf (precisionStr, 10, "%%.%hhuf", valuePrecision);
|
|
snprintf (tmp, 255, precisionStr, getValue ());
|
|
string = tmp;
|
|
}
|
|
|
|
if (converted)
|
|
{
|
|
CTextLabel::setText (UTF8String (std::move (string)));
|
|
if (platformControl)
|
|
platformControl->setText (getText ());
|
|
}
|
|
else
|
|
setText (UTF8String (std::move (string)));
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CTextEdit::setText (const UTF8String& txt)
|
|
{
|
|
if (stringToValueFunction)
|
|
{
|
|
float val = getValue ();
|
|
if (stringToValueFunction (txt, val, this))
|
|
{
|
|
CTextLabel::setValue (val);
|
|
if (valueToStringFunction)
|
|
{
|
|
std::string string;
|
|
valueToStringFunction (getValue (), string, this);
|
|
CTextLabel::setText (UTF8String (std::move (string)));
|
|
if (platformControl)
|
|
platformControl->setText (getText ());
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
CTextLabel::setText (txt);
|
|
if (platformControl)
|
|
platformControl->setText (getText ());
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CTextEdit::valueChanged ()
|
|
{
|
|
if (stringToValueFunction)
|
|
CTextLabel::valueChanged ();
|
|
|
|
CParamDisplay::valueChanged ();
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CTextEdit::setPlaceholderString (const UTF8String& str)
|
|
{
|
|
placeholderString = str;
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CTextEdit::draw (CDrawContext *pContext)
|
|
{
|
|
if (platformControl)
|
|
{
|
|
drawBack (pContext);
|
|
if (!platformControl->drawsPlaceholder () && !placeholderString.empty () &&
|
|
platformControl->getText ().empty ())
|
|
{
|
|
pContext->saveGlobalState ();
|
|
pContext->setGlobalAlpha (pContext->getGlobalAlpha () * 0.5f);
|
|
drawPlatformText (pContext, placeholderString);
|
|
pContext->restoreGlobalState ();
|
|
}
|
|
setDirty (false);
|
|
return;
|
|
}
|
|
drawBack (pContext);
|
|
if (text.empty ())
|
|
{
|
|
if (!placeholderString.empty ())
|
|
{
|
|
pContext->saveGlobalState ();
|
|
pContext->setGlobalAlpha (pContext->getGlobalAlpha () * 0.5f);
|
|
drawPlatformText (pContext, placeholderString);
|
|
pContext->restoreGlobalState ();
|
|
}
|
|
}
|
|
else if (getSecureStyle ())
|
|
{
|
|
constexpr auto bulletCharacter = "\xE2\x80\xA2";
|
|
UTF8String str;
|
|
for (auto i = 0u; i < text.length (); ++i)
|
|
str += bulletCharacter;
|
|
drawPlatformText (pContext, str);
|
|
}
|
|
else
|
|
CTextLabel::draw (pContext);
|
|
setDirty (false);
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
CMouseEventResult CTextEdit::onMouseDown (CPoint& where, const CButtonState& buttons)
|
|
{
|
|
if (buttons & kLButton)
|
|
{
|
|
if (getFrame ()->getFocusView () != this)
|
|
{
|
|
if (isDoubleClickStyle ())
|
|
{
|
|
if (!(buttons & kDoubleClick))
|
|
return kMouseEventNotHandled;
|
|
}
|
|
|
|
takeFocus ();
|
|
return kMouseDownEventHandledButDontNeedMovedOrUpEvents;
|
|
}
|
|
}
|
|
return kMouseEventNotHandled;
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CTextEdit::onKeyboardEvent (KeyboardEvent& event)
|
|
{
|
|
if (!platformControl || event.type != EventType::KeyDown)
|
|
return;
|
|
|
|
if (event.virt == VirtualKey::Escape)
|
|
{
|
|
bWasReturnPressed = false;
|
|
platformControl->setText (text);
|
|
getFrame ()->setFocusView (nullptr);
|
|
looseFocus ();
|
|
event.consumed = true;
|
|
}
|
|
else if (event.virt == VirtualKey::Return)
|
|
{
|
|
bWasReturnPressed = true;
|
|
getFrame ()->setFocusView (nullptr);
|
|
looseFocus ();
|
|
event.consumed = true;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
CFontRef CTextEdit::platformGetFont () const
|
|
{
|
|
CFontRef font = getFont ();
|
|
CCoord fontSize = font->getSize ();
|
|
fontSize *= getGlobalTransform ().m11;
|
|
if (fontSize == font->getSize ())
|
|
return font;
|
|
platformFont = makeOwned<CFontDesc> (*font);
|
|
platformFont->setSize (fontSize);
|
|
return platformFont;
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
CRect CTextEdit::platformGetSize () const
|
|
{
|
|
return translateToGlobal (getViewSize ());
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
CRect CTextEdit::platformGetVisibleSize () const
|
|
{
|
|
return translateToGlobal (getVisibleViewSize ());
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CTextEdit::platformLooseFocus (bool returnPressed)
|
|
{
|
|
remember ();
|
|
bWasReturnPressed = returnPressed;
|
|
if (getFrame ()->getFocusView () == this)
|
|
getFrame ()->setFocusView (nullptr);
|
|
forget ();
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CTextEdit::platformOnKeyboardEvent (KeyboardEvent& event)
|
|
{
|
|
dynamic_cast<IPlatformFrameCallback*> (getFrame ())->platformOnEvent (event);
|
|
if (event.consumed)
|
|
return;
|
|
if (event.virt == VirtualKey::Return)
|
|
{
|
|
platformLooseFocus (true);
|
|
event.consumed = true;
|
|
}
|
|
else if (event.virt == VirtualKey::Escape)
|
|
{
|
|
platformLooseFocus (false);
|
|
event.consumed = true;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CTextEdit::platformTextDidChange ()
|
|
{
|
|
if (platformControl && immediateTextChange)
|
|
updateText (platformControl);
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
bool CTextEdit::platformIsSecureTextEdit ()
|
|
{
|
|
return getSecureStyle ();
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CTextEdit::parentSizeChanged ()
|
|
{
|
|
if (platformControl)
|
|
platformControl->updateSize ();
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CTextEdit::setViewSize (const CRect& newSize, bool invalid)
|
|
{
|
|
CTextLabel::setViewSize (newSize, invalid);
|
|
if (platformControl)
|
|
platformControl->updateSize ();
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CTextEdit::createPlatformTextEdit ()
|
|
{
|
|
if (platformControl)
|
|
return;
|
|
|
|
bWasReturnPressed = false;
|
|
platformControl = getFrame ()->getPlatformFrame ()->createPlatformTextEdit (this);
|
|
textEditListeners.forEach (
|
|
[this] (ITextEditListener* l) { l->onTextEditPlatformControlTookFocus (this); });
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
bool CTextEdit::wantsFocus () const
|
|
{
|
|
if (isDoubleClickStyle () && !platformControl)
|
|
return false;
|
|
return CTextLabel::wantsFocus ();
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CTextEdit::takeFocus ()
|
|
{
|
|
if (!getFrame ())
|
|
return;
|
|
createPlatformTextEdit ();
|
|
if (getFrame()->getFocusView () != this)
|
|
getFrame()->setFocusView (this);
|
|
CTextLabel::takeFocus ();
|
|
invalid ();
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CTextEdit::looseFocus ()
|
|
{
|
|
if (platformControl == nullptr)
|
|
return;
|
|
|
|
CBaseObjectGuard guard (this);
|
|
|
|
auto _platformControl = std::move (platformControl);
|
|
updateText (_platformControl);
|
|
|
|
_platformControl = nullptr;
|
|
|
|
textEditListeners.forEach (
|
|
[this] (ITextEditListener* l) { l->onTextEditPlatformControlLostFocus (this); });
|
|
|
|
// if you want to destroy the text edit do it with the loose focus message
|
|
CView* receiver = getParentView () ? getParentView () : getFrame ();
|
|
while (receiver)
|
|
{
|
|
if (receiver->notify (this, kMsgLooseFocus) == kMessageNotified)
|
|
break;
|
|
receiver = receiver->getParentView ();
|
|
}
|
|
CTextLabel::looseFocus ();
|
|
invalid ();
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
void CTextEdit::updateText (IPlatformTextEdit* pte)
|
|
{
|
|
auto newText = pte->getText ();
|
|
if (newText != getText ())
|
|
{
|
|
beginEdit ();
|
|
|
|
setText (newText);
|
|
|
|
CParamDisplay::valueChanged ();
|
|
|
|
endEdit ();
|
|
}
|
|
}
|
|
|
|
} // VSTGUI
|