From 102e899c331bd2ed9902467a077164e209c918f9 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Tue, 12 Aug 2008 00:20:16 +0000 Subject: VSTUI X11 port and embeddable GTK wrapper. Build mdaSpecMeter and GUI. git-svn-id: http://svn.drobilla.net/lad/mda-lv2@1340 a436a847-0d15-0410-975c-d299462d15a1 --- vstgui/TODO | 19 + vstgui/vstcontrols.cpp | 3651 +++++++++++++++++++++++++++++++++++++++++++ vstgui/vstcontrols.h | 994 ++++++++++++ vstgui/vstgui.cpp | 3996 ++++++++++++++++++++++++++++++++++++++++++++++++ vstgui/vstgui.h | 1105 +++++++++++++ vstgui/vstkeycode.h | 104 ++ 6 files changed, 9869 insertions(+) create mode 100644 vstgui/TODO create mode 100644 vstgui/vstcontrols.cpp create mode 100644 vstgui/vstcontrols.h create mode 100644 vstgui/vstgui.cpp create mode 100644 vstgui/vstgui.h create mode 100644 vstgui/vstkeycode.h (limited to 'vstgui') diff --git a/vstgui/TODO b/vstgui/TODO new file mode 100644 index 0000000..27096e5 --- /dev/null +++ b/vstgui/TODO @@ -0,0 +1,19 @@ +//----------------------------------------------------------------------------- +// VST Plug-Ins SDK Linux ONLY Port +// VSTGUIL: Graphical User Interface Framework for VST plugins on LINUX: +// +// Version: 0.1 +// Author: kRAkEn/gORe +// Date: 2007/01/21 +//----------------------------------------------------------------------------- + +Todo List: + +- Fix multiple CParamDisplay objects not showed correctly (only the first is shown) +- Update other controls from a single control->update (), usually params displays not updating while mouse drag +- Fix fonts names and sizes (actually only fixed and courier) +- COffscreenContext not working (add an internal GC different from the frame GC) +- Fix COffscreenContext CopyFrom +- Turn back on CViewContainer::bOffscreenDraw (actually turned off to see something) +- Keep out MOTIF defines (now that IS the default) +- Make CBitmap work on every kind of GC (not pFrame only) diff --git a/vstgui/vstcontrols.cpp b/vstgui/vstcontrols.cpp new file mode 100644 index 0000000..0b0800c --- /dev/null +++ b/vstgui/vstcontrols.cpp @@ -0,0 +1,3651 @@ +/* ---------------------------------------------------------------------------- + * VSTGUI for X11/LV2/PNG + * Author: Dave Robillard + * Released under the revised BSD license, as below + * ---------------------------------------------------------------------------- + * + * Based on: + * ---------------------------------------------------------------------------- + * VSTGUIL: Graphical User Interface Framework for VST plugins on LINUX + * Version: 0.1, Date: 2007/01/21 + * Author: kRAkEn/gORe + * + * Which was based on: + * ---------------------------------------------------------------------------- + * VSTGUI: Graphical User Interface Framework for VST plugins + * Version 3.0 $Date: 2005/08/12 12:45:00 $ + * ---------------------------------------------------------------------------- + * VSTGUI LICENSE + * 2004, Steinberg Media Technologies, All Rights Reserved + * ---------------------------------------------------------------------------- + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Steinberg Media Technologies nor the names of + * its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#include +#include +#include +#include + +#ifndef __vstcontrols__ +#include "vstcontrols.h" +#endif + +#include "vstkeycode.h" + +namespace VSTGUI { + +// some external variables (vstgui.cpp) +extern long gStandardFontSize []; +extern const char *gStandardFontName []; + +//------------------------------------------------------------------------ +// CControl +//------------------------------------------------------------------------ +/*! @class CControl +This object manages the tag identification and the value of a control object. + +Note: +Since version 2.1, when an object uses the transparency for its background and draws on it (tranparency area) +or the transparency area changes during different draws (CMovieBitmap ,...), the background will be false (not updated), +you have to rewrite the draw function in order to redraw the background and then call the draw of the object. +*/ +CControl::CControl (const CRect &size, CControlListener *listener, long tag, + CBitmap *pBackground) +: CView (size), + listener (listener), tag (tag), oldValue (1), defaultValue (0.5f), + value (0), vmin (0), vmax (1.f), wheelInc (0.1f), lastTicks (-1) +{ + delta = 500; + + if (delta < 250) + delta = 250; + + setTransparency (false); + setMouseEnabled (true); + backOffset (0 ,0); + + setBackground (pBackground); +} + +//------------------------------------------------------------------------ +CControl::~CControl () +{ +} + +//------------------------------------------------------------------------ +void CControl::beginEdit () +{ + // begin of edit parameter + getFrame ()->setFocusView(this); + getFrame ()->beginEdit (tag); +} + +//------------------------------------------------------------------------ +void CControl::endEdit () +{ + // end of edit parameter + getFrame ()->endEdit (tag); +} + +//------------------------------------------------------------------------ +bool CControl::isDirty () const +{ + if (oldValue != value || CView::isDirty ()) + return true; + return false; +} + +//------------------------------------------------------------------------ +void CControl::setDirty (const bool val) +{ + CView::setDirty (val); + if (val) + { + if (value != -1.f) + oldValue = -1.f; + else + oldValue = 0.f; + } + else + oldValue = value; +} + +//------------------------------------------------------------------------ +void CControl::setBackOffset (CPoint &offset) +{ + backOffset = offset; +} + +//----------------------------------------------------------------------------- +void CControl::copyBackOffset () +{ + backOffset (size.left, size.top); +} + +//------------------------------------------------------------------------ +void CControl::bounceValue () +{ + if (value > vmax) + value = vmax; + else if (value < vmin) + value = vmin; +} + +//----------------------------------------------------------------------------- +bool CControl::checkDefaultValue (CDrawContext *pContext, long button) +{ + if (button == (kControl|kLButton)) + { + // begin of edit parameter + beginEdit (); + + value = getDefaultValue (); + if (isDirty () && listener) + listener->valueChanged (pContext, this); + + // end of edit parameter + endEdit (); + return true; + } + return false; +} + +//----------------------------------------------------------------------------- +bool CControl::isDoubleClick () +{ + long ticks = getFrame ()->getTicks (); + if (lastTicks <= 0) + { + lastTicks = ticks; + return false; + } + + if (lastTicks + delta > ticks) + lastTicks = 0; + else + { + lastTicks = ticks; + return false; + } + return true; +} + +//------------------------------------------------------------------------ +// COnOffButton +//------------------------------------------------------------------------ +/*! @class COnOffButton +Define a button with 2 positions. +The pixmap includes the 2 subpixmaps (i.e the rectangle used for the display of this button is half-height of the pixmap). +When its value changes, the listener is called. +*/ +COnOffButton::COnOffButton (const CRect &size, CControlListener *listener, long tag, + CBitmap *background, long style) +: CControl (size, listener, tag, background) +, style (style) +{} + +//------------------------------------------------------------------------ +COnOffButton::~COnOffButton () +{} + +//------------------------------------------------------------------------ +void COnOffButton::draw (CDrawContext *pContext) +{ +// DBG ("COnOffButton::draw"); + + CCoord off; + + if (value && pBackground) + off = pBackground->getHeight () / 2; + else + off = 0; + + if (pBackground) + { + if (bTransparencyEnabled) + pBackground->drawTransparent (pContext, size, CPoint (0, off)); + else + pBackground->draw (pContext, size, CPoint (0, off)); + } + setDirty (false); +} + +//------------------------------------------------------------------------ +void COnOffButton::mouse (CDrawContext *pContext, CPoint &where, long button) +{ + if (!bMouseEnabled) + return; + + if (button == -1) button = pContext->getMouseButtons (); + if (!(button & kLButton)) + return; + + if (listener && (button & (kAlt | kShift | kControl | kApple))) + { + if (listener->controlModifierClicked (pContext, this, button) != 0) + return; + } + + value = ((long)value) ? 0.f : 1.f; + + if (listener && style == kPostListenerUpdate) + { + // begin of edit parameter + beginEdit (); + + listener->valueChanged (pContext, this); + + // end of edit parameter + endEdit (); + } + + doIdleStuff (); + + if (listener && style == kPreListenerUpdate) + { + // begin of edit parameter + beginEdit (); + + listener->valueChanged (pContext, this); + + // end of edit parameter + endEdit (); + } +} + + +//------------------------------------------------------------------------ +// CKnob +//------------------------------------------------------------------------ +/*! @class CKnob +Define a knob with a given background and foreground handle. +The handle describes a circle over the background (between -45deg and +225deg). +By clicking Alt+Left Mouse the default value is used. +By clicking Alt+Left Mouse the value changes with a vertical move (version 2.1) +*/ +CKnob::CKnob (const CRect &size, CControlListener *listener, long tag, + CBitmap *background, CBitmap *handle, const CPoint &offset) +: CControl (size, listener, tag, background), offset (offset), pHandle (handle) +{ + if (pHandle) + { + pHandle->remember (); + inset = (long)((float)pHandle->getWidth () / 2.f + 2.5f); + } + else + inset = 3; + + colorShadowHandle = kGreyCColor; + colorHandle = kWhiteCColor; + radius = (float)(size.right - size.left) / 2.f; + + rangeAngle = 1.f; + setStartAngle ((float)(5.f * kPI / 4.f)); + setRangeAngle ((float)(-3.f * kPI / 2.f)); + zoomFactor = 1.5f; + + setWantsFocus (true); +} + +//------------------------------------------------------------------------ +CKnob::~CKnob () +{ + if (pHandle) + pHandle->forget (); +} + +//------------------------------------------------------------------------ +void CKnob::draw (CDrawContext *pContext) +{ +// DBG ("CKnob::draw"); + + if (pBackground) + { + if (bTransparencyEnabled) + pBackground->drawTransparent (pContext, size, offset); + else + pBackground->draw (pContext, size, offset); + } + drawHandle (pContext); + setDirty (false); +} + +//------------------------------------------------------------------------ +void CKnob::drawHandle (CDrawContext *pContext) +{ + CPoint where; + valueToPoint (where); + + if (pHandle) + { + long width = (long)pHandle->getWidth (); + long height = (long)pHandle->getHeight (); + where.offset (size.left - width / 2, size.top - height / 2); + + CRect handleSize (0, 0, width, height); + handleSize.offset (where.h, where.v); + pHandle->drawTransparent (pContext, handleSize); + } + else + { + CPoint origin (size.width () / 2, size.height () / 2); + + where.offset (size.left - 1, size.top); + origin.offset (size.left - 1, size.top); + pContext->setFrameColor (colorShadowHandle); + pContext->moveTo (where); + pContext->lineTo (origin); + + where.offset (1, -1); + origin.offset (1, -1); + pContext->setFrameColor (colorHandle); + pContext->moveTo (where); + pContext->lineTo (origin); + } +} + +//------------------------------------------------------------------------ +void CKnob::mouse (CDrawContext *pContext, CPoint &where, long button) +{ + if (!bMouseEnabled) + return; + + if (button == -1) button = pContext->getMouseButtons (); + if (!(button & kLButton)) + return; + + if (listener && button & (kAlt | kShift | kControl | kApple)) + { + if (listener->controlModifierClicked (pContext, this, button) != 0) + return; + } + + // check if default value wanted + if (checkDefaultValue (pContext, button)) + return; + + float old = oldValue; + CPoint firstPoint; + bool modeLinear = false; + float fEntryState = value; + float middle = (vmax - vmin) * 0.5f; + float range = 200.f; + float coef = (vmax - vmin) / range; + long oldButton = button; + + long mode = kCircularMode; + long newMode = getFrame ()->getKnobMode (); + if (kLinearMode == newMode) + { + if (!(button & kAlt)) + mode = newMode; + } + else if (button & kAlt) + mode = kLinearMode; + + if (mode == kLinearMode && (button & kLButton)) + { + if (button & kShift) + range *= zoomFactor; + firstPoint = where; + modeLinear = true; + coef = (vmax - vmin) / range; + } + else + { + CPoint where2 (where); + where2.offset (-size.left, -size.top); + old = valueFromPoint (where2); + } + + CPoint oldWhere (-1, -1); + + // begin of edit parameter + beginEdit (); + do + { + button = pContext->getMouseButtons (); + if (where != oldWhere) + { + oldWhere = where; + if (modeLinear) + { + CCoord diff = (firstPoint.v - where.v) + (where.h - firstPoint.h); + if (button != oldButton) + { + range = 200.f; + if (button & kShift) + range *= zoomFactor; + + float coef2 = (vmax - vmin) / range; + fEntryState += diff * (coef - coef2); + coef = coef2; + oldButton = button; + } + value = fEntryState + diff * coef; + bounceValue (); + } + else + { + where.offset (-size.left, -size.top); + value = valueFromPoint (where); + if (old - value > middle) + value = vmax; + else if (value - old > middle) + value = vmin; + else + old = value; + } + if (isDirty () && listener) + listener->valueChanged (pContext, this); + } + getMouseLocation (pContext, where); + doIdleStuff (); + + } while (button & kLButton); + + // end of edit parameter + endEdit (); +} + +//------------------------------------------------------------------------ +bool CKnob::onWheel (CDrawContext *pContext, const CPoint &where, float distance) +{ + if (!bMouseEnabled) + return false; + + long buttons = pContext->getMouseButtons (); + if (buttons & kShift) + value += 0.1f * distance * wheelInc; + else + value += distance * wheelInc; + bounceValue (); + + if (isDirty () && listener) + { + // begin of edit parameter + beginEdit (); + + listener->valueChanged (pContext, this); + + // end of edit parameter + endEdit (); + } + return true; +} + +//------------------------------------------------------------------------ +long CKnob::onKeyDown (VstKeyCode& keyCode) +{ + switch (keyCode.virt) + { + case VKEY_UP : + case VKEY_RIGHT : + case VKEY_DOWN : + case VKEY_LEFT : + { + float distance = 1.f; + if (keyCode.virt == VKEY_DOWN || keyCode.virt == VKEY_LEFT) + distance = -distance; + + if (keyCode.modifier & MODIFIER_SHIFT) + value += 0.1f * distance * wheelInc; + else + value += distance * wheelInc; + bounceValue (); + + if (isDirty () && listener) + { + // begin of edit parameter + beginEdit (); + + listener->valueChanged (0, this); + + // end of edit parameter + endEdit (); + } + } return 1; + } + return -1; +} + +//------------------------------------------------------------------------ +void CKnob::setStartAngle (float val) +{ + startAngle = val; + compute (); +} + +//------------------------------------------------------------------------ +void CKnob::setRangeAngle (float val) +{ + rangeAngle = val; + compute (); +} + +//------------------------------------------------------------------------ +void CKnob::compute () +{ + aCoef = (vmax - vmin) / rangeAngle; + bCoef = vmin - aCoef * startAngle; + halfAngle = ((float)k2PI - fabsf (rangeAngle)) * 0.5f; + setDirty (); +} + +//------------------------------------------------------------------------ +void CKnob::valueToPoint (CPoint &point) const +{ + float alpha = (value - bCoef) / aCoef; + point.h = (long)(radius + cosf (alpha) * (radius - inset) + 0.5f); + point.v = (long)(radius - sinf (alpha) * (radius - inset) + 0.5f); +} + +//------------------------------------------------------------------------ +float CKnob::valueFromPoint (CPoint &point) const +{ + float v; + float alpha = (float)atan2 (radius - point.v, point.h - radius); + if (alpha < 0.f) + alpha += (float)k2PI; + + float alpha2 = alpha - startAngle; + if (rangeAngle < 0) + { + alpha2 -= rangeAngle; + float alpha3 = alpha2; + if (alpha3 < 0.f) + alpha3 += (float)k2PI; + else if (alpha3 > k2PI) + alpha3 -= (float)k2PI; + if (alpha3 > halfAngle - rangeAngle) + v = vmax; + else if (alpha3 > -rangeAngle) + v = vmin; + else + { + if (alpha2 > halfAngle - rangeAngle) + alpha2 -= (float)k2PI; + else if (alpha2 < -halfAngle) + alpha2 += (float)k2PI; + v = aCoef * alpha2 + vmax; + } + } + else + { + float alpha3 = alpha2; + if (alpha3 < 0.f) + alpha3 += (float)k2PI; + else if (alpha3 > k2PI) + alpha3 -= (float)k2PI; + if (alpha3 > rangeAngle + halfAngle) + v = vmin; + else if (alpha3 > rangeAngle) + v = vmax; + else + { + if (alpha2 > rangeAngle + halfAngle) + alpha2 -= (float)k2PI; + else if (alpha2 < -halfAngle) + alpha2 += (float)k2PI; + v = aCoef * alpha2 + vmin; + } + } + + return v; +} + +//------------------------------------------------------------------------ +void CKnob::setColorShadowHandle (CColor color) +{ + colorShadowHandle = color; + setDirty (); +} + +//------------------------------------------------------------------------ +void CKnob::setColorHandle (CColor color) +{ + colorHandle = color; + setDirty (); +} + +//------------------------------------------------------------------------ +void CKnob::setHandleBitmap (CBitmap *bitmap) +{ + if (pHandle) + { + pHandle->forget (); + pHandle = 0; + } + + if (bitmap) + { + pHandle = bitmap; + pHandle->remember (); + inset = (long)((float)pHandle->getWidth () / 2.f + 2.5f); + } +} + + +//------------------------------------------------------------------------ +// CParamDisplay +//------------------------------------------------------------------------ +/*! @class CParamDisplay +Define a rectangle view where a text-value can be displayed with a given font and color. +The user can specify its convert function (from float to char) by default the string format is "%2.2f". +The text-value is centered in the given rect. +*/ +CParamDisplay::CParamDisplay (const CRect &size, CBitmap *background, const long style) +: CControl (size, 0, 0, background), stringConvert (0), stringConvert2 (0), string2FloatConvert (0), + horiTxtAlign (kCenterText), style (style), bTextTransparencyEnabled (true) +{ + backOffset (0, 0); + + fontID = kNormalFont; + txtFace = kNormalFace; + fontColor = kWhiteCColor; + backColor = kBlackCColor; + frameColor = kBlackCColor; + shadowColor = kRedCColor; + userData = 0; + if (style & kNoDrawStyle) + setDirty (false); +} + +//------------------------------------------------------------------------ +CParamDisplay::~CParamDisplay () +{} + +//------------------------------------------------------------------------ +void CParamDisplay::setStyle (long val) +{ + if (style != val) + { + style = val; + setDirty (); + } +} + +//------------------------------------------------------------------------ +void CParamDisplay::draw (CDrawContext *pContext) +{ +// DBG ("CParamDisplay::draw"); + + char string[256]; + string[0] = 0; + + if (stringConvert2) + stringConvert2 (value, string, userData); + else if (stringConvert) + stringConvert (value, string); + else + sprintf (string, "%2.2f", value); + + drawText (pContext, string); +} + +//------------------------------------------------------------------------ +void CParamDisplay::drawText (CDrawContext *pContext, char *string, CBitmap *newBack) +{ + setDirty (false); + + if (style & kNoDrawStyle) + return; + + // draw the background + if (newBack) + { + if (bTransparencyEnabled) + newBack->drawTransparent (pContext, size, backOffset); + else + newBack->draw (pContext, size, backOffset); + } + else if (pBackground) + { + if (bTransparencyEnabled) + pBackground->drawTransparent (pContext, size, backOffset); + else + pBackground->draw (pContext, size, backOffset); + } + else + { + if (!bTransparencyEnabled) + { + pContext->setFillColor (backColor); + pContext->fillRect (size); + + if (!(style & (k3DIn|k3DOut|kNoFrame))) + { + pContext->setFrameColor (frameColor); + pContext->drawRect (size); + } + } + } + // draw the frame for the 3D effect + if (style & (k3DIn|k3DOut)) + { + if (style & k3DIn) + pContext->setFrameColor (backColor); + else + pContext->setFrameColor (frameColor); + CPoint p; + pContext->moveTo (p (size.left, size.bottom)); + pContext->lineTo (p (size.left, size.top)); + pContext->lineTo (p (size.right + 1, size.top)); + + if (style & k3DIn) + pContext->setFrameColor (frameColor); + else + pContext->setFrameColor (backColor); + pContext->moveTo (p (size.right, size.top + 1)); + pContext->lineTo (p (size.right, size.bottom)); + pContext->lineTo (p (size.left, size.bottom)); + } + + if (!(style & kNoTextStyle) && string) + { + CRect oldClip; + pContext->getClipRect (oldClip); + CRect newClip (size); + newClip.bound (oldClip); + pContext->setClipRect (newClip); + pContext->setFont (fontID, 0, txtFace); + + // draw darker text (as shadow) + if (style & kShadowText) + { + CRect newSize (size); + newSize.offset (1, 1); + pContext->setFontColor (shadowColor); + pContext->drawString (string, newSize, !bTextTransparencyEnabled, horiTxtAlign); + } + pContext->setFontColor (fontColor); + pContext->drawString (string, size, !bTextTransparencyEnabled, horiTxtAlign); + pContext->setClipRect (oldClip); + } +} + +//------------------------------------------------------------------------ +void CParamDisplay::setFont (CFont newFontID) +{ + // to force the redraw + if (fontID != newFontID) + setDirty (); + fontID = newFontID; +} + +//------------------------------------------------------------------------ +void CParamDisplay::setTxtFace (CTxtFace newTxtFace) +{ + // to force the redraw + if (txtFace != newTxtFace) + setDirty (); + txtFace = newTxtFace; +} + +//------------------------------------------------------------------------ +void CParamDisplay::setFontColor (CColor color) +{ + // to force the redraw + if (fontColor != color) + setDirty (); + fontColor = color; +} + +//------------------------------------------------------------------------ +void CParamDisplay::setBackColor (CColor color) +{ + // to force the redraw + if (backColor != color) + setDirty (); + backColor = color; +} + +//------------------------------------------------------------------------ +void CParamDisplay::setFrameColor (CColor color) +{ + // to force the redraw + if (frameColor != color) + setDirty (); + frameColor = color; +} + +//------------------------------------------------------------------------ +void CParamDisplay::setShadowColor (CColor color) +{ + // to force the redraw + if (shadowColor != color) + setDirty (); + shadowColor = color; +} + +//------------------------------------------------------------------------ +void CParamDisplay::setHoriAlign (CHoriTxtAlign hAlign) +{ + // to force the redraw + if (horiTxtAlign != hAlign) + setDirty (); + horiTxtAlign = hAlign; +} + +//------------------------------------------------------------------------ +void CParamDisplay::setStringConvert (void (*convert) (float value, char *string)) +{ + stringConvert = convert; +} + +//------------------------------------------------------------------------ +void CParamDisplay::setStringConvert (void (*convert) (float value, char *string, + void *userDta), void *userData_) +{ + stringConvert2 = convert; + userData = userData_; +} + +//------------------------------------------------------------------------ +void CParamDisplay::setString2FloatConvert (void (*convert) (char *string, float &output)) +{ + string2FloatConvert = convert; +} + +//------------------------------------------------------------------------ +// CTextLabel +//------------------------------------------------------------------------ +/*! @class CTextLabel +*/ +CTextLabel::CTextLabel (const CRect& size, const char* txt, CBitmap* background, const long style) +: CParamDisplay (size, background, style) +, text (0) +{ + setText (txt); +} + +//------------------------------------------------------------------------ +CTextLabel::~CTextLabel () +{ + freeText (); +} + +//------------------------------------------------------------------------ +void CTextLabel::freeText () +{ + if (text) + free (text); + text = 0; +} + +//------------------------------------------------------------------------ +void CTextLabel::setText (const char* txt) +{ + freeText (); + if (txt) + { + text = (char*)malloc (strlen (txt)+1); + strcpy (text, txt); + } +} + +//------------------------------------------------------------------------ +const char* CTextLabel::getText () const +{ + return text; +} + +//------------------------------------------------------------------------ +void CTextLabel::draw (CDrawContext *pContext) +{ +// DBG ("CTextLabel::draw"); + + drawText (pContext, text); + setDirty (false); +} + + +//------------------------------------------------------------------------ +// 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 pixmap can be used as background. +*/ +CTextEdit::CTextEdit (const CRect &size, CControlListener *listener, long tag, + const char *txt, CBitmap *background, const long style) +: CParamDisplay (size, background, style), platformFontColor (0), platformControl (0), + platformFont (0), editConvert (0), editConvert2 (0) +{ + this->listener = listener; + this->tag = tag; + + if (txt) + strcpy (text, txt); + else + strcpy (text, ""); + setWantsFocus (true); +} + +//------------------------------------------------------------------------ +CTextEdit::~CTextEdit () +{} + +//------------------------------------------------------------------------ +void CTextEdit::setText (char *txt) +{ + if (txt) + { + if (strcmp (text, txt)) + { + strcpy (text, txt); + + // to force the redraw + setDirty (); + } + } + else + { + if (strcmp (text, "")) + { + strcpy (text, ""); + + // to force the redraw + setDirty (); + } + } +} + +//------------------------------------------------------------------------ +void CTextEdit::getText (char *txt) const +{ + if (txt) + strcpy (txt, text); +} + +//------------------------------------------------------------------------ +void CTextEdit::draw (CDrawContext *pContext) +{ +// DBG ("CTextEdit::draw"); + + if (platformControl) + { + setDirty (false); + return; + } + + char string[256]; + string[0] = 0; + + if (editConvert2) + editConvert2 (text, string, userData); + else if (editConvert) + editConvert (text, string); + // Allow to display strings through the stringConvert + // callbacks inherited from CParamDisplay + else if (stringConvert2) + { + string[0] = 0; + stringConvert2 (value, string, userData); + strcpy(text, string); + } + else if (stringConvert) + { + string[0] = 0; + stringConvert (value, string); + strcpy(text, string); + } + else + sprintf (string, "%s", text); + + drawText (pContext, string); + setDirty (false); +} + +//------------------------------------------------------------------------ +void CTextEdit::mouse (CDrawContext *pContext, CPoint &where, long button) +{ + if (!bMouseEnabled) + return; + + if (button == -1) button = pContext->getMouseButtons (); + + if (listener && button & (kAlt | kShift | kControl | kApple)) + { + if (listener->controlModifierClicked (pContext, this, button) != 0) + return; + } + + if (button & kLButton) + { + if (getFrame ()->getFocusView () != this) + { + if (style & kDoubleClickStyle) + if (!isDoubleClick ()) + return; + + beginEdit(); + takeFocus (pContext); + } + } +} + +//------------------------------------------------------------------------ +// #include +extern XFontStruct *gFontStructs[]; + +//------------------------------------------------------------------------ +void CTextEdit::takeFocus (CDrawContext *pContext) +{ + bWasReturnPressed = false; + +/* + // we have to add the Text to the parent !! + Dimension posX, posY; + Widget widget = (Widget)(getFrame ()->getSystemWindow ()); + XtVaGetValues (widget, XmNx, &posX, XmNy, &posY, 0); + + Arg args[20]; + int n = 0; + XtSetArg (args[n], XmNx, size.left + posX); n++; + XtSetArg (args[n], XmNy, size.top + posY); n++; + XtSetArg (args[n], XmNwidth, size.width () + 1); n++; + XtSetArg (args[n], XmNheight, size.height () + 2); n++; + + XtSetArg (args[n], XmNvalue, text); n++; + + XtSetArg (args[n], XmNshadowType, XmSHADOW_IN); n++; + XtSetArg (args[n], XmNshadowThickness, 0); n++; + XtSetArg (args[n], XmNcursorPositionVisible, true); n++; + + XtSetArg (args[n], XmNmarginWidth, 0); n++; + XtSetArg (args[n], XmNmarginHeight, 0); n++; + XtSetArg (args[n], XmNresizeHeight, True); n++; + XtSetArg (args[n], XmNborderWidth, 0); n++; + XtSetArg (args[n], XmNeditMode, XmSINGLE_LINE_EDIT); n++; + + // get/set the current font + XmFontList fl = 0; + XFontStruct* fs = gFontStructs [fontID]; + if (fs) + { + XmFontListEntry entry = XmFontListEntryCreate (XmFONTLIST_DEFAULT_TAG, XmFONT_IS_FONT, fs); + XmFontList fl = XmFontListAppendEntry (0, entry); + XtSetArg (args[n], XmNfontList, fl); n++; + } + + platformControl = XmCreateText (XtParent (widget), "Text", args, n); + XtManageChild ((Widget)platformControl); + if (fl) + XmFontListFree (fl); + XmTextSetSelection ((Widget)platformControl, 0, strlen (text), 0); + XmTextSetHighlight ((Widget)platformControl, 0, strlen (text), XmHIGHLIGHT_SELECTED); +*/ +} + +//------------------------------------------------------------------------ +void CTextEdit::looseFocus (CDrawContext *pContext) +{ + // Call this yet to avoid recursive call + endEdit(); + if (getFrame ()->getFocusView () == this) + getFrame ()->setFocusView (0); + + if (platformControl == 0) + return; + +/* + char oldText[256]; + strcpy (oldText, text); + + char *pNewText = XmTextGetString ((Widget)platformControl); + strcpy (text, pNewText); + XtFree (pNewText); + + XtUnmanageChild ((Widget)platformControl); + XtDestroyWidget ((Widget)platformControl); + + CPoint origOffset; + bool resetContextOffset = false; + if (!pContext) + { + // create a local context + pContext = getFrame ()->createDrawContext (); + if (getParentView ()) + { + resetContextOffset = true; + origOffset.x = pContext->offset.x; + origOffset.y = pContext->offset.y; + CView *view= getParentView (); + CRect rect2; + view->getViewSize (rect2); + CPoint offset; + view->localToFrame (offset); + rect2.offset (offset.x, offset.y); + pContext->offset.h = rect2.left; + pContext->offset.v = rect2.top; + } + } + else + pContext->remember (); + + // update dependency + bool change = false; + if (strcmp (oldText, text)) + { + change = true; + if (listener) + listener->valueChanged (pContext, this); + } + + platformControl = 0; + if (resetContextOffset) + { + pContext->offset.x = origOffset.x; + pContext->offset.y = origOffset.y; + } + pContext->forget (); + + if (change) + doIdleStuff (); + + CView* receiver = pParentView ? pParentView : pParentFrame; + if (receiver) + receiver->notify (this, "LooseFocus"); +*/ +} + +//------------------------------------------------------------------------ +void CTextEdit::setTextEditConvert (void (*convert) (char *input, char *string)) +{ + editConvert = convert; +} + +//------------------------------------------------------------------------ +void CTextEdit::setTextEditConvert (void (*convert) (char *input, char *string, + void *userDta), void *userData) +{ + editConvert2 = convert; + this->userData = userData; +} + +//------------------------------------------------------------------------ +// COptionMenuScheme +//------------------------------------------------------------------------ +/*! @class COptionMenuScheme +Used to define the appearance (font color, background color...) of a popup-menu. +To define the scheme of a menu, use the appropriate setScheme method (see COptionMenu). +@section coptionmenuscheme_new_in_3_0 New since 3.0 +You can also use the global variable gOptionMenuScheme to use one scheme on all menus. +@section coptionmenuscheme_note Note +If you want to use it on Mac OS X, you must set the macro MAC_ENABLE_MENU_SCHEME (needs Mac OS X 10.3 or higher) +*/ +COptionMenuScheme* gOptionMenuScheme = 0; + +//------------------------------------------------------------------------ +COptionMenuScheme::COptionMenuScheme () +{ + backgroundColor = kGreyCColor; + selectionColor = kBlueCColor; + textColor = kBlackCColor; + hiliteTextColor = kWhiteCColor; + disableTextColor = kWhiteCColor; + + font = kNormalFontSmall; +} + +//------------------------------------------------------------------------ +COptionMenuScheme::~COptionMenuScheme () +{ +} + +//------------------------------------------------------------------------ +void COptionMenuScheme::getItemSize (const char* text, CDrawContext* pContext, CPoint& size) +{ + if (!strcmp (text, kMenuSeparator)) // separator + { + // was: size.h = size.v = 6; + size.h = 6; + size.v = 18; + // separators must have same height, otherwise we have problems + // in multi-column menus :( + } + else + { + pContext->setFont (font); + size.h = pContext->getStringWidth (text) + 18; + size.v = 18; + } +} + +//------------------------------------------------------------------------ +void COptionMenuScheme::drawItemBack (CDrawContext* pContext, const CRect& rect, bool hilite) +{ + if (hilite) + pContext->setFillColor (selectionColor); + else + pContext->setFillColor (backgroundColor); + pContext->fillRect (rect); +} + +//------------------------------------------------------------------------ +void COptionMenuScheme::drawItem (const char* text, long itemId, long state, CDrawContext* pContext, const CRect& rect) +{ + bool hilite = (state & kSelected) != 0; + + drawItemBack (pContext, rect, hilite); + + if (!strcmp (text, kMenuSeparator)) + { + CCoord y = rect.top + rect.height () / 2; + + const CColor bc = { 0, 0, 0, 150}; + const CColor wc = { 255, 255, 255, 150}; + + pContext->setFrameColor (bc); + pContext->moveTo (CPoint (rect.left + 2, y - 1)); + pContext->lineTo (CPoint (rect.right - 2, y - 1)); + pContext->setFrameColor (wc); + pContext->moveTo (CPoint (rect.left + 2, y)); + pContext->lineTo (CPoint (rect.right - 2, y)); + return; + } + + CRect r; + if (state & kChecked) + { + r (6, 4, 14, 12); + r.offset (rect.left, rect.top); + if (hilite) + pContext->setFillColor (hiliteTextColor); + else + pContext->setFillColor (textColor); + pContext->fillEllipse (r); + } + + r = rect; + r.left += 18; + pContext->setFont (font); + if (state & kDisabled) + pContext->setFontColor (disableTextColor); + else + { + if (hilite) + pContext->setFontColor (hiliteTextColor); + else + pContext->setFontColor (textColor); + } + + // this needs to be done right, without changing the text pointer in anyway ;-) + char *ptr = (char*)strstr (text, "\t"); + if (ptr) + { + char modifier[32]; + strcpy (modifier, ptr + 1); + *ptr = 0; + pContext->drawString (text, r, false, kLeftText); + + *ptr = '\t'; + r.left = r.right - 50; + pContext->drawString (modifier, r, false, kLeftText); + } + else + pContext->drawString (text, r, false, kLeftText); +} + + +//------------------------------------------------------------------------ +// COptionMenu +//------------------------------------------------------------------------ +/*! @class COptionMenu +Define a rectangle view where a text-value can be displayed with a given font and color. +The text-value is centered in the given rect. +A pixmap can be used as background, a second pixmap can be used when the option menu is popuped. +There are 2 styles with or without a shadowed text. When a mouse click occurs, a popup menu is displayed. +*/ +COptionMenu::COptionMenu (const CRect &size, CControlListener *listener, long tag, + CBitmap *background, CBitmap *bgWhenClick, const long style) +: CParamDisplay (size, background, style), bgWhenClick (bgWhenClick), nbItemsPerColumn (-1), + prefixNumbers (0), scheme (0) +{ + this->listener = listener; + this->tag = tag; + + nbEntries = 0; + nbSubMenus = 0; + currentIndex = -1; + lastButton = kRButton; + platformControl = 0; + lastResult = -1; + lastMenu = 0; + + if (bgWhenClick) + bgWhenClick->remember (); + + nbSubMenuAllocated = nbAllocated = 0; + + check = 0; + entry = 0; + submenuEntry = 0; +} + +//------------------------------------------------------------------------ +COptionMenu::~COptionMenu () +{ + removeAllEntry (); + + if (bgWhenClick) + bgWhenClick->forget (); +} + +//------------------------------------------------------------------------ +void COptionMenu::setPrefixNumbers (long preCount) +{ + prefixNumbers = preCount; +} + +//----------------------------------------------------------------------------- +bool COptionMenu::allocateSubMenu (long nb) +{ + long newAllocated = nbSubMenuAllocated + nb; + + if (submenuEntry) + submenuEntry = (COptionMenu**)realloc (submenuEntry, newAllocated * sizeof (COptionMenu*)); + else + submenuEntry = (COptionMenu**)malloc (newAllocated * sizeof (COptionMenu*)); + + long i; + for (i = nbSubMenuAllocated; i < newAllocated; i++) + submenuEntry[i] = 0; + + nbSubMenuAllocated = newAllocated; + + return true; +} + +//------------------------------------------------------------------------ +bool COptionMenu::allocateMenu (long nb) +{ + long newAllocated = nbAllocated + nb; + + if (check) + check = (bool*)realloc (check, newAllocated * sizeof (bool)); + else + check = (bool*)malloc (newAllocated * sizeof (bool)); + if (!check) + return false; + + if (entry) + entry = (char**)realloc (entry, newAllocated * sizeof (char*)); + else + entry = (char**)malloc (newAllocated * sizeof (char*)); + if (!entry) + { + free (check); + return false; + } + + long i; + for (i = nbAllocated; i < newAllocated; i++) + { + check[i] = false; + entry[i] = 0; + } + + nbAllocated = newAllocated; + + return true; +} + +//------------------------------------------------------------------------ +COptionMenu* COptionMenu::getSubMenu (long idx) const +{ + if (submenuEntry && idx < nbSubMenus) + return submenuEntry[idx]; + return 0; +} + +//------------------------------------------------------------------------ +bool COptionMenu::addEntry (COptionMenu *subMenu, char *txt) +{ + if (nbEntries >= MAX_ENTRY || !subMenu || !txt) + return false; + + if (nbEntries >= nbAllocated) + if (!allocateMenu (32)) + return false; + + entry[nbEntries] = (char*)malloc (256); + switch (prefixNumbers) + { + case 2: + sprintf (entry[nbEntries], "-M%1d %s", (int)(nbEntries + 1), txt); + break; + + case 3: + sprintf (entry[nbEntries], "-M%02d %s", (int)(nbEntries + 1), txt); + break; + + case 4: + sprintf (entry[nbEntries], "-M%03d %s", (int)(nbEntries + 1), txt); + break; + + default: + sprintf (entry[nbEntries], "-M%s", txt); + } + + + if (nbSubMenus >= nbSubMenuAllocated) + if (!allocateSubMenu (10)) + return false; + + submenuEntry[nbSubMenus++] = subMenu; + subMenu->remember (); + + nbEntries++; + + if (currentIndex < 0) + currentIndex = 0; + + return true; +} + +//------------------------------------------------------------------------ +bool COptionMenu::addEntry (char *txt, long index) +{ + if (nbEntries >= MAX_ENTRY) + return false; + + if (nbEntries >= nbAllocated) + if (!allocateMenu (32)) + return false; + + entry[nbEntries] = (char*)malloc (256); + + long pos = nbEntries; + + // switch the entries for the insert + if (index >= 0) + { + for (long i = nbEntries; i > index; i--) + strcpy (entry[i], entry[i - 1]); + if (index >= nbEntries) + pos = nbEntries; + else + pos = index; + if (currentIndex >= index) + currentIndex++; + } + + *entry[pos] = 0; + if (txt) + { + switch (prefixNumbers) + { + case 2: + sprintf (entry[pos], "%1d %s", (int)(index + 1), txt); + break; + + case 3: + sprintf (entry[pos], "%02d %s", (int)(index + 1), txt); + break; + + case 4: + sprintf (entry[pos], "%03d %s", (int)(index + 1), txt); + break; + + default: + strncpy (entry[pos], txt, 256); + } + } + + nbEntries++; + + if (currentIndex < 0) + currentIndex = 0; + + return true; +} + +//------------------------------------------------------------------------ +long COptionMenu::getCurrent (char *txt, bool countSeparator) const +{ + if (currentIndex < 0) + return -1; + + long result = 0; + + if (countSeparator) + { + if (txt) + strcpy (txt, entry[currentIndex]); + result = currentIndex; + } + else + { + for (long i = 0; i < currentIndex; i++) + { + if (strcmp (entry[i], kMenuSeparator) && strncmp (entry[i], kMenuTitle, 2)) + result++; + } + if (txt) + strcpy (txt, entry[currentIndex]); + } + return result; +} + +//------------------------------------------------------------------------ +bool COptionMenu::setCurrent (long index, bool countSeparator) +{ + if (index < 0 || index >= nbEntries) + return false; + + if (countSeparator) + { + if (!strcmp (entry[index], kMenuSeparator) && strncmp (entry[index], kMenuTitle, 2)) + return false; + + currentIndex = index; + } + else + { + long newCurrent = 0; + long i = 0; + while (i <= index && newCurrent < nbEntries) + { + if (strcmp (entry[newCurrent], kMenuSeparator) && strncmp (entry[newCurrent], kMenuTitle, 2)) + i++; + newCurrent++; + } + currentIndex = newCurrent - 1; + } + if (style & (kMultipleCheckStyle & ~kCheckStyle)) + check[currentIndex] = !check[currentIndex]; + + // to force the redraw + setDirty (); + + return true; +} + +//------------------------------------------------------------------------ +bool COptionMenu::getEntry (long index, char *txt) const +{ + if (index < 0 || index >= nbEntries) + return false; + + if (txt) + strcpy (txt, entry[index]); + return true; +} + +//------------------------------------------------------------------------ +bool COptionMenu::setEntry (long index, char *txt) +{ + if (index < 0 || index >= nbEntries) + return false; + + if (txt) + strcpy (entry[index], txt); + return true; +} + +//------------------------------------------------------------------------ +bool COptionMenu::removeEntry (long index) +{ + if (index < 0 || index >= nbEntries) + return false; + + nbEntries--; + + // switch the entries + for (long i = index; i < nbEntries; i++) + { + strcpy (entry[i], entry[i + 1]); + check[i] = check [i + 1]; + } + + if (currentIndex >= index) + currentIndex--; + + // delete the last one + free (entry[nbEntries]); + entry[nbEntries] = 0; + check[nbEntries] = false; + + if (nbEntries == 0) + currentIndex = -1; + return true; +} + +//------------------------------------------------------------------------ +bool COptionMenu::removeAllEntry () +{ + long i; + for (i = 0; i < nbEntries; i++) + { + free (entry[i]); + entry[i] = 0; + check[i] = false; + } + + nbEntries = 0; + currentIndex = -1; + + for (i = 0; i < nbSubMenus; i++) + { + submenuEntry[i]->forget (); + submenuEntry[i] = 0; + } + nbSubMenus = 0; + + if (check) + free (check); + check = 0; + if (entry) + free (entry); + entry = 0; + if (submenuEntry) + free (submenuEntry); + submenuEntry = 0; + nbAllocated = 0; + nbSubMenuAllocated = 0; + + return true; +} + +//------------------------------------------------------------------------ +long COptionMenu::getIndex (char *txt) const +{ + if (!txt) + return -1; + + // search entries + for (long i = 0; i < nbEntries; i++) + if (!strcmp (entry[i], txt)) + return i; + + // not found + return -1; +} + +//------------------------------------------------------------------------ +bool COptionMenu::checkEntry (long index, bool state) +{ + if (index < 0 || index >= nbEntries) + return false; + + check[index] = state; + + return true; +} + +//------------------------------------------------------------------------ +bool COptionMenu::checkEntryAlone (long index) +{ + if (index < 0 || index >= nbEntries) + return false; + for (long i = 0; i < nbEntries; i++) + check[i] = false; + check[index] = true; + + return true; +} + +//------------------------------------------------------------------------ +bool COptionMenu::isCheckEntry (long index) const +{ + if (index < 0 || index >= nbEntries) + return false; + + return check[index]; +} + +//------------------------------------------------------------------------ +void COptionMenu::draw (CDrawContext *pContext) +{ +// DBG ("COptionMenu::draw"); + + if (currentIndex >= 0 && nbEntries) + drawText (pContext, entry[currentIndex] + prefixNumbers); + else + drawText (pContext, NULL); +} + +//------------------------------------------------------------------------ +void COptionMenu::mouse (CDrawContext *pContext, CPoint &where, long button) +{ + if (!bMouseEnabled || !getFrame () || !pContext) + return; + + lastButton = (button != -1) ? button : pContext->getMouseButtons (); + + if (listener && button & (kAlt | kShift | kControl | kApple)) + { + if (listener->controlModifierClicked (pContext, this, button) != 0) + return; + } + + if (lastButton & (kLButton|kRButton|kApple)) + { + if (bgWhenClick) + { + char string[256]; + if (currentIndex >= 0) + sprintf (string, "%s", entry[currentIndex]); + else + string[0] = 0; + + drawText (pContext, string, bgWhenClick); + } + + beginEdit(); + takeFocus (pContext); + } +} + +//------------------------------------------------------------------------ +/* +#include +#include +#include +#include + +static void _unmapCallback (Widget item, XtPointer clientData, XtPointer callData); +static void _activateCallback (Widget item, XtPointer clientData, XtPointer callData); + +//------------------------------------------------------------------------ +static void _unmapCallback (Widget item, XtPointer clientData, XtPointer callData) +{ + COptionMenu *optionMenu= (COptionMenu*)clientData; + optionMenu->looseFocus (); +} + +//------------------------------------------------------------------------ +static void _activateCallback (Widget item, XtPointer clientData, XtPointer callData) +{ + COptionMenu *optionMenu= (COptionMenu*)clientData; + optionMenu->setCurrentSelected ((void*)item); +} +*/ + +//------------------------------------------------------------------------ +COptionMenu *COptionMenu::getLastItemMenu (long &idxInMenu) const +{ + idxInMenu = lastMenu ? (long)lastMenu->getValue (): -1; + return lastMenu; +} + +//------------------------------------------------------------------------ +COptionMenu *COptionMenu::getItemMenu (long idx, long &idxInMenu, long &offsetIdx) +{ + COptionMenu *menu = 0; + for (long i = 0; i < nbSubMenus; i++) + { + menu = submenuEntry[i]->getItemMenu (idx, idxInMenu, offsetIdx); + if (menu) + break; + } + return menu; +} + +//------------------------------------------------------------------------ +void COptionMenu::removeItems () +{ + for (long i = 0; i < nbSubMenus; i++) + submenuEntry[i]->removeItems (); +} + +//------------------------------------------------------------------------ +void *COptionMenu::appendItems (long &offsetIdx) +{ + //bool multipleCheck = style & (kMultipleCheckStyle & ~kCheckStyle); + return NULL; +} + +//------------------------------------------------------------------------ +void COptionMenu::setValue (float val) +{ + if ((long)val < 0 || (long)val >= nbEntries) + return; + + currentIndex = (long)val; + if (style & (kMultipleCheckStyle & ~kCheckStyle)) + check[currentIndex] = !check[currentIndex]; + CParamDisplay::setValue (val); + + // to force the redraw + setDirty (); +} + +//------------------------------------------------------------------------ +void COptionMenu::takeFocus (CDrawContext *pContext) +{ + if (!getFrame ()) + return; + +/* + + bool multipleCheck = style & (kMultipleCheckStyle & ~kCheckStyle); + lastResult = -1; + lastMenu = 0; + + Arg args[10]; + int n = 0; + + // get the position of the pParent + CRect rect; + getFrame ()->getSize (&rect); + + if (pContext) + { + rect.left += pContext->offset.h; + rect.top += pContext->offset.v; + } + + // create a popup menu + int offset; + if (style & kPopupStyle) + offset = (int)(rect.top + size.top); + else + offset = (int)(rect.top + size.bottom); + + XtSetArg (args[n], XmNx, rect.left + size.left); n++; + XtSetArg (args[n], XmNy, offset); n++; + XtSetArg (args[n], XmNmenuHistory, currentIndex); n++; + XtSetArg (args[n], XmNtraversalOn, true); n++; + + platformControl = (void*)XmCreatePopupMenu ((Widget)(getFrame ()->getSystemWindow ()), + "popup", args, n); + + XtAddCallback ((Widget)platformControl, XmNunmapCallback, _unmapCallback, this); + + // insert the menu items + for (long i = 0; i < nbEntries; i++) + { + if (!strcmp (entry[i], kMenuSeparator)) + { + itemWidget[i] = (void*)XtCreateManagedWidget ("separator", + xmSeparatorGadgetClass, (Widget)platformControl, 0, 0); + } + else + { + if (multipleCheck) + { + itemWidget[i] = (void*)XtVaCreateManagedWidget (entry[i], + xmToggleButtonWidgetClass, (Widget)platformControl, + XmNset, check[i], XmNvisibleWhenOff, false, 0); + XtAddCallback ((Widget)itemWidget[i], XmNvalueChangedCallback, _activateCallback, this); + } + else if (style & kCheckStyle) + { + itemWidget[i] = (void*)XtVaCreateManagedWidget (entry[i], + xmToggleButtonWidgetClass, (Widget)platformControl, + XmNset, (i == currentIndex) ? true : false, XmNvisibleWhenOff, false, 0); + XtAddCallback ((Widget)itemWidget[i], XmNvalueChangedCallback, _activateCallback, this); + } + else + { + itemWidget[i] = (void*)XtVaCreateManagedWidget (entry[i], + xmPushButtonWidgetClass, (Widget)platformControl, 0); + XtAddCallback ((Widget)itemWidget[i], XmNactivateCallback, _activateCallback, this); + } + } + } + + XtManageChild ((Widget)platformControl); + getFrame ()->setFocusView (0); + endEdit(); +*/ +} + +//------------------------------------------------------------------------ +void COptionMenu::looseFocus (CDrawContext *pContext) +{ + if (platformControl == 0) + return; + +/* + for (long i = 0; i < nbEntries; i++) + if (itemWidget[i]) + XtDestroyWidget ((Widget)itemWidget[i]); + + if (platformControl) + { + XtUnmanageChild ((Widget)platformControl); + XtDestroyWidget ((Widget)platformControl); + } +*/ + platformControl = 0; +} + +//------------------------------------------------------------------------ +void COptionMenu::setCurrentSelected (void *itemSelected) +{ + // retrieve the current index + if (itemSelected != 0) + { + for (long i = 0; i < nbEntries; i++) + if (itemWidget[i] == itemSelected) + { + currentIndex = i; + break; + } + } + + // update dependency + CDrawContext *pContext = new CDrawContext (getFrame (), (void*)getFrame ()->getGC (), (void*)getFrame ()->getBackBuffer ()); + + setValue (currentIndex); + + if (listener) + listener->valueChanged (pContext, this); + delete pContext; +} + + +//------------------------------------------------------------------------ +// CAnimKnob +//------------------------------------------------------------------------ +/*! @class CAnimKnob +Such as a CKnob control object, but there is a unique pixmap which contains different views (subpixmaps) of this knob. +According to the value, a specific subpixmap is displayed. The different subpixmaps are stacked in the pixmap object. +*/ +CAnimKnob::CAnimKnob (const CRect &size, CControlListener *listener, long tag, + CBitmap *background, CPoint &offset) +: CKnob (size, listener, tag, background, 0, offset), bInverseBitmap (false) +{ + heightOfOneImage = size.height (); + subPixmaps = (short)(background->getHeight () / heightOfOneImage); + inset = 0; +} + +//------------------------------------------------------------------------ +CAnimKnob::CAnimKnob (const CRect &size, CControlListener *listener, long tag, + long subPixmaps, // number of subPixmaps + CCoord heightOfOneImage, // height of one image in pixel + CBitmap *background, CPoint &offset) +: CKnob (size, listener, tag, background, 0, offset), + subPixmaps (subPixmaps), heightOfOneImage (heightOfOneImage), bInverseBitmap (false) +{ + inset = 0; +} + +//------------------------------------------------------------------------ +CAnimKnob::~CAnimKnob () +{} + +//----------------------------------------------------------------------------------------------- +bool CAnimKnob::isDirty () const +{ + if (!bDirty) + { + CPoint p; + valueToPoint (p); + if (p == lastDrawnPoint) + return false; + } + return CKnob::isDirty (); +} + +//------------------------------------------------------------------------ +void CAnimKnob::draw (CDrawContext *pContext) +{ +// DBG ("CAnimKnob::draw"); + + CPoint where (0, 0); + if (value >= 0.f) + { + CCoord tmp = heightOfOneImage * (subPixmaps - 1); + if (bInverseBitmap) + where.v = (long)((1 - value) * (float)tmp); + else + where.v = (long)(value * (float)tmp); + for (CCoord realY = 0; realY <= tmp; realY += heightOfOneImage) + { + if (where.v < realY) + { + where.v = realY - heightOfOneImage; + if (where.v < 0) + where.v = 0; + break; + } + } + } + + if (pBackground) + { + if (bTransparencyEnabled) + pBackground->drawTransparent (pContext, size, where); + else + pBackground->draw (pContext, size, where); + } + valueToPoint (lastDrawnPoint); + setDirty (false); +} + +//------------------------------------------------------------------------ +// CVerticalSwitch +//------------------------------------------------------------------------ +/*! @class CVerticalSwitch +Define a switch with a given number of positions, the current position is defined by the position +of the last click on this object (the object is divided in its height by the number of position). +Each position has its subpixmap, each subpixmap is stacked in the given handle pixmap. +By clicking Alt+Left Mouse the default value is used. +*/ +CVerticalSwitch::CVerticalSwitch (const CRect &size, CControlListener *listener, long tag, + CBitmap *background, CPoint &offset) +: CControl (size, listener, tag, background), offset (offset) +{ + heightOfOneImage = size.height (); + subPixmaps = (long)(background->getHeight () / heightOfOneImage); + iMaxPositions = subPixmaps; + + setDefaultValue (0.f); +} + +//------------------------------------------------------------------------ +CVerticalSwitch::CVerticalSwitch (const CRect &size, CControlListener *listener, long tag, + long subPixmaps, // number of subPixmaps + CCoord heightOfOneImage, // height of one image in pixel + long iMaxPositions, + CBitmap *background, CPoint &offset) +: CControl (size, listener, tag, background), offset (offset), + subPixmaps (subPixmaps), heightOfOneImage (heightOfOneImage), + iMaxPositions (iMaxPositions) +{ + setDefaultValue (0.f); +} + +//------------------------------------------------------------------------ +CVerticalSwitch::~CVerticalSwitch () +{} + +//------------------------------------------------------------------------ +void CVerticalSwitch::draw (CDrawContext *pContext) +{ +// DBG ("CVerticalSwitch::draw"); + + if (pBackground) + { + // source position in bitmap + CPoint where (0, heightOfOneImage * ((long)(value * (iMaxPositions - 1) + 0.5f))); + + if (bTransparencyEnabled) + pBackground->drawTransparent (pContext, size, where); + else + pBackground->draw (pContext, size, where); + } + setDirty (false); +} + +//------------------------------------------------------------------------ +void CVerticalSwitch::mouse (CDrawContext *pContext, CPoint &where, long button) +{ + if (!bMouseEnabled) + return; + + if (button == -1) button = pContext->getMouseButtons (); + if (!(button & kLButton)) + return; + + if (listener && button & (kAlt | kShift | kControl | kApple)) + { + if (listener->controlModifierClicked (pContext, this, button) != 0) + return; + } + + // check if default value wanted + if (checkDefaultValue (pContext, button)) + return; + + double coef = (double)heightOfOneImage / (double)iMaxPositions; + + // begin of edit parameter + beginEdit (); + do + { + value = (long)((where.v - size.top) / coef) / (float)(iMaxPositions - 1); + if (value > 1.f) + value = 1.f; + else if (value < 0.f) + value = 0.f; + + if (isDirty () && listener) + listener->valueChanged (pContext, this); + + getMouseLocation (pContext, where); + + doIdleStuff (); + } + while (pContext->getMouseButtons () == button); + + // end of edit parameter + endEdit (); +} + + +//------------------------------------------------------------------------ +// CHorizontalSwitch +//------------------------------------------------------------------------ +/*! @class CHorizontalSwitch +Same as the CVerticalSwitch but horizontal. +*/ +CHorizontalSwitch::CHorizontalSwitch (const CRect &size, CControlListener *listener, long tag, + CBitmap *background, CPoint &offset) +: CControl (size, listener, tag, background), offset (offset) +{ + heightOfOneImage = size.width (); + subPixmaps = (long)(background->getWidth () / heightOfOneImage); + iMaxPositions = subPixmaps; + + setDefaultValue (0.f); +} + +//------------------------------------------------------------------------ +CHorizontalSwitch::CHorizontalSwitch (const CRect &size, CControlListener *listener, long tag, + long subPixmaps, // number of subPixmaps + CCoord heightOfOneImage, // height of one image in pixel + long iMaxPositions, + CBitmap *background, CPoint &offset) +: CControl (size, listener, tag, background), offset (offset), + subPixmaps (subPixmaps), + iMaxPositions (iMaxPositions), + heightOfOneImage (heightOfOneImage) +{ + setDefaultValue (0.f); +} + +//------------------------------------------------------------------------ +CHorizontalSwitch::~CHorizontalSwitch () +{} + +//------------------------------------------------------------------------ +void CHorizontalSwitch::draw (CDrawContext *pContext) +{ +// DBG ("CHorizontalSwitch::draw"); + + if (pBackground) + { + // source position in bitmap + CPoint where (0, heightOfOneImage * ((long)(value * (iMaxPositions - 1) + 0.5f))); + + if (bTransparencyEnabled) + pBackground->drawTransparent (pContext, size, where); + else + pBackground->draw (pContext, size, where); + } + setDirty (false); +} + +//------------------------------------------------------------------------ +void CHorizontalSwitch::mouse (CDrawContext *pContext, CPoint &where, long button) +{ + if (!bMouseEnabled) + return; + + if (button == -1) button = pContext->getMouseButtons (); + + if (listener && button & (kAlt | kShift | kControl | kApple)) + { + if (listener->controlModifierClicked (pContext, this, button) != 0) + return; + } + + if (!(button & kLButton)) + return; + + // check if default value wanted + if (checkDefaultValue (pContext, button)) + return; + + double coef = (double)pBackground->getWidth () / (double)iMaxPositions; + + // begin of edit parameter + beginEdit (); + do + { + value = (long)((where.h - size.left) / coef) / (float)(iMaxPositions - 1); + if (value > 1.f) + value = 1.f; + else if (value < 0.f) + value = 0.f; + + if (isDirty () && listener) + listener->valueChanged (pContext, this); + + getMouseLocation (pContext, where); + + doIdleStuff (); + } + while (pContext->getMouseButtons () == button); + + // end of edit parameter + endEdit (); +} + + +//------------------------------------------------------------------------ +// CRockerSwitch +//------------------------------------------------------------------------ +/*! @class CRockerSwitch +Define a rocker switch with 3 states using 3 subpixmaps. +One click on its leftside, then the first subpixmap is displayed. +One click on its rightside, then the third subpixmap is displayed. +When the mouse button is relaxed, the second subpixmap is framed. +*/ +CRockerSwitch::CRockerSwitch (const CRect &size, CControlListener *listener, long tag, // identifier tag (ID) + CBitmap *background, CPoint &offset, const long style) +: CControl (size, listener, tag, background), offset (offset), style (style) +{ + heightOfOneImage = size.width (); +} + +//------------------------------------------------------------------------ +CRockerSwitch::CRockerSwitch (const CRect &size, CControlListener *listener, long tag, // identifier tag (ID) + CCoord heightOfOneImage, // height of one image in pixel + CBitmap *background, CPoint &offset, const long style) +: CControl (size, listener, tag, background), offset (offset), + heightOfOneImage (heightOfOneImage), style (style) +{} + +//------------------------------------------------------------------------ +CRockerSwitch::~CRockerSwitch () +{} + +//------------------------------------------------------------------------ +void CRockerSwitch::draw (CDrawContext *pContext) +{ +// DBG ("CRockerSwitch::draw"); + + CPoint where (offset.h, offset.v); + + if (value == 1.f) + where.v += 2 * heightOfOneImage; + else if (value == 0.f) + where.v += heightOfOneImage; + + if (pBackground) + { + if (bTransparencyEnabled) + pBackground->drawTransparent (pContext, size, where); + else + pBackground->draw (pContext, size, where); + } + setDirty (false); +} + +//------------------------------------------------------------------------ +void CRockerSwitch::mouse (CDrawContext *pContext, CPoint &where, long button) +{ + if (!bMouseEnabled) + return; + + if (button == -1) button = pContext->getMouseButtons (); + + if (listener && button & (kAlt | kShift | kControl | kApple)) + { + if (listener->controlModifierClicked (pContext, this, button) != 0) + return; + } + + if (!(button & kLButton)) + return; + + float fEntryState = value; + + CCoord width_2 = size.width () / 2; + CCoord height_2 = size.height () / 2; + + // begin of edit parameter + beginEdit (); + + if (button) + { + do + { + if (style & kHorizontal) + { + if (where.h >= size.left && where.v >= size.top && + where.h <= (size.left + width_2) && where.v <= size.bottom) + value = -1.0f; + else if (where.h >= (size.left + width_2) && where.v >= size.top && + where.h <= size.right && where.v <= size.bottom) + value = 1.0f; + else + value = fEntryState; + } + else + { + if (where.h >= size.left && where.v >= size.top && + where.h <= size.right && where.v <= (size.top + height_2)) + value = -1.0f; + else if (where.h >= size.left && where.v >= (size.top + height_2) && + where.h <= size.right && where.v <= size.bottom) + value = 1.0f; + else + value = fEntryState; + } + + if (isDirty () && listener) + listener->valueChanged (pContext, this); + + getMouseLocation (pContext, where); + + doIdleStuff (); + } + while (pContext->getMouseButtons ()); + } + else + { + if (where.h >= size.left && where.v >= size.top && + where.h <= (size.left + width_2) && where.v <= size.bottom) + value = -1.0f; + else if (where.h >= (size.left + width_2) && where.v >= size.top && + where.h <= size.right && where.v <= size.bottom) + value = 1.0f; + + if (listener) + listener->valueChanged (pContext, this); + } + + value = 0.f; // set button to UNSELECTED state + if (listener) + listener->valueChanged (pContext, this); + + // end of edit parameter + endEdit (); +} + +//------------------------------------------------------------------------ +bool CRockerSwitch::onWheel (CDrawContext *pContext, const CPoint &where, float distance) +{ + if (!bMouseEnabled) + return false; + + if (distance > 0) + value = -1.0f; + else + value = 1.0f; + + // begin of edit parameter + beginEdit (); + + if (isDirty () && listener) + listener->valueChanged (pContext, this); + + value = 0.0f; // set button to UNSELECTED state + if (listener) + listener->valueChanged (pContext, this); + + // end of edit parameter + endEdit (); + + return true; +} + + +//------------------------------------------------------------------------ +// CMovieBitmap +//------------------------------------------------------------------------ +/*! @class CMovieBitmap +A movie pixmap allows to display different subpixmaps according to its current value. +*/ +CMovieBitmap::CMovieBitmap (const CRect &size, CControlListener *listener, long tag, + CBitmap *background, CPoint &offset) + : CControl (size, listener, tag, background), offset (offset), + subPixmaps (subPixmaps), heightOfOneImage (heightOfOneImage) +{ + heightOfOneImage = size.height (); + subPixmaps = (long)(background->getHeight () / heightOfOneImage); +} + +//------------------------------------------------------------------------ +CMovieBitmap::CMovieBitmap (const CRect &size, CControlListener *listener, long tag, + long subPixmaps, // number of subPixmaps + CCoord heightOfOneImage, // height of one image in pixel + CBitmap *background, CPoint &offset) + : CControl (size, listener, tag, background), offset (offset), + subPixmaps (subPixmaps), heightOfOneImage (heightOfOneImage) +{} + +//------------------------------------------------------------------------ +CMovieBitmap::~CMovieBitmap () +{} + +//------------------------------------------------------------------------ +void CMovieBitmap::draw (CDrawContext *pContext) +{ + // DBG ("CMovieBitmap::draw"); + + CPoint where (offset.h, offset.v); + + if (value > 1.0f) + value = 1.0f; + + if (value > 0.0f) + where.v += heightOfOneImage * (int)(value * (subPixmaps - 1) + 0.5); + + if (pBackground) + { + if (bTransparencyEnabled) + pBackground->drawTransparent (pContext, size, where); + else + pBackground->draw (pContext, size, where); + } + setDirty (false); +} + + +//------------------------------------------------------------------------ +// CMovieButton +//------------------------------------------------------------------------ +/*! @class CMovieButton +A movie button is a bi-states button with 2 subpixmaps. These subpixmaps are stacked in the pixmap. +*/ +CMovieButton::CMovieButton (const CRect &size, CControlListener *listener, long tag, // identifier tag (ID) + CBitmap *background, CPoint &offset) +: CControl (size, listener, tag, background), offset (offset), buttonState (value) +{ + heightOfOneImage = size.height (); +} + +//------------------------------------------------------------------------ +CMovieButton::CMovieButton (const CRect &size, CControlListener *listener, long tag, + CCoord heightOfOneImage, // height of one image in pixel + CBitmap *background, CPoint &offset) + : CControl (size, listener, tag, background), offset (offset), + heightOfOneImage (heightOfOneImage), buttonState (value) +{} + +//------------------------------------------------------------------------ +CMovieButton::~CMovieButton () +{} + +//------------------------------------------------------------------------ +void CMovieButton::draw (CDrawContext *pContext) +{ + // DBG ("CMovieButton::draw"); + + CPoint where; + + where.h = 0; + + bounceValue (); + + if (value) + where.v = heightOfOneImage; + else + where.v = 0; + + if (pBackground) + { + if (bTransparencyEnabled) + pBackground->drawTransparent (pContext, size, where); + else + pBackground->draw (pContext, size, where); + } + buttonState = value; + + setDirty (false); +} + +//------------------------------------------------------------------------ +void CMovieButton::mouse (CDrawContext *pContext, CPoint &where, long button) +{ + if (!bMouseEnabled) + return; + + if (button == -1) button = pContext->getMouseButtons (); + + if (listener && button & (kAlt | kShift | kControl | kApple)) + { + if (listener->controlModifierClicked (pContext, this, button) != 0) + return; + } + + if (!(button & kLButton)) + return; + + // this simulates a real windows button + float fEntryState = value; + + // begin of edit parameter + beginEdit (); + + if (pContext->getMouseButtons ()) + { + do + { + if (where.h >= size.left && + where.v >= size.top && + where.h <= size.right && + where.v <= size.bottom) + value = !fEntryState; + else + value = fEntryState; + + if (isDirty () && listener) + listener->valueChanged (pContext, this); + + getMouseLocation (pContext, where); + + doIdleStuff (); + } + while (pContext->getMouseButtons () == button); + } + else + { + value = !value; + if (listener) + listener->valueChanged (pContext, this); + } + + // end of edit parameter + endEdit (); + + buttonState = value; +} + + +//------------------------------------------------------------------------ +// CAutoAnimation +//------------------------------------------------------------------------ +/*! @class CAutoAnimation +An auto-animation control contains a given number of subpixmap which can be displayed in loop. +Two functions allows to get the previous or the next subpixmap (these functions increase or decrease the current value of this control). +*/ +// displays bitmaps within a (child-) window +CAutoAnimation::CAutoAnimation (const CRect &size, CControlListener *listener, long tag, + CBitmap *background, CPoint &offset) +: CControl (size, listener, tag, background), offset (offset), bWindowOpened (false) +{ + heightOfOneImage = size.height (); + subPixmaps = (long)(background->getHeight () / heightOfOneImage); + + totalHeightOfBitmap = heightOfOneImage * subPixmaps; +} + +//------------------------------------------------------------------------ +CAutoAnimation::CAutoAnimation (const CRect &size, CControlListener *listener, long tag, + long subPixmaps, // number of subPixmaps... + CCoord heightOfOneImage, // height of one image in pixel + CBitmap *background, CPoint &offset) + : CControl (size, listener, tag, background), offset (offset), + subPixmaps (subPixmaps), heightOfOneImage (heightOfOneImage), + bWindowOpened (false) +{ + totalHeightOfBitmap = heightOfOneImage * subPixmaps; +} + +//------------------------------------------------------------------------ +CAutoAnimation::~CAutoAnimation () +{} + +//------------------------------------------------------------------------ +void CAutoAnimation::draw (CDrawContext *pContext) +{ + // DBG ("CAutoAnimation::draw"); + + if (isWindowOpened ()) + { + CPoint where; + where.v = (long)value + offset.v; + where.h = offset.h; + + if (pBackground) + { + if (bTransparencyEnabled) + pBackground->drawTransparent (pContext, size, where); + else + pBackground->draw (pContext, size, where); + } + } + setDirty (false); +} + +//------------------------------------------------------------------------ +void CAutoAnimation::mouse (CDrawContext *pContext, CPoint &where, long button) +{ + if (!bMouseEnabled) + return; + + if (button == -1) button = pContext->getMouseButtons (); + + if (listener && button & (kAlt | kShift | kControl | kApple)) + { + if (listener->controlModifierClicked (pContext, this, button) != 0) + return; + } + + if (!(button & kLButton)) + return; + + if (!isWindowOpened ()) + { + value = 0; + openWindow (); + setDirty (); // force to redraw + if (listener) + listener->valueChanged (pContext, this); + } + else + { + // stop info animation + value = 0; // draw first pic of bitmap + setDirty (); + closeWindow (); + } +} + +//------------------------------------------------------------------------ +void CAutoAnimation::openWindow () +{ + bWindowOpened = true; +} + +//------------------------------------------------------------------------ +void CAutoAnimation::closeWindow () +{ + bWindowOpened = false; +} + +//------------------------------------------------------------------------ +void CAutoAnimation::nextPixmap () +{ + value += heightOfOneImage; + if (value >= (totalHeightOfBitmap - heightOfOneImage)) + value = 0; +} + +//------------------------------------------------------------------------ +void CAutoAnimation::previousPixmap () +{ + value -= heightOfOneImage; + if (value < 0.f) + value = (float)(totalHeightOfBitmap - heightOfOneImage - 1); +} + + +//------------------------------------------------------------------------ +// CSlider +//------------------------------------------------------------------------ +/*! @class CSlider +Define a slider with a given background and handle. +The range of variation of the handle should be defined. +By default the handler is drawn with transparency (white color). +By clicking Alt+Left Mouse the default value is used. +*/ +CSlider::CSlider (const CRect &rect, CControlListener *listener, long tag, + long iMinPos, // min position in pixel + long iMaxPos, // max position in pixel + CBitmap *handle, // bitmap of slider + CBitmap *background, // bitmap of background + CPoint &offset, // offset in the background + const long style) // style (kBottom,kRight,kTop,kLeft,kHorizontal,kVertical) + : CControl (rect, listener, tag, background), offset (offset), pHandle (handle), + pOScreen (0), style (style), bFreeClick (true) +{ + setDrawTransparentHandle (true); + + if (pHandle) + { + pHandle->remember (); + widthOfSlider = pHandle->getWidth (); + heightOfSlider = pHandle->getHeight (); + } + else + { + widthOfSlider = 1; + heightOfSlider = 1; + } + + widthControl = size.width (); + heightControl = size.height (); + + if (style & kHorizontal) + { + minPos = iMinPos - size.left; + rangeHandle = iMaxPos - iMinPos; + CPoint p (0, 0); + setOffsetHandle (p); + } + else + { + minPos = iMinPos - size.top; + rangeHandle = iMaxPos - iMinPos; + CPoint p (0, 0); + setOffsetHandle (p); + } + + zoomFactor = 10.f; + + setWantsFocus (true); +} + +//------------------------------------------------------------------------ +CSlider::CSlider (const CRect &rect, CControlListener *listener, long tag, + CPoint &offsetHandle, // handle offset + long _rangeHandle, // size of handle range + CBitmap *handle, // bitmap of slider + CBitmap *background, // bitmap of background + CPoint &offset, // offset in the background + const long style) // style (kBottom,kRight,kTop,kLeft,kHorizontal,kVertical) +: CControl (rect, listener, tag, background), offset (offset), pHandle (handle), + pOScreen (0), style (style), minPos (0), bFreeClick (true) +{ + setDrawTransparentHandle (true); + + if (pHandle) + { + pHandle->remember (); + widthOfSlider = pHandle->getWidth (); + heightOfSlider = pHandle->getHeight (); + } + else + { + widthOfSlider = 1; + heightOfSlider = 1; + } + + widthControl = size.width (); + heightControl = size.height (); + if (style & kHorizontal) + rangeHandle = _rangeHandle - widthOfSlider; + else + rangeHandle = _rangeHandle - heightOfSlider; + + setOffsetHandle (offsetHandle); + + zoomFactor = 10.f; + + setWantsFocus (true); +} + +//------------------------------------------------------------------------ +CSlider::~CSlider () +{ + if (pHandle) + pHandle->forget (); +} + +//------------------------------------------------------------------------ +void CSlider::setOffsetHandle (CPoint &val) +{ + offsetHandle = val; + + if (style & kHorizontal) + { + minTmp = offsetHandle.h + minPos; + maxTmp = minTmp + rangeHandle + widthOfSlider; + } + else + { + minTmp = offsetHandle.v + minPos; + maxTmp = minTmp + rangeHandle + heightOfSlider; + } +} + +//----------------------------------------------------------------------------- +bool CSlider::attached (CView *parent) +{ + if (pOScreen) + delete pOScreen; + + pOScreen = 0; // @TODO - faking offscreen +// pOScreen = new COffscreenContext (getFrame (), widthControl, heightControl, kBlackCColor); + + return CControl::attached (parent); +} + +//----------------------------------------------------------------------------- +bool CSlider::removed (CView *parent) +{ + if (pOScreen) + { + delete pOScreen; + pOScreen = 0; + } + return CControl::removed (parent); +} + +//------------------------------------------------------------------------ +void CSlider::draw (CDrawContext *pContext) +{ + // DBG ("CSlider::draw"); + + CDrawContext* drawContext = pOScreen ? pOScreen : pContext; + + if (pOScreen && bTransparencyEnabled) + pOScreen->copyTo (pContext, size); + + float fValue; + if (style & kLeft || style & kTop) + fValue = value; + else + fValue = 1.f - value; + + // (re)draw background + CRect rect (0, 0, widthControl, heightControl); + if (!pOScreen) + rect.offset (size.left, size.top); + if (pBackground) + { + if (bTransparencyEnabled) + pBackground->drawTransparent (drawContext, rect, offset); + else + pBackground->draw (drawContext, rect, offset); + } + + // calc new coords of slider + CRect rectNew; + if (style & kHorizontal) + { + rectNew.top = offsetHandle.v; + rectNew.bottom = rectNew.top + heightOfSlider; + + rectNew.left = offsetHandle.h + (int)(fValue * rangeHandle); + rectNew.left = (rectNew.left < minTmp) ? minTmp : rectNew.left; + + rectNew.right = rectNew.left + widthOfSlider; + rectNew.right = (rectNew.right > maxTmp) ? maxTmp : rectNew.right; + } + else + { + rectNew.left = offsetHandle.h; + rectNew.right = rectNew.left + widthOfSlider; + + rectNew.top = offsetHandle.v + (int)(fValue * rangeHandle); + rectNew.top = (rectNew.top < minTmp) ? minTmp : rectNew.top; + + rectNew.bottom = rectNew.top + heightOfSlider; + rectNew.bottom = (rectNew.bottom > maxTmp) ? maxTmp : rectNew.bottom; + } + if (!pOScreen) + rectNew.offset (size.left, size.top); + + // draw slider at new position + if (pHandle) + { + if (bDrawTransparentEnabled) + pHandle->drawTransparent (drawContext, rectNew); + else + pHandle->draw (drawContext, rectNew); + } + + if (pOScreen) + pOScreen->copyFrom (pContext, size); + + setDirty (false); +} + +//------------------------------------------------------------------------ +void CSlider::mouse (CDrawContext *pContext, CPoint &where, long button) +{ + if (!bMouseEnabled) + return; + + if (button == -1) button = pContext->getMouseButtons (); + + if (listener && button & (kAlt | kShift | kControl | kApple)) + { + if (listener->controlModifierClicked (pContext, this, button) != 0) + return; + } + + // check if default value wanted + if (checkDefaultValue (pContext, button)) + return; + + // allow left mousebutton only + if (!(button & kLButton)) + return; + + CCoord delta; + if (style & kHorizontal) + delta = size.left + offsetHandle.h; + else + delta = size.top + offsetHandle.v; + if (!bFreeClick) + { + float fValue; + if (style & kLeft || style & kTop) + fValue = value; + else + fValue = 1.f - value; + CCoord actualPos; + CRect rect; + + if (style & kHorizontal) + { + actualPos = offsetHandle.h + (int)(fValue * rangeHandle) + size.left; + + rect.left = actualPos; + rect.top = size.top + offsetHandle.v; + rect.right = rect.left + widthOfSlider; + rect.bottom = rect.top + heightOfSlider; + + if (!where.isInside (rect)) + return; + else + delta += where.h - actualPos; + } + else + { + actualPos = offsetHandle.v + (int)(fValue * rangeHandle) + size.top; + + rect.left = size.left + offsetHandle.h; + rect.top = actualPos; + rect.right = rect.left + widthOfSlider; + rect.bottom = rect.top + heightOfSlider; + + if (!where.isInside (rect)) + return; + else + delta += where.v - actualPos; + } + } + else + { + if (style & kHorizontal) + delta += widthOfSlider / 2 - 1; + else + delta += heightOfSlider / 2 - 1; + } + + float oldVal = value; + long oldButton = button; + + // begin of edit parameter + beginEdit (); + + while (1) + { + button = pContext->getMouseButtons (); + if (!(button & kLButton)) + break; + + if ((oldButton != button) && (button & kShift)) + { + oldVal = value; + oldButton = button; + } + else if (!(button & kShift)) + oldVal = value; + + if (style & kHorizontal) + value = (float)(where.h - delta) / (float)rangeHandle; + else + value = (float)(where.v - delta) / (float)rangeHandle; + + if (style & kRight || style & kBottom) + value = 1.f - value; + + if (button & kShift) + value = oldVal + ((value - oldVal) / zoomFactor); + bounceValue (); + + if (isDirty () && listener) + listener->valueChanged (pContext, this); + + getMouseLocation (pContext, where); + + doIdleStuff (); + } + + // end of edit parameter + endEdit (); +} + +//------------------------------------------------------------------------ +bool CSlider::onWheel (CDrawContext *pContext, const CPoint &where, float distance) +{ + if (!bMouseEnabled) + return false; + + long buttons = pContext->getMouseButtons (); + if (buttons & kShift) + value += 0.1f * distance * wheelInc; + else + value += distance * wheelInc; + bounceValue (); + + if (isDirty () && listener) + { + // begin of edit parameter + beginEdit (); + + listener->valueChanged (pContext, this); + + // end of edit parameter + endEdit (); + } + + return true; +} + +//------------------------------------------------------------------------ +long CSlider::onKeyDown (VstKeyCode& keyCode) +{ + switch (keyCode.virt) + { + case VKEY_UP : + case VKEY_RIGHT : + case VKEY_DOWN : + case VKEY_LEFT : + { + float distance = 1.f; + if (keyCode.virt == VKEY_DOWN || keyCode.virt == VKEY_LEFT) + distance = -distance; + + if (keyCode.modifier & MODIFIER_SHIFT) + value += 0.1f * distance * wheelInc; + else + value += distance * wheelInc; + bounceValue (); + + if (isDirty () && listener) + { + // begin of edit parameter + beginEdit (); + + listener->valueChanged (0, this); + + // end of edit parameter + endEdit (); + } + } return 1; + } + return -1; +} + +//------------------------------------------------------------------------ +void CSlider::setHandle (CBitmap *_pHandle) +{ + if (pHandle) + pHandle->forget (); + pHandle = _pHandle; + if (pHandle) + { + pHandle->remember (); + widthOfSlider = pHandle->getWidth (); + heightOfSlider = pHandle->getHeight (); + } +} + + +//------------------------------------------------------------------------ +// CVerticalSlider +//------------------------------------------------------------------------ +/*! @class CVerticalSlider +This is the vertical slider. See CSlider. +*/ +CVerticalSlider::CVerticalSlider (const CRect &rect, CControlListener *listener, long tag, + long iMinPos, // min position in pixel + long iMaxPos, // max position in pixel + CBitmap *handle, // bitmap of slider + CBitmap *background, // bitmap of background + CPoint &offset, // offset in the background + const long style) // style (kLeft, kRight) + : CSlider (rect, listener, tag, iMinPos, iMaxPos, handle, background, offset, style|kVertical) +{} + +//------------------------------------------------------------------------ +CVerticalSlider::CVerticalSlider (const CRect &rect, CControlListener *listener, long tag, + CPoint &offsetHandle, // handle offset + long rangeHandle, // size of handle range + CBitmap *handle, // bitmap of slider + CBitmap *background, // bitmap of background + CPoint &offset, // offset in the background + const long style) // style (kLeft, kRight) +: CSlider (rect, listener, tag, offsetHandle, rangeHandle, handle, background, offset, style|kVertical) +{} + + +//------------------------------------------------------------------------ +// CHorizontalSlider +//------------------------------------------------------------------------ +/*! @class CHorizontalSlider +This is the horizontal slider. See CSlider. +*/ +CHorizontalSlider::CHorizontalSlider (const CRect &rect, CControlListener *listener, long tag, + long iMinPos, // min Y position in pixel + long iMaxPos, // max Y position in pixel + CBitmap *handle, // bitmap of slider + CBitmap *background, // bitmap of background + CPoint &offset, // offset in the background + const long style) // style (kLeft, kRight) + : CSlider (rect, listener, tag, iMinPos, iMaxPos, handle, background, offset, style|kHorizontal) +{} + +//------------------------------------------------------------------------ +CHorizontalSlider::CHorizontalSlider (const CRect &rect, CControlListener *listener, long tag, + CPoint &offsetHandle, // handle offset + long rangeHandle, // size of handle range + CBitmap *handle, // bitmap of slider + CBitmap *background, // bitmap of background + CPoint &offset, // offset in the background + const long style) // style (kLeft, kRight) +: CSlider (rect, listener, tag, offsetHandle, rangeHandle, handle, background, offset, style|kHorizontal) +{} + + +//------------------------------------------------------------------------ +// CSpecialDigit +//------------------------------------------------------------------------ +/*! @class CSpecialDigit +Can be used to display a counter with maximum 7 digits. +All digit have the same size and are stacked in height in the pixmap. +*/ +CSpecialDigit::CSpecialDigit (const CRect &size, + CControlListener *listener, + long tag, // tag identifier + long dwPos, // actual value + long iNumbers, // amount of numbers (max 7) + long *xpos, // array of all XPOS + long *ypos, // array of all YPOS + long width, // width of ONE number + long height, // height of ONE number + CBitmap *background) // bitmap numbers + : CControl (size, listener, tag, background), + iNumbers (iNumbers), width (width), height (height) +{ + setValue ((float)dwPos); // actual value + + if (iNumbers > 7) + iNumbers = 7; + + if (xpos == NULL) + { + // automatically init xpos/ypos if not provided by caller + const int numw = (const int)background->getWidth(); + int x = (int)size.left; + for (long i = 0; i < iNumbers; i++) + { + this->xpos[i] = x; + this->ypos[i] = (long)size.top; + x += numw; + } + } + else + { + // store coordinates of x/y pos of each digit + for (long i = 0; i < iNumbers; i++) + { + this->xpos[i] = xpos[i]; + this->ypos[i] = ypos[i]; + } + } + + setMax ((float)pow (10., (double)iNumbers) - 1.0f); + setMin (0.0f); +} + +//------------------------------------------------------------------------ +CSpecialDigit::~CSpecialDigit () +{} + +//------------------------------------------------------------------------ +void CSpecialDigit::draw (CDrawContext *pContext) +{ +// DBG ("CSpecialDigit::draw"); + + CPoint where; + CRect rectDest; + long i, j; + long dwValue; + long one_digit[16]; + + if ((long)value >= getMax ()) + dwValue = (long)getMax (); + else if ((long)value < getMin ()) + dwValue = (long)getMin (); + else + dwValue = (long)value; + + for (i = 0, j = ((long)getMax () + 1) / 10; i < iNumbers; i++, j /= 10) + { + one_digit[i] = dwValue / j; + dwValue -= (one_digit[i] * j); + } + + where.h = 0; + for (i = 0; i < iNumbers; i++) + { + j = one_digit[i]; + if (j > 9) + j = 9; + + rectDest.left = xpos[i]; + rectDest.top = ypos[i]; + + rectDest.right = rectDest.left + width; + rectDest.bottom = rectDest.top + height; + + // where = src from bitmap + where.v = j * height; + if (pBackground) + { + if (bTransparencyEnabled) + pBackground->drawTransparent (pContext, rectDest, where); + else + pBackground->draw (pContext, rectDest, where); + } + } + + setDirty (false); +} + +//------------------------------------------------------------------------ +float CSpecialDigit::getNormValue () const +{ + float fTemp; + fTemp = value / getMax (); + if (fTemp > 1.0f) + fTemp = 1.0f; + else if (fTemp < 0.0f) + fTemp = 0.0f; + + return fTemp; +} + + +//------------------------------------------------------------------------ +// CKickButton +//------------------------------------------------------------------------ +/*! @class CKickButton +Define a button with 2 states using 2 subpixmaps. +One click on it, then the second subpixmap is displayed. +When the mouse button is relaxed, the first subpixmap is framed. +*/ +CKickButton::CKickButton (const CRect &size, CControlListener *listener, long tag, + CBitmap *background, CPoint &offset) +: CControl (size, listener, tag, background), offset (offset) +{ + heightOfOneImage = size.height (); +} + +//------------------------------------------------------------------------ +CKickButton::CKickButton (const CRect &size, CControlListener *listener, long tag, + CCoord heightOfOneImage, // height of one image in pixel + CBitmap *background, CPoint &offset) +: CControl (size, listener, tag, background), offset (offset), + heightOfOneImage (heightOfOneImage) +{} + +//------------------------------------------------------------------------ +CKickButton::~CKickButton () +{} + +//------------------------------------------------------------------------ +void CKickButton::draw (CDrawContext *pContext) +{ + // DBG ("CKickButton::draw"); + + CPoint where (offset.h, offset.v); + + bounceValue (); + + if (value) + where.v += heightOfOneImage; + + if (pBackground) + { + if (bTransparencyEnabled) + pBackground->drawTransparent (pContext, size, where); + else + pBackground->draw (pContext, size, where); + } + setDirty (false); +} + +//------------------------------------------------------------------------ +void CKickButton::mouse (CDrawContext *pContext, CPoint &where, long button) +{ + if (!bMouseEnabled) + return; + + if (button == -1) button = pContext->getMouseButtons (); + + if (listener && button & (kAlt | kShift | kControl | kApple)) + { + if (listener->controlModifierClicked (pContext, this, button) != 0) + return; + } + + if (!(button & kLButton)) + return; + + // this simulates a real windows button + float fEntryState = value; + + // begin of edit parameter + beginEdit (); + + if (pContext->getMouseButtons () == kLButton) + { + do + { + if (where.h >= size.left && where.v >= size.top && + where.h <= size.right && where.v <= size.bottom) + value = !fEntryState; + else + value = fEntryState; + + if (isDirty () && listener) + listener->valueChanged (pContext, this); + + getMouseLocation (pContext, where); + + doIdleStuff (); + } + while (pContext->getMouseButtons () == kLButton); + } + else + { + value = !value; + if (listener) + listener->valueChanged (pContext, this); + } + + value = 0.0f; // set button to UNSELECTED state + if (listener) + listener->valueChanged (pContext, this); + + // end of edit parameter + endEdit (); +} + + +//------------------------------------------------------------------------ +// CSplashScreen +//------------------------------------------------------------------------ +/*! @class CSplashScreen +One click on its activated region and its pixmap is displayed, in this state the other control can not be used, +an another click on the displayed area reinstalls the normal frame. +This can be used to display a help view over the other views. +*/ +// one click draw its pixmap, an another click redraw its parent +CSplashScreen::CSplashScreen (const CRect &size, CControlListener *listener, long tag, + CBitmap *background, + CRect &toDisplay, + CPoint &offset) +: CControl (size, listener, tag, background), + toDisplay (toDisplay), offset (offset), bitmapTransparency (255) +{} + +//------------------------------------------------------------------------ +CSplashScreen::~CSplashScreen () +{} + +//------------------------------------------------------------------------ +void CSplashScreen::setBitmapTransparency (unsigned char transparency) +{ + bitmapTransparency = transparency; + setTransparency (bitmapTransparency != 255); +} + +//------------------------------------------------------------------------ +void CSplashScreen::draw (CDrawContext *pContext) +{ + // DBG ("CSplashScreen::draw"); + + if (value && pBackground) + { + if (bTransparencyEnabled) + { + if (bitmapTransparency) + pBackground->drawAlphaBlend (pContext, toDisplay, offset, bitmapTransparency); + else + pBackground->drawTransparent (pContext, toDisplay, offset); + } + else + pBackground->draw (pContext, toDisplay, offset); + } + setDirty (false); +} + +//------------------------------------------------------------------------ +bool CSplashScreen::hitTest (const CPoint& where, const long buttons) +{ + bool result = CView::hitTest (where, buttons); + if (result && !(buttons & kLButton)) + return false; + return result; +} + +//------------------------------------------------------------------------ +void CSplashScreen::mouse (CDrawContext *pContext, CPoint &where, long button) +{ + if (!bMouseEnabled) + return; + + if (button == -1) button = pContext->getMouseButtons (); + + if (listener && button & (kAlt | kShift | kControl | kApple)) + { + if (listener->controlModifierClicked (pContext, this, button) != 0) + return; + } + + if (!(button & kLButton)) + return; + + value = !value; + if (value) + { + if (getFrame () && getFrame ()->setModalView (this)) + { + keepSize = size; + size = toDisplay; + mouseableArea = size; +// draw (pContext); + if (listener) + listener->valueChanged (pContext, this); + } + setDirty (); + } + else + { + size = keepSize; + mouseableArea = size; + if (listener) + listener->valueChanged (pContext, this); + if (getFrame ()) + { + getFrame ()->setDirty (true); + getFrame ()->setModalView (NULL); + } + } +} + +//------------------------------------------------------------------------ +void CSplashScreen::unSplash () +{ + setDirty (); + value = 0.f; + + size = keepSize; + if (getFrame ()) + { + if (getFrame ()->getModalView () == this) + { + getFrame ()->setModalView (NULL); + getFrame ()->redraw (); + } + } +} + +//------------------------------------------------------------------------ +// CVuMeter +//------------------------------------------------------------------------ +CVuMeter::CVuMeter (const CRect &size, CBitmap *onBitmap, CBitmap *offBitmap, + long nbLed, const long style) + : CControl (size, 0, 0), + onBitmap (onBitmap), offBitmap (offBitmap), pOScreen (0), + nbLed (nbLed), style (style) +{ + bUseOffscreen = false; + + setDecreaseStepValue (0.1f); + + if (onBitmap) + onBitmap->remember (); + if (offBitmap) + offBitmap->remember (); + + rectOn (size.left, size.top, size.right, size.bottom); + rectOff (size.left, size.top, size.right, size.bottom); +} + +//------------------------------------------------------------------------ +CVuMeter::~CVuMeter () +{ + if (onBitmap) + onBitmap->forget (); + if (offBitmap) + offBitmap->forget (); +} + +//------------------------------------------------------------------------ +void CVuMeter::setDirty (const bool val) +{ + CView::setDirty (val); +} + +//----------------------------------------------------------------------------- +bool CVuMeter::attached (CView *parent) +{ + if (pOScreen) + delete pOScreen; +/* + if (bUseOffscreen) + { + pOScreen = new COffscreenContext (getFrame (), (long)size.width (), (long)size.height (), kBlackCColor); + rectOn (0, 0, size.width (), size.height ()); + rectOff (0, 0, size.width (), size.height ()); + } + else +*/ + { + rectOn (size.left, size.top, size.right, size.bottom); + rectOff (size.left, size.top, size.right, size.bottom); + } + + return CControl::attached (parent); +} + +//------------------------------------------------------------------------ +void CVuMeter::setUseOffscreen (bool val) +{ +// bUseOffscreen = val; // @TODO - faking offscreen + bUseOffscreen = false; +} + +//----------------------------------------------------------------------------- +bool CVuMeter::removed (CView *parent) +{ + if (pOScreen) + { + delete pOScreen; + pOScreen = 0; + } + return CControl::removed (parent); +} + +//------------------------------------------------------------------------ +void CVuMeter::draw (CDrawContext *_pContext) +{ + // DBG ("CVuMeter::draw"); + + if (!onBitmap) + return; + + CPoint pointOn; + CPoint pointOff; + CDrawContext *pContext = _pContext; + + bounceValue (); + + float newValue = oldValue - decreaseValue; + if (newValue < value) + newValue = value; + oldValue = newValue; + +/* + if (bUseOffscreen) + { + if (!pOScreen) + { + pOScreen = new COffscreenContext (getFrame (), (long)size.width (), (long)size.height (), kBlackCColor); + rectOn (0, 0, size.width (), size.height ()); + rectOff (0, 0, size.width (), size.height ()); + } + pContext = pOScreen; + } +*/ + + if (style & kHorizontal) + { + CCoord tmp = (long)(((long)(nbLed * newValue + 0.5f) / (float)nbLed) * onBitmap->getWidth ()); + pointOff (tmp, 0); + if (!bUseOffscreen) + tmp += size.left; + + rectOff.left = tmp; + rectOn.right = tmp; + } + else + { + CCoord tmp = (long)(((long)(nbLed * (getMax () - newValue) + 0.5f) / (float)nbLed) * onBitmap->getHeight ()); + pointOn (0, tmp); + if (!bUseOffscreen) + tmp += size.top; + + rectOff.bottom = tmp; + rectOn.top = tmp; + } + + if (offBitmap) + { + if (bTransparencyEnabled) + offBitmap->drawTransparent (pContext, rectOff, pointOff); + else + offBitmap->draw (pContext, rectOff, pointOff); + } + + if (bTransparencyEnabled) + onBitmap->drawTransparent (pContext, rectOn, pointOn); + else + onBitmap->draw (pContext, rectOn, pointOn); + + if (pOScreen) + pOScreen->copyFrom (_pContext, size); + + setDirty (false); +} + +} // namespace VSTGUI + +//------------------------------------------------------------------------ +// END. +//------------------------------------------------------------------------ diff --git a/vstgui/vstcontrols.h b/vstgui/vstcontrols.h new file mode 100644 index 0000000..0505f82 --- /dev/null +++ b/vstgui/vstcontrols.h @@ -0,0 +1,994 @@ +/* ---------------------------------------------------------------------------- + * VSTGUI for X11/LV2/PNG + * Author: Dave Robillard + * Released under the revised BSD license, as below + * ---------------------------------------------------------------------------- + * + * Based on: + * ---------------------------------------------------------------------------- + * VSTGUIL: Graphical User Interface Framework for VST plugins on LINUX + * Version: 0.1, Date: 2007/01/21 + * Author: kRAkEn/gORe + * + * Which was based on: + * ---------------------------------------------------------------------------- + * VSTGUI: Graphical User Interface Framework for VST plugins + * Version 3.0 $Date: 2005/08/12 12:45:00 $ + * ---------------------------------------------------------------------------- + * VSTGUI LICENSE + * 2004, Steinberg Media Technologies, All Rights Reserved + * ---------------------------------------------------------------------------- + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Steinberg Media Technologies nor the names of + * its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#ifndef __vstcontrols__ +#define __vstcontrols__ + +#ifndef __vstgui__ +#include "vstgui.h" +#endif + +//------------------ +// defines +//------------------ +#ifndef kPI +#define kPI 3.14159265358979323846 +#endif + +#ifndef k2PI +#define k2PI 6.28318530717958647692 +#endif + +#ifndef kPI_2 +#define kPI_2 1.57079632679489661923f +#endif + +#ifndef kPI_4 +#define kPI_4 0.78539816339744830962 +#endif + +#ifndef kE +#define kE 2.7182818284590452354 +#endif + +#ifndef kLN2 +#define kLN2 0.69314718055994530942 +#endif + +#ifndef kSQRT2 +#define kSQRT2 1.41421356237309504880 +#endif + +//------------------ +// CControlEnum type +//------------------ +enum CControlEnum +{ + kHorizontal = 1 << 0, + kVertical = 1 << 1, + kShadowText = 1 << 2, + kLeft = 1 << 3, + kRight = 1 << 4, + kTop = 1 << 5, + kBottom = 1 << 6, + k3DIn = 1 << 7, + k3DOut = 1 << 8, + kPopupStyle = 1 << 9, + kCheckStyle = 1 << 10, + kMultipleCheckStyle, + kNoTextStyle = 1 << 11, + kNoDrawStyle = 1 << 12, + kDoubleClickStyle = 1 << 13, + kNoFrame = 1 << 14 +}; + +//--------------------------- +// Some defines for Menu item +//--------------------------- +#define kMenuTitle "-T" +#define kMenuSeparator "-" +#define kMenuDisable "-G" +#define kMenuSubMenu "-M" + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +class CControlListener +{ +public: + virtual ~CControlListener () {} + + virtual void valueChanged (VSTGUI::CDrawContext *pContext, VSTGUI::CControl *pControl) = 0; + virtual long controlModifierClicked (VSTGUI::CDrawContext *pContext, VSTGUI::CControl *pControl, long button) { return 0; } // return 1 if you want the control to not handle it, otherwise 0 +}; + +class AudioEffectX; + +//----------------------------------------------------------------------------- +namespace VSTGUI { +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// CControl Declaration +//! base class of all VSTGUI controls +//----------------------------------------------------------------------------- +class CControl : public CView +{ +public: + CControl (const CRect &size, CControlListener *listener = 0, long tag = 0, + CBitmap *pBackground = 0); + virtual ~CControl (); + + virtual void draw (CDrawContext *pContext) = 0; + virtual void doIdleStuff () { if (pParentFrame) pParentFrame->doIdleStuff (); } + + virtual void setValue (float val) { value = val; } + virtual float getValue () const { return value; }; + + virtual void setMin (float val) { vmin = val; } + virtual float getMin () const { return vmin; } + virtual void setMax (float val) { vmax = val; } + virtual float getMax () const { return vmax; } + + virtual void setOldValue (float val) { oldValue = val; } + virtual float getOldValue (void) const { return oldValue; } + virtual void setDefaultValue (float val) { defaultValue = val; } + virtual float getDefaultValue (void) const { return defaultValue; } + + virtual void setTag (long val) { tag = val; } + virtual long getTag () const { return tag; } + + virtual bool isDirty () const; + virtual void setDirty (const bool val = true); + + virtual void beginEdit (); + virtual void endEdit (); + + virtual void setBackOffset (CPoint &offset); + virtual void copyBackOffset (); + + virtual void setWheelInc (float val) { wheelInc = val; } + virtual float getWheelInc () const { return wheelInc; } + + virtual void bounceValue (); + virtual bool checkDefaultValue (CDrawContext *pContext, long button); + + CControlListener* getListener () const { return listener; } + void setListener (CControlListener* l) { listener = l; } + bool isDoubleClick (); + + CLASS_METHODS(CControl, CView) + +protected: + CControlListener *listener; + long tag; + float oldValue; + float defaultValue; + float value; + float vmin; + float vmax; + float wheelInc; + + long lastTicks; + long delta; + + CPoint backOffset; +}; + + +//----------------------------------------------------------------------------- +// COnOffButton Declaration +//! a button control with 2 states +//----------------------------------------------------------------------------- +class COnOffButton : public CControl +{ +public: + COnOffButton (const CRect &size, CControlListener *listener, long tag, + CBitmap *background, long style = kPreListenerUpdate); + virtual ~COnOffButton (); + + virtual void draw (CDrawContext*); + virtual void mouse (CDrawContext *pContext, CPoint &where, long button = -1); + + virtual long getStyle () const { return style; } + virtual void setStyle (long newStyle) { style = newStyle; } + + enum { + kPreListenerUpdate, ///< listener will be called after doIdleStuff was called + kPostListenerUpdate ///< listener will be called before doIdleStuff is called + }; + + CLASS_METHODS(COnOffButton, CControl) +protected: + long style; +}; + + +//----------------------------------------------------------------------------- +// CParamDisplay Declaration +//! a parameter display control +//----------------------------------------------------------------------------- +class CParamDisplay : public CControl +{ +public: + CParamDisplay (const CRect &size, CBitmap *background = 0, const long style = 0); + virtual ~CParamDisplay (); + + virtual void setFont (CFont fontID); + CFont getFont () const { return fontID; } + + virtual void setFontColor (CColor color); + CColor getFontColor () const { return fontColor; } + + virtual void setBackColor (CColor color); + CColor getBackColor () const { return backColor; } + + virtual void setFrameColor (CColor color); + CColor getFrameColor () const { return frameColor; } + + virtual void setShadowColor (CColor color); + CColor getShadowColor () const { return shadowColor; } + + virtual void setHoriAlign (CHoriTxtAlign hAlign); + + virtual void setStringConvert (void (*convert) (float value, char *string)); + virtual void setStringConvert (void (*convert) (float value, char *string, void *userDta), + void *userData); + virtual void setString2FloatConvert (void (*convert) (char *string, float &output)); + + virtual void setStyle (long val); + long getStyle () const { return style; } + + virtual void setTxtFace (CTxtFace val); + CTxtFace getTxtFace () const { return txtFace; } + + virtual void draw (CDrawContext *pContext); + + virtual void setTextTransparency (bool val) { bTextTransparencyEnabled = val; } + bool getTextTransparency () const { return bTextTransparencyEnabled; } + + CLASS_METHODS(CParamDisplay, CControl) + +protected: + void drawText (CDrawContext *pContext, char *string, CBitmap *newBack = 0); + + void (*stringConvert) (float value, char *string); + void (*stringConvert2) (float value, char *string, void *userData); + void (*string2FloatConvert) (char *string, float &output); + void *userData; + + CHoriTxtAlign horiTxtAlign; + long style; + + CFont fontID; + CTxtFace txtFace; + CColor fontColor; + CColor backColor; + CColor frameColor; + CColor shadowColor; + bool bTextTransparencyEnabled; +}; + + +//----------------------------------------------------------------------------- +// CLabel Declaration +//! a text label +//----------------------------------------------------------------------------- +class CTextLabel : public CParamDisplay +{ +public: + CTextLabel (const CRect& size, const char* txt = 0, CBitmap* background = 0, const long style = 0); + ~CTextLabel (); + + virtual void setText (const char* txt); + virtual const char* getText () const; + + virtual void draw (CDrawContext *pContext); + + CLASS_METHODS(CTextLabel, CParamDisplay) + +protected: + void freeText (); + char* text; +}; + +//----------------------------------------------------------------------------- +// CTextEdit Declaration +//! a text edit control +//----------------------------------------------------------------------------- +class CTextEdit : public CParamDisplay +{ +public: + CTextEdit (const CRect &size, CControlListener *listener, long tag, const char *txt = 0, + CBitmap *background = 0, const long style = 0); + virtual ~CTextEdit (); + + virtual void setText (char *txt); + virtual void getText (char *txt) const; + + virtual void draw (CDrawContext *pContext); + virtual void mouse (CDrawContext *pContext, CPoint &where, long button = -1); + + virtual void setTextEditConvert (void (*editConvert) (char *input, char *string)); + virtual void setTextEditConvert (void (*editConvert2) (char *input, char *string, + void *userDta), void *userData); + + virtual void takeFocus (CDrawContext *pContext = 0); + virtual void looseFocus (CDrawContext *pContext = 0); + + void *platformFontColor; + void *platformControl; + bool bWasReturnPressed; + + CLASS_METHODS(CTextEdit, CParamDisplay) + +protected: + void *platformFont; + char text[256]; + + void (*editConvert) (char *input, char *string); + void (*editConvert2) (char *input, char *string, void *userData); +}; + + +//----------------------------------------------------------------------------- +// COptionMenuScheme Declaration +//----------------------------------------------------------------------------- +class COptionMenuScheme : public CReferenceCounter +{ +public: + COptionMenuScheme (); + virtual ~COptionMenuScheme (); + + enum { kChecked = 0x01, kDisabled = 0x02, kSelected = 0x04, kSubMenu = 0x08, kTitle = 0x10 }; + + virtual void getItemSize (const char* text, CDrawContext* pContext, CPoint& size); + virtual void drawItem (const char* text, long itemId, long state, CDrawContext* pContext, const CRect& rect); + + void setColors (CColor back, CColor select, CColor text, CColor htext, CColor dtext) + { backgroundColor = back; selectionColor = select; textColor = text; + hiliteTextColor = htext; disableTextColor = dtext;} + + void setFont (CFont f) { font = f; } +protected: + + CColor backgroundColor; + CColor selectionColor; + CColor textColor; + CColor hiliteTextColor; + CColor disableTextColor; + CFont font; + + virtual void drawItemBack (CDrawContext* pContext, const CRect& rect, bool hilite); +}; + +//----------------------------------------------------------------------------- +extern COptionMenuScheme* gOptionMenuScheme; + +//----------------------------------------------------------------------------- +// COptionMenu Declaration +//! a popup menu control +//----------------------------------------------------------------------------- +class COptionMenu : public CParamDisplay +{ +public: + COptionMenu (const CRect &size, CControlListener *listener, long tag, + CBitmap *background = 0, CBitmap *bgWhenClick = 0, + const long style = 0); + virtual ~COptionMenu (); + + enum { MAX_ENTRY = 1024 }; + + virtual void setValue (float val); + virtual bool addEntry (COptionMenu *subMenu, char *txt); + virtual bool addEntry (char *txt, long index = -1); + virtual long getCurrent (char *txt = 0, bool countSeparator = true) const; + virtual bool setCurrent (long index, bool countSeparator = true); + virtual bool getEntry (long index, char *txt) const; + virtual bool setEntry (long index, char *txt); + virtual bool removeEntry (long index); + virtual bool removeAllEntry (); + virtual long getNbEntries () const { return nbEntries; } + virtual long getIndex (char *txt) const; + + virtual bool checkEntry (long index, bool state); + virtual bool checkEntryAlone (long index); + virtual bool isCheckEntry (long index) const; + + virtual void draw (CDrawContext *pContext); + virtual void mouse (CDrawContext *pContext, CPoint &where, long button = -1); + + virtual void takeFocus (CDrawContext *pContext = 0); + virtual void looseFocus (CDrawContext *pContext = 0); + + virtual void setNbItemsPerColumn (long val) { nbItemsPerColumn = val; } + virtual long getNbItemsPerColumn () const { return nbItemsPerColumn; } + + void setCurrentSelected (void *itemSelected); + + long getLastResult () const { return lastResult; } + COptionMenu *getLastItemMenu (long &idxInMenu) const; + + void setScheme (COptionMenuScheme* s) { scheme = s; } + virtual COptionMenuScheme* getScheme () const { return scheme; } + + virtual void setPrefixNumbers (long preCount); + + COptionMenu* getSubMenu (long idx) const; + + CLASS_METHODS(COptionMenu, CParamDisplay) + +protected: + COptionMenu *getItemMenu (long idx, long &idxInMenu, long &offsetIdx); + void removeItems (); + void *appendItems (long &offsetIdx); + + void *platformControl; + + bool allocateMenu (long nb); + bool allocateSubMenu (long nb); + + char **entry; + COptionMenu **submenuEntry; + bool *check; + + void *itemWidget[MAX_ENTRY]; + + long nbEntries; + long nbSubMenus; + long currentIndex; + CBitmap *bgWhenClick; + long lastButton; + long nbItemsPerColumn; + long nbAllocated; + long nbSubMenuAllocated; + long lastResult; + long prefixNumbers; + COptionMenu *lastMenu; + COptionMenuScheme* scheme; +}; + + +//----------------------------------------------------------------------------- +// CKnob Declaration +//! a knob control +//----------------------------------------------------------------------------- +class CKnob : public CControl +{ +public: + CKnob (const CRect &size, CControlListener *listener, long tag, + CBitmap *background, CBitmap *handle, const CPoint &offset); + virtual ~CKnob (); + + virtual void draw (CDrawContext *pContext); + virtual void mouse (CDrawContext *pContext, CPoint &where, long button = -1); + virtual bool onWheel (CDrawContext *pContext, const CPoint &where, float distance); + virtual long onKeyDown (VstKeyCode& keyCode); + + virtual void drawHandle (CDrawContext *pContext); + + virtual void setStartAngle (float val); + virtual float getStartAngle () const { return startAngle; } + + virtual void setRangeAngle (float val); + virtual float getRangeAngle () const { return rangeAngle; } + + virtual void valueToPoint (CPoint &point) const; + virtual float valueFromPoint (CPoint &point) const; + + virtual void setInsetValue (long val) { inset = val; } + + virtual void setColorShadowHandle (CColor color); + virtual void setColorHandle (CColor color); + + virtual void setHandleBitmap (CBitmap *bitmap); + + virtual void setZoomFactor (float val) { zoomFactor = val; } + virtual float getZoomFactor () const { return zoomFactor; } + + CLASS_METHODS(CKnob, CControl) + +protected: + void compute (); + + CPoint offset; + CColor colorHandle, colorShadowHandle; + + CBitmap *pHandle; + long inset; + float startAngle, rangeAngle, halfAngle; + float aCoef, bCoef; + float radius; + float zoomFactor; +}; + +//----------------------------------------------------------------------------- +// CAnimKnob Declaration +//! a bitmap knob control +//----------------------------------------------------------------------------- +class CAnimKnob : public CKnob +{ +public: + CAnimKnob (const CRect &size, CControlListener *listener, long tag, + CBitmap *background, CPoint &offset); + CAnimKnob (const CRect &size, CControlListener *listener, long tag, + long subPixmaps, // number of subPixmaps + CCoord heightOfOneImage, // pixel + CBitmap *background, CPoint &offset); + virtual ~CAnimKnob (); + + virtual bool isDirty () const; + + virtual void draw (CDrawContext* pContext); + + void setInverseBitmap (bool val) { bInverseBitmap = val; } + + CLASS_METHODS(CAnimKnob, CKnob) + +protected: + long subPixmaps; // number of subPixmaps + CCoord heightOfOneImage; + bool bInverseBitmap; + CPoint lastDrawnPoint; +}; + +//----------------------------------------------------------------------------- +// CVerticalSwitch Declaration +//! a vertical switch control +//----------------------------------------------------------------------------- +class CVerticalSwitch : public CControl +{ +public: + CVerticalSwitch (const CRect &size, CControlListener *listener, long tag, + CBitmap *background, CPoint &offset); + CVerticalSwitch (const CRect &size, CControlListener *listener, long tag, + long subPixmaps, // number of subPixmaps + CCoord heightOfOneImage, // pixel + long iMaxPositions, + CBitmap *background, CPoint &offset); + virtual ~CVerticalSwitch (); + + virtual void draw (CDrawContext*); + virtual void mouse (CDrawContext *pContext, CPoint &where, long button = -1); + + CLASS_METHODS(CVerticalSwitch, CControl) + +protected: + CPoint offset; + long subPixmaps; // number of subPixmaps + CCoord heightOfOneImage; + long iMaxPositions; +}; + + +//----------------------------------------------------------------------------- +// CHorizontalSwitch Declaration +//! a horizontal switch control +//----------------------------------------------------------------------------- +class CHorizontalSwitch : public CControl +{ +public: + CHorizontalSwitch (const CRect &size, CControlListener *listener, long tag, + CBitmap *background, CPoint &offset); + CHorizontalSwitch (const CRect &size, CControlListener *listener, long tag, + long subPixmaps, // number of subPixmaps + CCoord heightOfOneImage, // pixel + long iMaxPositions, + CBitmap *background, CPoint &offset); + virtual ~CHorizontalSwitch (); + + virtual void draw (CDrawContext*); + virtual void mouse (CDrawContext *pContext, CPoint &where, long button = -1); + + CLASS_METHODS(CHorizontalSwitch, CControl) + +protected: + CPoint offset; + long subPixmaps; // number of subPixmaps + long iMaxPositions; + CCoord heightOfOneImage; +}; + + +//----------------------------------------------------------------------------- +// CRockerSwitch Declaration +//! a switch control with 3 sub bitmaps +//----------------------------------------------------------------------------- +class CRockerSwitch : public CControl +{ +public: + CRockerSwitch (const CRect &size, CControlListener *listener, long tag, + CBitmap *background, CPoint &offset, const long style = kHorizontal); + CRockerSwitch (const CRect &size, CControlListener *listener, long tag, + CCoord heightOfOneImage, // pixel + CBitmap *background, CPoint &offset, const long style = kHorizontal); + virtual ~CRockerSwitch (); + + virtual void draw (CDrawContext*); + virtual void mouse (CDrawContext *pContext, CPoint &where, long button = -1); + virtual bool onWheel (CDrawContext *pContext, const CPoint &where, float distance); + + CLASS_METHODS(CRockerSwitch, CControl) + +protected: + CPoint offset; + CCoord heightOfOneImage; + long style; +}; + + +//----------------------------------------------------------------------------- +// CMovieBitmap Declaration +//! a bitmap control that displays different bitmaps according to its current value +//----------------------------------------------------------------------------- +class CMovieBitmap : public CControl +{ +public: + CMovieBitmap (const CRect &size, CControlListener *listener, long tag, + CBitmap *background, CPoint &offset); + CMovieBitmap (const CRect &size, CControlListener *listener, long tag, + long subPixmaps, // number of subPixmaps + CCoord heightOfOneImage, // pixel + CBitmap *background, CPoint &offset); + virtual ~CMovieBitmap (); + + virtual void draw (CDrawContext*); + + CLASS_METHODS(CMovieBitmap, CControl) + +protected: + CPoint offset; + long subPixmaps; // number of subPixmaps + CCoord heightOfOneImage; +}; + + +//----------------------------------------------------------------------------- +// CMovieButton Declaration +//! a bi-states button with 2 subbitmaps +//----------------------------------------------------------------------------- +class CMovieButton : public CControl +{ +public: + CMovieButton (const CRect &size, CControlListener *listener, long tag, + CBitmap *background, CPoint &offset); + CMovieButton (const CRect &size, CControlListener *listener, long tag, + CCoord heightOfOneImage, // pixel + CBitmap *background, CPoint &offset); + virtual ~CMovieButton (); + + virtual void draw (CDrawContext*); + virtual void mouse (CDrawContext *pContext, CPoint &where, long button = -1); + + CLASS_METHODS(CMovieButton, CControl) + +protected: + CPoint offset; + CCoord heightOfOneImage; + float buttonState; +}; + + +//----------------------------------------------------------------------------- +// CAutoAnimation Declaration +//! +//----------------------------------------------------------------------------- +class CAutoAnimation : public CControl +{ +public: + CAutoAnimation (const CRect &size, CControlListener *listener, long tag, + CBitmap *background, CPoint &offset); + CAutoAnimation (const CRect &size, CControlListener *listener, long tag, + long subPixmaps, // number of subPixmaps... + CCoord heightOfOneImage, // pixel + CBitmap *background, CPoint &offset); + virtual ~CAutoAnimation (); + + virtual void draw (CDrawContext*); + virtual void mouse (CDrawContext *pContext, CPoint &where, long button = -1); + + virtual void openWindow (void); + virtual void closeWindow (void); + + virtual void nextPixmap (void); + virtual void previousPixmap (void); + + bool isWindowOpened () const { return bWindowOpened; } + + CLASS_METHODS(CAutoAnimation, CControl) + +protected: + CPoint offset; + + long subPixmaps; + CCoord heightOfOneImage; + CCoord totalHeightOfBitmap; + + bool bWindowOpened; +}; + + +//----------------------------------------------------------------------------- +// CSlider Declaration +//! a slider control +//----------------------------------------------------------------------------- +class CSlider : public CControl +{ +public: + CSlider (const CRect &size, CControlListener *listener, long tag, + long iMinPos, // min position in pixel + long iMaxPos, // max position in pixel + CBitmap *handle, // handle bitmap + CBitmap *background, // background bitmap + CPoint &offset, // offset in the background + const long style = kLeft|kHorizontal); // style (kBottom,kRight,kTop,kLeft,kHorizontal,kVertical) + + CSlider (const CRect &rect, CControlListener *listener, long tag, + CPoint &offsetHandle, // handle offset + long rangeHandle, // size of handle range + CBitmap *handle, // handle bitmap + CBitmap *background, // background bitmap + CPoint &offset, // offset in the background + const long style = kLeft|kHorizontal); // style (kBottom,kRight,kTop,kLeft,kHorizontal,kVertical) + + virtual ~CSlider (); + + virtual bool attached (CView *parent); + virtual bool removed (CView *parent); + virtual void draw (CDrawContext*); + virtual void mouse (CDrawContext *pContext, CPoint &where, long button = -1); + virtual bool onWheel (CDrawContext *pContext, const CPoint &where, float distance); + virtual long onKeyDown (VstKeyCode& keyCode); + + virtual void setDrawTransparentHandle (bool val) { bDrawTransparentEnabled = val; } + virtual void setFreeClick (bool val) { bFreeClick = val; } + virtual bool getFreeClick () const { return bFreeClick; } + virtual void setOffsetHandle (CPoint &val); + + virtual void setHandle (CBitmap* pHandle); + virtual CBitmap *getHandle () const { return pHandle; } + + virtual void setZoomFactor (float val) { zoomFactor = val; } + virtual float getZoomFactor () const { return zoomFactor; } + + CLASS_METHODS(CSlider, CControl) + +protected: + CPoint offset; + CPoint offsetHandle; + + CBitmap *pHandle; + COffscreenContext *pOScreen; + + long style; + + CCoord widthOfSlider; // size of the handle-slider + CCoord heightOfSlider; + CCoord rangeHandle; + CCoord minTmp; + CCoord maxTmp; + CCoord minPos; + CCoord widthControl; + CCoord heightControl; + float zoomFactor; + + bool bDrawTransparentEnabled; + bool bFreeClick; +}; + +//----------------------------------------------------------------------------- +// CVerticalSlider Declaration +//! a vertical slider control +//----------------------------------------------------------------------------- +class CVerticalSlider : public CSlider +{ +public: + CVerticalSlider (const CRect &size, CControlListener *listener, long tag, + long iMinPos, // min Y position in pixel + long iMaxPos, // max Y position in pixel + CBitmap *handle, // bitmap slider + CBitmap *background, // bitmap background + CPoint &offset, // offset in the background + const long style = kBottom); // style (kBottom, kTop)) + + CVerticalSlider (const CRect &rect, CControlListener *listener, long tag, + CPoint &offsetHandle, // handle offset + long rangeHandle, // size of handle range + CBitmap *handle, // bitmap of slider + CBitmap *background, // bitmap of background + CPoint &offset, // offset in the background + const long style = kBottom); // style (kBottom, kTop) +}; + +//----------------------------------------------------------------------------- +// CHorizontalSlider Declaration +//! a horizontal slider control +//----------------------------------------------------------------------------- +class CHorizontalSlider : public CSlider +{ +public: + CHorizontalSlider (const CRect &size, CControlListener *listener, long tag, + long iMinPos, // min X position in pixel + long iMaxPos, // max X position in pixel + CBitmap *handle, // bitmap slider + CBitmap *background, // bitmap background + CPoint &offset, // offset in the background + const long style = kRight); // style (kRight, kLeft) + + CHorizontalSlider (const CRect &rect, CControlListener *listener, long tag, + CPoint &offsetHandle, // handle offset + long rangeHandle, // size of handle range + CBitmap *handle, // bitmap of slider + CBitmap *background, // bitmap of background + CPoint &offset, // offset in the background + const long style = kRight); // style (kRight, kLeft) +}; + + +//----------------------------------------------------------------------------- +// CSpecialDigit Declaration +//! special display with custom numbers (0...9) +//----------------------------------------------------------------------------- +class CSpecialDigit : public CControl +{ +public: + CSpecialDigit (const CRect &size, CControlListener *listener, long tag, // tag identifier + long dwPos, // actual value + long iNumbers, // amount of numbers (max 7) + long *xpos, // array of all XPOS + long *ypos, // array of all YPOS + long width, // width of ONE number + long height, // height of ONE number + CBitmap *background); // bitmap numbers + virtual ~CSpecialDigit (); + + virtual void draw (CDrawContext*); + + virtual float getNormValue (void) const; + + CLASS_METHODS(CSpecialDigit, CControl) + +protected: + long iNumbers; // amount of numbers + long xpos[7]; // array of all XPOS, max 7 possible + long ypos[7]; // array of all YPOS, max 7 possible + long width; // width of ONE number + long height; // height of ONE number +}; + + +//----------------------------------------------------------------------------- +// CKickButton Declaration +//! +//----------------------------------------------------------------------------- +class CKickButton : public CControl +{ +public: + CKickButton (const CRect &size, CControlListener *listener, long tag, + CBitmap *background, CPoint &offset); + CKickButton (const CRect &size, CControlListener *listener, long tag, + CCoord heightOfOneImage, // pixel + CBitmap *background, CPoint &offset); + virtual ~CKickButton (); + + virtual void draw (CDrawContext*); + virtual void mouse (CDrawContext *pContext, CPoint &where, long button = -1); + + CLASS_METHODS(CKickButton, CControl) + +protected: + CPoint offset; + CCoord heightOfOneImage; +}; + + +//----------------------------------------------------------------------------- +// CSplashScreen Declaration +//! +//----------------------------------------------------------------------------- +class CSplashScreen : public CControl +{ +public: + CSplashScreen (const CRect &size, CControlListener *listener, long tag, + CBitmap *background, + CRect &toDisplay, + CPoint &offset); + virtual ~CSplashScreen (); + + virtual void draw (CDrawContext*); + virtual bool hitTest (const CPoint& where, const long buttons = -1); + virtual void mouse (CDrawContext *pContext, CPoint &where, long button = -1); + virtual void unSplash (); + + void setBitmapTransparency (unsigned char transparency); + + CLASS_METHODS(CSplashScreen, CControl) + +protected: + CRect toDisplay; + CRect keepSize; + CPoint offset; + unsigned char bitmapTransparency; +}; + + +//----------------------------------------------------------------------------- +// CVuMeter Declaration +//! +//----------------------------------------------------------------------------- +class CVuMeter : public CControl +{ +public: + CVuMeter (const CRect& size, CBitmap *onBitmap, CBitmap *offBitmap, + long nbLed, const long style = kVertical); + virtual ~CVuMeter (); + + virtual void setDecreaseStepValue (float value) { decreaseValue = value; } + + virtual bool attached (CView *parent); + virtual bool removed (CView *parent); + virtual void draw (CDrawContext *pContext); + virtual void setDirty (const bool val = true); + + void setUseOffscreen (bool val = true); + bool getUseOffscreen () const { return bUseOffscreen; } + + CLASS_METHODS(CVuMeter, CControl) + +protected: + CBitmap *onBitmap; + CBitmap *offBitmap; + COffscreenContext *pOScreen; + + long nbLed; + long style; + float decreaseValue; + bool bUseOffscreen; + + CRect rectOn; + CRect rectOff; +}; + + +#if !PLUGGUI +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +class CFileSelector +{ +public: + CFileSelector (AudioEffectX* effect); + virtual ~CFileSelector (); + + long run (VstFileSelect *vstFileSelect); + +protected: + AudioEffectX* effect; + VstFileSelect *vstFileSelect; +}; +#endif + +} // namespace VSTGUI + +#endif // __vstcontrol__ diff --git a/vstgui/vstgui.cpp b/vstgui/vstgui.cpp new file mode 100644 index 0000000..ab52007 --- /dev/null +++ b/vstgui/vstgui.cpp @@ -0,0 +1,3996 @@ +/* ---------------------------------------------------------------------------- + * VSTGUI for X11/LV2/PNG + * Author: Dave Robillard + * Released under the revised BSD license, as below + * ---------------------------------------------------------------------------- + * + * Based on: + * ---------------------------------------------------------------------------- + * VSTGUIL: Graphical User Interface Framework for VST plugins on LINUX + * Version: 0.1, Date: 2007/01/21 + * Author: kRAkEn/gORe + * + * Which was based on: + * ---------------------------------------------------------------------------- + * VSTGUI: Graphical User Interface Framework for VST plugins + * Version 3.0 $Date: 2005/08/12 12:45:00 $ + * ---------------------------------------------------------------------------- + * VSTGUI LICENSE + * 2004, Steinberg Media Technologies, All Rights Reserved + * ---------------------------------------------------------------------------- + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Steinberg Media Technologies nor the names of + * its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#include +#include +#include +#include +#include + +#include "vstgui.h" +#include "audioeffectx.h" +#include "vstkeycode.h" + +//----------------------------------------------------------------------------- +// Some defines +//----------------------------------------------------------------------------- +#ifdef DEBUG + #define DBG(x) std::cout << x << std::endl; + #define assertfalse assert (false); +#else + #define DBG(x) + #define assertfalse +#endif + +#define USE_ALPHA_BLEND 0 +#define USE_CLIPPING_DRAWRECT 1 +#define NEW_UPDATE_MECHANISM 1 + + +//----------------------------------------------------------------------------- +// our global display +Display* display = 0; + + +//----------------------------------------------------------------------------- +// AEffGUIEditor Implementation +//----------------------------------------------------------------------------- +#define kIdleRate 100 // host idle rate in ms +#define kIdleRate2 50 +#define kIdleRateMin 4 // minimum time between 2 idles in ms + +//----------------------------------------------------------------------------- +VstInt32 AEffGUIEditor::knobMode = kCircularMode; + +//----------------------------------------------------------------------------- +AEffGUIEditor::AEffGUIEditor (AudioEffect* effect) +: AEffEditor (effect), + lLastTicks (0), + inIdleStuff (false), + bundlePath(NULL), + frame (0) +{ + rect.left = rect.top = rect.right = rect.bottom = 0; + lLastTicks = getTicks (); + + effect->setEditor (this); +} + +//----------------------------------------------------------------------------- +AEffGUIEditor::~AEffGUIEditor () +{ +} + +//----------------------------------------------------------------------------- +void AEffGUIEditor::setParameter (VstInt32 index, float value) +{} + +//----------------------------------------------------------------------------- +void AEffGUIEditor::beginEdit (VstInt32 index) +{ + ((AudioEffectX*)effect)->beginEdit (index); +} + +//----------------------------------------------------------------------------- +void AEffGUIEditor::endEdit (VstInt32 index) +{ + ((AudioEffectX*)effect)->endEdit (index); +} + +//----------------------------------------------------------------------------- +#if VST_2_1_EXTENSIONS +long AEffGUIEditor::onKeyDown (VstKeyCode& keyCode) +{ + return frame && frame->onKeyDown (keyCode) == 1 ? 1 : 0; +} + +//----------------------------------------------------------------------------- +long AEffGUIEditor::onKeyUp (VstKeyCode& keyCode) +{ + return frame && frame->onKeyUp (keyCode) == 1 ? 1 : 0; +} + +//----------------------------------------------------------------------------- +long AEffGUIEditor::setKnobMode (VstInt32 val) +{ + knobMode = val; + return 1; +} + +//----------------------------------------------------------------------------- +bool AEffGUIEditor::onWheel (float distance) +{ +/* + if (frame) + { + CDrawContext context (frame, NULL, systemWindow); + CPoint where; + context.getMouseLocation (where); + return frame->onWheel (&context, where, distance); + } +*/ + return false; +} +#endif + +//----------------------------------------------------------------------------- +long AEffGUIEditor::getRect (ERect **ppErect) +{ + *ppErect = ▭ + return 1; +} + +//----------------------------------------------------------------------------- +void AEffGUIEditor::idle () +{ + if (inIdleStuff) + return; + + AEffEditor::idle (); + if (frame) + frame->idle (); +} + +//----------------------------------------------------------------------------- +void AEffGUIEditor::wait (unsigned int ms) +{ + usleep (ms * 1000); +} + +//----------------------------------------------------------------------------- +unsigned int AEffGUIEditor::getTicks () +{ + return _getTicks (); +} + +//----------------------------------------------------------------------------- +void AEffGUIEditor::doIdleStuff () +{ + // get the current time + unsigned int currentTicks = getTicks (); + + // YG TEST idle (); + if (currentTicks < lLastTicks) + { + wait (kIdleRateMin); + + currentTicks += kIdleRateMin; + if (currentTicks < lLastTicks - kIdleRate2) + return; + } + + idle (); + + // save the next time + lLastTicks = currentTicks + kIdleRate; + + inIdleStuff = true; + + if (effect) + effect->masterIdle (); + + inIdleStuff = false; +} + +void AEffGUIEditor::update () +{ + if (frame) + frame->invalidate (CRect (0, 0, rect.right, rect.bottom)); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +//---For Debugging------------------------ +#if DEBUG +long gNbCBitmap = 0; +long gNbCView = 0; +long gNbCDrawContext = 0; +long gNbCOffscreenContext = 0; +long gBitmapAllocation = 0; +long gNbDC = 0; +#include +void DebugPrint (const char *format, ...); +void DebugPrint (const char *format, ...) +{ + char string[300]; + va_list marker; + va_start (marker, format); + vsprintf (string, format, marker); + if (!strcmp(string, "")) + strcpy (string, "Empty string\n"); + fprintf (stderr, string); +} +#endif +//---End For Debugging------------------------ + +#include +#include +#include +#include +#include +#include + +#define XDRAWPARAM display, (Window)pWindow, (GC) pSystemContext +#define XWINPARAM display, (Window)pFrame->getWindow() +#define XGCPARAM display, (GC) pSystemContext + +// #define XDRAWPARAM display, (Window)pWindow, (GC)pSystemContext +// #define XWINPARAM display, (Window)pWindow +// #define XGCPARAM display, (GC)pSystemContext + +// init the static variable about font +bool gFontInit = false; +XFontStruct *gFontStructs[] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; + +struct SFontTable { const char* name; const char* string; }; + +static SFontTable gFontTable[] = { + {"SystemFont", "-*-fixed-*-*-*--12-*-*-*-*-*-*-*"}, // kSystemFont + {"NormalFontVeryBig", "-*-fixed-*-*-*--18-*-*-*-*-*-*-*"}, // kNormalFontVeryBig + {"NormalFontBig", "-*-fixed-*-*-*--18-*-*-*-*-*-*-*"}, // kNormalFontBig + {"NormalFont", "-*-fixed-*-*-*--12-*-*-*-*-*-*-*"}, // kNormalFont + {"NormalFontSmall", "-*-courier-*-*-*--10-*-*-*-*-*-*-*"}, // kNormalFontSmall + {"NormalFontSmaller", "-*-courier-*-*-*--9-*-*-*-*-*-*-*"}, // kNormalFontSmaller + {"NormalFontVerySmall", "-*-courier-*-*-*--8-*-*-*-*-*-*-*"}, // kNormalFontVerySmall + {"SymbolFont", "-*-fixed-*-*-*--12-*-*-*-*-*-*-*"} // kSymbolFont +}; + +long gStandardFontSize[] = { 12, 18, 18, 12, 10, 9, 8, 13 }; + +// declaration of different local functions +static long convertPoint2Angle (CPoint &pm, CPoint &pt); + +// stuff for color +long CDrawContext::nbNewColor = 0; + +//----------------------------------------------------------------------------- +bool CRect::pointInside (const CPoint& where) const +{ + return where.h >= left && where.h < right && where.v >= top && where.v < bottom; +} + +//----------------------------------------------------------------------------- +bool CRect::isEmpty () const +{ + if (right <= left) + return true; + if (bottom <= top) + return true; + return false; +} + +//----------------------------------------------------------------------------- +void CRect::bound (const CRect& rect) +{ + if (left < rect.left) + left = rect.left; + if (top < rect.top) + top = rect.top; + if (right > rect.right) + right = rect.right; + if (bottom > rect.bottom) + bottom = rect.bottom; + if (bottom < top) + bottom = top; + if (right < left) + right = left; +} + +namespace VSTGUI { + +CColor kTransparentCColor = {255, 255, 255, 0}; +CColor kBlackCColor = { 0, 0, 0, 255}; +CColor kWhiteCColor = {255, 255, 255, 255}; +CColor kGreyCColor = {127, 127, 127, 255}; +CColor kRedCColor = {255, 0, 0, 255}; +CColor kGreenCColor = { 0, 255, 0, 255}; +CColor kBlueCColor = { 0, 0, 255, 255}; +CColor kYellowCColor = {255, 255, 0, 255}; +CColor kMagentaCColor = {255, 0, 255, 255}; +CColor kCyanCColor = { 0, 255, 255, 255}; + +#define kDragDelay 0 + +//----------------------------------------------------------------------------- +// CDrawContext Implementation +//----------------------------------------------------------------------------- +/** + * CDrawContext constructor. + * @param inFrame the parent CFrame + * @param inSystemContext the platform system context, can be NULL + * @param inWindow the platform window object + */ +CDrawContext::CDrawContext (CFrame *inFrame, void *inSystemContext, void *inWindow) +: pSystemContext (inSystemContext) +, pWindow (inWindow) +, pFrame (inFrame) +, fontSize (-1) +, fontStyle (0) +, fontId (kNumStandardFonts) +, frameWidth (0) +, lineStyle (kLineOnOffDash) +, drawMode (kAntialias) +{ +#if DEBUG + gNbCDrawContext++; +#endif + + // initialize values + if (pFrame) + pFrame->getViewSize (clipRect); + else + clipRect (0, 0, 1000, 1000); + + const CColor notInitalized = {0, 0, 0, 0}; + frameColor = notInitalized; + fillColor = notInitalized; + fontColor = notInitalized; + + // offsets use by offscreen + offset (0, 0); + offsetScreen (0, 0); + + // set the current font + if (pSystemContext) + { + // set the default values + setFont (kNormalFont); + setFrameColor (kWhiteCColor); + setLineStyle (kLineSolid); + setLineWidth (1); + setFont (kSystemFont); + setDrawMode (kCopyMode); + } +} + +//----------------------------------------------------------------------------- +CDrawContext::~CDrawContext () +{ +#if DEBUG + gNbCDrawContext--; +#endif +} + +//----------------------------------------------------------------------------- +void CDrawContext::setLineStyle (CLineStyle style) +{ + if (lineStyle == style) + return; + + lineStyle = style; + + long line_width; + long line_style; + if (frameWidth == 1) + line_width = 0; + else + line_width = frameWidth; + + switch (lineStyle) + { + case kLineOnOffDash: + line_style = LineOnOffDash; + break; + default: + line_style = LineSolid; + break; + } + + XSetLineAttributes (XGCPARAM, line_width, line_style, CapNotLast, JoinRound); +} + +//----------------------------------------------------------------------------- +void CDrawContext::setLineWidth (CCoord width) +{ + if (frameWidth == width) + return; + + frameWidth = width; + + setLineStyle (lineStyle); +} + +//----------------------------------------------------------------------------- +void CDrawContext::setDrawMode (CDrawMode mode) +{ + if (drawMode == mode) + return; + + drawMode = mode; + + long iMode = 0; + switch (drawMode) + { + case kXorMode : + iMode = GXinvert; + break; + case kOrMode : + iMode = GXor; + break; + default: + iMode = GXcopy; + } + + ((XGCValues*)pSystemContext)->function = iMode; + + XChangeGC (XGCPARAM, GCFunction, (XGCValues*)pSystemContext); +} + +//------------------------------------------------------------------------------ +void CDrawContext::setClipRect (const CRect &clip) +{ + CRect _clip (clip); + _clip.offset (offset.h, offset.v); + + if (clipRect == _clip) + return; + + clipRect = _clip; + + XRectangle r; + r.x = 0; + r.y = 0; + r.width = clipRect.right - clipRect.left + 1; + r.height = clipRect.bottom - clipRect.top + 1; + + XSetClipRectangles (XGCPARAM, clipRect.left, clipRect.top, &r, 1, Unsorted); +} + +//------------------------------------------------------------------------------ +void CDrawContext::resetClipRect () +{ + CRect newClip; + if (pFrame) + pFrame->getViewSize (newClip); + else + newClip (0, 0, 1000, 1000); + + setClipRect (newClip); + + clipRect = newClip; +} + +//----------------------------------------------------------------------------- +void CDrawContext::moveTo (const CPoint &_point) +{ + CPoint point (_point); + point.offset (offset.h, offset.v); + + penLoc = point; +} + +//----------------------------------------------------------------------------- +void CDrawContext::lineTo (const CPoint& _point) +{ + CPoint point (_point); + point.offset (offset.h, offset.v); + + CPoint start (penLoc); + CPoint end (point); + if (start.h == end.h) + { + if (start.v < -5) + start.v = -5; + else if (start.v > 10000) + start.v = 10000; + + if (end.v < -5) + end.v = -5; + else if (end.v > 10000) + end.v = 10000; + } + if (start.v == end.v) + { + if (start.h < -5) + start.h = -5; + else if (start.h > 10000) + start.h = 10000; + + if (end.h < -5) + end.h = -5; + else if (end.h > 10000) + end.h = 10000; + } + + XDrawLine (XDRAWPARAM, start.h, start.v, end.h, end.v); + + // keep trace of the new position + penLoc = point; +} + +//----------------------------------------------------------------------------- +void CDrawContext::drawLines (const CPoint* points, const long& numLines) +{ + // default implementation, when no platform optimized code is implemented + for (long i = 0; i < numLines * 2; i+=2) + { + moveTo (points[i]); + lineTo (points[i+1]); + } +} + +//----------------------------------------------------------------------------- +void CDrawContext::drawPolygon (const CPoint *pPoints, long numberOfPoints, const CDrawStyle drawStyle) +{ + if (drawStyle == kDrawFilled || drawStyle == kDrawFilledAndStroked) + fillPolygon (pPoints, numberOfPoints); + if (drawStyle == kDrawStroked || drawStyle == kDrawFilledAndStroked) + polyLine (pPoints, numberOfPoints); +} + +//----------------------------------------------------------------------------- +void CDrawContext::polyLine (const CPoint *pPoints, long numberOfPoints) +{ + XPoint* pt = (XPoint*)malloc (numberOfPoints * sizeof (XPoint)); + if (!pt) + return; + for (long i = 0; i < numberOfPoints; i++) + { + pt[i].x = (short)pPoints[i].h + offset.h; + pt[i].y = (short)pPoints[i].v + offset.v; + } + + XDrawLines (XDRAWPARAM, pt, numberOfPoints, CoordModeOrigin); + + free (pt); +} + +//----------------------------------------------------------------------------- +void CDrawContext::fillPolygon (const CPoint *pPoints, long numberOfPoints) +{ + // convert the points + XPoint* pt = (XPoint*)malloc (numberOfPoints * sizeof (XPoint)); + if (!pt) + return; + for (long i = 0; i < numberOfPoints; i++) + { + pt[i].x = (short)pPoints[i].h + offset.h; + pt[i].y = (short)pPoints[i].v + offset.v; + } + + XFillPolygon (XDRAWPARAM, pt, numberOfPoints, Convex, CoordModeOrigin); + + free (pt); +} + +//----------------------------------------------------------------------------- +void CDrawContext::drawRect (const CRect &_rect, const CDrawStyle drawStyle) +{ + CRect rect (_rect); + rect.offset (offset.h, offset.v); + + XDrawRectangle (XDRAWPARAM, rect.left, rect.top, rect.width (), rect.height ()); +} + +//----------------------------------------------------------------------------- +void CDrawContext::fillRect (const CRect &_rect) +{ + CRect rect (_rect); + rect.offset (offset.h, offset.v); + + // Don't draw boundary + XFillRectangle (XDRAWPARAM, rect.left + 1, rect.top + 1, rect.width () - 1, rect.height () - 1); +} + +//----------------------------------------------------------------------------- +void CDrawContext::drawEllipse (const CRect &_rect, const CDrawStyle drawStyle) +{ + CPoint point (_rect.left + (_rect.right - _rect.left) / 2, _rect.top); + drawArc (_rect, point, point); +} + +//----------------------------------------------------------------------------- +void CDrawContext::fillEllipse (const CRect &_rect) +{ + CRect rect (_rect); + rect.offset (offset.h, offset.v); + + // Don't draw boundary + CPoint point (_rect.left + ((_rect.right - _rect.left) / 2), _rect.top); + fillArc (_rect, point, point); +} + +//----------------------------------------------------------------------------- +void CDrawContext::drawPoint (const CPoint &_point, CColor color) +{ + CPoint point (_point); + + CColor oldframecolor = frameColor; + setFrameColor (color); + + XDrawPoint (XDRAWPARAM, point.h, point.v); + + setFrameColor (oldframecolor); +} + +//----------------------------------------------------------------------------- +CColor CDrawContext::getPoint (const CPoint& _point) +{ +// CPoint point (_point); +// point.offset (offset.h, offset.v); + + assertfalse // not implemented ! + + CColor color = kBlackCColor; + return color; +} + +//----------------------------------------------------------------------------- +void CDrawContext::floodFill (const CPoint& _start) +{ +// CPoint start (_start); +// start.offset (offset.h, offset.v); + + assertfalse // not implemented ! +} + +//----------------------------------------------------------------------------- +void CDrawContext::drawArc (const CRect &_rect, const float _startAngle, const float _endAngle, const CDrawStyle drawStyle) // in degree +{ + CRect rect (_rect); + rect.offset (offset.h, offset.v); + + XDrawArc (XDRAWPARAM, rect.left, rect.top, rect.width (), rect.height (), + (int) _startAngle * 64, (int) _endAngle * 64); +} + +//----------------------------------------------------------------------------- +void CDrawContext::drawArc (const CRect &_rect, const CPoint &_point1, const CPoint &_point2) +{ + CRect rect (_rect); + rect.offset (offset.h, offset.v); + CPoint point1 (_point1); + point1.offset (offset.h, offset.v); + CPoint point2 (_point2); + point2.offset (offset.h, offset.v); + + int angle1, angle2; + if ((point1.v == point2.v) && (point1.h == point2.h)) + { + angle1 = 0; + angle2 = 23040; // 360 * 64 + } + else + { + CPoint pm ((rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2); + angle1 = convertPoint2Angle (pm, point1); + angle2 = convertPoint2Angle (pm, point2) - angle1; + if (angle2 < 0) + angle2 += 23040; // 360 * 64 + } + + XDrawArc (XDRAWPARAM, rect.left, rect.top, rect.width (), rect.height (), + angle1, angle2); +} + +//----------------------------------------------------------------------------- +void CDrawContext::fillArc (const CRect &_rect, const CPoint &_point1, const CPoint &_point2) +{ + CRect rect (_rect); + rect.offset (offset.h, offset.v); + CPoint point1 (_point1); + point1.offset (offset.h, offset.v); + CPoint point2 (_point2); + point2.offset (offset.h, offset.v); + + // Don't draw boundary + int angle1, angle2; + if ((point1.v == point2.v) && (point1.h == point2.h)) + { + angle1 = 0; + angle2 = 23040; // 360 * 64 + } + else + { + CPoint pm ((rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2); + angle1 = convertPoint2Angle (pm, point1); + angle2 = convertPoint2Angle (pm, point2); + } + + XFillArc (XDRAWPARAM, rect.left, rect.top, rect.width (), rect.height (), + angle1, angle2); +} + +//----------------------------------------------------------------------------- +void CDrawContext::setFontColor (const CColor color) +{ + fontColor = color; + + setFrameColor (fontColor); +} + +//----------------------------------------------------------------------------- +void CDrawContext::setFrameColor (const CColor color) +{ + if (frameColor == color) + return; + + frameColor = color; + + XSetForeground (XGCPARAM, getIndexColor (frameColor)); +} + +//----------------------------------------------------------------------------- +void CDrawContext::setFillColor (const CColor color) +{ + if (fillColor == color) + return; + + fillColor = color; + + // set the background for the text + //XSetBackground (XGCPARAM, getIndexColor (fillColor)); + XSetBackground (display, pFrame->getGC(), getIndexColor (fillColor)); + + // set the foreground for the fill + setFrameColor (fillColor); +} + +//----------------------------------------------------------------------------- +void CDrawContext::setFont (CFont fontID, const long size, long style) +{ + if (fontID < 0 || fontID >= kNumStandardFonts) + fontID = kSystemFont; + + if (fontId == fontID && fontSize == (size != 0 ? size : gStandardFontSize[fontID]) && fontStyle == style) + return; + + fontStyle = style; + fontId = fontID; + if (size != 0) + fontSize = size; + else + fontSize = gStandardFontSize[fontID]; + + if (gFontStructs[fontID] != NULL) + XSetFont (display, pFrame->getGC(), gFontStructs[fontID]->fid); + else + fprintf(stderr, "ERROR: Font not defined\n"); + + // keep trace of the current font + pFontInfoStruct = gFontStructs[fontID]; + +#ifdef DEBUG +// if (!pFontInfoStruct) assert (false); // fonts have invalid pointers ! +#endif +} + +//------------------------------------------------------------------------------ +CCoord CDrawContext::getStringWidth (const char *pStr) +{ + CCoord result = 0; + + result = (long) XTextWidth (pFontInfoStruct, pStr, strlen (pStr)); + + return result; +} + +//----------------------------------------------------------------------------- +void CDrawContext::drawString (const char *string, const CRect &_rect, + const short opaque, const CHoriTxtAlign hAlign) +{ + if (!string) + return; + + CRect rect (_rect); + rect.offset (offset.h, offset.v); + + int width; + int fontHeight = pFontInfoStruct->ascent + pFontInfoStruct->descent; + int xPos; + int yPos; + int rectHeight = rect.height (); + + if (rectHeight >= fontHeight) + yPos = rect.bottom - (rectHeight - fontHeight) / 2; + else + yPos = rect.bottom; + yPos -= pFontInfoStruct->descent; + + switch (hAlign) + { + case kCenterText: + width = XTextWidth (pFontInfoStruct, string, strlen (string)); + xPos = (rect.right + rect.left - width) / 2; + break; + + case kRightText: + width = XTextWidth (pFontInfoStruct, string, strlen (string)); + xPos = rect.right - width; + break; + + default: // left adjust + xPos = rect.left + 1; + } + + if (opaque) + XDrawImageString (XDRAWPARAM, xPos, yPos, string, strlen (string)); + else + XDrawString (XDRAWPARAM, xPos, yPos, string, strlen (string)); +} + +//----------------------------------------------------------------------------- +long CDrawContext::getMouseButtons () +{ + long buttons = 0; + + Window root, child; + int rootX, rootY, childX, childY; + unsigned int mask; + + XQueryPointer (XWINPARAM, + &root, + &child, + &rootX, + &rootY, + &childX, + &childY, + &mask); + + if (mask & Button1Mask) + buttons |= kLButton; + if (mask & Button2Mask) + buttons |= kMButton; + if (mask & Button3Mask) + buttons |= kRButton; + + if (mask & ShiftMask) + buttons |= kShift; + if (mask & ControlMask) + buttons |= kControl; + if (mask & Mod1Mask) + buttons |= kAlt; + + return buttons; +} + +//----------------------------------------------------------------------------- +void CDrawContext::getMouseLocation (CPoint &point) +{ + Window root, child; + int rootX, rootY, childX, childY; + unsigned int mask; + + XQueryPointer (XWINPARAM, + &root, + &child, + &rootX, + &rootY, + &childX, + &childY, + &mask); + + point (childX, childY); + + point.offset (-offsetScreen.h, -offsetScreen.v); +} + +//----------------------------------------------------------------------------- +bool CDrawContext::waitDoubleClick () +{ + bool doubleClick = false; + + long currentTime = _getTicks (); + long clickTime = currentTime + 200; // XtGetMultiClickTime (display); + + XEvent e; + while (currentTime < clickTime) + { + if (XCheckTypedEvent (display, ButtonPress, &e)) + { + doubleClick = true; + break; + } + + currentTime = _getTicks (); + } + + return doubleClick; +} + +//----------------------------------------------------------------------------- +bool CDrawContext::waitDrag () +{ + if (!pFrame) + return false; + + CPoint mouseLoc; + getMouseLocation (mouseLoc); + CRect observe (mouseLoc.h - 2, mouseLoc.v - 2, mouseLoc.h + 2, mouseLoc.v + 2); + + long currentTime = pFrame->getTicks (); + bool wasOutside = false; + + while (((getMouseButtons () & ~(kMButton|kRButton)) & kLButton) != 0) + { + pFrame->doIdleStuff (); + if (!wasOutside) + { + getMouseLocation (mouseLoc); + if (!observe.pointInside (mouseLoc)) + { + if (kDragDelay <= 0) + return true; + wasOutside = true; + } + } + + if (wasOutside && (pFrame->getTicks () - currentTime > kDragDelay)) + return true; + } + return false; +} + +//----------------------------------------------------------------------------- +void CDrawContext::forget () +{ + CReferenceCounter::forget (); +} + +//----------------------------------------------------------------------------- +long CDrawContext::getIndexColor (CColor color) +{ + XColor xcol; + xcol.red = color.red << 8; + xcol.green = color.green << 8; + xcol.blue = color.blue << 8; + xcol.flags = (DoRed | DoGreen | DoBlue); + XAllocColor (display, XDefaultColormap (display, 0), &xcol); + return xcol.pixel; +} + +//----------------------------------------------------------------------------- +Colormap CDrawContext::getColormap () +{ + if (pFrame) + return pFrame->getColormap (); + else + return None; +} + +//----------------------------------------------------------------------------- +Visual* CDrawContext::getVisual () +{ + if (pFrame) + return pFrame->getVisual (); + else + return None; +} + +//----------------------------------------------------------------------------- +unsigned int CDrawContext::getDepth () +{ + if (pFrame) + return pFrame->getDepth (); + else + return None; +} + + +//----------------------------------------------------------------------------- +// COffscreenContext Implementation +//----------------------------------------------------------------------------- +COffscreenContext::COffscreenContext (CDrawContext *pContext, CBitmap *pBitmapBg, bool drawInBitmap) +: CDrawContext (pContext->pFrame, NULL, NULL) +, pBitmap (0) +, pBitmapBg (pBitmapBg) +, height (20) +, width (20) +{ + std::cout << "COffscreenContext::COffscreenContext with bitmap" << std::endl; + + if (pBitmapBg) + { + height = pBitmapBg->getHeight (); + width = pBitmapBg->getWidth (); + + clipRect (0, 0, width, height); + } + +#if DEBUG + gNbCOffscreenContext++; + gBitmapAllocation += (long)height * (long)width; +#endif + + bDestroyPixmap = false; + +// Window root = RootWindow (display, DefaultScreen (display)); + + // if no bitmap handle => create one + if (! pWindow) + { + pWindow = (void*) XCreatePixmap (display, pFrame->getWindow(), width, height, pFrame->getDepth ()); + bDestroyPixmap = true; + } + + // set the current font + if (pSystemContext) + setFont (kNormalFont); + + if (!drawInBitmap) + { + // draw bitmap to Offscreen + CRect r (0, 0, width, height); + if (pBitmapBg) + pBitmapBg->draw (this, r); + else + { + setFillColor (kBlackCColor); + fillRect (r); + } + } +} + +//----------------------------------------------------------------------------- +COffscreenContext::COffscreenContext (CFrame *pFrame, long width, long height, const CColor backgroundColor) +: CDrawContext (pFrame, NULL, NULL) +, pBitmap (0) +, pBitmapBg (0) +, height (height) +, width (width) +, backgroundColor (backgroundColor) +{ + std::cout << "COffscreenContext::COffscreenContext without bitmap" << std::endl; + + clipRect (0, 0, width, height); + +#if DEBUG + gNbCOffscreenContext++; + gBitmapAllocation += height * width; +#endif + + bDestroyPixmap = true; + + pWindow = (void*) XCreatePixmap (display, + pFrame->getWindow(), + width, + height, + pFrame->getDepth ()); + +/* + // clear the pixmap + XGCValues values; + values.foreground = getIndexColor (backgroundColor); + GC gc = XCreateGC (display, (Window)pWindow, GCForeground, &values); + XFillRectangle (display, (Window)pWindow, gc, 0, 0, width, height); + XFreeGC (display, gc); +*/ + + XGCValues values; + values.foreground = getIndexColor (backgroundColor); + pSystemContext = XCreateGC (display, (Window)pWindow, GCForeground, &values); + XFillRectangle (display, (Window)pWindow, (GC) pSystemContext, 0, 0, width, height); + + // set the current font + if (pSystemContext) + setFont (kNormalFont); +} + +//----------------------------------------------------------------------------- +COffscreenContext::~COffscreenContext () +{ +#if DEBUG + gNbCOffscreenContext--; + gBitmapAllocation -= (long)height * (long)width; +#endif + + if (pBitmap) + pBitmap->forget (); + + if (bDestroyPixmap && pWindow) + XFreePixmap (display, (Pixmap)pWindow); + + if (pSystemContext) + XFreeGC (display, (GC) pSystemContext); +} + +//----------------------------------------------------------------------------- +void COffscreenContext::copyTo (CDrawContext* pContext, CRect& srcRect, CPoint destOffset) +{ + std::cout << "COffscreenContext::copyTo" << std::endl; + + XCopyArea (display, + (Drawable) pContext->pWindow, + (Drawable) pWindow, + (GC) pSystemContext, + srcRect.left, + srcRect.top, + srcRect.width (), + srcRect.height (), + destOffset.h, + destOffset.v); +} + +//----------------------------------------------------------------------------- +void COffscreenContext::copyFrom (CDrawContext *pContext, CRect destRect, CPoint srcOffset) +{ + //std::cout << "COffscreenContext::copyFrom "; + + XCopyArea (display, + (Drawable) pContext->pWindow, + (Drawable) pWindow, + (GC) pSystemContext, + srcOffset.h, + srcOffset.v, + destRect.width(), + destRect.height(), + destRect.left, + destRect.top); + + pContext->setFrameColor (kRedCColor); + pContext->drawRect (destRect); +} + + +//----------------------------------------------------------------------------- +class CAttributeListEntry +{ +public: + CAttributeListEntry (long size, CViewAttributeID id) + : nextEntry (0) + , pointer (0) + , sizeOfPointer (size) + , id (id) + { + pointer = malloc (size); + } + + ~CAttributeListEntry () + { + if (pointer) + free (pointer); + } + + CViewAttributeID getID () const { return id; } + long getSize () const { return sizeOfPointer; } + void* getPointer () const { return pointer; } + CAttributeListEntry* getNext () const { return nextEntry; } + + void setNext (CAttributeListEntry* entry) { nextEntry = entry; } + +protected: + CAttributeListEntry () : nextEntry (0), pointer (0), sizeOfPointer (0), id (0) {} + + CAttributeListEntry* nextEntry; + void* pointer; + long sizeOfPointer; + CViewAttributeID id; +}; + +//----------------------------------------------------------------------------- +const char* kMsgCheckIfViewContainer = "kMsgCheckIfViewContainer"; + +//----------------------------------------------------------------------------- +// CView +//----------------------------------------------------------------------------- +/*! @class CView +base class of all view objects +*/ +//----------------------------------------------------------------------------- +CView::CView (const CRect& size) +: size (size) +, mouseableArea (size) +, pParentFrame (0) +, pParentView (0) +, bDirty (false) +, bMouseEnabled (true) +, bTransparencyEnabled (false) +, bWantsFocus (false) +, bVisible (true) +, pBackground (0) +, pAttributeList (0) +{ +#if DEBUG + gNbCView++; +#endif +} + +//----------------------------------------------------------------------------- +CView::~CView () +{ + if (pBackground) + pBackground->forget (); + + if (pAttributeList) + { + CAttributeListEntry* entry = pAttributeList; + while (entry) + { + CAttributeListEntry* nextEntry = entry->getNext (); + delete entry; + entry = nextEntry; + } + } +#if DEBUG + gNbCView--; +#endif +} + +//----------------------------------------------------------------------------- +void CView::getMouseLocation (CDrawContext* context, CPoint &point) +{ + if (context) + { + if (pParentView && pParentView->notify (this, kMsgCheckIfViewContainer) == kMessageNotified) + { + CCoord save[4]; + ((CViewContainer*)pParentView)->modifyDrawContext (save, context); + pParentView->getMouseLocation (context, point); + ((CViewContainer*)pParentView)->restoreDrawContext (context, save); + } + else + context->getMouseLocation (point); + } +} + +//----------------------------------------------------------------------------- +CPoint& CView::frameToLocal (CPoint& point) const +{ + if (pParentView && pParentView->isTypeOf ("CViewContainer")) + return pParentView->frameToLocal (point); + return point; +} + +//----------------------------------------------------------------------------- +CPoint& CView::localToFrame (CPoint& point) const +{ + if (pParentView && pParentView->isTypeOf ("CViewContainer")) + return pParentView->localToFrame (point); + return point; +} + +//----------------------------------------------------------------------------- +void CView::redraw () +{ + if (pParentFrame) + pParentFrame->draw (this); +} + +//----------------------------------------------------------------------------- +void CView::redrawRect (CDrawContext* context, const CRect& rect) +{ + if (pParentView) + pParentView->redrawRect (context, rect); + else if (pParentFrame) + pParentFrame->drawRect (context, rect); +} + +//----------------------------------------------------------------------------- +void CView::draw (CDrawContext *pContext) +{ + if (pBackground) + { + if (bTransparencyEnabled) + pBackground->drawTransparent (pContext, size); + else + pBackground->draw (pContext, size); + } + setDirty (false); +} + +//----------------------------------------------------------------------------- +void CView::mouse (CDrawContext *pContext, CPoint &where, long buttons) +{} + +//----------------------------------------------------------------------------- +bool CView::onWheel (CDrawContext *pContext, const CPoint &where, float distance) +{ + return false; +} + +//------------------------------------------------------------------------ +bool CView::onWheel (CDrawContext *pContext, const CPoint &where, const CMouseWheelAxis axis, float distance) +{ + return onWheel (pContext, where, distance); +} + +//------------------------------------------------------------------------ +void CView::update (CDrawContext *pContext) +{ + if (isDirty ()) + { +#if NEW_UPDATE_MECHANISM + if (pContext) + redrawRect (pContext, size); + else + redraw (); +#else + #if USE_ALPHA_BLEND + if (pContext) + { + if (bTransparencyEnabled) + getFrame ()->drawRect (pContext, size); + else + draw (pContext); + } + #else + if (pContext) + draw (pContext); + #endif + else + redraw (); +#endif + setDirty (false); + } +} + +//------------------------------------------------------------------------------ +long CView::onKeyDown (VstKeyCode& keyCode) +{ + return -1; +} + +//------------------------------------------------------------------------------ +long CView::onKeyUp (VstKeyCode& keyCode) +{ + return -1; +} + +//------------------------------------------------------------------------------ +long CView::notify (CView* sender, const char* message) +{ + return kMessageUnknown; +} + +//------------------------------------------------------------------------------ +void CView::looseFocus (CDrawContext *pContext) +{} + +//------------------------------------------------------------------------------ +void CView::takeFocus (CDrawContext *pContext) +{} + +//------------------------------------------------------------------------------ +void CView::setViewSize (CRect &rect) +{ + size = rect; + setDirty (); +} + +//----------------------------------------------------------------------------- +void *CView::getEditor () const +{ + return pParentFrame ? pParentFrame->getEditor () : 0; +} + +//----------------------------------------------------------------------------- +void CView::setBackground (CBitmap *background) +{ + if (pBackground) + pBackground->forget (); + pBackground = background; + if (pBackground) + pBackground->remember (); + setDirty (true); +} + +//----------------------------------------------------------------------------- +const CViewAttributeID kCViewAttributeReferencePointer = (CViewAttributeID) "cvrp"; + +//----------------------------------------------------------------------------- +/** + * @param id the ID of the Attribute + * @param outSize on return the size of the attribute + */ +bool CView::getAttributeSize (const CViewAttributeID id, long& outSize) const +{ + if (pAttributeList) + { + CAttributeListEntry* entry = pAttributeList; + while (entry) + { + if (entry->getID () == id) + break; + entry = entry->getNext (); + } + if (entry) + { + outSize = entry->getSize (); + return true; + } + } + return false; +} + +//----------------------------------------------------------------------------- +/** + * @param id the ID of the Attribute + * @param inSize the size of the outData pointer + * @param outData a pointer where to copy the attribute data + * @param outSize the size in bytes which was copied into outData + */ +bool CView::getAttribute (const CViewAttributeID id, const long inSize, void* outData, long& outSize) const +{ + if (pAttributeList) + { + CAttributeListEntry* entry = pAttributeList; + while (entry) + { + if (entry->getID () == id) + break; + entry = entry->getNext (); + } + if (entry && inSize >= entry->getSize ()) + { + outSize = entry->getSize (); + memcpy (outData, entry->getPointer (), outSize); + return true; + } + } + return false; +} + +//----------------------------------------------------------------------------- +/** + * copies data into the attribute. If it does not exist, creates a new attribute. + * @param id the ID of the Attribute + * @param inSize the size of the outData pointer + * @param inData a pointer to the data + */ +bool CView::setAttribute (const CViewAttributeID id, const long inSize, void* inData) +{ + CAttributeListEntry* lastEntry = 0; + if (pAttributeList) + { + CAttributeListEntry* entry = pAttributeList; + while (entry) + { + if (entry->getID () == id) + break; + if (entry->getNext () == 0) + lastEntry = entry; + entry = entry->getNext (); + } + if (entry) + { + if (entry->getSize () >= inSize) + { + memcpy (entry->getPointer (), inData, inSize); + return true; + } + else + return false; + } + } + + // create a new attribute + CAttributeListEntry* newEntry = new CAttributeListEntry (inSize, id); + memcpy (newEntry->getPointer (), inData, inSize); + if (lastEntry) + lastEntry->setNext (newEntry); + else if (!pAttributeList) + pAttributeList = newEntry; + else + { + delete newEntry; + return false; + } + return true; +} + +#if DEBUG +//----------------------------------------------------------------------------- +void CView::dumpInfo () +{ + CRect viewRect = getViewSize (viewRect); + DebugPrint ("left:%4d, top:%4d, width:%4d, height:%4d ", viewRect.left, viewRect.top, viewRect.getWidth (), viewRect.getHeight ()); + if (getMouseEnabled ()) + DebugPrint ("(Mouse Enabled) "); + if (getTransparency ()) + DebugPrint ("(Transparent) "); + CRect mouseRect = getMouseableArea (mouseRect); + if (mouseRect != viewRect) + DebugPrint (" (Mouseable Area: left:%4d, top:%4d, width:%4d, height:%4d ", mouseRect.left, mouseRect.top, mouseRect.getWidth (), mouseRect.getHeight ()); +} +#endif + +#define FOREACHSUBVIEW for (CCView *pSv = pFirstView; pSv; pSv = pSv->pNext) {CView *pV = pSv->pView; +#define FOREACHSUBVIEW_REVERSE(reverse) for (CCView *pSv = reverse ? pLastView : pFirstView; pSv; pSv = reverse ? pSv->pPrevious : pSv->pNext) {CView *pV = pSv->pView; +#define ENDFOR } + +//----------------------------------------------------------------------------- +// CFrame Implementation +//----------------------------------------------------------------------------- +/*! @class CFrame +It creates a platform dependend view object. +On classic Mac OS it just draws into the provided window. +On Mac OS X it is a ControlRef. +On Windows it's a WS_CHILD Window. +*/ +CFrame::CFrame (const CRect &inSize, void *inSystemWindow, void *inEditor) +: CViewContainer (inSize, 0, 0) +, pEditor (inEditor) +, pModalView (0) +, pFocusView (0) +, bFirstDraw (true) +, bDropActive (false) +, bUpdatesDisabled (false) +, pSystemWindow ((Window)inSystemWindow) +, pFrameContext (0) +, bAddedWindow (false) +, defaultCursor (0) +{ + setOpenFlag (true); + + pParentFrame = this; + + depth = 0; + pVisual = 0; + window = 0; + gc = 0; + + if (display == NULL) + display = XOpenDisplay(NULL); + + initFrame ((void*)pSystemWindow); + backBuffer = XdbeAllocateBackBufferName(display, (Window)window, XdbeUndefined); + + XGCValues values; + values.foreground = 1; + gc = XCreateGC (display, (Window)backBuffer, GCForeground, &values); + + pFrameContext = new CDrawContext (this, gc, (void*)backBuffer); +} + +//----------------------------------------------------------------------------- +CFrame::~CFrame () +{ + if (pModalView) + removeView (pModalView, false); + + setCursor (kCursorDefault); + + setDropActive (false); + + if (pFrameContext) + pFrameContext->forget (); + + if (getOpenFlag ()) + close (); + + if (window) + XDestroyWindow (display, (Window) window); + window = 0; + + // remove callbacks to avoid undesirable update + if (gc) + freeGc (); +} + +//----------------------------------------------------------------------------- +bool CFrame::open () +{ + if (! window) + return false; + + XMapRaised (display, window); + + return getOpenFlag (); +} + +//----------------------------------------------------------------------------- +bool CFrame::close () +{ + if (!window || !getOpenFlag () || !pSystemWindow) + return false; + + XUnmapWindow (display, window); + + return true; +} + +//----------------------------------------------------------------------------- +bool xerror; +int errorHandler (Display *dp, XErrorEvent *e) +{ + xerror = true; + return 0; +} +int getProperty (Window handle, Atom atom) +{ + int result = 0, userSize; + unsigned long bytes, userCount; + unsigned char *data; + Atom userType; + xerror = false; + XErrorHandler olderrorhandler = XSetErrorHandler (errorHandler); + XGetWindowProperty (display, handle, atom, 0, 1, false, AnyPropertyType, + &userType, &userSize, &userCount, &bytes, &data); + if (xerror == false && userCount == 1) + result = *(int*)data; + XSetErrorHandler (olderrorhandler); + return result; +} + +void eventProc (XEvent* ev) +{ + CFrame* frame = (CFrame*) getProperty (ev->xany.window, XInternAtom (display, "_this", false)); + if (frame == 0) + return; + + switch (ev->type) + { + case ButtonPress: + { + CPoint where (ev->xbutton.x, ev->xbutton.y); + frame->mouse (frame->createDrawContext(), where); + break; + } + + case MotionNotify: + { + CPoint where (ev->xbutton.x, ev->xbutton.y); + frame->mouse (frame->createDrawContext(), where); + break; + } + + case ButtonRelease: + { + break; + } + + case Expose: + { + CRect rc (ev->xexpose.x, ev->xexpose.y, + ev->xexpose.x + ev->xexpose.width, ev->xexpose.y + ev->xexpose.height); + + while (XCheckTypedWindowEvent (display, ev->xexpose.window, Expose, ev)) + { + rc.left = std::min ((int) rc.left, ev->xexpose.x); + rc.top = std::min ((int) rc.top, ev->xexpose.y); + rc.right = std::max ((int) rc.right, ev->xexpose.x + ev->xexpose.width); + rc.bottom = std::max ((int) rc.bottom, ev->xexpose.y + ev->xexpose.height); + } + + frame->drawRect (0, rc); + break; + } + + case EnterNotify: + break; + + case LeaveNotify: + { + XCrossingEvent *xevent = (XCrossingEvent*) ev; + if (frame->getFocusView ()) + { + if (xevent->x < 0 || xevent->x >= frame->getWidth () + || xevent->y < 0 || xevent->y >= frame->getHeight ()) + { + // if button pressed => don't defocus + if (xevent->state & (Button1Mask | Button2Mask | Button3Mask)) + break; + + frame->getFocusView ()->looseFocus (); + frame->setFocusView (0); + } + } + break; + } + + case ConfigureNotify: + { + frame->draw (); // @XXX - keep out ? + break; + } + } +} + +//----------------------------------------------------------------------------- +bool CFrame::initFrame (void *systemWin) +{ + if (!systemWin) + return false; + + // window attributes + XSetWindowAttributes swa; + swa.override_redirect = false; + swa.background_pixmap = None; + swa.colormap = 0; + swa.event_mask = + StructureNotifyMask | ExposureMask | KeyPressMask | KeyReleaseMask | + ButtonPressMask | ButtonReleaseMask | FocusChangeMask | PointerMotionMask | + EnterWindowMask | LeaveWindowMask | PropertyChangeMask; + + // create child window of host supplied window + window = XCreateWindow (display, (Window)systemWin, + 0, 0, size.width(), size.height(), + 0, CopyFromParent, InputOutput, (Visual*) CopyFromParent, + CWEventMask | CWOverrideRedirect | CWColormap | CWBackPixmap | CWEventMask, &swa); + + XGrabButton (display, AnyButton, AnyModifier, window, False, + ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask, + GrabModeAsync, GrabModeAsync, None, None); + +#if 0 + // remove window caption/frame + #define MWM_HINTS_DECORATIONS (1L << 1) + #define PROP_MOTIF_WM_HINTS_ELEMENTS 5 + typedef struct + { + unsigned long flags; + unsigned long functions; + unsigned long decorations; + long inputMode; + unsigned long status; + } + PropMotifWmHints; + + PropMotifWmHints motif_hints; + motif_hints.flags = MWM_HINTS_DECORATIONS; + motif_hints.decorations = 0; + Atom prop = XInternAtom (display, "_MOTIF_WM_HINTS", True ); + XChangeProperty (display, window, prop, prop, 32, PropModeReplace, + (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS); +#endif + + Atom atom; + void* data = this; + atom = XInternAtom (display, "_this", false); + XChangeProperty (display, (Window)window, atom, atom, 32, + PropModeReplace, (unsigned char*)&data, 1); + + data = (void*)&eventProc; + atom = XInternAtom (display, "_XEventProc", false); + XChangeProperty (display, (Window)window, atom, atom, 32, + PropModeReplace, (unsigned char*)&data, 1); + + XGCValues values; + values.foreground = 1; + gc = XCreateGC (display, (Window)window, GCForeground, &values); + + // get the std colormap + XWindowAttributes attr; + XGetWindowAttributes (display, (Window) window, &attr); + colormap = attr.colormap; + pVisual = attr.visual; + depth = attr.depth; + + // init and load the fonts + if (! gFontInit) { + for (long i = 0; i < kNumStandardFonts; i++) { + DBG (gFontTable[i].string); + gFontStructs[i] = XLoadQueryFont (display, gFontTable[i].string); + assert (gFontStructs[i] != 0); + } + gFontInit = true; + } + + setDropActive (true); + bAddedWindow = true; + + //XReparentWindow (display, window, (Window) systemWin, 0, 0); + //XMapRaised (display, window); + + return true; +} + +//----------------------------------------------------------------------------- +bool CFrame::setDropActive (bool val) +{ + if (!bDropActive && !val) + return true; + + bDropActive = val; + return true; +} + +//----------------------------------------------------------------------------- +void CFrame::freeGc () +{ + XFreeGC (display, gc); +} + +//----------------------------------------------------------------------------- +CDrawContext* CFrame::createDrawContext () +{ + if (pFrameContext) + { + pFrameContext->remember (); + return pFrameContext; + } + + pFrameContext = new CDrawContext (this, gc, (void*)window); + + return pFrameContext; +} + +//----------------------------------------------------------------------------- +void CFrame::draw (CDrawContext *pContext) +{ + if (bFirstDraw) + bFirstDraw = false; + + bool localContext = false; + if (! pContext) + { + localContext = true; + pContext = createDrawContext (); + } + + // draw the background and the children + CViewContainer::draw (pContext); + + if (localContext) + pContext->forget (); +} + +//----------------------------------------------------------------------------- +void CFrame::drawRect (CDrawContext *pContext, const CRect& updateRect) +{ + if (bFirstDraw) + bFirstDraw = false; + + bool localContext = false; + if (! pContext) + { + localContext = true; + pContext = createDrawContext (); + } + +#if USE_CLIPPING_DRAWRECT + CRect oldClip; + pContext->getClipRect (oldClip); + CRect newClip (updateRect); + newClip.bound (oldClip); + pContext->setClipRect (newClip); +#endif + + // draw the background and the children + if (updateRect.getWidth () > 0 && updateRect.getHeight () > 0) + CViewContainer::drawRect (pContext, updateRect); + +#if USE_CLIPPING_DRAWRECT + pContext->setClipRect (oldClip); +#endif + + if (localContext) + pContext->forget (); +} + +//----------------------------------------------------------------------------- +void CFrame::draw (CView *pView) +{ + CView *pViewToDraw = 0; + + // Search it in the view list + if (pView && isChild(pView)) + pViewToDraw = pView; + + CDrawContext *pContext = createDrawContext (); + if (pContext) + { + if (pViewToDraw && pViewToDraw->isVisible()) + pViewToDraw->draw (pContext); + else + draw (pContext); + + pContext->forget (); + } +} + +//----------------------------------------------------------------------------- +void CFrame::mouse (CDrawContext *pContext, CPoint &where, long buttons) +{ +/* + XGrabPointer (display, + window, + False, + ButtonPressMask | ButtonReleaseMask | + EnterWindowMask | LeaveWindowMask | + PointerMotionMask | Button1MotionMask | + Button2MotionMask | Button3MotionMask | + Button4MotionMask | Button5MotionMask, + GrabModeAsync, + GrabModeAsync, + None, + None, + CurrentTime); +*/ + + if (!pContext) + pContext = pFrameContext; + + if (pFocusView) + setFocusView (NULL); + + if (buttons == -1 && pContext) + buttons = pContext->getMouseButtons (); + + if (pModalView && pModalView->isVisible()) + { + if (pModalView->hitTest (where, buttons)) + pModalView->mouse (pContext, where, buttons); + } + else + { + CViewContainer::mouse (pContext, where, buttons); + } + +// XUngrabPointer (display, CurrentTime); +} + +//----------------------------------------------------------------------------- +long CFrame::onKeyDown (VstKeyCode& keyCode) +{ + long result = -1; + + if (pFocusView && pFocusView->isVisible()) + result = pFocusView->onKeyDown (keyCode); + + if (result == -1 && pModalView && pModalView->isVisible()) + result = pModalView->onKeyDown (keyCode); + + if (result == -1 && keyCode.virt == VKEY_TAB) + result = advanceNextFocusView (pFocusView, (keyCode.modifier & MODIFIER_SHIFT) ? true : false) ? 1 : -1; + + return result; +} + +//----------------------------------------------------------------------------- +long CFrame::onKeyUp (VstKeyCode& keyCode) +{ + long result = -1; + + if (pFocusView && pFocusView->isVisible()) + result = pFocusView->onKeyUp (keyCode); + + if (result == -1 && pModalView && pModalView->isVisible()) + result = pModalView->onKeyUp (keyCode); + + return result; +} + +//------------------------------------------------------------------------ +bool CFrame::onWheel (CDrawContext *pContext, const CPoint &where, const CMouseWheelAxis axis, float distance) +{ + bool result = false; + + CView *view = pModalView ? pModalView : getViewAt (where); + if (view && view->isVisible()) + { + bool localContext = false; + if (!pContext) + { + localContext = true; + pContext = createDrawContext (); + } + + result = view->onWheel (pContext, where, axis, distance); + + if (localContext) + pContext->forget (); + } + return result; +} + +//----------------------------------------------------------------------------- +bool CFrame::onWheel (CDrawContext *pContext, const CPoint &where, float distance) +{ + return onWheel (pContext, where, kMouseWheelAxisY, distance); +} + +//----------------------------------------------------------------------------- +void CFrame::update (CDrawContext *pContext) +{ + if (!getOpenFlag () || updatesDisabled ()) + return; + + CDrawContext* dc = pContext; + + if (bDirty) + { + draw (dc); + setDirty (false); + } + else + { +#if USE_CLIPPING_DRAWRECT + CRect oldClipRect; + dc->getClipRect (oldClipRect); +#endif +#if NEW_UPDATE_MECHANISM + if (pModalView && pModalView->isVisible () && pModalView->isDirty ()) + pModalView->update (dc); +#endif + FOREACHSUBVIEW +#if USE_CLIPPING_DRAWRECT + CRect viewSize (pV->size); + viewSize.bound (oldClipRect); + dc->setClipRect (viewSize); +#endif + pV->update (dc); + ENDFOR +#if USE_CLIPPING_DRAWRECT + dc->setClipRect (oldClipRect); +#endif + } +} + +//----------------------------------------------------------------------------- +void CFrame::idle () +{ + if (!getOpenFlag ()) + return; + + // don't do an idle before a draw + if (bFirstDraw) + return; + + if (!isDirty ()) + return; + + XdbeBeginIdiom(display); + XdbeSwapInfo swap_info; + swap_info.swap_window = window; + swap_info.swap_action = XdbeUndefined; + XdbeSwapBuffers(display, &swap_info, 1); + + CDrawContext *pContext = createDrawContext (); + + update (pContext); + + pContext->forget (); + + XdbeEndIdiom(display); +} + +//----------------------------------------------------------------------------- +void CFrame::doIdleStuff () +{ + if (pEditor) + ((AEffGUIEditor*)pEditor)->doIdleStuff (); +} + +//----------------------------------------------------------------------------- +unsigned long CFrame::getTicks () const +{ + if (pEditor) + return ((AEffGUIEditor*)pEditor)->getTicks (); + return 0; +} + +//----------------------------------------------------------------------------- +long CFrame::getKnobMode () const +{ + return AEffGUIEditor::getKnobMode (); +} + +//----------------------------------------------------------------------------- +bool CFrame::setPosition (CCoord x, CCoord y) +{ + size.left = 0; + size.top = 0; + + XWindowChanges attr; + attr.x = x; + attr.y = y; + + XConfigureWindow (display, window, CWX | CWY, &attr); + + return false; +} + +//----------------------------------------------------------------------------- +bool CFrame::getPosition (CCoord &x, CCoord &y) const +{ + x = size.left; + y = size.top; + return true; +} + +//----------------------------------------------------------------------------- +void CFrame::setViewSize (CRect& inRect) +{ + setSize (inRect.width (), inRect.height ()); +} + +//----------------------------------------------------------------------------- +bool CFrame::setSize (CCoord width, CCoord height) +{ + if ((width == size.width ()) && (height == size.height ())) + return false; + + // set the new size + size.right = size.left + width; + size.bottom = size.top + height; + + XResizeWindow (display, window, size.width (), size.height ()); + + CRect myViewSize (0, 0, size.width (), size.height ()); + CViewContainer::setViewSize (myViewSize); + + return true; +} + +//----------------------------------------------------------------------------- +bool CFrame::getSize (CRect *pRect) const +{ +// if (!getOpenFlag ()) +// return false; + + pRect->left = 0; + pRect->top = 0; + pRect->right = size.width () + pRect->left; + pRect->bottom = size.height () + pRect->top; + + return true; +} + +//----------------------------------------------------------------------------- +bool CFrame::getSize (CRect& outSize) const +{ + return getSize (&outSize); +} + +//----------------------------------------------------------------------------- +long CFrame::setModalView (CView *pView) +{ + // There's already a modal view so we get out + if (pView && pModalView) + return 0; + + if (pModalView) + removeView (pModalView, false); + + pModalView = pView; + if (pModalView) + addView (pModalView); + + return 1; +} + +//----------------------------------------------------------------------------- +void CFrame::beginEdit (long index) +{ + if (pEditor) + ((AEffGUIEditor*)pEditor)->beginEdit (index); +} + +//----------------------------------------------------------------------------- +void CFrame::endEdit (long index) +{ + if (pEditor) + ((AEffGUIEditor*)pEditor)->endEdit (index); +} + +//----------------------------------------------------------------------------- +CView *CFrame::getCurrentView () const +{ + if (pModalView) + return pModalView; + + return CViewContainer::getCurrentView (); +} + +//----------------------------------------------------------------------------- +bool CFrame::getCurrentLocation (CPoint &where) +{ + // create a local context + CDrawContext *pContext = createDrawContext (); + if (pContext) + { + // get the current position + pContext->getMouseLocation (where); + pContext->forget (); + } + return true; +} + +//----------------------------------------------------------------------------- +void CFrame::setCursor (CCursorType type) +{ +} + +//----------------------------------------------------------------------------- +void CFrame::setFocusView (CView *pView) +{ + if (pView && ! pView->isVisible()) + return; + + CView *pOldFocusView = pFocusView; + pFocusView = pView; + + if (pFocusView && pFocusView->wantsFocus ()) + pFocusView->setDirty (); + + if (pOldFocusView) + { + pOldFocusView->looseFocus (); + if (pOldFocusView->wantsFocus ()) + pOldFocusView->setDirty (); + } +} + +//----------------------------------------------------------------------------- +bool CFrame::advanceNextFocusView (CView* oldFocus, bool reverse) +{ + if (pModalView) + return false; // currently not supported, but should be done sometime + if (oldFocus == 0) + { + if (pFocusView == 0) + return CViewContainer::advanceNextFocusView (0, reverse); + oldFocus = pFocusView; + } + if (isChild (oldFocus)) + { + if (CViewContainer::advanceNextFocusView (oldFocus, reverse)) + return true; + else + { + setFocusView (NULL); + return false; + } + } + CView* parentView = oldFocus->getParentView (); + if (parentView && parentView->isTypeOf ("CViewContainer")) + { + CView* tempOldFocus = oldFocus; + CViewContainer* vc = (CViewContainer*)parentView; + while (vc) + { + if (vc->advanceNextFocusView (tempOldFocus, reverse)) + return true; + else + { + tempOldFocus = vc; + if (vc->getParentView () && vc->getParentView ()->isTypeOf ("CViewContainer")) + vc = (CViewContainer*)vc->getParentView (); + else + vc = 0; + } + } + } + return CViewContainer::advanceNextFocusView (oldFocus, reverse); +} + +//----------------------------------------------------------------------------- +void CFrame::invalidate (const CRect &rect) +{ + CRect rectView; + FOREACHSUBVIEW + if (pV) + { + pV->getViewSize (rectView); + if (rect.rectOverlap (rectView)) + pV->setDirty (true); + } + ENDFOR + + XClearArea (display, + window, + rect.left, + rect.top, + rect.right - rect.left, + rect.bottom - rect.top, + true); + + XSync (display, false); + +/* + XEvent ev; + memset (&ev, 0, sizeof (XEvent)); + ev.xexpose.type = Expose; + ev.xexpose.display = display; + ev.xexpose.window = (Window) window; + + ev.xexpose.x = rect.left; + ev.xexpose.y = rect.top; + ev.xexpose.width = rect.right - rect.left; + ev.xexpose.height = rect.bottom - rect.top; + + XSendEvent (display, (Window) window, False, 0L, &ev); + XFlush (display); +*/ +} + +#if DEBUG +//----------------------------------------------------------------------------- +void CFrame::dumpHierarchy () +{ + dumpInfo (); + DebugPrint ("\n"); + CViewContainer::dumpHierarchy (); +} +#endif + +//----------------------------------------------------------------------------- +// CCView Implementation +//----------------------------------------------------------------------------- +CCView::CCView (CView *pView) + : pView (pView), pNext (0), pPrevious (0) +{ + if (pView) + pView->remember (); +} + +//----------------------------------------------------------------------------- +CCView::~CCView () +{ + if (pView) + pView->forget (); +} + +//----------------------------------------------------------------------------- +// CViewContainer Implementation +//----------------------------------------------------------------------------- +/** + * CViewContainer constructor. + * @param rect the size of the container + * @param pParent the parent CFrame + * @param pBackground the background bitmap, can be NULL + */ +CViewContainer::CViewContainer (const CRect &rect, CFrame *pParent, CBitmap *pBackground) + : CView (rect), + pFirstView (0), + pLastView (0), + mode (kNormalUpdate), + pOffscreenContext (0), + bDrawInOffscreen (false), + currentDragView (0) +{ + pParentFrame = pParent; + + backgroundOffset (0, 0); + + setBackground (pBackground); + backgroundColor = kBlackCColor; + +#if NEW_UPDATE_MECHANISM + mode = kOnlyDirtyUpdate; +#endif +} + +//----------------------------------------------------------------------------- +CViewContainer::~CViewContainer () +{ + // remove all views + removeAll (true); + + if (pOffscreenContext) + pOffscreenContext->forget (); + pOffscreenContext = 0; +} + +//----------------------------------------------------------------------------- +/** + * @param rect the new size of the container + */ +void CViewContainer::setViewSize (CRect &rect) +{ + CView::setViewSize (rect); + + if (pOffscreenContext && bDrawInOffscreen) + { + pOffscreenContext->forget (); + pOffscreenContext = new COffscreenContext (pParentFrame, (long)size.width (), (long)size.height (), kBlackCColor); + } +} + +//----------------------------------------------------------------------------- +/** + * @param color the new background color of the container + */ +void CViewContainer::setBackgroundColor (CColor color) +{ + backgroundColor = color; + setDirty (true); +} + +//------------------------------------------------------------------------------ +long CViewContainer::notify (CView* sender, const char* message) +{ + if (message == kMsgCheckIfViewContainer) + return kMessageNotified; + return kMessageUnknown; +} + +//----------------------------------------------------------------------------- +/** + * @param pView the view object to add to this container + */ +void CViewContainer::addView (CView *pView) +{ + if (!pView) + return; + + CCView *pSv = new CCView (pView); + + pView->pParentFrame = pParentFrame; + pView->pParentView = this; + + CCView *pV = pFirstView; + if (!pV) + { + pLastView = pFirstView = pSv; + } + else + { + while (pV->pNext) + pV = pV->pNext; + pV->pNext = pSv; + pSv->pPrevious = pV; + pLastView = pSv; + } + pView->attached (this); + pView->setDirty (); +} + +//----------------------------------------------------------------------------- +/** + * @param pView the view object to add to this container + * @param mouseableArea the view area in where the view will get mouse events + * @param mouseEnabled bool to set if view will get mouse events + */ +void CViewContainer::addView (CView *pView, CRect &mouseableArea, bool mouseEnabled) +{ + if (!pView) + return; + + pView->setMouseEnabled (mouseEnabled); + pView->setMouseableArea (mouseableArea); + + addView (pView); +} + +//----------------------------------------------------------------------------- +/** + * @param withForget bool to indicate if the view's reference counter should be decreased after removed from the container + */ +void CViewContainer::removeAll (const bool &withForget) +{ + CCView *pV = pFirstView; + while (pV) + { + CCView *pNext = pV->pNext; + if (pV->pView) + { + pV->pView->removed (this); + if (withForget) + pV->pView->forget (); + } + + delete pV; + + pV = pNext; + } + pFirstView = 0; + pLastView = 0; +} + +//----------------------------------------------------------------------------- +/** + * @param pView the view which should be removed from the container + * @param withForget bool to indicate if the view's reference counter should be decreased after removed from the container + */ +void CViewContainer::removeView (CView *pView, const bool &withForget) +{ + if (pParentFrame && pParentFrame->getFocusView () == pView) + pParentFrame->setFocusView (0); + CCView *pV = pFirstView; + while (pV) + { + if (pView == pV->pView) + { + CCView *pNext = pV->pNext; + CCView *pPrevious = pV->pPrevious; + if (pV->pView) + { + pV->pView->removed (this); + if (withForget) + pV->pView->forget (); + } + delete pV; + if (pPrevious) + { + pPrevious->pNext = pNext; + if (pNext) + pNext->pPrevious = pPrevious; + else + pLastView = pPrevious; + } + else + { + pFirstView = pNext; + if (pNext) + pNext->pPrevious = 0; + else + pLastView = 0; + } + break; + } + else + pV = pV->pNext; + } +} + +//----------------------------------------------------------------------------- +/** + * @param pView the view which should be checked if it is a child of this container + */ +bool CViewContainer::isChild (CView *pView) const +{ + bool found = false; + + CCView *pV = pFirstView; + while (pV) + { + if (pView == pV->pView) + { + found = true; + break; + } + pV = pV->pNext; + } + return found; +} + +//----------------------------------------------------------------------------- +long CViewContainer::getNbViews () const +{ + long nb = 0; + CCView *pV = pFirstView; + while (pV) + { + pV = pV->pNext; + nb++; + } + return nb; +} + +//----------------------------------------------------------------------------- +/** + * @param index the index of the view to return + */ +CView *CViewContainer::getView (long index) const +{ + long nb = 0; + CCView *pV = pFirstView; + while (pV) + { + if (nb == index) + return pV->pView; + pV = pV->pNext; + nb++; + } + return 0; +} + +//----------------------------------------------------------------------------- +/** + * @param pContext the context which to use to draw this container and its subviews + */ +void CViewContainer::draw (CDrawContext *pContext) +{ + CDrawContext *pC; + CCoord save[4]; + + if (!pOffscreenContext && bDrawInOffscreen) + pOffscreenContext = new COffscreenContext (pParentFrame, (long)size.width (), (long)size.height (), kBlackCColor); + +#if USE_ALPHA_BLEND + if (pOffscreenContext && bTransparencyEnabled) + pOffscreenContext->copyTo (pContext, size); +#endif + + if (bDrawInOffscreen) + pC = pOffscreenContext; + else + { + pC = pContext; + modifyDrawContext (save, pContext); + } + + CRect r (0, 0, size.width (), size.height ()); + +#if USE_CLIPPING_DRAWRECT + CRect oldClip; + pContext->getClipRect (oldClip); + CRect oldClip2 (oldClip); + if (bDrawInOffscreen && getFrame () != this) + oldClip.offset (-oldClip.left, -oldClip.top); + + CRect newClip (r); + newClip.bound (oldClip); + pC->setClipRect (newClip); +#endif + + // draw the background + if (pBackground) + { + if (bTransparencyEnabled) + pBackground->drawTransparent (pC, r, backgroundOffset); + else + pBackground->draw (pC, r, backgroundOffset); + } + else if (!bTransparencyEnabled) + { + pC->setFillColor (backgroundColor); + pC->fillRect (r); + } + + // draw each view + FOREACHSUBVIEW +#if USE_CLIPPING_DRAWRECT + CRect vSize (pV->size); + vSize.bound (oldClip); + pC->setClipRect (vSize); +#endif + if (pV->isVisible()) + pV->draw (pC); + ENDFOR + +#if USE_CLIPPING_DRAWRECT + pC->setClipRect (oldClip2); +#endif + + // transfert offscreen + if (bDrawInOffscreen) + ((COffscreenContext*)pC)->copyFrom (pContext, size); + else + restoreDrawContext (pContext, save); + + setDirty (false); +} + +//----------------------------------------------------------------------------- +/** + * @param pContext the context which to use to draw the background + * @param _updateRect the area which to draw + */ +void CViewContainer::drawBackgroundRect (CDrawContext *pContext, CRect& _updateRect) +{ + if (pBackground) + { + CRect oldClip; + pContext->getClipRect (oldClip); + CRect newClip (_updateRect); + newClip.bound (oldClip); + pContext->setClipRect (newClip); + CRect tr (0, 0, pBackground->getWidth (), pBackground->getHeight ()); + if (bTransparencyEnabled) + pBackground->drawTransparent (pContext, tr, backgroundOffset); + else + pBackground->draw (pContext, tr, backgroundOffset); + pContext->setClipRect (oldClip); + } + else if (!bTransparencyEnabled) + { + pContext->setFillColor (backgroundColor); + pContext->fillRect (_updateRect); + } +} + +//----------------------------------------------------------------------------- +/** + * @param pContext the context which to use to draw + * @param _updateRect the area which to draw + */ +void CViewContainer::drawRect (CDrawContext *pContext, const CRect& _updateRect) +{ + CDrawContext *pC; + CCoord save[4]; + + if (!pOffscreenContext && bDrawInOffscreen) + pOffscreenContext = new COffscreenContext (pParentFrame, (long)size.width (), (long)size.height (), kBlackCColor); + +#if USE_ALPHA_BLEND + if (pOffscreenContext && bTransparencyEnabled) + pOffscreenContext->copyTo (pContext, size); +#endif + + if (bDrawInOffscreen) + pC = pOffscreenContext; + else + { + pC = pContext; + modifyDrawContext (save, pContext); + } + + CRect updateRect (_updateRect); + updateRect.bound (size); + + CRect clientRect (updateRect); + clientRect.offset (-size.left, -size.top); + +#if USE_CLIPPING_DRAWRECT + CRect oldClip; + pContext->getClipRect (oldClip); + CRect oldClip2 (oldClip); + if (bDrawInOffscreen && getFrame () != this) + oldClip.offset (-oldClip.left, -oldClip.top); + + CRect newClip (clientRect); + newClip.bound (oldClip); + pC->setClipRect (newClip); +#endif + + // draw the background + drawBackgroundRect (pC, clientRect); + + // draw each view + FOREACHSUBVIEW + if (pV->isVisible() && pV->checkUpdate (clientRect)) + { +#if USE_CLIPPING_DRAWRECT + CRect viewSize (pV->size); + viewSize.bound (newClip); + if (viewSize.getWidth () == 0 || viewSize.getHeight () == 0) + continue; + pC->setClipRect (viewSize); +#endif + + bool wasDirty = pV->isDirty (); + pV->drawRect (pC, clientRect); + +#if DEBUG_FOCUS_DRAWING + if (getFrame ()->getFocusView() == pV && pV->wantsFocus ()) + { + pC->setDrawMode (kCopyMode); + pC->setFrameColor (kRedCColor); + pC->drawRect (pV->size); + } +#endif + if (wasDirty && /* pV->size != viewSize &&*/ !isTypeOf ("CScrollContainer")) + { + pV->setDirty (true); + } + } + ENDFOR + +#if USE_CLIPPING_DRAWRECT + pC->setClipRect (oldClip2); +#endif + + // transfer offscreen + if (bDrawInOffscreen) + ((COffscreenContext*)pC)->copyFrom (pContext, updateRect, CPoint (clientRect.left, clientRect.top)); + else + restoreDrawContext (pContext, save); + +#if EVENT_DRAW_FIX + if (bDirty && newClip == size) +#endif + setDirty (false); +} + +//----------------------------------------------------------------------------- +/** + * @param context the context which to use to redraw this container + * @param rect the area which to redraw + */ +void CViewContainer::redrawRect (CDrawContext* context, const CRect& rect) +{ + CRect _rect (rect); + _rect.offset (size.left, size.top); + if (bTransparencyEnabled) + { + // as this is transparent, we call the parentview to redraw this area. + if (pParentView) + pParentView->redrawRect (context, _rect); + else if (pParentFrame) + pParentFrame->drawRect (context, _rect); + } + else + { + CCoord save[4]; + if (pParentView) + { + CPoint off; + pParentView->localToFrame (off); + // store + save[0] = context->offsetScreen.h; + save[1] = context->offsetScreen.v; + save[2] = context->offset.h; + save[3] = context->offset.v; + + context->offsetScreen.h += off.x; + context->offsetScreen.v += off.y; + context->offset.h += off.x; + context->offset.v += off.y; + + drawRect (context, _rect); + + // restore + context->offsetScreen.h = save[0]; + context->offsetScreen.v = save[1]; + context->offset.h = save[2]; + context->offset.v = save[3]; + } + else + { + drawRect (context, _rect); + } + } +} + +//----------------------------------------------------------------------------- +bool CViewContainer::hitTestSubViews (const CPoint& where, const long buttons) +{ + CPoint where2 (where); + where2.offset (-size.left, -size.top); + + CCView *pSv = pLastView; + while (pSv) + { + CView *pV = pSv->pView; + if (pV && pV->getMouseEnabled () && pV->hitTest (where2, buttons)) + return true; + pSv = pSv->pPrevious; + } + return false; +} + +//----------------------------------------------------------------------------- +bool CViewContainer::hitTest (const CPoint& where, const long buttons) +{ + //return hitTestSubViews (where); would change default behavior + return CView::hitTest (where, buttons); +} + +//----------------------------------------------------------------------------- +void CViewContainer::mouse (CDrawContext *pContext, CPoint &where, long buttons) +{ + // convert to relativ pos + CPoint where2 (where); + where2.offset (-size.left, -size.top); + + if (buttons == -1 && pContext) + buttons = pContext->getMouseButtons (); + + CCView *pSv = pLastView; + while (pSv) + { + CView *pV = pSv->pView; + if (pV && pV->getMouseEnabled () && pV->hitTest (where2, buttons)) + { + pV->mouse (pContext, where2, buttons); + break; + } + pSv = pSv->pPrevious; + } +} + +//----------------------------------------------------------------------------- +long CViewContainer::onKeyDown (VstKeyCode& keyCode) +{ + long result = -1; + + CCView* pSv = pLastView; + while (pSv) + { + long result = pSv->pView->onKeyDown (keyCode); + if (result != -1) + break; + + pSv = pSv->pPrevious; + } + + return result; +} + +//----------------------------------------------------------------------------- +long CViewContainer::onKeyUp (VstKeyCode& keyCode) +{ + long result = -1; + + CCView* pSv = pLastView; + while (pSv) + { + long result = pSv->pView->onKeyUp (keyCode); + if (result != -1) + break; + + pSv = pSv->pPrevious; + } + + return result; +} + +//----------------------------------------------------------------------------- +bool CViewContainer::onWheel (CDrawContext *pContext, const CPoint &where, const CMouseWheelAxis axis, float distance) +{ + bool result = false; + CView *view = getViewAt (where); + if (view) + { + // convert to relativ pos + CPoint where2 (where); + where2.offset (-size.left, -size.top); + + CCoord save[4]; + modifyDrawContext (save, pContext); + + result = view->onWheel (pContext, where2, axis, distance); + + restoreDrawContext (pContext, save); + } + return result; +} + +//----------------------------------------------------------------------------- +bool CViewContainer::onWheel (CDrawContext *pContext, const CPoint &where, float distance) +{ + return onWheel (pContext, where, kMouseWheelAxisY, distance); +} + +//----------------------------------------------------------------------------- +bool CViewContainer::onDrop (CDrawContext* context, CDragContainer* drag, const CPoint& where) +{ + if (!pParentFrame) + return false; + + bool result = false; + + CCoord save[4]; + modifyDrawContext (save, context); + + // convert to relativ pos + CPoint where2 (where); + where2.offset (-size.left, -size.top); + + CView* view = getViewAt (where); + if (view != currentDragView) + { + if (currentDragView) + currentDragView->onDragLeave (context, drag, where2); + currentDragView = view; + } + if (currentDragView) + { + result = currentDragView->onDrop (context, drag, where2); + currentDragView->onDragLeave (context, drag, where2); + } + currentDragView = 0; + + restoreDrawContext (context, save); + + return result; +} + +//----------------------------------------------------------------------------- +void CViewContainer::onDragEnter (CDrawContext* context, CDragContainer* drag, const CPoint& where) +{ + if (!pParentFrame) + return; + + CCoord save[4]; + modifyDrawContext (save, context); + + // convert to relativ pos + CPoint where2 (where); + where2.offset (-size.left, -size.top); + + if (currentDragView) + currentDragView->onDragLeave (context, drag, where2); + CView* view = getViewAt (where); + currentDragView = view; + if (view) + view->onDragEnter (context, drag, where2); + + restoreDrawContext (context, save); +} + +//----------------------------------------------------------------------------- +void CViewContainer::onDragLeave (CDrawContext* context, CDragContainer* drag, const CPoint& where) +{ + if (!pParentFrame) + return; + + CCoord save[4]; + modifyDrawContext (save, context); + + // convert to relativ pos + CPoint where2 (where); + where2.offset (-size.left, -size.top); + + if (currentDragView) + currentDragView->onDragLeave (context, drag, where2); + currentDragView = 0; + + restoreDrawContext (context, save); +} + +//----------------------------------------------------------------------------- +void CViewContainer::onDragMove (CDrawContext* context, CDragContainer* drag, const CPoint& where) +{ + if (!pParentFrame) + return; + + CCoord save[4]; + modifyDrawContext (save, context); + + // convert to relativ pos + CPoint where2 (where); + where2.offset (-size.left, -size.top); + + CView* view = getViewAt (where); + if (view != currentDragView) + { + if (currentDragView) + currentDragView->onDragLeave (context, drag, where2); + if (view) + view->onDragEnter (context, drag, where2); + currentDragView = view; + } + else if (currentDragView) + currentDragView->onDragMove (context, drag, where2); + + restoreDrawContext (context, save); +} + +//----------------------------------------------------------------------------- +void CViewContainer::update (CDrawContext *pContext) +{ + switch (mode) + { + //---Normal : redraw all... + case kNormalUpdate: + if (isDirty ()) + { +#if NEW_UPDATE_MECHANISM + CRect ur (0, 0, size.width (), size.height ()); + redrawRect (pContext, ur); +#else + #if USE_ALPHA_BLEND + if (bTransparencyEnabled) + { + CRect updateRect (size); + CPoint offset (0,0); + localToFrame (offset); + updateRect.offset (offset.x, offset.y); + getFrame ()->drawRect (pContext, updateRect); + } + else + #endif + draw (pContext); + #endif + setDirty (false); + } + break; + + //---Redraw only dirty controls----- + case kOnlyDirtyUpdate: + { +#if NEW_UPDATE_MECHANISM + if (bDirty) + { + CRect ur (0, 0, size.width (), size.height ()); + redrawRect (pContext, ur); + } + else + { + CRect updateRect (size); + updateRect.offset (-size.left, -size.top); + FOREACHSUBVIEW + if (pV->isDirty () && pV->checkUpdate (updateRect)) + { + if (pV->notify (this, kMsgCheckIfViewContainer)) + pV->update (pContext); + else + { + CRect drawSize (pV->size); + drawSize.bound (updateRect); + pV->redrawRect (pContext, drawSize); + } + } + ENDFOR + } +#else + #if USE_ALPHA_BLEND + if (bTransparencyEnabled) + { + if (bDirty) + { + CRect updateRect (size); + CPoint offset (0,0); + localToFrame (offset); + updateRect.offset (offset.x, offset.y); + getFrame ()->drawRect (pContext, updateRect); + } + else + { + CRect updateRect (size); + updateRect.offset (-size.left, -size.top); + FOREACHSUBVIEW + if (pV->isDirty () && pV->checkUpdate (updateRect)) + { + if (pV->notify (this, kMsgCheckIfViewContainer)) + { + pV->update (pContext); + } + else + { + CPoint offset; + CRect viewSize (pV->size); + pV->localToFrame (offset); + viewSize.offset (offset.x, offset.y); + getFrame ()->drawRect (pContext, viewSize); + } + } + ENDFOR + } + setDirty (false); + return; + } + #endif + if (bDirty) + draw (pContext); + else if (bDrawInOffscreen && pOffscreenContext) + { + bool doCopy = false; + if (isDirty ()) + doCopy = true; + + FOREACHSUBVIEW + pV->update (pOffscreenContext); + ENDFOR + + // transfert offscreen + if (doCopy) + pOffscreenContext->copyFrom (pContext, size); + } + else + { + long save[4]; + modifyDrawContext (save, pContext); + + FOREACHSUBVIEW + if (pV->isDirty ()) + { + long oldMode = 0; + CViewContainer* child = 0; + if (pV->notify (this, kMsgCheckIfViewContainer)) + { + child = (CViewContainer*)pV; + oldMode = child->getMode (); + child->setMode (kNormalUpdate); + } + CRect viewSize (pV->size); + drawBackgroundRect (pContext, viewSize); + pV->update (pContext); + if (child) + child->setMode (oldMode); + } + ENDFOR + + restoreDrawContext (pContext, save); + } +#endif + setDirty (false); + break; + } + } +} + +//----------------------------------------------------------------------------- +void CViewContainer::looseFocus (CDrawContext *pContext) +{ + FOREACHSUBVIEW + pV->looseFocus (pContext); + ENDFOR +} + +//----------------------------------------------------------------------------- +void CViewContainer::takeFocus (CDrawContext *pContext) +{ + FOREACHSUBVIEW + pV->takeFocus (pContext); + ENDFOR +} + +//----------------------------------------------------------------------------- +bool CViewContainer::advanceNextFocusView (CView* oldFocus, bool reverse) +{ + bool foundOld = false; + FOREACHSUBVIEW_REVERSE(reverse) + if (oldFocus && !foundOld) + { + if (oldFocus == pV) + { + foundOld = true; + continue; + } + } + else + { + if (pV->wantsFocus ()) + { + getFrame ()->setFocusView (pV); + return true; + } + else if (pV->isTypeOf ("CViewContainer")) + { + if (((CViewContainer*)pV)->advanceNextFocusView (0, reverse)) + return true; + } + } + ENDFOR + return false; +} + +//----------------------------------------------------------------------------- +bool CViewContainer::isDirty () const +{ + if (bDirty) + return true; + + CRect viewSize (size); + viewSize.offset (-size.left, -size.top); + + FOREACHSUBVIEW + if (pV->isDirty ()) + { + CRect r (pV->size); + r.bound (viewSize); + if (r.getWidth () > 0 && r.getHeight () > 0) + return true; + } + ENDFOR + return false; +} + +//----------------------------------------------------------------------------- +CView *CViewContainer::getCurrentView () const +{ + if (!pParentFrame) + return 0; + + // get the current position + CPoint where; + pParentFrame->getCurrentLocation (where); + + frameToLocal (where); + + CCView *pSv = pLastView; + while (pSv) + { + CView *pV = pSv->pView; + if (pV && where.isInside (pV->mouseableArea)) + return pV; + pSv = pSv->pPrevious; + } + + return 0; +} + +//----------------------------------------------------------------------------- +CView *CViewContainer::getViewAt (const CPoint& p, bool deep) const +{ + if (!pParentFrame) + return 0; + + CPoint where (p); + + // convert to relativ pos + where.offset (-size.left, -size.top); + + CCView *pSv = pLastView; + while (pSv) + { + CView *pV = pSv->pView; + if (pV && where.isInside (pV->mouseableArea)) + { + if (deep) + { + if (pV->isTypeOf ("CViewContainer")) + return ((CViewContainer*)pV)->getViewAt (where, deep); + } + return pV; + } + pSv = pSv->pPrevious; + } + + return 0; +} + +//----------------------------------------------------------------------------- +CPoint& CViewContainer::frameToLocal (CPoint& point) const +{ + point.offset (-size.left, -size.top); + if (pParentView && pParentView->isTypeOf ("CViewContainer")) + return pParentView->frameToLocal (point); + return point; +} + +//----------------------------------------------------------------------------- +CPoint& CViewContainer::localToFrame (CPoint& point) const +{ + point.offset (size.left, size.top); + if (pParentView && pParentView->isTypeOf ("CViewContainer")) + return pParentView->localToFrame (point); + return point; +} + +//----------------------------------------------------------------------------- +bool CViewContainer::removed (CView* parent) +{ + if (pOffscreenContext) + pOffscreenContext->forget (); + pOffscreenContext = 0; + + return true; +} + +//----------------------------------------------------------------------------- +bool CViewContainer::attached (CView* view) +{ + // create offscreen bitmap + if (!pOffscreenContext && bDrawInOffscreen) + pOffscreenContext = new COffscreenContext (pParentFrame, (long)size.width (), (long)size.height (), kBlackCColor); + + return true; +} + +//----------------------------------------------------------------------------- +void CViewContainer::useOffscreen (bool b) +{ + bDrawInOffscreen = b; + + if (!bDrawInOffscreen && pOffscreenContext) + { + pOffscreenContext->forget (); + pOffscreenContext = 0; + } +} + +//----------------------------------------------------------------------------- +void CViewContainer::modifyDrawContext (CCoord save[4], CDrawContext* pContext) +{ + // store + save[0] = pContext->offsetScreen.h; + save[1] = pContext->offsetScreen.v; + save[2] = pContext->offset.h; + save[3] = pContext->offset.v; + + pContext->offsetScreen.h += size.left; + pContext->offsetScreen.v += size.top; + pContext->offset.h += size.left; + pContext->offset.v += size.top; +} + +//----------------------------------------------------------------------------- +void CViewContainer::restoreDrawContext (CDrawContext* pContext, CCoord save[4]) +{ + // restore + pContext->offsetScreen.h = save[0]; + pContext->offsetScreen.v = save[1]; + pContext->offset.h = save[2]; + pContext->offset.v = save[3]; +} + +#if DEBUG +static long _debugDumpLevel = 0; +//----------------------------------------------------------------------------- +void CViewContainer::dumpInfo () +{ + static const char* modeString[] = { "Normal Update Mode", "Only Dirty Update Mode"}; + DebugPrint ("CViewContainer: Mode: %s, Offscreen:%s ", modeString[mode], bDrawInOffscreen ? "Yes" : "No"); + CView::dumpInfo (); +} + +//----------------------------------------------------------------------------- +void CViewContainer::dumpHierarchy () +{ + _debugDumpLevel++; + FOREACHSUBVIEW + for (long i = 0; i < _debugDumpLevel; i++) + DebugPrint ("\t"); + pV->dumpInfo (); + DebugPrint ("\n"); + if (pV->isTypeOf ("CViewContainer")) + ((CViewContainer*)pV)->dumpHierarchy (); + ENDFOR + _debugDumpLevel--; +} + +#endif + + +//----------------------------------------------------------------------------- +// CBitmap Implementation +//----------------------------------------------------------------------------- +/*! @class CBitmap +@section cbitmap_alphablend Alpha Blend and Transparency +With Version 3.0 of VSTGUI it is possible to use alpha blended bitmaps. This comes free on Mac OS X and with Windows you need to include libpng. +Per default PNG images will be rendered alpha blended. If you want to use a transparency color with PNG Bitmaps, you need to call setNoAlpha(true) on the bitmap and set the transparency color. +@section cbitmap_macos Classic Apple Mac OS +The Bitmaps are PICTs and stored inside the resource fork. +@section cbitmap_macosx Apple Mac OS X +The Bitmaps can be of type PNG, JPEG, PICT, BMP and are stored in the Resources folder of the plugin bundle. +They must be named bmp00100.png (or bmp00100.jpg, etc). The number is the resource id. +@section cbitmap_windows Microsoft Windows +The Bitmaps are .bmp files and must be included in the plug (usually using a .rc file). +It's also possible to use png as of version 3.0 if you define the macro USE_LIBPNG and include the libpng and zlib libraries/sources to your project. +*/ +CBitmap::CBitmap (AEffGUIEditor& editor, const char* filename) + : resourceID (resourceID), width (0), height (0), noAlpha (true) +{ +#if DEBUG + gNbCBitmap++; +#endif + + bool found = false; + long i = 0; + long ncolors, cpp; + + pHandle = 0; + pMask = 0; + + if (editor.getBundlePath() == NULL) { + std::cerr << "ERROR: No bundle path set, unable to load images" << std::endl; + } else { + std::string path = std::string(editor.getBundlePath()) + filename; + if (openPng(path.c_str())) // reads width, height + closePng(); + } + + setTransparentColor (kTransparentCColor); + +#if DEBUG + gBitmapAllocation += (long)height * (long)width; +#endif +} + +//----------------------------------------------------------------------------- +CBitmap::CBitmap (CFrame &frame, CCoord width, CCoord height) + : width (width), height (height), noAlpha (true), pMask (0) +{ +#if DEBUG + gNbCBitmap++; +#endif + + pHandle = (void*) XCreatePixmap (display, + frame.getBackBuffer (), + width, + height, + frame.getDepth ()); + + setTransparentColor (kTransparentCColor); +} + +//----------------------------------------------------------------------------- +CBitmap::CBitmap () + : resourceID (0) + , width (0) + , height (0) + , noAlpha (true) +{ + pMask = 0; + pHandle = 0; +} + +//----------------------------------------------------------------------------- +CBitmap::~CBitmap () +{ + dispose (); +} + +//----------------------------------------------------------------------------- +void CBitmap::dispose () +{ +#if DEBUG + gNbCBitmap--; + gBitmapAllocation -= (long)height * (long)width; +#endif + + if (pHandle) + XFreePixmap (display, (Pixmap)pHandle); + if (pMask) + XFreePixmap (display, (Pixmap)pMask); + + pHandle = 0; + pMask = 0; + + width = 0; + height = 0; + +} + +//----------------------------------------------------------------------------- +void *CBitmap::getHandle () const +{ + return pHandle; +} + +//----------------------------------------------------------------------------- +bool CBitmap::loadFromResource (long resourceID) +{ + dispose (); + fprintf (stderr, "CBitmap::loadFromResource not implemented\n"); + return false; +} + +//----------------------------------------------------------------------------- +bool CBitmap::loadFromPath (const void* platformPath) +{ + if (pHandle != NULL) { + dispose (); + closePng (); + } + + bool success = openPng ((char*)platformPath); + if (success) + closePng (); + + return success; +} + +//----------------------------------------------------------------------------- +bool CBitmap::isLoaded () const +{ + return (pHandle != NULL); +} + +//----------------------------------------------------------------------------- +void CBitmap::draw (CDrawContext *pContext, CRect &rect, const CPoint &offset) +{ + if (!pHandle) + { + // the first time try to decode the pixmap + pHandle = createPixmapFromPng (pContext); + if (!pHandle) + return; + } + + CFrame* frame = pContext->pFrame; + + XCopyArea (display, + (Drawable) pHandle, + (Drawable) frame->getBackBuffer(), + (GC) frame->getGC(), + offset.h, + offset.v, + std::min (rect.width (), getWidth()), + std::min (rect.height (), getHeight()), + rect.left + pContext->offset.h, + rect.top + pContext->offset.v); +} + +//----------------------------------------------------------------------------- +void CBitmap::drawTransparent (CDrawContext *pContext, CRect &rect, const CPoint &offset) +{ + if (!pHandle) + { + // the first time try to decode the pixmap + pHandle = createPixmapFromPng (pContext); + if (!pHandle) + return; + } + + CFrame* frame = pContext->pFrame; + + if (pMask == 0) + { + // get image from the pixmap + XImage* image = XGetImage (display, (Drawable)pHandle, + 0, 0, width, height, AllPlanes, ZPixmap); + assert (image); + + // create the bitmap mask + pMask = (void*) XCreatePixmap (display, (Drawable)frame->getWindow(), + width, height, 1); + assert (pMask); + + // create a associated GC + XGCValues values; + values.foreground = 1; + GC gc = XCreateGC (display, (Drawable)pMask, GCForeground, &values); + + // clear the mask + XFillRectangle (display, (Drawable)pMask, gc, 0, 0, width, height); + + // get the transparent color index + int color = pContext->getIndexColor (transparentCColor); + + // inverse the color + values.foreground = 0; + XChangeGC (display, gc, GCForeground, &values); + + // compute the mask + XPoint *points = new XPoint [height * width]; + int x, y, nbPoints = 0; + switch (image->depth) + { + case 8: + for (y = 0; y < height; y++) + { + char* src = image->data + (y * image->bytes_per_line); + + for (x = 0; x < width; x++) + { + if (src[x] == color) + { + points[nbPoints].x = x; + points[nbPoints].y = y; + nbPoints++; + } + } + } + break; + + case 24: { + int bytesPerPixel = image->bits_per_pixel >> 3; + char *lp = image->data; + for (y = 0; y < height; y++) + { + char* cp = lp; + for (x = 0; x < width; x++) + { + if (*(int*)cp == color) + { + points[nbPoints].x = x; + points[nbPoints].y = y; + nbPoints++; + } + cp += bytesPerPixel; + } + lp += image->bytes_per_line; + } + } break; + + default : + break; + } + + XDrawPoints (display, (Drawable)pMask, gc, + points, nbPoints, CoordModeOrigin); + + // free + XFreeGC (display, gc); + delete []points; + + // delete + XDestroyImage (image); + } + + // set the new clipmask + XGCValues value; + value.clip_mask = (Pixmap)pMask; + value.clip_x_origin = (rect.left + pContext->offset.h) - offset.h; + value.clip_y_origin = (rect.top + pContext->offset.v) - offset.v; + + XChangeGC (display, + (GC) /*frame->getGC(),*/ pContext->pSystemContext, + GCClipMask | GCClipXOrigin | GCClipYOrigin, + &value); + + XCopyArea (display, + (Drawable) pHandle, + (Drawable) frame->getBackBuffer(), + (GC) frame->getGC(), + offset.h, + offset.v, + rect.width (), + rect.height (), + rect.left + pContext->offset.h, + rect.top + pContext->offset.v); + + // unset the clipmask + XSetClipMask (display, (GC)frame->getGC(), None); +} + +//----------------------------------------------------------------------------- +void CBitmap::drawAlphaBlend (CDrawContext *pContext, CRect &rect, const CPoint &offset, unsigned char alpha) +{ + std::cout << "CBitmap::drawAlphaBlend (not implemented!)" << std::endl; +} + +//----------------------------------------------------------------------------- +void CBitmap::setTransparentColor (const CColor color) +{ + transparentCColor = color; +} + +//----------------------------------------------------------------------------- +void CBitmap::setTransparencyMask (CDrawContext* pContext, const CPoint& offset) +{ + // todo: implement me! +} + + +//----------------------------------------------------------------------------- +bool CBitmap::openPng (const char* path) +{ + assert(path); + + FILE* fp = fopen(path, "rb"); + if (!fp) { + fprintf(stderr, "Unable to open file %s\n", path); + return false; + } + + png_byte header[8]; + fread(header, 1, 8, fp); + if (png_sig_cmp(header, 0, 8)) { + fprintf(stderr, "File not recognized as a PNG image"); + return false; + } + + pngRead = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!pngRead) { + fprintf(stderr, "Unable to initialize libpng\n"); + return false; + } + + pngInfo = png_create_info_struct(pngRead); + if (!pngInfo) { + png_destroy_read_struct(&pngRead, NULL, NULL); + return false; + } + + png_init_io(pngRead, fp); + png_set_sig_bytes(pngRead, 8); + + png_read_info(pngRead, pngInfo); + + width = pngInfo->width; + height = pngInfo->height; + + pngFp = fp; + pngRead = pngRead; + pngPath = path; + + return true; +} + +//----------------------------------------------------------------------------- +bool CBitmap::closePng () +{ + png_destroy_read_struct(&pngRead, &pngInfo, NULL); + fclose(pngFp); + pngFp = NULL; + return true; +} + +//----------------------------------------------------------------------------- +void* CBitmap::createPixmapFromPng (CDrawContext *pContext) +{ + if (!openPng(pngPath.c_str())) + return NULL; + + assert(width > 0 && height > 0); + + png_byte** rows = (png_byte**)malloc(height * sizeof(png_byte*)); + for (int i = 0; i < height; ++i) + rows[i] = (png_byte*)(malloc(pngInfo->width * sizeof(uint32_t))); + + png_read_image(pngRead, rows); + + CFrame* frame = pContext->pFrame; + + Pixmap p = XCreatePixmap(display, frame->getBackBuffer(), + pngInfo->width, pngInfo->height, 24); + + XGCValues values; + values.foreground = 0xFFFFFFFF; + + // Draw + GC gc = XCreateGC (display, p, GCForeground, &values); + for (unsigned y = 0; y < pngInfo->height; y++) { + for (unsigned x = 0; x < pngInfo->width; ++x) { + char r = rows[y][(x*3)]; + char g = rows[y][(x*3)+1]; + char b = rows[y][(x*3)+2]; + uint32_t color = (r << 16) + (g << 8) + b; + XSetForeground(display, gc, color); + XDrawPoint(display, p, gc, x, y); + } + } + XFreeGC (display, gc); + + closePng(); + + return (void*)p; +} + +//----------------------------------------------------------------------------- +// CDragContainer Implementation +//----------------------------------------------------------------------------- +CDragContainer::CDragContainer (void* platformDrag) +: platformDrag (platformDrag) +, nbItems (0) +, iterator (0) +, lastItem (0) +{ +} + +//----------------------------------------------------------------------------- +CDragContainer::~CDragContainer () +{ + if (lastItem) + { + free (lastItem); + lastItem = 0; + } +} + +//----------------------------------------------------------------------------- +long CDragContainer::getType (long idx) const +{ + // not implemented + return kUnknown; +} + +//----------------------------------------------------------------------------- +void* CDragContainer::first (long& size, long& type) +{ + iterator = 0; + return next (size, type); +} + +//----------------------------------------------------------------------------- +void* CDragContainer::next (long& size, long& type) +{ + if (lastItem) + { + free (lastItem); + lastItem = 0; + } + size = 0; + type = kUnknown; + + // not implemented + + return NULL; +} + +} // namespace VSTGUI + +//----------------------------------------------------------------------------- +// return a degre value between [0, 360 * 64[ +static long convertPoint2Angle (CPoint &pm, CPoint &pt) +{ + long angle; + if (pt.h == pm.h) + { + if (pt.v < pm.v) + angle = 5760; // 90 * 64 + else + angle = 17280; // 270 * 64 + } + else if (pt.v == pm.v) + { + if (pt.h < pm.h) + angle = 11520; // 180 * 64 + else + angle = 0; + } + else + { + // 3666.9299 = 180 * 64 / pi + angle = (long)(3666.9298 * atan ((double)(pm.v - pt.v) / (double)(pt.h - pm.h))); + + if (pt.v < pm.v) + { + if (pt.h < pm.h) + angle += 11520; // 180 * 64 + } + else + { + if (pt.h < pm.h) + angle += 11520; // 180 * 64 + else + angle += 23040; // 360 * 64 + } + } + return angle; +} + + + +#if !PLUGGUI +//----------------------------------------------------------------------------- +// CFileSelector Implementation +//----------------------------------------------------------------------------- +#define stringAnyType "Any Type (*.*)" +#define stringAllTypes "All Types: (" +#define stringSelect "Select" +#define stringCancel "Cancel" +#define stringLookIn "Look in" +#define kPathMax 1024 + +namespace VSTGUI { + +//----------------------------------------------------------------------------- +CFileSelector::CFileSelector (AudioEffectX* effect) +: effect (effect), vstFileSelect (0) +{} + +//----------------------------------------------------------------------------- +CFileSelector::~CFileSelector () +{ + if (vstFileSelect) + { + if (effect && effect->canHostDo ("closeFileSelector")) + effect->closeFileSelector (vstFileSelect); + else + { + if (vstFileSelect->reserved == 1 && vstFileSelect->returnPath) + { + delete []vstFileSelect->returnPath; + vstFileSelect->returnPath = 0; + vstFileSelect->sizeReturnPath = 0; + } + if (vstFileSelect->returnMultiplePaths) + { + for (long i = 0; i < vstFileSelect->nbReturnPath; i++) + { + delete []vstFileSelect->returnMultiplePaths[i]; + vstFileSelect->returnMultiplePaths[i] = 0; + } + delete[] vstFileSelect->returnMultiplePaths; + vstFileSelect->returnMultiplePaths = 0; + } + } + } +} + +//----------------------------------------------------------------------------- +long CFileSelector::run (VstFileSelect *vstFileSelect_) +{ + vstFileSelect = vstFileSelect_; + vstFileSelect->nbReturnPath = 0; + vstFileSelect->returnPath[0] = 0; + + if (effect + && effect->canHostDo ("openFileSelector") + && effect->canHostDo ("closeFileSelector")) + { + if (effect->openFileSelector (vstFileSelect)) + return vstFileSelect->nbReturnPath; + } + return 0; +} + +} // namespace VSTGUI + +//----------------------------------------------------------------------------- +#endif // !PLUGGUI +//----------------------------------------------------------------------------- + diff --git a/vstgui/vstgui.h b/vstgui/vstgui.h new file mode 100644 index 0000000..2ab0e7d --- /dev/null +++ b/vstgui/vstgui.h @@ -0,0 +1,1105 @@ +/* ---------------------------------------------------------------------------- + * VSTGUI for X11/LV2/PNG + * Author: Dave Robillard + * Released under the revised BSD license, as below + * ---------------------------------------------------------------------------- + * + * Based on: + * ---------------------------------------------------------------------------- + * VSTGUIL: Graphical User Interface Framework for VST plugins on LINUX + * Version: 0.1, Date: 2007/01/21 + * Author: kRAkEn/gORe + * + * Which was based on: + * ---------------------------------------------------------------------------- + * VSTGUI: Graphical User Interface Framework for VST plugins + * Version 3.0 $Date: 2005/08/12 12:45:00 $ + * ---------------------------------------------------------------------------- + * VSTGUI LICENSE + * 2004, Steinberg Media Technologies, All Rights Reserved + * ---------------------------------------------------------------------------- + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Steinberg Media Technologies nor the names of + * its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#ifndef __vstgui__ +#define __vstgui__ + +// define global defines +#define MOTIF 1 +#define PNG 1 +#define DEBUG 1 + +#include "audioeffectx.h" +#include +#include +#include +#include + +// VSTGUI Version +#define VSTGUI_VERSION_MAJOR 3 +#define VSTGUI_VERSION_MINOR 0 + +struct ERect { + VstInt16 left; + VstInt16 top; + VstInt16 right; + VstInt16 bottom; +}; + +//---------------------------------------------------- +//---------------------------------------------------- +namespace VSTGUI { + +class CFrame; +class CDrawContext; +class COffscreenContext; +class CControl; +class CBitmap; + +} // namespace VSTGUI + +class AudioEffect; + +#ifndef __aeffeditor__ +#include "AEffEditor.hpp" +#endif + +//----------------------------------------------------------------------------- +// AEffGUIEditor Declaration +//----------------------------------------------------------------------------- +class AEffGUIEditor : public AEffEditor +{ +public: +//----------------------------------------------------------------------------- + AEffGUIEditor (AudioEffect* effect); + ~AEffGUIEditor (); + + // get the CFrame object + VSTGUI::CFrame* getFrame () { return frame; } + + virtual void setParameter (VstInt32 index, float value); + virtual void beginEdit (VstInt32 index); + virtual void endEdit (VstInt32 index); + + // feedback to application + virtual void doIdleStuff (); + + // wait (in ms) + void wait (unsigned int ms); + + // get the current time (in ms) + unsigned int getTicks (); + + // get version of this VSTGUI + static int getVstGuiVersion () { return (VSTGUI_VERSION_MAJOR << 16) + VSTGUI_VERSION_MINOR; } + + // get the knob mode + static VstInt32 getKnobMode () { return knobMode; } + + long getRect (ERect** rect); + void idle (); + void update (); + + void setBundlePath(const char* path) { bundlePath = strdup(path); } + const char* getBundlePath() { return bundlePath; } + +#if VST_2_1_EXTENSIONS + long onKeyDown (VstKeyCode& keyCode); + long onKeyUp (VstKeyCode& keyCode); + bool onWheel (float distance); + long setKnobMode (VstInt32 val); +#endif +//----------------------------------------------------------------------------- +protected: + ERect rect; + unsigned int lLastTicks; + bool inIdleStuff; + static VstInt32 knobMode; + char* bundlePath; + friend class VSTGUI::CFrame; + VSTGUI::CFrame* frame; +}; + +//---------------------------------------------------- +#include +#include +#include +#include +#include + +inline unsigned int _getTicks () +{ + // gettimeofday is not what we need here, checkout API for hw time + struct timeval tv; + struct timezone tz; + gettimeofday (&tv, &tz); + return tv.tv_sec * 1000 + tv.tv_usec / 1000; +} + +struct VstKeyCode; + +namespace VSTGUI { + +struct CPoint; + +#define CLASS_METHODS(name, parent) \ + virtual bool isTypeOf (const char* s) const \ + { return (!strcmp (s, (#name))) ? true : parent::isTypeOf (s); }\ + +#ifdef VSTGUI_FLOAT_COORDINATES + typedef float CCoord; +#else + typedef long CCoord; +#endif + +//----------------------------------------------------------------------------- +// Structure CRect +//----------------------------------------------------------------------------- +struct CRect +{ + CRect (CCoord l = 0, CCoord t = 0, CCoord r = 0, CCoord b = 0) + : left (l), top (t), right (r), bottom (b) {} + CRect (const CRect& r) + : left (r.left), top (r.top), right (r.right), bottom (r.bottom) {} + CRect& operator () (CCoord l, CCoord t, CCoord r, CCoord b) + { + if (l < r) + this->left = l, this->right = r; + else + this->left = r, this->right = l; + if (top < bottom) + this->top = t, this->bottom = b; + else + this->top = b, this->bottom = t; + return *this; + } + + bool operator != (const CRect& other) const + { return (left != other.left || right != other.right || + top != other.top || bottom != other.bottom); } + + bool operator == (const CRect& other) const + { return (left == other.left && right == other.right && + top == other.top && bottom == other.bottom); } + + inline CCoord width () const { return right - left; } + inline CCoord height () const { return bottom - top; } + + inline CCoord getWidth () const { return right - left; } + inline CCoord getHeight () const { return bottom - top; } + + inline void setWidth (CCoord w) { right = left + w; } + inline void setHeight (CCoord h) { bottom = top + h; } + + CRect &offset (CCoord off_x, CCoord off_y) + { left += off_x; right += off_x; top += off_y; bottom += off_y; return *this; } + + CRect &inset (CCoord deltaX, CCoord deltaY) + { left += deltaX; right -= deltaX; top += deltaY; bottom -= deltaY; + return *this; } + + CRect &moveTo (CCoord dest_x, CCoord dest_y) + { CCoord vDiff = dest_y - top; CCoord hDiff = dest_x - left; + top += vDiff; bottom += vDiff; left += hDiff; right += hDiff; + return *this; } + + bool pointInside (const CPoint& where) const; // Checks if point is inside this rect + bool isEmpty () const; + + bool rectOverlap (const CRect& rect) const + { + if (right < rect.left) return false; + if (left > rect.right) return false; + if (bottom < rect.top) return false; + if (top > rect.bottom) return false; + return true; + } + + void bound (const CRect& rect); + + union + { CCoord left; CCoord x;}; + + union + { CCoord top; CCoord y;}; + + union + { CCoord right; CCoord x2;}; + + union + { CCoord bottom; CCoord y2;}; +}; + +//----------------------------------------------------------------------------- +// Structure CPoint +//----------------------------------------------------------------------------- +struct CPoint +{ + CPoint (CCoord a_h = 0, CCoord a_v = 0) : h (a_h), v (a_v) {} + CPoint& operator () (CCoord a_h, CCoord a_v) + { this->h = a_h; this->v = a_v; return *this; } + + bool isInside (CRect& r) const + { return h >= r.left && h <= r.right && v >= r.top && v <= r.bottom; } + + bool operator != (const CPoint &other) const + { return (h != other.h || v != other.v); } + + bool operator == (const CPoint &other) const + { return (h == other.h && v == other.v); } + + CPoint &offset (CCoord off_h, CCoord off_v) + { this->h += off_h; this->v += off_v; return *this; } + + union + { CCoord h; CCoord x;}; + + union + { CCoord v; CCoord y;}; +}; + +//----------------------------------------------------------------------------- +// Structure CColor +//----------------------------------------------------------------------------- +struct CColor +{ + CColor& operator () (unsigned char red, + unsigned char green, + unsigned char blue, + unsigned char alpha) + { + this->red = red; + this->green = green; + this->blue = blue; + this->alpha = alpha; + return *this; + } + + CColor& operator = (const CColor& newColor) + { + red = newColor.red; + green = newColor.green; + blue = newColor.blue; + alpha = newColor.alpha; + return *this; + } + + CColor operator ~ () + { + CColor c; + c.red = ~red; + c.green = ~green; + c.blue = ~blue; + c.alpha = ~alpha; + return c; + } + + bool operator != (const CColor &other) const + { return (red != other.red || green != other.green || blue != other.blue || alpha != other.alpha); } + + bool operator == (const CColor &other) const + { return (red == other.red && green == other.green && blue == other.blue && alpha == other.alpha); } + + unsigned char red; + unsigned char green; + unsigned char blue; + unsigned char alpha; +}; + +// define some basic colors +extern CColor kTransparentCColor; +extern CColor kBlackCColor; +extern CColor kWhiteCColor; +extern CColor kGreyCColor; +extern CColor kRedCColor; +extern CColor kGreenCColor; +extern CColor kBlueCColor; +extern CColor kYellowCColor; +extern CColor kCyanCColor; +extern CColor kMagentaCColor; + + +//----------------------------------------------------------------------------- +// Definitions of special characters in a platform independent way + +#define kDegreeSymbol "\xB0" +#define kInfiniteSymbol "oo" +#define kCopyrightSymbol "\xA9" +#define kTrademarkSymbol "\x99" +#define kRegisteredSymbol "\xAE" +#define kMicroSymbol "\x85" +#define kPerthousandSymbol "\x89" + +class CDragContainer; +class CCView; +class CAttributeListEntry; + +//----------------------------------------------------------------------------- +typedef intptr_t CViewAttributeID; +//----------------------------------------------------------------------------- +// Attributes +// all attributes where the first letter is lowercase are reserved for the vstgui lib + +extern const CViewAttributeID kCViewAttributeReferencePointer; // 'cvrp' + +//----------------------------------------------------------------------------- +//----------- +// Font Type +//----------- +enum CFont +{ + kSystemFont = 0, + kNormalFontVeryBig, + kNormalFontBig, + kNormalFont, + kNormalFontSmall, + kNormalFontSmaller, + kNormalFontVerySmall, + kSymbolFont, + + kNumStandardFonts +}; + +//----------- +// Text Face +//----------- +enum CTxtFace +{ + kNormalFace = 0, + kBoldFace = 1, + kItalicFace = 2, + kUnderlineFace = 4 +}; + +//----------- +// Line Style +//----------- +enum CLineStyle +{ + kLineSolid = 0, + kLineOnOffDash +}; + +//----------- +// Draw Mode +//----------- +enum CDrawMode +{ + kCopyMode = 0, + kOrMode, + kXorMode, + kAntialias +}; + +//---------------------------- +// Text Alignment (Horizontal) +//---------------------------- +enum CHoriTxtAlign +{ + kLeftText = 0, + kCenterText, + kRightText +}; + +//---------------------------- +// Buttons Type (+modifiers) +//---------------------------- +enum CButton +{ + kLButton = 1, + kMButton = 2, + kRButton = 4, + kShift = 8, + kControl = 16, + kAlt = 32, + kApple = 64 +}; + +//---------------------------- +// Cursor Type +//---------------------------- +enum CCursorType +{ + kCursorDefault = 0, + kCursorWait, + kCursorHSize, + kCursorVSize, + kCursorSizeAll, + kCursorNESWSize, + kCursorNWSESize, + kCursorCopy, + kCursorNotAllowed, + kCursorHand +}; + +//---------------------------- +// Knob Mode +//---------------------------- +enum CKnobMode +{ + kCircularMode = 0, + kRelativCircularMode, + kLinearMode +}; + +//---------------------------- +// Draw Style +//---------------------------- +enum CDrawStyle +{ + kDrawStroked = 0, + kDrawFilled, + kDrawFilledAndStroked +}; + +enum CMouseWheelAxis +{ + kMouseWheelAxisX = 0, + kMouseWheelAxisY +}; + +//----------------------------------------------------------------------------- +// CReferenceCounter Declaration (Reference Counting) +//----------------------------------------------------------------------------- +class CReferenceCounter +{ +public: + CReferenceCounter () : nbReference (1) {} + virtual ~CReferenceCounter () {} + + virtual void forget () { nbReference--; if (nbReference == 0) delete this; } + virtual void remember () { nbReference++; } + long getNbReference () const { return nbReference; } + +private: + long nbReference; +}; + +//----------------------------------------------------------------------------- +// CDrawContext Declaration +//! A drawing context encapsulates the drawing context of the underlying OS. It implements the drawing functions. +//----------------------------------------------------------------------------- +class CDrawContext : public CReferenceCounter +{ +public: + CDrawContext (CFrame *pFrame, void *pSystemContext, void *pWindow = 0); + virtual ~CDrawContext (); + + void moveTo (const CPoint &point); ///< move line position to point + void lineTo (const CPoint &point); ///< draw a line from current position to point + void drawLines (const CPoint* points, const long& numberOfLines); ///< draw multiple lines at once + + void drawPolygon (const CPoint *pPoints, long numberOfPoints, const CDrawStyle drawStyle = kDrawStroked); ///< draw a polygon + void polyLine (const CPoint *pPoint, long numberOfPoints); ///< draw a stroked polygon + void fillPolygon (const CPoint *pPoint, long numberOfPoints); ///< draw a filled polygon + + void drawRect (const CRect &rect, const CDrawStyle drawStyle = kDrawStroked); ///< draw a stroked rect + void fillRect (const CRect &rect); ///< draw a filled rect + + void drawArc (const CRect &rect, const float startAngle1, const float endAngle2, const CDrawStyle drawStyle = kDrawStroked); ///< draw a stroked arc, where the angles are in degree + void drawArc (const CRect &rect, const CPoint &point1, const CPoint &point2); ///< draw a stroked arc between point1 and point2 + void fillArc (const CRect &rect, const CPoint &point1, const CPoint &point2); ///< draw a filled arc between point1 and point2 + + void drawEllipse (const CRect &rect, const CDrawStyle drawStyle = kDrawStroked); ///< draw an ellipse + void fillEllipse (const CRect &rect); ///< draw a filled ellipse + + void drawPoint (const CPoint &point, CColor color); ///< draw a point + CColor getPoint (const CPoint& point); ///< \deprecated + + void floodFill (const CPoint& start); ///< \deprecated + + void setLineStyle (CLineStyle style); ///< set the current line style + CLineStyle getLineStyle () const { return lineStyle; } ///< get the current line style + + void setLineWidth (CCoord width); ///< set the current line width + CCoord getLineWidth () const { return frameWidth; } ///< get the current line width + + void setDrawMode (CDrawMode mode); ///< set the current draw mode, see CDrawMode + CDrawMode getDrawMode () const { return drawMode; } ///< get the current draw mode, see CDrawMode + + void setClipRect (const CRect &clip); ///< set the current clip + CRect &getClipRect (CRect &clip) const { clip = clipRect; clip.offset (-offset.h, -offset.v); return clip; } ///< get the current clip + void resetClipRect (); ///< reset the clip to the default state + + void setFillColor (const CColor color); ///< set current fill color + CColor getFillColor () const { return fillColor; } ///< get current fill color + + void setFrameColor (const CColor color); ///< set current stroke color + CColor getFrameColor () const { return frameColor; } ///< get current stroke color + + void setFontColor (const CColor color); ///< set current font color + CColor getFontColor () const { return fontColor; } ///< get current font color + void setFont (CFont fontID, const long size = 0, long style = 0); ///< set current font + CFont getFont () const { return fontId; } ///< get current font + long getFontSize () const { return fontSize; } ///< get current font size + + CCoord getStringWidth (const char* pStr); ///< get the width of a string + + void drawString (const char *pString, const CRect &rect, const short opaque = false, + const CHoriTxtAlign hAlign = kCenterText); ///< draw a string + + long getMouseButtons (); ///< get current mouse buttons + void getMouseLocation (CPoint &point); ///< get current mouse location. should not be used, see CView::getMouseLocation + bool waitDoubleClick (); ///< check if another mouse click occurs in the near future + bool waitDrag (); ///< check if the mouse will be dragged + +#if MOTIF + long getIndexColor (CColor color); + Colormap getColormap (); + Visual *getVisual (); + unsigned int getDepth (); + static long nbNewColor; +#endif + + void *getWindow () { return pWindow; } + void setWindow (void *ptr) { pWindow = ptr; } + void getLoc (CPoint &where) const { where = penLoc; } + CFrame* getFrame () const { return pFrame; } + + CPoint offsetScreen; + CPoint offset; + + void *getSystemContext () const { return pSystemContext; } + + virtual void forget (); + + //------------------------------------------- +protected: + + friend class CBitmap; + friend class COffscreenContext; + + void *pSystemContext; + void *pWindow; + CFrame *pFrame; + + long fontSize; + long fontStyle; + CFont fontId; + CColor fontColor; + CPoint penLoc; + + CCoord frameWidth; + CColor frameColor; + CColor fillColor; + CLineStyle lineStyle; + CDrawMode drawMode; + CRect clipRect; + +#if MOTIF + XFontStruct *pFontInfoStruct; +#endif +}; + + +//----------------------------------------------------------------------------- +// COffscreenContext Declaration +//! A drawing device which uses a pixmap as its drawing surface. +//----------------------------------------------------------------------------- +class COffscreenContext : public CDrawContext +{ +public: + COffscreenContext (CDrawContext *pContext, CBitmap *pBitmap, bool drawInBitmap = false); + COffscreenContext (CFrame *pFrame, long width, long height, const CColor backgroundColor = kBlackCColor); + + virtual ~COffscreenContext (); + + void copyFrom (CDrawContext *pContext, CRect destRect, CPoint srcOffset = CPoint (0, 0)); ///< copy from offscreen to pContext + void copyTo (CDrawContext* pContext, CRect& srcRect, CPoint destOffset = CPoint (0, 0)); ///< copy to offscreen from pContext + + inline CCoord getWidth () const { return width; } + inline CCoord getHeight () const { return height; } + + //------------------------------------------- +protected: + CBitmap *pBitmap; + CBitmap *pBitmapBg; + CCoord height; + CCoord width; + bool bDestroyPixmap; + + CColor backgroundColor; + +#if MOTIF + Display *pXdisplay; +#endif +}; + + +//----------------------------------------------------------------------------- +// CBitmap Declaration +//! Encapsulates various platform depended kinds of bitmaps. +//----------------------------------------------------------------------------- +class CBitmap : public CReferenceCounter +{ +public: + CBitmap (AEffGUIEditor& editor, const char* img_name); ///< Create from a filename + CBitmap (CFrame &frame, CCoord width, CCoord height); ///< Create a pixmap with a given size. + virtual ~CBitmap (); + + virtual void draw (CDrawContext *pContext, CRect &rect, const CPoint &offset = CPoint (0, 0)); ///< Draw the pixmap using a given rect as output position and a given offset of its source pixmap. + virtual void drawTransparent (CDrawContext *pContext, CRect &rect, const CPoint &offset = CPoint (0, 0)); + virtual void drawAlphaBlend (CDrawContext *pContext, CRect &rect, const CPoint &offset = CPoint (0, 0), unsigned char alpha = 128); ///< Same as CBitmap::draw except that it uses the alpha value to draw the bitmap alpha blended. + + inline CCoord getWidth () const { return width; } + inline CCoord getHeight () const { return height; } + + bool isLoaded () const; + void *getHandle () const; + + void setTransparentColor (const CColor color); + CColor getTransparentColor () const { return transparentCColor; } + void setTransparencyMask (CDrawContext* pContext, const CPoint& offset = CPoint (0, 0)); + + void setNoAlpha (bool state) { noAlpha = state; } + bool getNoAlpha () const { return noAlpha; } + + //------------------------------------------- +protected: + CBitmap (); + + virtual void dispose (); + virtual bool loadFromResource (long resourceID); + virtual bool loadFromPath (const void* platformPath); // platformPath is a C string + + long resourceID; + CCoord width; + CCoord height; + + CColor transparentCColor; + bool noAlpha; + +#if PNG + void *createPixmapFromPng (CDrawContext *pContext); + bool openPng (const char* path); + bool closePng (); + std::string pngPath; + png_structp pngRead; + png_infop pngInfo; + FILE* pngFp; +#endif +#if MOTIF + void *createPixmapFromXpm (CDrawContext *pContext); + + char **ppDataXpm; + void *pHandle; + void *pMask; +#endif +}; + +enum { + kMessageUnknown = 0, + kMessageNotified = 1 +}; + +//----------------------------------------------------------------------------- +// CView Declaration +//----------------------------------------------------------------------------- +class CView : public CReferenceCounter +{ +public: + CView (const CRect &size); + virtual ~CView (); + + virtual void draw (CDrawContext *pContext); ///< called if the view should draw itself + virtual void drawRect (CDrawContext *pContext, const CRect& updateRect) { draw (pContext); } ///< called if the view should draw itself + virtual bool checkUpdate (CRect& updateRect) const { return updateRect.rectOverlap (size); } + virtual void mouse (CDrawContext *pContext, CPoint &where, long buttons = -1); ///< called if a mouse click event occurs + + virtual void setBackground (CBitmap *background); ///< set the background image of this view + virtual CBitmap *getBackground () const { return pBackground; } ///< get the background image of this view + + virtual long onKeyDown (VstKeyCode& keyCode); ///< called if a key down event occurs and this view has focus + virtual long onKeyUp (VstKeyCode& keyCode); ///< called if a key up event occurs and this view has focus + + virtual bool onWheel (CDrawContext *pContext, const CPoint &where, float distance); ///< called if a mouse wheel event is happening over this view + virtual bool onWheel (CDrawContext *pContext, const CPoint &where, const CMouseWheelAxis axis, float distance); ///< called if a mouse wheel event is happening over this view + + virtual bool onDrop (CDrawContext* context, CDragContainer* drag, const CPoint& where) { return false; } ///< called if a drag is dropped onto this view + virtual void onDragEnter (CDrawContext* context, CDragContainer* drag, const CPoint& where) {} ///< called if a drag is entering this view + virtual void onDragLeave (CDrawContext* context, CDragContainer* drag, const CPoint& where) {} ///< called if a drag is leaving this view + virtual void onDragMove (CDrawContext* context, CDragContainer* drag, const CPoint& where) {} ///< called if a drag is current moved over this view + + virtual void looseFocus (CDrawContext *pContext = 0); ///< called if view should loose focus + virtual void takeFocus (CDrawContext *pContext = 0); ///< called if view should take focus + + virtual bool isDirty () const { return bDirty; } ///< check if view is dirty + virtual void setDirty (const bool val = true) { bDirty = val; } ///< set the view to dirty so that it is redrawn in the next idle. Thread Safe ! + + virtual bool isVisible () const { return bVisible; } ///< check if view is dirty + virtual void setVisible (const bool val = true) { bVisible = val; } ///< set the view to dirty so that it is redrawn in the next idle. Thread Safe ! + + virtual void setMouseEnabled (const bool bEnable = true) { bMouseEnabled = bEnable; } ///< turn on/off mouse usage for this view + virtual bool getMouseEnabled () const { return bMouseEnabled; } ///< get the state of wheather this view uses the mouse or not + + virtual void setMouseableArea (const CRect &rect) { mouseableArea = rect; } ///< set the area in which the view reacts to the mouse + virtual CRect &getMouseableArea (CRect &rect) const { rect = mouseableArea; return rect;} ///< get the area in which the view reacts to the mouse + + virtual bool hitTest (const CPoint& where, const long buttons = -1) { return where.isInside (mouseableArea); } ///< check if where hits this view + + virtual void setTransparency (bool val) { bTransparencyEnabled = val; } ///< set views transparent state + virtual bool getTransparency () const { return bTransparencyEnabled; } ///< is view transparent ? + + CCoord getHeight () const { return size.height (); } ///< get the height of the view + CCoord getWidth () const { return size.width (); } ///< get the width of the view + + virtual void setViewSize (CRect &rect); ///< set views size + virtual CRect &getViewSize (CRect &rect) const { rect = size; return rect; } ///< returns the current view size + virtual const CRect &getViewSize () const { return size; } ///< returns the current view size + + virtual bool removed (CView* parent) { return true; } ///< view is removed from parent view + virtual bool attached (CView* view) { return true; } ///< view is attached to a parent view + + virtual void getMouseLocation (CDrawContext* context, CPoint &point); ///< get current mouse location in local view coordinates + + virtual CPoint& frameToLocal (CPoint& point) const; ///< conversion from frame coordinates to local view coordinates + virtual CPoint& localToFrame (CPoint& point) const; ///< conversion from local view coordinates to frame coordinates + + bool getAttributeSize (const CViewAttributeID id, long& outSize) const; ///< get the size of an attribute + bool getAttribute (const CViewAttributeID id, const long inSize, void* outData, long& outSize) const; ///< get an attribute + bool setAttribute (const CViewAttributeID id, const long inSize, void* inData); ///< set an attribute + + CView *getParentView () const { return pParentView; } + CFrame *getParent () const { return pParentFrame; } + CFrame *getFrame () const { return pParentFrame; } + virtual void *getEditor () const; + + virtual long notify (CView* sender, const char* message); + void redraw (); + virtual void redrawRect (CDrawContext* context, const CRect& rect); + + virtual bool wantsFocus () const { return bWantsFocus; } ///< check if view supports focus + virtual void setWantsFocus (bool state) { bWantsFocus = state; } ///< set focus support on/off + +#if DEBUG + virtual void dumpInfo (); +#endif + + virtual bool isTypeOf (const char* s) const + { return (!strcmp (s, "CView")); } + + virtual void update (CDrawContext *pContext); // don't call this !!! + + //------------------------------------------- +protected: + friend class CControl; + friend class CFrame; + friend class CViewContainer; + + CRect size; + CRect mouseableArea; + + CFrame *pParentFrame; + CView *pParentView; + + bool bDirty; + bool bMouseEnabled; + bool bTransparencyEnabled; + bool bWantsFocus; + bool bVisible; + + CBitmap* pBackground; + CAttributeListEntry* pAttributeList; +}; + +// Message to check if View is a CViewContainer +const extern char* kMsgCheckIfViewContainer; + +//----------------------------------------------------------------------------- +// CViewContainer Declaration +//! Container Class of CView objects. +//----------------------------------------------------------------------------- +class CViewContainer : public CView +{ +public: + CViewContainer (const CRect &size, CFrame *pParent, CBitmap *pBackground = 0); + virtual ~CViewContainer (); + + virtual void addView (CView *pView); ///< add a child view + virtual void addView (CView *pView, CRect &mouseableArea, bool mouseEnabled = true); ///< add a child view + virtual void removeView (CView *pView, const bool &withForget = true); ///< remove a child view + virtual void removeAll (const bool &withForget = true); ///< remove all child views + virtual bool isChild (CView *pView) const; ///< check if pView is a child view of this container + virtual long getNbViews () const; ///< get the number of child views + virtual CView *getView (long index) const; ///< get the child view at index + + virtual void setBackgroundColor (const CColor color); ///< set the background color (will only be drawn if this container is not set to transparent and does not have a background bitmap) + virtual CColor getBackgroundColor () const { return backgroundColor; } ///< get the background color + virtual void setBackgroundOffset (const CPoint &p) { backgroundOffset = p; } ///< set the offset of the background bitmap + virtual const CPoint& getBackgroundOffset () const { return backgroundOffset; } ///< get the offset of the background bitmap + + virtual void drawBackgroundRect (CDrawContext *pContext, CRect& _updateRect); ///< draw the background + + enum { + kNormalUpdate = 0, ///< this mode redraws the whole container if something is dirty + kOnlyDirtyUpdate ///< this mode only redraws the views which are dirty + }; + + virtual void setMode (long val) { mode = val; } ///< set the update mode + virtual long getMode () const { return mode; } ///< get the update mode + + virtual void useOffscreen (bool b); ///< turn on/off using an offscreen + + virtual CView *getCurrentView () const; ///< get the current view under the mouse + virtual CView *getViewAt (const CPoint& where, bool deep = false) const; ///< get the view at point where + + void modifyDrawContext (CCoord save[4], CDrawContext* pContext); + void restoreDrawContext (CDrawContext* pContext, CCoord save[4]); + + // CView + virtual void draw (CDrawContext *pContext); + virtual void drawRect (CDrawContext *pContext, const CRect& updateRect); + virtual void mouse (CDrawContext *pContext, CPoint &where, long buttons = -1); + virtual bool onWheel (CDrawContext *pContext, const CPoint &where, float distance); + virtual bool onWheel (CDrawContext *pContext, const CPoint &where, const CMouseWheelAxis axis, float distance); + virtual void update (CDrawContext *pContext); + virtual bool hitTest (const CPoint& where, const long buttons = -1); + virtual long onKeyDown (VstKeyCode& keyCode); + virtual long onKeyUp (VstKeyCode& keyCode); + virtual long notify (CView* sender, const char* message); + + virtual bool onDrop (CDrawContext* context, CDragContainer* drag, const CPoint& where); + virtual void onDragEnter (CDrawContext* context, CDragContainer* drag, const CPoint& where); + virtual void onDragLeave (CDrawContext* context, CDragContainer* drag, const CPoint& where); + virtual void onDragMove (CDrawContext* context, CDragContainer* drag, const CPoint& where); + + virtual void looseFocus (CDrawContext *pContext = 0); + virtual void takeFocus (CDrawContext *pContext = 0); + virtual bool advanceNextFocusView (CView* oldFocus, bool reverse = false); + + virtual bool isDirty () const; + + virtual void setViewSize (CRect &rect); + + virtual bool removed (CView* parent); + virtual bool attached (CView* view); + + virtual CPoint& frameToLocal (CPoint& point) const; + virtual CPoint& localToFrame (CPoint& point) const; + + virtual void redrawRect (CDrawContext* context, const CRect& rect); + + CLASS_METHODS(CViewContainer, CView) + +#if DEBUG + virtual void dumpInfo (); + virtual void dumpHierarchy (); +#endif + + //------------------------------------------- +protected: + bool hitTestSubViews (const CPoint& where, const long buttons = -1); + + CCView *pFirstView; + CCView *pLastView; + long mode; + COffscreenContext *pOffscreenContext; + CColor backgroundColor; + CPoint backgroundOffset; + bool bDrawInOffscreen; + + CView* currentDragView; +}; + +//----------------------------------------------------------------------------- +// CFrame Declaration +//! The CFrame is the parent container of all views. +//----------------------------------------------------------------------------- +class CFrame : public CViewContainer +{ +public: + CFrame (const CRect &size, void *pSystemWindow, void *pEditor); + + virtual ~CFrame (); + + virtual bool open (); + virtual bool close (); + virtual bool isOpen () const { return bOpenFlag; } + + virtual void idle (); + virtual void doIdleStuff (); + + virtual unsigned long getTicks () const; ///< get the current time (in ms) + virtual long getKnobMode () const; ///< get hosts knob mode + + virtual bool setPosition (CCoord x, CCoord y); + virtual bool getPosition (CCoord &x, CCoord &y) const; + + virtual bool setSize (CCoord width, CCoord height); + virtual bool getSize (CRect *pSize) const; + virtual bool getSize (CRect &pSize) const; + + virtual long setModalView (CView *pView); + virtual CView *getModalView () const { return pModalView; } + + virtual void beginEdit (long index); + virtual void endEdit (long index); + + virtual bool getCurrentLocation (CPoint &where); + virtual void setCursor (CCursorType type); + + virtual void setFocusView (CView *pView); + virtual CView *getFocusView () const { return pFocusView; } + virtual bool advanceNextFocusView (CView* oldFocus, bool reverse = false); + + virtual bool setDropActive (bool val); + virtual bool isDropActive () const { return bDropActive; }; + + CDrawContext* createDrawContext (); + + virtual void setOpenFlag (bool val) { bOpenFlag = val;}; + virtual bool getOpenFlag () const { return bOpenFlag; }; + + virtual void invalidate (const CRect &rect); + + virtual bool updatesDisabled () const { return bUpdatesDisabled; } + virtual bool updatesDisabled (bool state) { bool before = bUpdatesDisabled; bUpdatesDisabled = state; return before; } + + void *getSystemWindow () const { return (void*)pSystemWindow; } + void *getParentSystemWindow () const { return (void*)pSystemWindow; } + void setParentSystemWindow (void *val) { pSystemWindow = (XdbeBackBuffer)val; } + + // CView + virtual void draw (CDrawContext *pContext); + virtual void drawRect (CDrawContext *pContext, const CRect& updateRect); + virtual void draw (CView *pView = 0); + virtual void mouse (CDrawContext *pContext, CPoint &where, long buttons = -1); + virtual bool onWheel (CDrawContext *pContext, const CPoint &where, float distance); + virtual bool onWheel (CDrawContext *pContext, const CPoint &where, const CMouseWheelAxis axis, float distance); + virtual long onKeyDown (VstKeyCode& keyCode); + virtual long onKeyUp (VstKeyCode& keyCode); + virtual void update (CDrawContext *pContext); + virtual void setViewSize (CRect& inRect); + virtual CView *getCurrentView () const; + + virtual void *getEditor () const { return pEditor; } + +#if MOTIF + Colormap getColormap () const { return colormap; } + Visual *getVisual () const { return pVisual; } + unsigned int getDepth () const { return depth; } + Window getWindow () const { return window; } + Drawable getBackBuffer () const { return backBuffer; } + void freeGc (); + + Region region; + + GC gc; + GC getGC () const { return gc; } +#endif + +#if DEBUG + virtual void dumpHierarchy (); +#endif + + CLASS_METHODS(CFrame, CViewContainer) + + //------------------------------------------- +protected: + bool initFrame (void *pSystemWin); + + void *pEditor; + + CView *pModalView; + CView *pFocusView; + + bool bFirstDraw; + bool bOpenFlag; + bool bDropActive; + bool bUpdatesDisabled; + +#if MOTIF + Colormap colormap; + Visual *pVisual; + Window window; + unsigned int depth; + XdbeBackBuffer backBuffer; + Window pSystemWindow; +#endif + + //------------------------------------------- +private: + CDrawContext *pFrameContext; + bool bAddedWindow; + void *defaultCursor; +}; + +//----------------------------------------------------------------------------- +// CDragContainer Declaration +//----------------------------------------------------------------------------- +class CDragContainer : public CReferenceCounter +{ +public: + CDragContainer (void* platformDrag); + ~CDragContainer (); + + void* first (long& size, long& type); ///< returns pointer on a char array if type is known + void* next (long& size, long& type); ///< returns pointer on a char array if type is known + + long getType (long idx) const; + long getCount () const { return nbItems; } + + enum { + kFile = 0, + kText, + + kUnknown = -1 + }; + +protected: + void* platformDrag; + long nbItems; + + long iterator; + void* lastItem; +}; + +//----------------------------------------------------------------------------- +// CCView Declaration +//----------------------------------------------------------------------------- +class CCView +{ +public: + CCView (CView *pView); + ~CCView (); + + CView *pView; + CCView *pNext; + CCView *pPrevious; +}; + +} // namespace VSTGUI + +// include the control objects +#ifndef __vstcontrols__ +#include "vstcontrols.h" +#endif + +#ifndef USE_NAMESPACE +using namespace VSTGUI; +#endif + +#endif // __vstgui__ diff --git a/vstgui/vstkeycode.h b/vstgui/vstkeycode.h new file mode 100644 index 0000000..1eba98c --- /dev/null +++ b/vstgui/vstkeycode.h @@ -0,0 +1,104 @@ +/* ---------------------------------------------------------------------------- + * VSTGUI for X11/LV2/PNG + * Author: Dave Robillard + * Released under the revised BSD license, as below + * ---------------------------------------------------------------------------- + * + * Based on: + * ---------------------------------------------------------------------------- + * VST Plug-Ins SDK Linux ONLY Port + * VSTGUIL: Graphical User Interface Framework for VST plugins on LINUX + * Version: 0.1, Date: 2007/01/21 + * Author: kRAkEn/gORe + * ---------------------------------------------------------------------------- + */ + +#ifndef __vstkeycode__ +#define __vstkeycode__ + + +/** Structure and enum used for keyUp/keyDown */ +struct VstKeyCode +{ + long character; + unsigned char virt; ///< see enum VstVirtualKey + unsigned char modifier; ///< see enum VstModifierKey +}; + + +/** Used by member virt of VstKeyCode */ +enum VstVirtualKey +{ + VKEY_BACK = 1, + VKEY_TAB, + VKEY_CLEAR, + VKEY_RETURN, + VKEY_PAUSE, + VKEY_ESCAPE, + VKEY_SPACE, + VKEY_NEXT, + VKEY_END, + VKEY_HOME, + + VKEY_LEFT, + VKEY_UP, + VKEY_RIGHT, + VKEY_DOWN, + VKEY_PAGEUP, + VKEY_PAGEDOWN, + + VKEY_SELECT, + VKEY_PRINT, + VKEY_ENTER, + VKEY_SNAPSHOT, + VKEY_INSERT, + VKEY_DELETE, + VKEY_HELP, + VKEY_NUMPAD0, + VKEY_NUMPAD1, + VKEY_NUMPAD2, + VKEY_NUMPAD3, + VKEY_NUMPAD4, + VKEY_NUMPAD5, + VKEY_NUMPAD6, + VKEY_NUMPAD7, + VKEY_NUMPAD8, + VKEY_NUMPAD9, + VKEY_MULTIPLY, + VKEY_ADD, + VKEY_SEPARATOR, + VKEY_SUBTRACT, + VKEY_DECIMAL, + VKEY_DIVIDE, + VKEY_F1, + VKEY_F2, + VKEY_F3, + VKEY_F4, + VKEY_F5, + VKEY_F6, + VKEY_F7, + VKEY_F8, + VKEY_F9, + VKEY_F10, + VKEY_F11, + VKEY_F12, + VKEY_NUMLOCK, + VKEY_SCROLL, + + VKEY_SHIFT, + VKEY_CONTROL, + VKEY_ALT, + + VKEY_EQUALS +}; + +/** Used by member modifier of VstKeyCode */ +enum VstModifierKey +{ + MODIFIER_SHIFT = 1<<0, ///< Shift + MODIFIER_ALTERNATE = 1<<1, ///< Alt + MODIFIER_COMMAND = 1<<2, ///< Control on Mac + MODIFIER_CONTROL = 1<<3 ///< Ctrl on PC, Apple on Mac +}; + +#endif -- cgit v1.2.1