summaryrefslogtreecommitdiffstats
path: root/src/Authoring/Qt3DStudio/Controls
diff options
context:
space:
mode:
Diffstat (limited to 'src/Authoring/Qt3DStudio/Controls')
-rw-r--r--src/Authoring/Qt3DStudio/Controls/AppFonts.cpp76
-rw-r--r--src/Authoring/Qt3DStudio/Controls/AppFonts.h61
-rw-r--r--src/Authoring/Qt3DStudio/Controls/BufferedRenderer.cpp214
-rw-r--r--src/Authoring/Qt3DStudio/Controls/BufferedRenderer.h60
-rw-r--r--src/Authoring/Qt3DStudio/Controls/ClickableLabel.cpp51
-rw-r--r--src/Authoring/Qt3DStudio/Controls/ClickableLabel.h48
-rw-r--r--src/Authoring/Qt3DStudio/Controls/Control.cpp1738
-rw-r--r--src/Authoring/Qt3DStudio/Controls/Control.h259
-rw-r--r--src/Authoring/Qt3DStudio/Controls/ControlData.cpp765
-rw-r--r--src/Authoring/Qt3DStudio/Controls/ControlData.h273
-rw-r--r--src/Authoring/Qt3DStudio/Controls/ControlGraph.cpp188
-rw-r--r--src/Authoring/Qt3DStudio/Controls/ControlGraph.h68
-rw-r--r--src/Authoring/Qt3DStudio/Controls/ControlGraphIterators.h156
-rw-r--r--src/Authoring/Qt3DStudio/Controls/OffscreenRenderer.cpp58
-rw-r--r--src/Authoring/Qt3DStudio/Controls/OffscreenRenderer.h61
-rw-r--r--src/Authoring/Qt3DStudio/Controls/Renderer.cpp74
-rw-r--r--src/Authoring/Qt3DStudio/Controls/Renderer.h105
-rw-r--r--src/Authoring/Qt3DStudio/Controls/WidgetControl.cpp243
-rw-r--r--src/Authoring/Qt3DStudio/Controls/WidgetControl.h83
-rw-r--r--src/Authoring/Qt3DStudio/Controls/WinRenderer.cpp518
-rw-r--r--src/Authoring/Qt3DStudio/Controls/WinRenderer.h131
21 files changed, 5230 insertions, 0 deletions
diff --git a/src/Authoring/Qt3DStudio/Controls/AppFonts.cpp b/src/Authoring/Qt3DStudio/Controls/AppFonts.cpp
new file mode 100644
index 00000000..6b491cf1
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Controls/AppFonts.cpp
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "Qt3DSCommonPrecompile.h"
+#include "AppFonts.h"
+#include "StudioPreferences.h"
+
+/**
+ * Constructor for a CAppFonts object.
+ */
+//=============================================================================
+CAppFonts::CAppFonts()
+{
+ // Normal font
+ const QString theFontFace = CStudioPreferences::GetFontFaceName();
+
+ m_NormalFont.setFamily(theFontFace);
+ m_NormalFont.setPointSize(13);
+}
+
+//==============================================================================
+/**
+ * Releases the object.
+ */
+//==============================================================================
+CAppFonts::~CAppFonts()
+{
+}
+
+//==============================================================================
+/**
+ * Returns a pointer to the only instance of this class. Automatically cleaned
+ * up when the program exits.
+ */
+//==============================================================================
+CAppFonts *CAppFonts::GetInstance()
+{
+ static CAppFonts theAppFonts;
+ return &theAppFonts;
+}
+
+//==============================================================================
+/**
+ * Returns the normal font for use on GUI elements for the application.
+ */
+//==============================================================================
+QFont CAppFonts::GetNormalFont()
+{
+ return m_NormalFont;
+}
diff --git a/src/Authoring/Qt3DStudio/Controls/AppFonts.h b/src/Authoring/Qt3DStudio/Controls/AppFonts.h
new file mode 100644
index 00000000..a3c10b01
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Controls/AppFonts.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Includes
+//==============================================================================
+
+#ifndef INCLUDED_APP_FONTS_H
+#define INCLUDED_APP_FONTS_H 1
+
+#pragma once
+
+//==============================================================================
+// Includes
+//==============================================================================
+
+#include <QtGui/qfont.h>
+//==============================================================================
+/**
+ * Dispatches commands
+ */
+//==============================================================================
+class CAppFonts
+{
+public:
+ CAppFonts();
+ virtual ~CAppFonts();
+ static CAppFonts *GetInstance();
+ QFont GetNormalFont();
+
+private:
+ QFont m_NormalFont;
+};
+
+#endif // INCLUDED_APP_FONTS_H
diff --git a/src/Authoring/Qt3DStudio/Controls/BufferedRenderer.cpp b/src/Authoring/Qt3DStudio/Controls/BufferedRenderer.cpp
new file mode 100644
index 00000000..5a97f0d3
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Controls/BufferedRenderer.cpp
@@ -0,0 +1,214 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "Qt3DSCommonPrecompile.h"
+
+#include "BufferedRenderer.h"
+#include "AppFonts.h"
+
+
+//=============================================================================
+/**
+ * Create a buffered renderer.
+ * @param inSize the size of this renderer.
+ */
+CBufferedRenderer::CBufferedRenderer(const QSize &inSize)
+ : CWinRenderer()
+{
+ m_CurrentBitmap = QPixmap(inSize);
+
+ // KDAB_TODO: I don't see why m_OldBitmap is needed, nor what is the difference between CBufferedRenderer and COffscreenRenderer
+ m_OldBitmap = m_CurrentBitmap;
+
+ m_painter = new QPainter(&m_CurrentBitmap);
+ QFont font = CAppFonts::GetInstance()->GetNormalFont();
+ m_painter->setFont(font);
+
+ m_Size = inSize;
+
+ PushClippingRect(QRect(QPoint(0,0), inSize));
+}
+
+
+//=============================================================================
+/**
+ * Destructor
+ */
+CBufferedRenderer::~CBufferedRenderer()
+{
+ delete m_painter;
+ m_painter = nullptr;
+}
+
+//=============================================================================
+/**
+ * Copy this BufferedRenderer to inRenderer using alpha blend.
+ * This will semi-transparently copy the contents of this buffer to inRenderer
+ * using the alpha.
+ * @param inRenderer the destination renderer.
+ * @param inAlpha the opacity, 255 = opaque 0 = transparent.
+ */
+/*void CBufferedRenderer::TransparentBltTo( CRenderer* inRenderer, short inAlpha )
+{
+
+ CPt theDestination;
+ theDestination.Offset( inRenderer->GetTranslation( ) );
+
+ AlphaBlendExt( inRenderer->GetGraphicsDevice( )->m_hDC, (short)theDestination.x,
+(short)theDestination.y, (short)m_Size.x, (short)m_Size.y, m_DC->m_hDC, 0, 0, (short)m_Size.x,
+(short)m_Size.y, inAlpha );
+// ::DrawAlphaBlendBitmap( inRenderer->GetDC( ), (short)theDestination.x,
+(short)theDestination.y, m_CurrentBitmap, (short)m_Size.x, (short)m_Size.y, 0, 0, inAlpha );
+
+}*/
+
+//==============================================================================
+/**
+ * Draws a bitmap using alpha blending. Works in NT/2000/9x
+ *
+ * @param inDCDest Destination device context
+ * @param inX X coordinate for drawing
+ * @param inY Y coordinate for drawing
+ * @param inWidth Drawing width
+ * @param inHeight Drawing height
+ * @param inDCSrc Source device context
+ * @param inSourceX X source coordinate
+ * @param inSourceY Y source coordinate
+ * @param inSourceWidth Source drawing width
+ * @param inSourceHeight Source drawing height
+ * @param inAlpha Alpha blend: 0-255, where 255 is opaque
+ */
+//==============================================================================
+/*bool CBufferedRenderer::AlphaBlendExt( HDC inDCDest, short inX, short inY, short inWidth, short
+inHeight, HDC inDCSrc, short inSourceX, short inSourceY, short inSourceWidth, short inSourceHeight,
+short inAlpha )
+{
+ BITMAPINFOHEADER theBMI;
+
+ theBMI.biSize = sizeof( BITMAPINFOHEADER );
+ theBMI.biWidth = inWidth;
+ theBMI.biHeight = inHeight;
+ theBMI.biPlanes = 1;
+ theBMI.biBitCount = 32; // 24 bits + alpha channel
+ theBMI.biCompression = BI_RGB; // no compression
+ theBMI.biSizeImage = 0;
+ theBMI.biXPelsPerMeter = 0;
+ theBMI.biYPelsPerMeter = 0;
+ theBMI.biClrUsed = 0; // use the whole palette
+ theBMI.biClrImportant = 0;
+
+ BYTE* theSrcBits;
+ HBITMAP theBmpSrc;
+
+ // Create DIB section in shared memory
+ theBmpSrc = CreateDIBSection( inDCSrc, ( BITMAPINFO* ) &theBMI, DIB_RGB_COLORS, ( void** )
+&theSrcBits, 0, 0L );
+
+ BYTE* theDestBits;
+ HBITMAP theBmpDest;
+
+ // Create DIB section in shared memory
+ theBmpDest = CreateDIBSection( inDCDest, ( BITMAPINFO* ) &theBMI, DIB_RGB_COLORS, ( void** )
+&theDestBits, 0, 0L );
+
+ // Copy our source and destination bitmaps onto our DIBSections.
+ // so we can get access to their bits using the BYTE*'s we used
+ // in the CreateDIBSection()s above.
+
+ HDC theDC = CreateCompatibleDC( nullptr );
+
+ HBITMAP theDCOld = ( HBITMAP ) SelectObject( theDC, theBmpSrc );
+
+ if ( !StretchBlt( theDC, 0, 0, inWidth, inHeight, inDCSrc, inSourceX, inSourceY,
+inSourceWidth, inSourceHeight, SRCCOPY ) )
+ {
+ SelectObject( theDC, theDCOld );
+ DeleteDC( theDC );
+ DeleteObject( theBmpSrc );
+ DeleteObject( theBmpDest );
+ return false;
+ }
+
+ SelectObject( theDC, theBmpDest );
+
+ if (! StretchBlt( theDC, 0, 0, inWidth, inHeight, inDCDest, inX, inY, inWidth, inHeight,
+SRCCOPY ) )
+ {
+ SelectObject( theDC, theDCOld );
+ DeleteDC( theDC );
+ DeleteObject( theBmpSrc );
+ DeleteObject( theBmpDest );
+ return true;
+ }
+
+ SelectObject( theDC, theDCOld );
+ DeleteDC( theDC );
+
+ short theXLoop, theYLoop;
+
+ for( theYLoop=0; theYLoop<inHeight; ++theYLoop )
+ {
+ LPBYTE theDestRGB = ( LPBYTE ) &( ( DWORD* ) theDestBits)[theYLoop * inWidth];
+ LPBYTE theSrcRGB = ( LPBYTE ) &( ( DWORD* ) theSrcBits)[theYLoop * inWidth];
+
+ for( theXLoop=0; theXLoop<inWidth; theXLoop++ )
+ {
+ theSrcRGB[0] = ( BYTE ) ( ( theDestRGB[0] * ( 255 - inAlpha ) + theSrcRGB[0]
+* inAlpha ) >> 8 );
+ theSrcRGB[1] = ( BYTE ) ( ( theDestRGB[1] * ( 255 - inAlpha ) + theSrcRGB[1]
+* inAlpha ) >> 8 );
+ theSrcRGB[2] = ( BYTE ) ( ( theDestRGB[2] * ( 255 - inAlpha ) + theSrcRGB[2]
+* inAlpha ) >> 8 );
+
+ theSrcRGB += 4;
+ theDestRGB += 4;
+ }
+ }
+
+ theDC = CreateCompatibleDC( nullptr );
+
+ theDCOld = ( HBITMAP ) SelectObject( theDC, theBmpSrc );
+
+ if ( !BitBlt( inDCDest, inX, inY, inWidth, inHeight, theDC, 0, 0, SRCCOPY ) )
+ {
+ SelectObject( theDC, theDCOld );
+ DeleteDC( theDC );
+ DeleteObject( theBmpSrc );
+ DeleteObject( theBmpDest );
+ return false;
+ }
+
+ SelectObject( theDC, theDCOld );
+ DeleteDC( theDC );
+
+ DeleteObject( theBmpSrc );
+ DeleteObject( theBmpDest );
+
+ return true;
+}*/
diff --git a/src/Authoring/Qt3DStudio/Controls/BufferedRenderer.h b/src/Authoring/Qt3DStudio/Controls/BufferedRenderer.h
new file mode 100644
index 00000000..19cc8f78
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Controls/BufferedRenderer.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_BUFFERED_RENDERER_H
+#define INCLUDED_BUFFERED_RENDERER_H 1
+
+#pragma once
+
+#include "WinRenderer.h"
+
+#include <QPainter>
+#include <QPixmap>
+#include <QFont>
+
+class CBufferedRenderer : public CWinRenderer
+{
+public:
+ CBufferedRenderer(const QSize &inSize);
+
+ virtual ~CBufferedRenderer();
+ QPixmap pixmap() const override { return m_CurrentBitmap;}
+
+ // void TransparentBltTo( CRenderer* inRenderer, short inAlpha );
+
+protected:
+ QPixmap m_OldBitmap;
+ QPixmap m_CurrentBitmap;
+ QSize m_Size;
+
+ // bool AlphaBlendExt( HDC inDCDest, short inX, short inY, short inWidth, short inHeight, HDC
+ //inDCSrc, short inSourceX, short inSourceY, short inSourceWidth, short inSourceHeight, short
+ //inAlpha );
+};
+#endif // INCLUDED_BUFFERED_RENDERER_H
diff --git a/src/Authoring/Qt3DStudio/Controls/ClickableLabel.cpp b/src/Authoring/Qt3DStudio/Controls/ClickableLabel.cpp
new file mode 100644
index 00000000..73995fcf
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Controls/ClickableLabel.cpp
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "ClickableLabel.h"
+
+#include <QMouseEvent>
+
+ClickableLabel::ClickableLabel(QWidget *pr) :
+ QLabel(pr)
+{
+
+}
+
+void ClickableLabel::mousePressEvent(QMouseEvent *event)
+{
+ if (rect().contains(event->pos()))
+ event->accept();
+}
+
+void ClickableLabel::mouseReleaseEvent(QMouseEvent *event)
+{
+ if (rect().contains(event->pos())) {
+ event->accept();
+ Q_EMIT clicked();
+ }
+}
diff --git a/src/Authoring/Qt3DStudio/Controls/ClickableLabel.h b/src/Authoring/Qt3DStudio/Controls/ClickableLabel.h
new file mode 100644
index 00000000..591baa9a
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Controls/ClickableLabel.h
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef CLICKABLELABEL_H
+#define CLICKABLELABEL_H
+
+#include <QLabel>
+
+class ClickableLabel : public QLabel
+{
+ Q_OBJECT
+public:
+ ClickableLabel(QWidget *pr = nullptr);
+
+Q_SIGNALS:
+ void clicked();
+
+protected:
+ void mouseReleaseEvent(QMouseEvent *event) override;
+ void mousePressEvent(QMouseEvent *event) override;
+};
+
+#endif // CLICKABLELABEL_H
diff --git a/src/Authoring/Qt3DStudio/Controls/Control.cpp b/src/Authoring/Qt3DStudio/Controls/Control.cpp
new file mode 100644
index 00000000..03f01403
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Controls/Control.cpp
@@ -0,0 +1,1738 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "Qt3DSCommonPrecompile.h"
+
+#include "Control.h"
+#include "Renderer.h"
+#include "MasterP.h"
+#include "StudioUtils.h"
+#include "HotKeys.h"
+#include "ControlGraph.h"
+#include "ControlData.h"
+#include "ResourceCache.h"
+#include "MouseCursor.h"
+
+#include <QtWidgets/qapplication.h>
+
+using namespace Q3DStudio::Control;
+
+IMPLEMENT_OBJECT_COUNTER(CControl)
+
+//=============================================================================
+/**
+ * Constructor, creates a control with all default values.
+ */
+CControl::CControl()
+ : m_cursorSet(-1)
+{
+ m_ControlData = CControlData::CreateControlData(*this);
+ ADDTO_OBJECT_COUNTER(CControl)
+}
+
+//=============================================================================
+/**
+ * Destructor
+ */
+CControl::~CControl()
+{
+ REMOVEFROM_OBJECT_COUNTER(CControl)
+ m_ControlData->ReleaseControl();
+}
+
+//=============================================================================
+/**
+ * Draw this control and all children below it.
+ * This can be overriden by controls to draw themselves but should still be
+ * called if sub controls are to be drawn.
+ * This will call Draw if this control is actually supposed to be drawn. It will
+ * be drawn if it is invalidated or if anything above it in it's heirarchy has
+ * been invalidated.
+ * @param inRenderer the renderer to draw this control out to.
+ */
+void CControl::OnDraw(CRenderer *inRenderer, CRct &inDirtyRect,
+ bool inIgnoreValidation /* = false */)
+{
+ EnsureLayout();
+ bool isInvalidated = IsInvalidated();
+
+ // inRenderer->PushClippingRect( GetSize( ) );
+
+ CRct theBoundingBox = inRenderer->GetClippingRect();
+
+ if (isInvalidated) {
+ CRct theRect(GetSize());
+ theRect.And(theBoundingBox);
+ theRect.Offset(inRenderer->GetTranslation());
+ inDirtyRect.Or(theRect);
+ }
+
+ if (isInvalidated || inIgnoreValidation)
+ Draw(inRenderer);
+
+ // Notify the children in the reverse order that they are drawn.
+ ControlGraph::SReverseIterator theRPos = ControlGraph::GetRChildren(*this);
+ for (; !theRPos.IsDone(); ++theRPos) {
+ (*theRPos)->EnsureLayout();
+ (*theRPos)->BeginDrawChildren(inRenderer);
+ }
+
+ // Go through all the children and draw them in the correct order. By keeping
+ // this order there is a semblance of depth.
+ ControlGraph::SIterator thePos = ControlGraph::GetChildren(*this);
+ for (; !thePos.IsDone(); ++thePos) {
+ std::shared_ptr<CControlData> theChild = (*thePos);
+ if (theChild->IsVisible()) {
+ CPt thePosition = theChild->GetPosition();
+ inRenderer->PushTranslation(thePosition);
+
+ // Clipping of non-visible objects.
+ if (theChild->IsInRect(theBoundingBox))
+ theChild->OnDraw(inRenderer, inDirtyRect, inIgnoreValidation || isInvalidated);
+ else
+ theChild->NotifyNotInClipRect();
+ inRenderer->PopTranslation();
+ }
+ }
+
+ // inRenderer->PopClippingRect( );
+
+ // Set this as not being invalidated.
+ Invalidate(false);
+}
+
+//=============================================================================
+/**
+ * Performs the drawing for this control.
+ * Does nothing by default.
+ * @param inRenderer the renderer to draw to.
+ */
+void CControl::Draw(CRenderer *inRenderer)
+{
+ Q_UNUSED(inRenderer);
+}
+
+//=============================================================================
+/**
+ * Notification that this control is not in the clipping rect and hence will
+ * not be drawn.
+ * By default, tell inform its children
+ */
+void CControl::NotifyNotInClipRect()
+{
+ ControlGraph::SIterator thePos = ControlGraph::GetChildren(*this);
+ for (; !thePos.IsDone(); ++thePos) {
+ std::shared_ptr<CControlData> theChild = (*thePos);
+ theChild->NotifyNotInClipRect();
+ }
+}
+
+//=============================================================================
+/**
+ * Get the position of this control.
+ * The position of this control is relative to it's parent's 0,0 coordinate.
+ * @return the position relative to it's parent's position.
+ */
+CPt CControl::GetPosition() const
+{
+ return m_ControlData->m_Position;
+}
+
+//=============================================================================
+/**
+ * Set the position of this control.
+ * The position of this control is relative to it's parent's 0,0 coordinate.
+ * @return the position relative to it's parent's position.
+ */
+void CControl::SetPosition(CPt inPosition)
+{
+ if (inPosition != m_ControlData->m_Position) {
+ MarkChildrenNeedLayout();
+ m_ControlData->m_Position = inPosition;
+ Invalidate();
+ }
+}
+
+//=============================================================================
+/**
+ * Overload of SetPosition to allow it to take 2 parameters.
+ * This will call SetPosition( CPt ) so there is no need to extend this
+ * method.
+ * @param inX the X position to set.
+ * @param inY the Y position to set.
+ */
+void CControl::SetPosition(long inX, long inY)
+{
+ SetPosition(CPt(inX, inY));
+}
+
+//=============================================================================
+/**
+ * Get the size of the control.
+ * The size is the width and height of the control from it's position.
+ * @return the size of this control.
+ */
+CPt CControl::GetSize() const
+{
+ return m_ControlData->m_Size;
+}
+
+//=============================================================================
+/**
+ * Set the size of this control.
+ * The size is the width and height of the control from it's position.
+ * @param inSize the new size of the control.
+ */
+void CControl::SetSize(CPt inSize)
+{
+ if (GetSize() != inSize) {
+ m_ControlData->m_Size = inSize;
+ if (GetParent() != nullptr)
+ GetParent()->OnChildSizeChanged(this); // this callback needs to die
+ OnSizeChanged(inSize);
+ }
+}
+
+void CControl::OnSizeChanged(CPt /*inSize*/)
+{
+ MarkChildrenNeedLayout();
+ Invalidate();
+}
+
+//=============================================================================
+/**
+ * Overload of SetSize to allow it to take 2 parameters.
+ * This will call SetSize( CPt ) so there is no need to extend this method.
+ * @param inWidth the new width of this control.
+ * @param inHeight the new height of this control.
+ */
+void CControl::SetSize(long inX, long inY)
+{
+ SetSize(CPt(inX, inY));
+}
+
+//=============================================================================
+/**
+ * Get the minimum allowable size of this control.
+ * This is used by layout managers to get the minimum size that a control is
+ * allowed to be when it is resizing the control. This defaults to 0,0.
+ * @return the minimum size that this control is allowed to be.
+ */
+CPt CControl::GetMinimumSize()
+{
+ return m_ControlData->m_MinSize;
+}
+
+//=============================================================================
+/**
+ * Set the minimum allowable size of this control.
+ * This is used by layout managers to get the minimum size that a control is
+ * allowed to be when it is resizing the control. This defaults to 0,0.
+ * param inSize the minimum size that this control is allowed to be.
+ */
+void CControl::SetMinimumSize(CPt inSize)
+{
+ if (inSize != m_ControlData->m_MinSize) {
+ NotifyParentNeedsLayout();
+ m_ControlData->m_MinSize = inSize;
+ if (inSize.x > m_ControlData->m_MaxSize.x)
+ m_ControlData->m_MaxSize.x = inSize.x;
+ if (inSize.y > m_ControlData->m_MaxSize.y)
+ m_ControlData->m_MaxSize.y = inSize.y;
+ }
+}
+
+//=============================================================================
+/**
+ * Get the maximum allowable size of this control.
+ * This is used by layout managers to get the maximum size that a control is
+ * allowed to be when it is resizing the control. This defaults to LONG_MAX,LONG_MAX.
+ * @return the maximum size that this control is allowed to be.
+ */
+CPt CControl::GetMaximumSize()
+{
+ return m_ControlData->m_MaxSize;
+}
+
+//=============================================================================
+/**
+ * Set the maximum allowable size of this control.
+ * This is used by layout managers to get the maximum size that a control is
+ * allowed to be when it is resizing the control. This defaults to LONG_MAX,LONG_MAX.
+ * @param inSize the maximum size that this control is allowed to be.
+ */
+void CControl::SetMaximumSize(CPt inSize)
+{
+ if (inSize != m_ControlData->m_MaxSize) {
+ NotifyParentNeedsLayout();
+ m_ControlData->m_MaxSize = inSize;
+ }
+}
+
+//=============================================================================
+/**
+ * Get the preferred size of this control.
+ * This is used by layout managers to get the preferred size of the control.
+ * The preferred size is often used for relative scaling of sibling controls.
+ * @return the preferred size of this control.
+ */
+CPt CControl::GetPreferredSize()
+{
+ return m_ControlData->m_PrefSize;
+}
+
+//=============================================================================
+/**
+ * Set the preferred size of this control.
+ * This is used by layout managers to get the preferred size of the control.
+ * The preferred size is often used for relative scaling of sibling controls.
+ * @param the preferred size of this control.
+ */
+void CControl::SetPreferredSize(CPt inSize)
+{
+ if (inSize != m_ControlData->m_PrefSize) {
+ NotifyParentNeedsLayout();
+ Invalidate();
+ m_ControlData->m_PrefSize = inSize;
+ }
+}
+
+void CControl::SetAbsoluteSize(CPt inSize)
+{
+ SetMinimumSize(inSize);
+ SetMaximumSize(inSize);
+ SetPreferredSize(inSize);
+ SetSize(inSize);
+}
+
+//=============================================================================
+/**
+ * Event called when the mouse is moving.
+ * This event will be called when the mouse is over this control or when this
+ * control has the focus. This can be extended by controls but should be called
+ * if the event is to be propagated down to child controls.
+ * @param inPoint the location of the mouse relative to this control.
+ * @param inFlags Modifier keys that are down at time of event. Can be any
+ * combination of the following: MODIFIER_CONTROL | MODIFIER_SHIFT |
+ * MODIFIER_ALT | MOUSE_LBUTTON | MOUSE_RBUTTON | MOUSE_MBUTTON
+ */
+void CControl::OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ bool theHitFlag = false;
+ // Go through all the children notifying them of mouse moves.
+ ControlGraph::SReverseIterator thePos = ControlGraph::GetRChildren(*this);
+ for (; thePos.HasNext(); ++thePos) {
+ std::shared_ptr<CControlData> theChild = (*thePos);
+ // If a child has not already gotten the move (higher level child covering a lower level
+ // one)
+ // then check the hit test.
+ if (!theHitFlag && theChild->HitTest(inPoint)) {
+ CPt theChildPoint = inPoint - theChild->GetPosition();
+ // This is the first child to be hit, do not allow the message to go onto another
+ // sibling under this one.
+ theHitFlag = true;
+
+ // Do not fire events to non-enabled children.
+ if (theChild->IsEnabled()) {
+ // If this is the first time the mouse is over this then fire a mouse over
+ if (!theChild->IsMouseOver())
+ theChild->OnMouseOver(theChildPoint, inFlags);
+ // Fire a mouse move as well, this will also propagate the mouse over to
+ // grand-children etc.
+ theChild->OnMouseMove(theChildPoint, inFlags);
+ }
+ }
+ // Check all the children and if they think the mouse is over them then notify them of a
+ // mouse out.
+ else if (theChild->IsMouseOver()) {
+ CPt theChildPoint = inPoint - theChild->GetPosition();
+ theChild->OnMouseOut(theChildPoint, inFlags);
+ }
+ }
+
+ // If there is a child with focus and the mouse is not over it then still notify it of the mouse
+ // move
+ // If the mouse is over it then it would have gotten the move from the above loop.
+ if (m_ControlData->m_MouseFocus && !m_ControlData->m_MouseFocus->IsMouseOver()) {
+ CPt theChildPoint = inPoint - m_ControlData->m_MouseFocus->GetPosition();
+ m_ControlData->m_MouseFocus->OnMouseMove(theChildPoint, inFlags);
+ }
+}
+
+//=============================================================================
+/**
+ * Notification that the mouse is over this control.
+ * This is only called once when the mouse enters the control, and does not get
+ * called until the mouse leaves then re-enters the control.
+ * @param inPoint where the mouse is, relative to this control.
+ * @param inFlags Modifier keys that are down at time of event. Can be any
+ * combination of the following: MODIFIER_CONTROL | MODIFIER_SHIFT |
+ * MODIFIER_ALT | MOUSE_LBUTTON | MOUSE_RBUTTON | MOUSE_MBUTTON
+ */
+void CControl::OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ Q_UNUSED(inPoint);
+ Q_UNUSED(inFlags);
+ m_ControlData->m_IsMouseOver = true;
+}
+
+//=============================================================================
+/**
+ * Notification that the mouse left this control.
+ * This is only called once when the mouse leaves the control and does not get
+ * called until the mouse enters then re-leaves the control.
+ * This also notifies all children that the mouse is over that it is no longer
+ * over.
+ * @param inPoint where the mouse is, relative to this control.
+ * @param inFlags Modifier keys that are down at time of event. Can be any
+ * combination of the following: MODIFIER_CONTROL | MODIFIER_SHIFT |
+ * MODIFIER_ALT | MOUSE_LBUTTON | MOUSE_RBUTTON | MOUSE_MBUTTON
+ */
+void CControl::OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ m_ControlData->m_IsMouseOver = false;
+
+ // Go through all the children looking for ones that think the mouse is over.
+ // If it is then notify it of a mouse out.
+ ControlGraph::SReverseIterator thePos = ControlGraph::GetRChildren(*this);
+ for (; thePos.HasNext(); ++thePos) {
+ std::shared_ptr<CControlData> theChild = (*thePos);
+ if (theChild->IsMouseOver()) {
+ CPt theChildPoint = inPoint - theChild->GetPosition();
+ theChild->OnMouseOut(inPoint, inFlags);
+ }
+ }
+}
+
+//=============================================================================
+/**
+ * Notification that the left mouse button was clicked on this control.
+ * This handles the mouse hits and sets the focus to the control that was
+ * clicked on.
+ * @param inPoint where the mouse was clicked, in local coordinates.
+ * @param inFlags Modifier keys that are down at time of event. Can be any
+ * combination of the following: MODIFIER_CONTROL | MODIFIER_SHIFT |
+ * MODIFIER_ALT | MOUSE_LBUTTON | MOUSE_RBUTTON | MOUSE_MBUTTON
+ * @return true if the mouse event is processed.
+ */
+bool CControl::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ bool theRetVal = false;
+ bool theChildGotHit = false;
+
+ // Go through all the children looking for the first one that was clicked on
+ ControlGraph::SReverseIterator thePos = ControlGraph::GetRChildren(*this);
+ for (; thePos.HasNext(); ++thePos) {
+ std::shared_ptr<CControlData> theChild = (*thePos);
+ // If the child was hit then notify it of the mouse down, and set the focus to
+ // be it.
+ if (theChild->HitTest(inPoint)) {
+ CPt theChildPoint = inPoint - theChild->GetPosition();
+ theChildGotHit = true;
+ // Only send the event if the child is enabled.
+ if (theChild->IsEnabled()) {
+ theRetVal = theChild->OnMouseDown(theChildPoint, inFlags);
+
+ if (m_ControlData->m_Focus != theChild) {
+ if (m_ControlData->m_Focus)
+ m_ControlData->m_Focus->OnLoseFocus();
+ if (theChild->CanGainFocus()) {
+ m_ControlData->m_Focus = theChild;
+ m_ControlData->m_Focus->OnGainFocus();
+ } else {
+ m_ControlData->m_Focus = std::shared_ptr<CControlData>();
+ }
+ }
+ m_ControlData->m_MouseFocus = theChild;
+ } else {
+ m_ControlData->m_Focus = std::shared_ptr<CControlData>();
+ }
+
+ // only want OnMouseDown to be called on the first child under the point.
+ break;
+ }
+ }
+ if (!theChildGotHit && m_ControlData->m_Focus) {
+ m_ControlData->m_Focus->OnLoseFocus();
+ m_ControlData->m_Focus = std::shared_ptr<CControlData>();
+ }
+ m_ControlData->SetMouseDown(!theRetVal);
+
+ return theRetVal;
+}
+
+//=============================================================================
+/**
+ * Notification that the right mouse button was clicked on this control.
+ * This handles the mouse hits and sets the focus to the control that was
+ * clicked on.
+ * @param inPoint where the mouse was clicked, in local coordinates.
+ * @param inFlags Modifier keys that are down at time of event. Can be any
+ * combination of the following: MODIFIER_CONTROL | MODIFIER_SHIFT |
+ * MODIFIER_ALT | MOUSE_LBUTTON | MOUSE_RBUTTON | MOUSE_MBUTTON
+ * @return true if the mouse event is processed.
+ */
+bool CControl::OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ bool theRetVal = false;
+
+ // Go through all the children looking for the first one that was clicked on
+ ControlGraph::SReverseIterator thePos = ControlGraph::GetRChildren(*this);
+ for (; thePos.HasNext(); ++thePos) {
+ std::shared_ptr<CControlData> theChild = (*thePos);
+ // If the child was hit then notify it of the mouse down, and set the focus to
+ // be it.
+ if (theChild->HitTest(inPoint)) {
+ CPt theChildPoint = inPoint - theChild->GetPosition();
+
+ // Only send the event if the child is enabled.
+ if (theChild->IsEnabled()) {
+ if (m_ControlData->m_Focus != theChild) {
+ if (m_ControlData->m_Focus)
+ m_ControlData->m_Focus->OnLoseFocus();
+ if (theChild->CanGainFocus()) {
+ m_ControlData->m_Focus = theChild;
+ m_ControlData->m_Focus->OnGainFocus();
+ } else {
+ m_ControlData->m_Focus = std::shared_ptr<CControlData>();
+ }
+ }
+ m_ControlData->m_MouseFocus = theChild;
+ theRetVal = theChild->OnMouseRDown(theChildPoint, inFlags);
+ } else {
+ m_ControlData->m_Focus = std::shared_ptr<CControlData>();
+ }
+
+ // only want OnMouseDown to be called on the first child under the point.
+ break;
+ }
+ }
+
+ return theRetVal;
+}
+
+//=============================================================================
+/**
+ * Notification thatthe mouse was double clicked on this control.
+ * This handled the mouse hits and passes it down to all the children.
+ * @param inPoint where the mouse was clicked, in local coordinates.
+ * @param inFlags Modifier keys that are down at time of event. Can be any
+ * combination of the following: MODIFIER_CONTROL | MODIFIER_SHIFT |
+ * MODIFIER_ALT | MOUSE_LBUTTON | MOUSE_RBUTTON | MOUSE_MBUTTON
+ * @return true if the mouse event is processed.
+ */
+bool CControl::OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ bool theRetVal = false;
+
+ // Go through all the children looking for the first one that was clicked on
+ ControlGraph::SReverseIterator thePos = ControlGraph::GetRChildren(*this);
+ for (; thePos.HasNext(); ++thePos) {
+ std::shared_ptr<CControlData> theChild = (*thePos);
+ // If the child was hit then notify it of the mouse down, and set the focus to
+ // be it.
+ if (theChild->HitTest(inPoint)) {
+ CPt theChildPoint = inPoint - theChild->GetPosition();
+ // Only send the event if the child is enabled.
+ if (theChild->IsEnabled())
+ theRetVal = theChild->OnMouseDoubleClick(theChildPoint, inFlags);
+
+ // only want OnMouseDown to be called on the first child under the point.
+ break;
+ }
+ }
+
+ return theRetVal;
+}
+
+bool CControl::OnMouseWheel(CPt inPoint, long inAmount, Qt::KeyboardModifiers inFlags)
+{
+ bool theRetVal = false;
+
+ // try letting the focus getting the wheel first
+ if (m_ControlData->m_Focus) {
+ CPt theChildPoint = inPoint - m_ControlData->m_Focus->GetPosition();
+ theRetVal = m_ControlData->m_Focus->OnMouseWheel(theChildPoint, inAmount, inFlags);
+ }
+
+ // if the focus does not want the wheel then let the mouse pos do it.
+ if (!theRetVal) {
+ // Go through all the children looking for the first one that was clicked on
+ ControlGraph::SReverseIterator thePos = ControlGraph::GetRChildren(*this);
+ for (; thePos.HasNext(); ++thePos) {
+ std::shared_ptr<CControlData> theChild = (*thePos);
+ if (theChild->GetMouseWheelEventState() == ControlEventState::Listening
+ && theChild->IsEnabled() && theChild->HitTest(inPoint)) {
+ CPt theChildPoint = inPoint - theChild->GetPosition();
+ theRetVal = theChild->OnMouseWheel(theChildPoint, inAmount, inFlags);
+ break;
+ }
+ }
+ }
+
+ return theRetVal;
+}
+
+//=============================================================================
+/**
+ * Notification that the mouse is hovering over this control.
+ * This handles the mouse hover and passes it down to all the children.
+ * @param inPoint where the mouse is located, in local coordinates.
+ * @param inFlags Modifier keys that are down at time of event. Can be any
+ * combination of the following: MODIFIER_CONTROL | MODIFIER_SHIFT |
+ * MODIFIER_ALT | MOUSE_LBUTTON | MOUSE_RBUTTON | MOUSE_MBUTTON
+ * @return true if the mouse event is processed.
+ */
+bool CControl::OnMouseHover(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ bool theRetVal = false;
+
+ // Go through all the children looking for the first one that was clicked on
+ ControlGraph::SReverseIterator thePos = ControlGraph::GetRChildren(*this);
+ for (; thePos.HasNext(); ++thePos) {
+ std::shared_ptr<CControlData> theChild = (*thePos);
+ // If the child was hit then notify it of the mouse down, and set the focus to
+ // be it.
+ if (theChild->HitTest(inPoint)) {
+ CPt theChildPoint = inPoint - theChild->GetPosition();
+ // Only send the event if the child is enabled.
+ if (theChild->IsEnabled())
+ theRetVal = theChild->OnMouseHover(theChildPoint, inFlags);
+
+ // only want OnMouseHover to be called on the first child under the point.
+ break;
+ }
+ }
+
+ return theRetVal;
+}
+
+//=============================================================================
+/**
+ * Notification that the left mouse button was released.
+ * This is only called on the control that has focus, not on the control under
+ * the mouse.
+ * @param inPoint where the mouse was released, in local coordinates.
+ * @param inFlags Modifier keys that are down at time of event. Can be any
+ * combination of the following: MODIFIER_CONTROL | MODIFIER_SHIFT |
+ * MODIFIER_ALT | MOUSE_LBUTTON | MOUSE_RBUTTON | MOUSE_MBUTTON
+ */
+void CControl::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ if (m_ControlData->m_MouseFocus) {
+ CPt theChildPoint = inPoint - m_ControlData->m_MouseFocus->GetPosition();
+ m_ControlData->m_MouseFocus->OnMouseUp(theChildPoint, inFlags);
+ }
+
+ // Go through all the children looking for the first one that was clicked on
+ ControlGraph::SReverseIterator thePos = ControlGraph::GetRChildren(*this);
+ for (; thePos.HasNext(); ++thePos) {
+ std::shared_ptr<CControlData> theChild = (*thePos);
+ // If the child was hit then notify it of the mouse down, and set the focus to
+ // be it.
+ if (theChild->HitTest(inPoint)) {
+ CPt theChildPoint = inPoint - theChild->GetPosition();
+ // Only send the event if the child is enabled.
+ if (theChild->IsEnabled() && theChild != m_ControlData->m_MouseFocus
+ && theChild != m_ControlData->m_Focus) {
+ theChild->OnMouseUp(theChildPoint, inFlags);
+ }
+
+ // only want OnMouseUp to be called on the first child under the point.
+ break;
+ }
+ }
+ m_ControlData->m_MouseFocus = std::shared_ptr<CControlData>();
+
+ if (m_ControlData->m_IsMouseDown) {
+ OnMouseClick(inPoint, inFlags);
+ m_ControlData->SetMouseDown(false);
+ }
+}
+
+//=============================================================================
+/**
+ * Notification that the right mouse button was released.
+ * This is only called on the control that has focus, not on the control under
+ * the mouse.
+ * @param inPoint where the mouse was released, in local coordinates.
+ * @param inFlags Modifier keys that are down at time of event. Can be any
+ * combination of the following: MODIFIER_CONTROL | MODIFIER_SHIFT |
+ * MODIFIER_ALT | MOUSE_LBUTTON | MOUSE_RBUTTON | MOUSE_MBUTTON
+ */
+void CControl::OnMouseRUp(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ if (m_ControlData->m_MouseFocus) {
+ CPt theChildPoint = inPoint - m_ControlData->m_MouseFocus->GetPosition();
+ m_ControlData->m_MouseFocus->OnMouseRUp(theChildPoint, inFlags);
+ }
+
+ // Go through all the children looking for the first one that was clicked on
+ ControlGraph::SReverseIterator thePos = ControlGraph::GetRChildren(*this);
+ for (; thePos.HasNext(); ++thePos) {
+ std::shared_ptr<CControlData> theChild = (*thePos);
+ // If the child was hit then notify it of the mouse down, and set the focus to
+ // be it.
+ if (theChild->HitTest(inPoint)) {
+ CPt theChildPoint = inPoint - theChild->GetPosition();
+ // Only send the event if the child is enabled.
+ if (theChild->IsEnabled() && theChild != m_ControlData->m_MouseFocus
+ && theChild != m_ControlData->m_Focus) {
+ theChild->OnMouseRUp(theChildPoint, inFlags);
+ }
+
+ // only want OnMouseUp to be called on the first child under the point.
+ break;
+ }
+ }
+ m_ControlData->m_MouseFocus = std::shared_ptr<CControlData>();
+}
+
+//=============================================================================
+/**
+ * Handles character input from the keyboard.
+ *
+ * @param inChar Character that was pressed
+ * @return true if the character was handled, false if this control does not
+ * care about the character that was pressed
+ */
+bool CControl::OnChar(const QString &inChar, Qt::KeyboardModifiers inModifiers)
+{
+ if (m_ControlData->m_Focus)
+ return m_ControlData->m_Focus->OnChar(inChar, inModifiers);
+ else
+ return false;
+}
+
+//=============================================================================
+/**
+ * Handles a key down message from the keyboard.
+ *
+ * @param inChar Character that was pressed
+ * @return true if the character was handled, false if this control does not
+ * care about the character that was pressed
+ */
+bool CControl::OnKeyDown(unsigned int inChar, Qt::KeyboardModifiers inModifiers)
+{
+ bool theRetVal = false;
+
+ if (m_ControlData->m_Focus)
+ theRetVal = m_ControlData->m_Focus->OnKeyDown(inChar, inModifiers);
+
+ if (!theRetVal) {
+ if (inChar == Qt::Key_Tab) {
+ if (inModifiers & Qt::ShiftModifier)
+ OnReverseTab();
+ else
+ OnTab();
+ theRetVal = true;
+ }
+ }
+
+ return theRetVal;
+}
+
+//=============================================================================
+/**
+ * Handles a key up from the keyboard.
+ *
+ * @param inChar Character that was pressed
+ * @return true if the character was handled, false if this control does not
+ * care about the character that was pressed
+ */
+bool CControl::OnKeyUp(unsigned int inChar, Qt::KeyboardModifiers)
+{
+ Q_UNUSED(inChar);
+ return false;
+}
+
+//=============================================================================
+/**
+ * Find the first child (descendant) control that has a valid drop target.
+ */
+CDropTarget *CControl::FindDropCandidate(CPt &inMousePoint, Qt::KeyboardModifiers inFlags,
+ EStudioObjectType objectType,
+ Q3DStudio::DocumentEditorFileType::Enum fileType)
+{
+ CDropTarget *theDropTarget = NULL;
+
+ // Go through all the children looking for the first one that was clicked on
+ ControlGraph::SReverseIterator thePos = ControlGraph::GetRChildren(*this);
+ for (; thePos.HasNext(); ++thePos) {
+ std::shared_ptr<CControlData> theChild = (*thePos);
+ if (theChild->IsMouseOver() && theChild->IsEnabled()) {
+ // Put the point into this childs coords.
+ CPt theChildPoint = inMousePoint - theChild->GetPosition();
+
+ // Allow the child the opportunity to respond
+ theDropTarget = theChild->FindDropCandidate(theChildPoint, inFlags, objectType,
+ fileType);
+
+ if (theDropTarget)
+ break;
+ }
+ }
+ return theDropTarget;
+}
+
+//=============================================================================
+/**
+ * Add a child control to this control.
+ * This will make the child behave as a child of this, get set up for drawing
+ * and events. The inInsertBefore control is used to determine Z-depth, or
+ * manually insert a control into a specific location.
+ * The child cannot already be a child of another control.
+ * @param inControl the control to be added.
+ * @param inInsertBefore the control to be inserted before, or std::shared_ptr<CControlData>() to
+ * be at the back.\
+ */
+void CControl::AddChild(CControl *inControl,
+ CControl *inInsertBefore /*=std::shared_ptr<CControlData>()*/)
+{
+ NotifyParentNeedsLayout();
+ ControlGraph::AddChild(*this, *inControl, inInsertBefore);
+}
+
+//=============================================================================
+/**
+ * Remove a child control from this control.
+ * This will remove it from drawing and getting any events.
+ * @param inControl the control to be removed.
+ */
+void CControl::RemoveChild(CControl *inControl)
+{
+ if (inControl) {
+ ControlGraph::RemoveChild(*this, *inControl);
+
+ if (m_ControlData->m_Focus == inControl->m_ControlData)
+ m_ControlData->m_Focus = std::shared_ptr<CControlData>();
+ if (m_ControlData->m_MouseFocus == inControl->m_ControlData)
+ m_ControlData->m_MouseFocus = std::shared_ptr<CControlData>();
+ }
+}
+
+//=============================================================================
+/**
+ * Remove all child controls from this control.
+ * This will remove it from drawing and getting any events.
+ *
+ * This is not recursive
+ */
+void CControl::RemoveAllChildren()
+{
+ NotifyParentNeedsLayout();
+ ControlGraph::RemoveAllChildren(*this);
+
+ m_ControlData->m_Focus = std::shared_ptr<CControlData>();
+ m_ControlData->m_MouseFocus = std::shared_ptr<CControlData>();
+}
+
+//=============================================================================
+/**
+ * Retrieve the index of a child control. The index will return the zero based position.
+ * @param inChildControl the control that is a direct child of this control
+ * @return the zero-based index of this control we will return -1 if we don't find the control
+ */
+long CControl::GetChildIndex(CControl *inChildControl)
+{
+ return ControlGraph::GetChildIndex(*this, *inChildControl);
+}
+
+static inline CControl *ToControl(std::shared_ptr<CControlData> inPtr)
+{
+ if (inPtr)
+ return inPtr->GetControl();
+ return nullptr;
+}
+
+//=============================================================================
+/**
+ * Finds a child control by its name
+ * @return the child if found, std::shared_ptr<CControlData>() otherwise
+ */
+CControl *CControl::FindChildByName(const Q3DStudio::CString &inName)
+{
+ std::shared_ptr<CControlData> theResult = std::shared_ptr<CControlData>();
+
+ ControlGraph::SIterator theChildIter = GetChildren();
+ for (; !theChildIter.IsDone(); ++theChildIter) {
+ if (theChildIter.GetCurrent()->GetName() == inName) {
+ theResult = theChildIter.GetCurrent();
+ break;
+ }
+ }
+
+ return ToControl(theResult);
+}
+
+CControl *CControl::FocusedChild()
+{
+ CControl *theResult = nullptr;
+
+ ControlGraph::SIterator theChildIter = GetChildren();
+ for (; !theChildIter.IsDone(); ++theChildIter) {
+ auto current = ToControl(theChildIter.GetCurrent());
+ auto hasFocus = HasFocus(current);
+ if (hasFocus) {
+ if (current->GetFirstChild())
+ theResult = current->FocusedChild();
+ else
+ theResult = current;
+ break;
+ }
+ }
+
+ return theResult;
+}
+
+//=============================================================================
+/**
+ * Check to see if the mouse is over this control or not.
+ * @return true if the mouse is over this control.
+ */
+bool CControl::IsMouseOver() const
+{
+ return m_ControlData->m_IsMouseOver;
+}
+
+//=============================================================================
+/**
+ * Check to see if inPoint is over this control or not.
+ * This is used for mouse hits and can be extended for non-standard control
+ * shapes. Non-visible controls always return false.
+ * @param inPoint the location of the mouse in local coordinates.
+ */
+bool CControl::HitTest(const CPt &inPoint) const
+{
+ CPt thePoint = inPoint - GetPosition();
+ CPt theSize = GetSize();
+ // Basic check to see if it's in the size.
+ if (IsVisible() && thePoint.x >= 0 && thePoint.y >= 0 && thePoint.x < theSize.x
+ && thePoint.y < theSize.y) {
+ return true;
+ }
+ return false;
+}
+
+//=============================================================================
+/**
+ * Checks to see if any part of this control is in the rect.
+ * This is used for drawing and ignoring objects that do not need to be
+ * redrawn or need to be drawn.
+ * @param inRect the rect to check to see if this is in.
+ * @return true if this is in the rect.
+ */
+bool CControl::IsInRect(const CRct &inRect) const
+{
+ CRct myRect(GetPosition(), GetSize());
+
+ if (myRect.position <= inRect.size + inRect.position) {
+ if (myRect.size + myRect.position >= inRect.position)
+ return true;
+ }
+ return false;
+}
+
+//=============================================================================
+/**
+ * Invalidate this control and cause it to be redrawn.
+ * @param inInvalidate true if this is to be invalidated.
+ */
+void CControl::Invalidate(bool inInvalidate /*= true*/)
+{
+ m_ControlData->m_IsInvalidated = inInvalidate;
+ if (inInvalidate && GetParent() != nullptr)
+ GetParent()->OnChildInvalidated();
+ if (!inInvalidate)
+ m_ControlData->m_IsChildInvalidated = false;
+}
+
+//=============================================================================
+/**
+ * Invalidate this object and all children within inRect.
+ * @param inRect the rect in which to invalidate all children.
+ */
+void CControl::InvalidateRect(const CRct &inRect)
+{
+ Invalidate();
+
+ ControlGraph::SIterator thePos = GetChildren();
+ for (; thePos.HasNext(); ++thePos) {
+ std::shared_ptr<CControlData> theChild = (*thePos);
+ if (theChild->IsInRect(inRect)) {
+ CRct theChildRect = inRect;
+ theChildRect.Offset(theChild->GetPosition());
+
+ theChild->InvalidateRect(inRect);
+ }
+ }
+}
+
+//=============================================================================
+/**
+ * Check to see if this control is invalidated or not.
+ * @return true if this control is invalidated.
+ */
+bool CControl::IsInvalidated() const
+{
+ return m_ControlData->IsInvalidated();
+}
+
+//=============================================================================
+/**
+ * Notifies this control that a child of it has been invalidated.
+ */
+void CControl::OnChildInvalidated()
+{
+ // Only do it if we haven't already, avoid multiple traversals up the tree.
+ if (!m_ControlData->m_IsChildInvalidated) {
+ if (GetParent() != nullptr)
+ GetParent()->OnChildInvalidated();
+ else if (m_ControlData->m_WindowListener != nullptr)
+ m_ControlData->m_WindowListener->OnControlInvalidated();
+
+ m_ControlData->m_IsChildInvalidated = true;
+ }
+}
+
+//=============================================================================
+/**
+ * Checks to see if a child of this control is invalidated.
+ */
+bool CControl::IsChildInvalidated() const
+{
+ return m_ControlData->m_IsChildInvalidated || m_ControlData->m_IsInvalidated;
+}
+
+//=============================================================================
+/**
+ * Set this control as being visible or not.
+ * If the control is not visible then it will not be drawn and will not
+ * get mouse clicks.
+ * @param inIsVisible true if this control is to be visible.
+ */
+void CControl::SetVisible(bool inIsVisible)
+{
+ if (inIsVisible != m_ControlData->m_IsVisible) {
+ m_ControlData->m_IsVisible = inIsVisible;
+ NotifyParentNeedsLayout();
+
+ if (GetParent() != nullptr)
+ GetParent()->OnChildSizeChanged(this);
+
+ OnVisibleStateChange(inIsVisible);
+ OnParentVisibleStateChanged(inIsVisible);
+
+ this->Invalidate();
+ }
+}
+
+//=============================================================================
+/**
+ * Notification that the visible state of a control has changed
+ */
+void CControl::OnVisibleStateChange(bool inIsVisible)
+{
+ Q_UNUSED(inIsVisible);
+}
+
+void CControl::OnParentVisibleStateChanged(bool inIsVisible)
+{
+ NotifyParentNeedsLayout();
+ ControlGraph::SIterator thePos = GetChildren();
+ for (; thePos.HasNext(); ++thePos) {
+ std::shared_ptr<CControlData> theChild = (*thePos);
+ theChild->OnParentVisibleStateChanged(inIsVisible);
+ }
+}
+
+//=============================================================================
+/**
+ * Checks to see if this control is visible or not.
+ * If the control is not visible then it will not be drawn and will not
+ * get mouse clicks.
+ * @return true if this control is visible.
+ */
+bool CControl::IsVisible() const
+{
+ return m_ControlData->m_IsVisible;
+}
+
+//=============================================================================
+/**
+ * Sets whether or not this control is enabled.
+ * If the control is not enabled then it is still drawn and still intercepts
+ * mouse clicks, but it will not actually process them.
+ * @param inIsEnabled true if this control is to be enabled.
+ */
+void CControl::SetEnabled(bool inIsEnabled)
+{
+ if (inIsEnabled != m_ControlData->m_IsEnabled) {
+ NotifyParentNeedsLayout();
+ m_ControlData->m_IsEnabled = inIsEnabled;
+
+ ControlGraph::SIterator thePos = GetChildren();
+ for (; thePos.HasNext(); ++thePos) {
+ std::shared_ptr<CControlData> theChild = (*thePos);
+ theChild->SetParentEnabled(inIsEnabled);
+ }
+ Invalidate();
+ }
+}
+
+void CControl::SetParentEnabled(bool inParentEnabled)
+{
+ NotifyParentNeedsLayout();
+ m_ControlData->m_IsParentEnabled = inParentEnabled;
+ ControlGraph::SIterator thePos = GetChildren();
+ for (; thePos.HasNext(); ++thePos) {
+ std::shared_ptr<CControlData> theChild = (*thePos);
+ theChild->SetParentEnabled(inParentEnabled);
+ }
+ Invalidate();
+}
+
+//=============================================================================
+/**
+ * Gets whether or not this control is enabled.
+ * If the control is not enabled then it is still drawn and still intercepts
+ * mouse clicks, but it will not actually process them.
+ * @param inIsEnabled true if this control is to be enabled.
+ */
+bool CControl::IsEnabled() const
+{
+ return m_ControlData->IsEnabled();
+}
+
+//=============================================================================
+/**
+ * Gets teh value of the enabled flag without its parent's flag
+ */
+bool CControl::GetEnabledFlag()
+{
+ return m_ControlData->GetEnabledFlag();
+}
+
+//=============================================================================
+/**
+ * Sets the enabled flag...this is used when a control wants to override the
+ * SetEnabled function and does not necessarily want to pass enabled messages
+ * to its children no matter what
+ */
+void CControl::SetEnabledFlag(bool inIsEnabled)
+{
+ m_ControlData->SetEnabledFlag(inIsEnabled);
+ Invalidate();
+}
+
+//=============================================================================
+/**
+ * Notification that the size of a child has changed.
+ * @param inControl the control that has changed size.
+ */
+void CControl::OnChildSizeChanged(CControl *inControl)
+{
+ Q_UNUSED(inControl);
+}
+
+void CControl::SetName(const QString &inName)
+{
+ m_ControlData->SetName(Q3DStudio::CString::fromQString(inName));
+}
+
+QString CControl::GetName()
+{
+ return m_ControlData->GetName().toQString();
+}
+
+void CControl::BeginDrawChildren(CRenderer *inRenderer)
+{
+ Q_UNUSED(inRenderer);
+}
+
+long CControl::DoPopup(QMenu *inMenu, CPt inLocation)
+{
+ inLocation.Offset(GetPosition());
+ CControl *theParent(GetParent());
+ if (theParent)
+ return theParent->DoPopup(inMenu, inLocation);
+ else
+ return m_ControlData->m_WindowListener->DoPopup(inMenu, inLocation);
+}
+
+//=============================================================================
+/**
+ * Called when a control acquires focus
+ */
+void CControl::OnGainFocus()
+{
+}
+
+//=============================================================================
+/**
+ * Causes focus to be lost.
+ */
+void CControl::OnLoseFocus()
+{
+ if (m_ControlData->m_Focus)
+ m_ControlData->m_Focus->OnLoseFocus();
+ FireFocusEvent(false);
+ m_ControlData->m_Focus = std::shared_ptr<CControlData>();
+}
+
+//=============================================================================
+/**
+ * @return the parent control of this class
+ */
+CControl *CControl::GetParent()
+{
+ return m_ControlData->GetParent();
+}
+
+const CControl *CControl::GetParent() const
+{
+ return m_ControlData->GetParent();
+}
+
+//=============================================================================
+/**
+ * Removes a control from the top level control
+ */
+void CControl::RemoveUberControl(CControl *inControl)
+{
+ if (GetParent() != nullptr)
+ GetParent()->RemoveUberControl(inControl);
+ else
+ RemoveChild(inControl);
+ Invalidate();
+}
+
+long CControl::GetChildCount()
+{
+ return ControlGraph::GetNumChildren(*this);
+}
+
+Q3DStudio::Control::ControlGraph::SIterator CControl::GetChildren()
+{
+ return ControlGraph::GetChildren(*this);
+}
+
+Q3DStudio::Control::ControlGraph::SReverseIterator CControl::GetReverseChildren()
+{
+ return ControlGraph::GetRChildren(*this);
+}
+
+//=============================================================================
+/**
+ * Gets the global position of the point in regards to the top level control
+ */
+CPt CControl::GetGlobalPosition(CPt inChildPoint) const
+{
+ CPt thePosition(GetPosition());
+ CPt thePoint = CPt(inChildPoint.x + thePosition.x, inChildPoint.y + thePosition.y);
+ if (GetParent())
+ return GetParent()->GetGlobalPosition(thePoint);
+ else
+ return thePoint;
+}
+
+//=============================================================================
+/**
+ * Query the platform specific render device (window)
+ */
+Qt3DSRenderDevice CControl::GetPlatformDevice()
+{
+ if (GetParent())
+ return GetParent()->GetPlatformDevice();
+ return nullptr;
+}
+
+//=============================================================================
+/**
+ * Does self or child use this render device?
+ * @see CWndControl::OnKillFocus
+ */
+bool CControl::IsChildPlatformDevice(Qt3DSRenderDevice inDevice)
+{
+ if (GetPlatformDevice() == inDevice)
+ return true;
+
+ ControlGraph::SIterator thePos = GetChildren();
+ for (; thePos.HasNext(); ++thePos) {
+ std::shared_ptr<CControlData> theChild = (*thePos);
+ if (theChild->IsChildPlatformDevice(inDevice))
+ return true;
+ }
+
+ return false;
+}
+
+//=============================================================================
+/**
+ * Shows the window's moveable window with text
+ *
+ * @param inLocation the postion of hte center point of the window
+ * @param inText the text the window will display
+ */
+void CControl::ShowMoveableWindow(CPt inLocation, const Q3DStudio::CString &inText,
+ CRct inBoundingRct)
+{
+ CPt thePosition(GetPosition());
+ CPt thePoint = CPt(inLocation.x + thePosition.x, inLocation.y + thePosition.y);
+
+ if (GetParent())
+ GetParent()->ShowMoveableWindow(thePoint, inText, inBoundingRct);
+ else if (m_ControlData->m_WindowListener)
+ m_ControlData->m_WindowListener->ShowMoveableWindow(thePoint, inText, inBoundingRct);
+}
+
+//=============================================================================
+/**
+ * Hides the window's moveable window
+ */
+void CControl::HideMoveableWindow()
+{
+ if (GetParent() != nullptr)
+ GetParent()->HideMoveableWindow();
+ else if (m_ControlData->m_WindowListener)
+ m_ControlData->m_WindowListener->HideMoveableWindow();
+}
+
+//=============================================================================
+/**
+ * Offsets the position of this control... this is useful if you don't want to calculate
+ * the global position every time
+ */
+void CControl::OffsetPosition(CPt inOffset)
+{
+ CPt thePosition(GetPosition());
+ thePosition.Offset(inOffset);
+ SetPosition(thePosition);
+}
+
+//=============================================================================
+/**
+ * Gets the first child of this control
+ */
+CControl *CControl::GetFirstChild()
+{
+ std::shared_ptr<CControlData> theChild = std::shared_ptr<CControlData>();
+ ControlGraph::SIterator thePos = ControlGraph::GetChildren(*this);
+ if (!thePos.IsDone())
+ theChild = (*thePos);
+ return ToControl(theChild);
+}
+
+//=============================================================================
+/**
+ * @return true if this control has focus
+ */
+bool CControl::HasFocus(CControl *inControl)
+{
+ return (ToControl(m_ControlData->m_Focus) == inControl);
+}
+
+//=============================================================================
+/**
+ * default is true for controls... override if the control cannot have focus
+ */
+bool CControl::CanGainFocus()
+{
+ if (IsVisible()) {
+ for (ControlGraph::SIterator thePos = ControlGraph::GetChildren(*this); !thePos.IsDone();
+ ++thePos) {
+ if ((*thePos)->CanGainFocus())
+ return true;
+ }
+ }
+ return false;
+}
+
+//=============================================================================
+/**
+ * Returns true if this CControl is in focus.
+ * @return True if this CControl is in focus.
+ */
+bool CControl::IsInFocus()
+{
+ if (GetParent())
+ return GetParent()->HasFocus(this);
+
+ return false;
+}
+
+//=============================================================================
+/**
+ * Handles the tab button in controls
+ */
+void CControl::OnTab()
+{
+ // Go through the children... if there is a focus, then get the next control
+ ControlGraph::SIterator thePos = ControlGraph::GetChildren(*this);
+ bool theFoundFlag = false;
+ if (m_ControlData->m_Focus) {
+ while (!thePos.IsDone() && !theFoundFlag) {
+ std::shared_ptr<CControlData> theCurrentControl = (*thePos);
+ if (theCurrentControl == m_ControlData->m_Focus) {
+ ++thePos;
+ while (!thePos.IsDone() && !theFoundFlag) {
+ std::shared_ptr<CControlData> theNextFocusCanidate = (*thePos);
+ if (theNextFocusCanidate->CanGainFocus()) {
+ m_ControlData->m_Focus->OnLoseFocus();
+ theFoundFlag = true;
+ m_ControlData->m_Focus = theNextFocusCanidate;
+ m_ControlData->m_Focus->SetFocusToFirstAvailable();
+ } else {
+ ++thePos;
+ }
+ }
+ } else {
+ ++thePos;
+ }
+ }
+ // If we didn't find it and we have a parent, then allow the parent to decide
+ if (!theFoundFlag) {
+ m_ControlData->m_Focus->OnLoseFocus();
+ m_ControlData->m_Focus = std::shared_ptr<CControlData>();
+ if (GetParent())
+ GetParent()->OnTab();
+ else
+ SetFocusToFirstAvailable();
+ }
+ } else {
+ // If no focus, then go to first available control
+ SetFocusToFirstAvailable();
+ }
+}
+
+//=============================================================================
+/**
+ * Handles the shift tab button in controls
+ */
+void CControl::OnReverseTab()
+{
+ // Go through the children in reverse order... if there is a focus, then get the next control
+ ControlGraph::SReverseIterator thePos = ControlGraph::GetRChildren(*this);
+ bool theFoundFlag = false;
+ if (m_ControlData->m_Focus) {
+ while (!thePos.IsDone() && !theFoundFlag) {
+ std::shared_ptr<CControlData> theCurrentControl = (*thePos);
+ if (theCurrentControl == m_ControlData->m_Focus) {
+ ++thePos;
+ while (!thePos.IsDone() && !theFoundFlag) {
+ std::shared_ptr<CControlData> theNextFocusCanidate = (*thePos);
+ if (theNextFocusCanidate->CanGainFocus()) {
+ m_ControlData->m_Focus->OnLoseFocus();
+ theFoundFlag = true;
+ m_ControlData->m_Focus = theNextFocusCanidate;
+ m_ControlData->m_Focus->SetFocusToLastAvailable();
+ } else {
+ ++thePos;
+ }
+ }
+ } else {
+ ++thePos;
+ }
+ }
+ // If we didn't find it and we have a parent, then allow the parent to decide
+ if (!theFoundFlag) {
+ m_ControlData->m_Focus->OnLoseFocus();
+ m_ControlData->m_Focus = std::shared_ptr<CControlData>();
+ if (GetParent())
+ GetParent()->OnReverseTab();
+ else
+ SetFocusToLastAvailable();
+ }
+ } else {
+ // If no focus, then go to last available control
+ SetFocusToLastAvailable();
+ }
+}
+
+//=============================================================================
+/**
+ * Sets the focus to the first available child control
+ */
+void CControl::SetFocusToFirstAvailable()
+{
+ bool theFlag = false;
+ OnGainFocus();
+
+ // if there are any child controls, then go through them
+ for (ControlGraph::SIterator thePos = ControlGraph::GetChildren(*this);
+ !thePos.IsDone() && !theFlag; ++thePos) {
+ std::shared_ptr<CControlData> theControl = (*thePos);
+ if (theControl->CanGainFocus()) {
+ m_ControlData->m_Focus = theControl;
+ m_ControlData->m_Focus->SetFocusToFirstAvailable();
+ theFlag = true;
+ }
+ }
+}
+
+//=============================================================================
+/**
+ * Sets the focus to the last available child control
+ */
+void CControl::SetFocusToLastAvailable()
+{
+ bool theFlag = false;
+ OnGainFocus();
+
+ // if there are any child controls, then go through them
+ for (ControlGraph::SReverseIterator thePos = ControlGraph::GetRChildren(*this);
+ !thePos.IsDone() && !theFlag; ++thePos) {
+ std::shared_ptr<CControlData> theControl = (*thePos);
+ if (theControl->CanGainFocus()) {
+ m_ControlData->m_Focus = theControl;
+ m_ControlData->m_Focus->SetFocusToLastAvailable();
+ theFlag = true;
+ }
+ }
+}
+
+//===============================================================================
+/**
+* Coverts the given point from local coordinates into global coordinates.
+* @param inPoint the point in local coordinates to be converted
+* @return The point translated to global coordinates
+*/
+CPt CControl::ClientToScreen(CPt inPoint)
+{
+ CPt theFinalPt = inPoint + m_ControlData->m_Position;
+
+ if (GetParent())
+ theFinalPt = GetParent()->ClientToScreen(theFinalPt);
+ else if (m_ControlData->m_WindowListener)
+ theFinalPt = m_ControlData->m_WindowListener->ClientToScreen(theFinalPt);
+
+ return theFinalPt;
+}
+
+//===============================================================================
+/**
+* Coverts the given point from screen coordinates into local space.
+* @param inPoint the point in screen coordinates to be converted
+* @return The point translated to local, client coordinates
+*/
+CPt CControl::ScreenToClient(CPt inPoint)
+{
+ CPt theFinalPt = inPoint - m_ControlData->m_Position;
+
+ if (GetParent())
+ theFinalPt = GetParent()->ScreenToClient(theFinalPt);
+ else if (m_ControlData->m_WindowListener)
+ theFinalPt = m_ControlData->m_WindowListener->ScreenToClient(theFinalPt);
+
+ return theFinalPt;
+}
+
+//===============================================================================
+/**
+* Adds a focus listener to this control
+*/
+void CControl::AddFocusListener(CChildFocusListener *inListener)
+{
+ m_ControlData->m_FocusListeners.AddListener(inListener);
+}
+
+//===============================================================================
+/**
+* Removes a focus listener to this control
+*/
+void CControl::RemoveFocusListener(CChildFocusListener *inListener)
+{
+ m_ControlData->m_FocusListeners.RemoveListener(inListener);
+}
+
+//===============================================================================
+/**
+* tells anyone listeneing that the focus of this control has changed
+*/
+void CControl::FireFocusEvent(bool inStatus)
+{
+ m_ControlData->m_FocusListeners.FireEvent(&CChildFocusListener::OnChildFocusChange, inStatus);
+}
+
+//===============================================================================
+/**
+ * Get the platform specific view that this is embedded into.
+ * Used for when platform dependent controls have to be embedded or used.
+ */
+TPlatformView CControl::GetPlatformView()
+{
+ if (GetParent())
+ return GetParent()->GetPlatformView();
+ else if (m_ControlData->m_WindowListener)
+ return m_ControlData->m_WindowListener->GetPlatformView();
+ return nullptr;
+}
+
+bool CControl::IsMouseDown()
+{
+ return m_ControlData->m_IsMouseDown;
+}
+
+void CControl::OnMouseClick(CPt, Qt::KeyboardModifiers)
+{
+}
+
+void CControl::GrabFocus(CControl *inControl)
+{
+ if (GetParent())
+ GetParent()->GrabFocus(this);
+
+ std::shared_ptr<CControlData> theNewFocus;
+ if (inControl)
+ theNewFocus = inControl->m_ControlData;
+
+ if (m_ControlData->m_Focus != theNewFocus) {
+ if (m_ControlData->m_Focus)
+ m_ControlData->m_Focus->OnLoseFocus();
+ m_ControlData->m_Focus = theNewFocus;
+ if (m_ControlData->m_Focus)
+ m_ControlData->m_Focus->OnGainFocus();
+ }
+}
+
+//===============================================================================
+/**
+ * Used to notify scrolling views that something should be visible.
+ */
+void CControl::EnsureVisible(CRct inRect)
+{
+ if (GetParent()) {
+ inRect.Offset(GetPosition());
+ GetParent()->EnsureVisible(inRect);
+ }
+}
+
+//===============================================================================
+/**
+ * Call to make this control visible.
+ */
+void CControl::EnsureVisible()
+{
+ CRct theRect(CPt(0, 0), GetSize());
+ EnsureVisible(theRect);
+}
+
+void CControl::OnParentChanged(CControl * /*inNewParent*/)
+{
+}
+
+void CControl::MarkChildrenNeedLayout()
+{
+ if (m_ControlData->m_ChildrenNeedLayout == false) {
+ for (ControlGraph::SIterator theIter = GetChildren(); theIter.IsDone() == false; ++theIter)
+ (*theIter)->MarkNeedsLayout();
+ m_ControlData->m_ChildrenNeedLayout = true;
+ }
+}
+
+void CControl::NotifyParentNeedsLayout()
+{
+ CControl *theParent(GetParent());
+ if (theParent)
+ theParent->MarkChildrenNeedLayout();
+}
+
+void CControl::MarkNeedsLayout()
+{
+ m_ControlData->m_NeedsLayout = true;
+}
+// Tell this control that one of its children need to be layed out.
+void CControl::SetLayout(CPt inSize, CPt inPosition)
+{
+ SetSize(inSize);
+ SetPosition(inPosition);
+ m_ControlData->m_NeedsLayout = false;
+}
+
+void CControl::LayoutChildren()
+{
+ for (ControlGraph::SIterator theIter = GetChildren(); theIter.IsDone() == false; ++theIter) {
+ std::shared_ptr<CControlData> theChild(*theIter);
+ // By default the children get the exact same layout that I do.
+ theChild->SetLayout(theChild->m_Size, theChild->m_Position);
+ }
+ m_ControlData->m_ChildrenNeedLayout = false;
+}
+
+void CControl::EnsureLayout()
+{
+ if (m_ControlData->m_NeedsLayout) {
+ if (IsVisible()) {
+ CControl *parent = GetParent();
+ if (parent)
+ parent->LayoutChildren();
+ }
+ m_ControlData->m_NeedsLayout = false;
+ }
+ if (m_ControlData->m_ChildrenNeedLayout) {
+ LayoutChildren();
+ m_ControlData->m_ChildrenNeedLayout = false;
+ }
+}
+
+void CControl::ChildrenChanged()
+{
+ MarkChildrenNeedLayout();
+ Invalidate();
+ m_ControlData->OnHierarchyChanged();
+}
+
+void CControl::setCursorIfNotSet(long cursor)
+{
+ if (cursor != m_cursorSet) {
+ if (m_cursorSet != -1)
+ qApp->changeOverrideCursor(CResourceCache::GetInstance()->GetCursor(cursor));
+ else
+ qApp->setOverrideCursor(CResourceCache::GetInstance()->GetCursor(cursor));
+ m_cursorSet = cursor;
+ }
+}
+
+void CControl::resetCursor()
+{
+ if (m_cursorSet != -1) {
+ // Restoring back to no-override state seems to not change the cursor automatically
+ // to the default cursor, so let's do that manually before restoring the cursor
+ qApp->changeOverrideCursor(Qt::ArrowCursor);
+ qApp->restoreOverrideCursor();
+ m_cursorSet = -1;
+ }
+}
+
+QCursor CControl::getCursor() const
+{
+ if (m_cursorSet != -1)
+ return CResourceCache::GetInstance()->GetCursor(m_cursorSet);
+ return QCursor();
+}
diff --git a/src/Authoring/Qt3DStudio/Controls/Control.h b/src/Authoring/Qt3DStudio/Controls/Control.h
new file mode 100644
index 00000000..570005fa
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Controls/Control.h
@@ -0,0 +1,259 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef INCLUDED_CONTROL_H
+#define INCLUDED_CONTROL_H 1
+
+#pragma once
+
+#include "Pt.h"
+#include "Rct.h"
+#include "SafeArray.h"
+#include "GenericFunctor.h"
+#include "PlatformTypes.h"
+
+#include "DropTarget.h"
+#include "ControlGraphIterators.h"
+#include "DocumentEditorEnumerations.h"
+
+class CRenderer;
+class CContextMenu;
+class Qt3DSFile;
+class IDragable;
+class CAsset;
+class CStudioApp;
+
+QT_FORWARD_DECLARE_CLASS(QMenu)
+
+namespace Q3DStudio {
+namespace Control {
+ class CControlData;
+ using std::pair;
+ using std::make_pair;
+ using std::vector;
+}
+}
+
+// this functor is used to tell when a child loses focus the boolean should be true if the child
+// gains focus
+GENERIC_FUNCTOR_1(CChildFocusListener, OnChildFocusChange, bool)
+
+#ifdef _WIN32
+typedef HWND TPlatformView;
+#else
+typedef void *TPlatformView;
+#endif
+
+class CControlWindowListener
+{
+public:
+ virtual void OnControlInvalidated() = 0;
+ virtual long DoPopup(QMenu *inMenu, CPt inLocation) = 0;
+ virtual CPt ClientToScreen(CPt inPoint) = 0;
+ virtual CPt ScreenToClient(CPt inPoint) = 0;
+ virtual TPlatformView GetPlatformView() = 0;
+ virtual void SetIsDragging(bool inIsDragging) = 0;
+ virtual void ShowTooltips(CPt inLocation, const QString &inText) = 0;
+ virtual void HideTooltips() = 0;
+ virtual void DoStartDrag(IDragable *inDragable) = 0;
+ virtual void DoStartDrag(std::vector<Q3DStudio::CString> &inDragFileList) = 0;
+ virtual void ShowMoveableWindow(CPt inLocation, const Q3DStudio::CString &inText,
+ CRct inBoundingRct) = 0;
+ virtual void HideMoveableWindow() = 0;
+};
+
+namespace Q3DStudio {
+namespace Control {
+ class CControlData;
+}
+}
+
+class CControl
+{
+
+ CControl(CControl &inOther);
+ CControl &operator=(CControl &inOther);
+
+public:
+ CControl();
+ virtual ~CControl();
+
+ DEFINE_OBJECT_COUNTER(CControl)
+
+ CControl *GetParent();
+ const CControl *GetParent() const;
+
+ virtual void OnDraw(CRenderer *inRenderer, CRct &inDirtyRect, bool inIgnoreValidation = false);
+ virtual void Draw(CRenderer *inRenderer);
+ virtual void NotifyNotInClipRect();
+
+ virtual CPt GetPosition() const;
+ virtual void SetPosition(CPt inPosition);
+ void SetPosition(long inX, long inY);
+
+ virtual CPt GetSize() const;
+ virtual void SetSize(CPt inSize);
+ virtual void SetSize(long inWidth, long inHeight);
+ virtual void OnSizeChanged(CPt inSize);
+
+ virtual CPt GetMinimumSize();
+ virtual void SetMinimumSize(CPt inSize);
+
+ virtual CPt GetMaximumSize();
+ virtual void SetMaximumSize(CPt inSize);
+
+ virtual CPt GetPreferredSize();
+ virtual void SetPreferredSize(CPt inSize);
+
+ virtual void SetAbsoluteSize(CPt inSize);
+
+ virtual void OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags);
+ virtual void OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags);
+ virtual void OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags);
+ virtual bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags);
+ virtual bool OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags);
+ virtual void OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags);
+ virtual void OnMouseRUp(CPt inPoint, Qt::KeyboardModifiers inFlags);
+ virtual void OnMouseClick(CPt inPoint, Qt::KeyboardModifiers inFlags);
+ virtual bool OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags);
+ virtual bool OnMouseHover(CPt inPoint, Qt::KeyboardModifiers inFlags);
+ /**
+ Note that just overriding this isn't enough, you need to call
+ m_ControlData->SetMouseWheelEnabled( true )
+ in order to receive mouse wheel events
+ */
+ virtual bool OnMouseWheel(CPt inPoint, long inAmount, Qt::KeyboardModifiers inFlags);
+ virtual bool OnKeyDown(unsigned int inChar, Qt::KeyboardModifiers inFlags);
+ virtual bool OnKeyUp(unsigned int inChar, Qt::KeyboardModifiers inFlags);
+ virtual bool OnChar(const QString &inChar, Qt::KeyboardModifiers inFlags);
+ virtual void OnLoseFocus();
+ virtual void OnGainFocus();
+ virtual bool CanGainFocus();
+ virtual bool IsInFocus();
+ void OnTab();
+ void OnReverseTab();
+ void SetFocusToFirstAvailable();
+ void SetFocusToLastAvailable();
+
+ virtual CDropTarget *FindDropCandidate(CPt &inMousePoint, Qt::KeyboardModifiers inFlags,
+ EStudioObjectType objectType,
+ Q3DStudio::DocumentEditorFileType::Enum fileType);
+
+ virtual void AddChild(CControl *inControl, CControl *inInsertBefore = NULL);
+ virtual void RemoveChild(CControl *inControl);
+ virtual void RemoveAllChildren();
+ virtual long GetChildIndex(CControl *inChildControl);
+ virtual CControl *FindChildByName(const Q3DStudio::CString &inName);
+ CControl *FocusedChild();
+
+ virtual bool IsMouseOver() const;
+
+ virtual bool HitTest(const CPt &inPoint) const;
+ virtual bool IsInRect(const CRct &inRect) const;
+
+ virtual void Invalidate(bool inInvalidate = true);
+ virtual void InvalidateRect(const CRct &inRect);
+ virtual bool IsInvalidated() const;
+
+ virtual void OnChildInvalidated();
+ virtual bool IsChildInvalidated() const;
+
+ virtual void SetVisible(bool inIsVisible);
+ virtual bool IsVisible() const;
+ virtual void OnVisibleStateChange(bool inIsVisible);
+ virtual void OnParentVisibleStateChanged(bool inIsVisible);
+
+ virtual void SetParentEnabled(bool inParentEnabled);
+ virtual void SetEnabled(bool inIsEnabled);
+ virtual bool IsEnabled() const;
+ bool GetEnabledFlag();
+ void SetEnabledFlag(bool inIsEnabled);
+
+ virtual void OnChildSizeChanged(CControl *inChild);
+ virtual void ResetMinMaxPref(){}
+
+ void SetName(const QString &inName);
+ QString GetName();
+
+ virtual void BeginDrawChildren(CRenderer *inRenderer);
+
+ virtual long DoPopup(QMenu *inContextMenu, CPt inPoint);
+ virtual void RemoveUberControl(CControl *inControl);
+ virtual void OffsetPosition(CPt inOffset);
+
+ virtual CPt GetGlobalPosition(CPt inChildPoint) const;
+ virtual Qt3DSRenderDevice GetPlatformDevice();
+ bool IsChildPlatformDevice(Qt3DSRenderDevice inDevice);
+ virtual void ShowMoveableWindow(CPt inLocation, const Q3DStudio::CString &inText,
+ CRct inBoundingRct);
+ virtual void HideMoveableWindow();
+ CControl *GetFirstChild();
+ bool HasFocus(CControl *inControl);
+ virtual void GrabFocus(CControl *inControl);
+
+ virtual CPt ClientToScreen(CPt inPoint);
+ virtual CPt ScreenToClient(CPt inPoint);
+
+ void AddFocusListener(CChildFocusListener *inListener);
+ void RemoveFocusListener(CChildFocusListener *inListener);
+ void FireFocusEvent(bool inStatus);
+
+ virtual void EnsureVisible(CRct inRect);
+ void EnsureVisible();
+
+ virtual void OnParentChanged(CControl *inNewParent);
+
+ virtual void MarkChildrenNeedLayout();
+ virtual void MarkNeedsLayout();
+ // Tell our parent that we (and all our siblings) need to be
+ // laid out.
+ virtual void NotifyParentNeedsLayout();
+ // Tell this control that one of its children need to be layed out.
+ virtual void SetLayout(CPt inSize, CPt inPosition);
+ virtual void LayoutChildren();
+ virtual void EnsureLayout();
+
+ virtual void ChildrenChanged();
+
+ Q3DStudio::Control::ControlGraph::SIterator GetChildren();
+ Q3DStudio::Control::ControlGraph::SReverseIterator GetReverseChildren();
+
+protected: ///< Current size of this control
+ // Member Functions
+
+ long GetChildCount();
+ TPlatformView GetPlatformView();
+ bool IsMouseDown();
+ void setCursorIfNotSet(long cursor);
+ void resetCursor();
+ QCursor getCursor() const;
+
+ std::shared_ptr<Q3DStudio::Control::CControlData> m_ControlData;
+ long m_cursorSet;
+};
+#endif // INCLUDED_CONTROL_H
diff --git a/src/Authoring/Qt3DStudio/Controls/ControlData.cpp b/src/Authoring/Qt3DStudio/Controls/ControlData.cpp
new file mode 100644
index 00000000..eb3bf0f2
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Controls/ControlData.cpp
@@ -0,0 +1,765 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "Qt3DSCommonPrecompile.h"
+#include "ControlData.h"
+#include "ControlGraph.h"
+#include "Control.h"
+
+#include <QtWidgets/qmenu.h>
+
+using namespace Q3DStudio::Control;
+using Q3DStudio::CString;
+
+CControlData::CControlData(CControl &inControl)
+ : m_Control(&inControl)
+ , m_MinSize(0, 0)
+ , m_MaxSize(LONG_MAX, LONG_MAX)
+ , m_PrefSize(10, 10)
+ , m_IsMouseOver(false)
+ , m_IsInvalidated(true)
+ , m_IsChildInvalidated(false)
+ , m_IsVisible(true)
+ , m_IsEnabled(true)
+ , m_IsParentEnabled(true)
+ , m_HasFocus(false)
+ , m_IsMouseDown(false)
+ , m_ShowTooltips(false)
+ , m_NeedsLayout(true)
+ , m_ChildrenNeedLayout(true)
+ , m_WindowListener(NULL)
+{
+}
+
+CControlData::~CControlData()
+{
+}
+
+void CControlData::ReleaseControl()
+{
+ if (m_Control) {
+ ControlGraph::RemoveNode(*m_Control);
+ m_Control = nullptr;
+ }
+}
+
+std::shared_ptr<CControlData> CControlData::CreateControlData(CControl &inControl)
+{
+ std::shared_ptr<CControlData> retval =
+ std::make_shared<CControlData>(std::ref(inControl));
+ ControlGraph::AddNode(retval);
+ return retval;
+}
+
+CControl *CControlData::GetControl()
+{
+ return m_Control;
+}
+
+CControl *CControlData::GetParent()
+{
+
+ if (m_Control) {
+ std::shared_ptr<CControlData> theParent(ControlGraph::GetParent(*m_Control));
+ if (theParent)
+ return theParent->GetControl();
+ }
+ return nullptr;
+}
+
+void CControlData::OnDraw(CRenderer *inRenderer, CRct &inDirtyRect, bool inIgnoreValidation)
+{
+ if (m_Control)
+ m_Control->OnDraw(inRenderer, inDirtyRect, inIgnoreValidation);
+}
+
+void CControlData::Draw(CRenderer *inRenderer)
+{
+ if (m_Control)
+ m_Control->Draw(inRenderer);
+}
+
+void CControlData::NotifyNotInClipRect()
+{
+ if (m_Control)
+ m_Control->NotifyNotInClipRect();
+}
+
+CPt CControlData::GetPosition() const
+{
+ if (m_Control)
+ return m_Control->GetPosition();
+ return CPt();
+}
+
+void CControlData::SetPosition(CPt inPosition)
+{
+ if (m_Control)
+ m_Control->SetPosition(inPosition);
+}
+
+void CControlData::SetPosition(long inX, long inY)
+{
+ SetPosition(CPt(inX, inY));
+}
+
+CPt CControlData::GetSize() const
+{
+ if (m_Control)
+ return m_Control->GetSize();
+ return CPt();
+}
+
+void CControlData::SetSize(CPt inSize)
+{
+ if (m_Control)
+ m_Control->SetSize(inSize);
+}
+
+void CControlData::SetSize(long inWidth, long inHeight)
+{
+ SetSize(CPt(inWidth, inHeight));
+}
+
+CPt CControlData::GetMinimumSize()
+{
+ if (m_Control)
+ return m_Control->GetMinimumSize();
+ return CPt();
+}
+
+void CControlData::SetMinimumSize(CPt inSize)
+{
+ if (m_Control)
+ m_Control->SetMinimumSize(inSize);
+}
+
+CPt CControlData::GetMaximumSize()
+{
+ if (m_Control)
+ return m_Control->GetMaximumSize();
+ return CPt();
+}
+
+void CControlData::SetMaximumSize(CPt inSize)
+{
+ if (m_Control)
+ m_Control->SetMaximumSize(inSize);
+}
+
+CPt CControlData::GetPreferredSize()
+{
+ if (m_Control)
+ return m_Control->GetPreferredSize();
+ return CPt();
+}
+
+void CControlData::SetPreferredSize(CPt inSize)
+{
+ if (m_Control)
+ return m_Control->SetPreferredSize(inSize);
+}
+
+void CControlData::SetAbsoluteSize(CPt inSize)
+{
+ if (m_Control)
+ m_Control->SetAbsoluteSize(inSize);
+}
+
+void CControlData::SetMouseDown(bool inMouseDown)
+{
+ m_IsMouseDown = inMouseDown;
+}
+
+void CControlData::OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ if (m_Control)
+ m_Control->OnMouseMove(inPoint, inFlags);
+}
+
+void CControlData::OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ if (m_Control)
+ m_Control->OnMouseOver(inPoint, inFlags);
+}
+
+void CControlData::OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ if (m_Control)
+ m_Control->OnMouseOut(inPoint, inFlags);
+}
+
+bool CControlData::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ if (m_Control)
+ return m_Control->OnMouseDown(inPoint, inFlags);
+ return false;
+}
+
+bool CControlData::OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ if (m_Control)
+ return m_Control->OnMouseRDown(inPoint, inFlags);
+ return false;
+}
+
+void CControlData::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ if (m_Control)
+ m_Control->OnMouseUp(inPoint, inFlags);
+}
+
+void CControlData::OnMouseRUp(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ if (m_Control)
+ m_Control->OnMouseRUp(inPoint, inFlags);
+}
+
+void CControlData::OnMouseClick(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ if (m_Control)
+ m_Control->OnMouseClick(inPoint, inFlags);
+}
+
+bool CControlData::OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ if (m_Control)
+ return m_Control->OnMouseDoubleClick(inPoint, inFlags);
+ return false;
+}
+
+bool CControlData::OnMouseHover(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ if (m_Control)
+ return m_Control->OnMouseHover(inPoint, inFlags);
+ return false;
+}
+
+bool CControlData::OnMouseWheel(CPt inPoint, long inAmount, Qt::KeyboardModifiers inFlags)
+{
+ if (m_Control)
+ return m_Control->OnMouseWheel(inPoint, inAmount, inFlags);
+ return false;
+}
+
+bool CControlData::OnKeyDown(unsigned int inChar, Qt::KeyboardModifiers inFlags)
+{
+ if (m_Control)
+ return m_Control->OnKeyDown(inChar, inFlags);
+ return false;
+}
+
+bool CControlData::OnKeyUp(unsigned int inChar, Qt::KeyboardModifiers inFlags)
+{
+ if (m_Control)
+ return m_Control->OnKeyUp(inChar, inFlags);
+ return false;
+}
+
+bool CControlData::OnChar(const QString &inChar, Qt::KeyboardModifiers inFlags)
+{
+ if (m_Control)
+ return m_Control->OnChar(inChar, inFlags);
+ return false;
+}
+
+void CControlData::OnLoseFocus()
+{
+ if (m_Control)
+ m_Control->OnLoseFocus();
+}
+
+void CControlData::OnGainFocus()
+{
+ if (m_Control)
+ m_Control->OnGainFocus();
+}
+
+bool CControlData::CanGainFocus()
+{
+ if (m_Control)
+ return m_Control->CanGainFocus();
+ return false;
+}
+
+bool CControlData::IsInFocus()
+{
+ if (m_Control)
+ return m_Control->IsInFocus();
+ return false;
+}
+
+void CControlData::OnTab()
+{
+ if (m_Control)
+ m_Control->OnTab();
+}
+
+void CControlData::OnReverseTab()
+{
+ if (m_Control)
+ m_Control->OnReverseTab();
+}
+
+void CControlData::SetFocusToFirstAvailable()
+{
+ if (m_Control)
+ m_Control->SetFocusToFirstAvailable();
+}
+
+void CControlData::SetFocusToLastAvailable()
+{
+ if (m_Control)
+ m_Control->SetFocusToLastAvailable();
+}
+
+void CControlData::ChildrenChanged()
+{
+ if (m_Control)
+ m_Control->ChildrenChanged();
+}
+
+void CControlData::SetMouseWheelEnabled(bool inEnabled)
+{
+ if (m_Control == nullptr)
+ return;
+
+ if (m_MouseWheelState.m_Enabled != inEnabled) {
+ m_MouseWheelState.m_Enabled = inEnabled;
+ ControlEventState::Enum theNewState;
+ if (m_MouseWheelState.m_Enabled == false)
+ theNewState = ControlEventState::Unknown;
+ else
+ theNewState = ControlEventState::Listening;
+ SetMouseWheelEventState(theNewState);
+ }
+}
+
+void CControlData::OnHierarchyChanged()
+{
+ ControlEventState::Enum theNewState;
+ if (m_MouseWheelState.m_Enabled)
+ theNewState = ControlEventState::Listening;
+ else
+ theNewState = ControlEventState::Unknown;
+ SetMouseWheelEventState(theNewState);
+}
+
+/**
+ Look at hierarchy information to figure out which events should
+ trickle down the tree to here (or deeper). Recursive call that
+ may take some time to complete.
+*/
+void CControlData::UpdateMouseWheelEventState()
+{
+ if (m_Control == nullptr)
+ return;
+ ControlEventState::Enum theNewState(ControlEventState::Ignoring);
+ if (m_MouseWheelState.m_Enabled == true)
+ theNewState = ControlEventState::Listening;
+ else if (m_MouseWheelState.m_EventState == ControlEventState::Unknown && m_Control != nullptr) {
+ for (ControlGraph::SIterator theIter(ControlGraph::GetChildren(*m_Control));
+ theIter.IsDone() == false; ++theIter) {
+ if (theIter->GetMouseWheelEventState() == ControlEventState::Listening) {
+ theNewState = ControlEventState::Listening;
+ break;
+ }
+ }
+ }
+ SetMouseWheelEventState(theNewState);
+}
+
+/**
+ Update our mouse wheel state and notify our parent if necessary. Note that we
+ can't set our event state to ignoring without checking all of our children
+ so the result of this function is that our event state is either listening
+ or unknown.
+*/
+void CControlData::SetMouseWheelEventState(ControlEventState::Enum inNewState)
+{
+ if (m_MouseWheelState.m_EventState != inNewState) {
+ m_MouseWheelState.m_EventState = inNewState;
+ std::shared_ptr<CControlData> theParent = ControlGraph::GetParent(*m_Control);
+ if (theParent)
+ theParent->ChildMouseWheelEventStateChanged(m_MouseWheelState.m_EventState);
+ }
+}
+
+/**
+ When a given child notifies us that its event state has changed then we can update
+ our state. We can't set the state to ignoring unless we *know* all of our
+ children are ignoring mouse wheel.
+ */
+void CControlData::ChildMouseWheelEventStateChanged(ControlEventState::Enum inNewState)
+{
+ ControlEventState::Enum theNewState;
+ if (inNewState == ControlEventState::Listening || m_MouseWheelState.m_Enabled == true)
+ theNewState = ControlEventState::Listening;
+ else
+ theNewState = ControlEventState::Unknown;
+
+ SetMouseWheelEventState(theNewState);
+}
+
+ControlEventState::Enum CControlData::GetMouseWheelEventState()
+{
+ if (m_MouseWheelState.m_EventState == ControlEventState::Unknown)
+ UpdateMouseWheelEventState();
+ assert(m_MouseWheelState.m_EventState != ControlEventState::Unknown);
+ return m_MouseWheelState.m_EventState;
+}
+
+CDropTarget *CControlData::FindDropCandidate(CPt &inMousePoint, Qt::KeyboardModifiers inFlags,
+ EStudioObjectType objectType,
+ Q3DStudio::DocumentEditorFileType::Enum fileType)
+{
+ if (m_Control)
+ return m_Control->FindDropCandidate(inMousePoint, inFlags, objectType, fileType);
+ return nullptr;
+}
+
+void CControlData::AddChild(CControl *inControl, CControl *inInsertBefore)
+{
+ if (m_Control)
+ m_Control->AddChild(inControl, inInsertBefore);
+}
+
+void CControlData::RemoveChild(CControl *inControl)
+{
+ if (m_Control)
+ m_Control->RemoveChild(inControl);
+}
+
+void CControlData::RemoveAllChildren()
+{
+ if (m_Control)
+ m_Control->RemoveAllChildren();
+}
+
+long CControlData::GetChildIndex(CControl *inChildControl)
+{
+ if (m_Control)
+ return m_Control->GetChildIndex(inChildControl);
+ return 0;
+}
+
+CControl *CControlData::FindChildByName(const Q3DStudio::CString &inName)
+{
+ if (m_Control)
+ m_Control->FindChildByName(inName);
+ return nullptr;
+}
+
+bool CControlData::IsMouseOver() const
+{
+ if (m_Control)
+ return m_Control->IsMouseOver();
+ return false;
+}
+
+bool CControlData::HitTest(const CPt &inPoint) const
+{
+ if (m_Control)
+ return m_Control->HitTest(inPoint);
+ return false;
+}
+bool CControlData::IsInRect(const CRct &inRect) const
+{
+ if (m_Control)
+ return m_Control->IsInRect(inRect);
+ return false;
+}
+
+void CControlData::Invalidate(bool inInvalidate)
+{
+ if (m_Control)
+ m_Control->Invalidate(inInvalidate);
+}
+
+void CControlData::InvalidateRect(const CRct &inRect)
+{
+ if (m_Control)
+ m_Control->InvalidateRect(inRect);
+}
+
+bool CControlData::IsInvalidated() const
+{
+ return m_IsInvalidated;
+}
+
+void CControlData::OnChildInvalidated()
+{
+ if (m_Control)
+ m_Control->OnChildInvalidated();
+}
+
+bool CControlData::IsChildInvalidated() const
+{
+ if (m_Control)
+ return m_Control->IsChildInvalidated();
+ return false;
+}
+
+void CControlData::SetVisible(bool inIsVisible)
+{
+ if (m_Control)
+ m_Control->SetVisible(inIsVisible);
+}
+
+bool CControlData::IsVisible() const
+{
+ if (m_Control)
+ return m_Control->IsVisible();
+ return false;
+}
+
+void CControlData::OnVisibleStateChange(bool inIsVisible)
+{
+ if (m_Control)
+ m_Control->OnVisibleStateChange(inIsVisible);
+}
+
+void CControlData::OnParentVisibleStateChanged(bool inIsVisible)
+{
+ if (m_Control)
+ m_Control->OnParentVisibleStateChanged(inIsVisible);
+}
+
+void CControlData::SetParentEnabled(bool inParentEnabled)
+{
+ if (m_Control)
+ m_Control->SetParentEnabled(inParentEnabled);
+}
+
+void CControlData::SetEnabled(bool inIsEnabled)
+{
+ if (m_Control)
+ m_Control->SetEnabled(inIsEnabled);
+}
+
+bool CControlData::IsEnabled() const
+{
+ return m_IsEnabled && m_IsParentEnabled;
+}
+
+bool CControlData::GetEnabledFlag()
+{
+ return m_IsEnabled;
+}
+
+void CControlData::SetEnabledFlag(bool inIsEnabled)
+{
+ m_IsEnabled = inIsEnabled;
+}
+
+void CControlData::OnChildSizeChanged(CControl *inChild)
+{
+ if (m_Control)
+ m_Control->OnChildSizeChanged(inChild);
+}
+
+void CControlData::ResetMinMaxPref()
+{
+ if (m_Control)
+ m_Control->ResetMinMaxPref();
+}
+
+void CControlData::SetName(CString inName)
+{
+ m_ControlName = inName;
+}
+
+CString CControlData::GetName()
+{
+ return m_ControlName;
+}
+
+void CControlData::BeginDrawChildren(CRenderer *inRenderer)
+{
+ if (m_Control)
+ m_Control->BeginDrawChildren(inRenderer);
+}
+
+long CControlData::DoPopup(QMenu *inContextMenu, CPt inPoint)
+{
+ if (m_Control)
+ return m_Control->DoPopup(inContextMenu, inPoint);
+ return 0;
+}
+
+void CControlData::RemoveUberControl(CControl *inControl)
+{
+ if (m_Control)
+ m_Control->RemoveUberControl(inControl);
+}
+
+void CControlData::OffsetPosition(CPt inOffset)
+{
+ if (m_Control)
+ m_Control->OffsetPosition(inOffset);
+}
+
+CPt CControlData::GetGlobalPosition(CPt inChildPoint) const
+{
+ if (m_Control)
+ return m_Control->GetGlobalPosition(inChildPoint);
+ return CPt();
+}
+
+Qt3DSRenderDevice CControlData::GetPlatformDevice()
+{
+ if (m_Control)
+ return m_Control->GetPlatformDevice();
+ return nullptr;
+}
+
+bool CControlData::IsChildPlatformDevice(Qt3DSRenderDevice inDevice)
+{
+ if (m_Control)
+ return m_Control->IsChildPlatformDevice(inDevice);
+ return false;
+}
+
+void CControlData::ShowMoveableWindow(CPt inLocation, Q3DStudio::CString inText, CRct inBoundingRct)
+{
+ if (m_Control)
+ m_Control->ShowMoveableWindow(inLocation, inText, inBoundingRct);
+}
+
+void CControlData::HideMoveableWindow()
+{
+ if (m_Control)
+ m_Control->HideMoveableWindow();
+}
+
+CControl *CControlData::GetFirstChild()
+{
+ if (m_Control)
+ m_Control->GetFirstChild();
+ return nullptr;
+}
+
+bool CControlData::HasFocus(CControl *inControl)
+{
+ if (m_Control)
+ return m_Control->HasFocus(inControl);
+ return false;
+}
+
+void CControlData::GrabFocus(CControl *inControl)
+{
+ if (m_Control)
+ m_Control->GrabFocus(inControl);
+}
+
+CPt CControlData::ClientToScreen(CPt inPoint)
+{
+ if (m_Control)
+ return m_Control->ClientToScreen(inPoint);
+ return CPt();
+}
+
+CPt CControlData::ScreenToClient(CPt inPoint)
+{
+ if (m_Control)
+ return m_Control->ScreenToClient(inPoint);
+ return CPt();
+}
+
+void CControlData::AddFocusListener(CChildFocusListener *inListener)
+{
+ if (m_Control)
+ m_Control->AddFocusListener(inListener);
+}
+
+void CControlData::RemoveFocusListener(CChildFocusListener *inListener)
+{
+ if (m_Control)
+ m_Control->RemoveFocusListener(inListener);
+}
+
+void CControlData::FireFocusEvent(bool inStatus)
+{
+ if (m_Control)
+ m_Control->FireFocusEvent(inStatus);
+}
+
+void CControlData::EnsureVisible(CRct inRect)
+{
+ if (m_Control)
+ m_Control->EnsureVisible(inRect);
+}
+
+void CControlData::EnsureVisible()
+{
+ if (m_Control)
+ m_Control->EnsureVisible();
+}
+
+void CControlData::OnParentChanged(CControl *inControl)
+{
+ if (m_Control)
+ m_Control->OnParentChanged(inControl);
+}
+
+void CControlData::NotifyParentNeedsLayout()
+{
+ if (m_Control)
+ m_Control->NotifyParentNeedsLayout();
+}
+
+void CControlData::MarkChildrenNeedLayout()
+{
+ if (m_Control)
+ m_Control->MarkChildrenNeedLayout();
+}
+
+void CControlData::MarkNeedsLayout()
+{
+ if (m_Control)
+ m_Control->MarkNeedsLayout();
+}
+
+// Tell this control that one of its children need to be layed out.
+void CControlData::SetLayout(CPt inSize, CPt inPosition)
+{
+ if (m_Control)
+ m_Control->SetLayout(inSize, inPosition);
+}
+
+void CControlData::LayoutChildren()
+{
+ if (m_Control)
+ m_Control->LayoutChildren();
+}
+
+void CControlData::EnsureLayout()
+{
+ if (m_Control)
+ m_Control->EnsureLayout();
+}
diff --git a/src/Authoring/Qt3DStudio/Controls/ControlData.h b/src/Authoring/Qt3DStudio/Controls/ControlData.h
new file mode 100644
index 00000000..d2f6870e
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Controls/ControlData.h
@@ -0,0 +1,273 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#pragma once
+#ifndef CONTROLDATAH
+#define CONTROLDATAH
+
+#include "DropTarget.h"
+#include "Pt.h"
+#include "Rct.h"
+#include "Multicaster.h"
+#include "Qt3DSString.h"
+#include "DocumentEditorEnumerations.h"
+
+class CControl;
+class CControlWindowListener;
+class CChildFocusListener;
+class CRenderer;
+
+QT_FORWARD_DECLARE_CLASS(QMenu)
+
+namespace Q3DStudio {
+namespace Control {
+
+using namespace std;
+
+struct ControlEventState
+{
+ enum Enum {
+ Unknown = 0,
+ Listening,
+ Ignoring,
+ };
+};
+
+struct SControlEventData
+{
+ bool m_Enabled;
+ ControlEventState::Enum m_EventState;
+ SControlEventData()
+ : m_Enabled(false)
+ , m_EventState(ControlEventState::Ignoring)
+ {
+ }
+};
+
+// Smart pointer object that referees access to a control.
+class CControlData
+{
+ Q_DISABLE_COPY(CControlData)
+public:
+ friend class ::CControl;
+ friend class std::shared_ptr<CControlData>;
+
+private:
+ // The physical address of the control is the key in the graph
+ // that points to this data item.
+ CControl *m_Control;
+
+ CPt m_Size; ///< Current size of this control
+
+ CPt m_Position; ///< Position of this control, relative to the parent
+ CPt m_MinSize; ///< Minimum allowed size of this control
+ CPt m_MaxSize; ///< Maximum allowed size of this contrl
+ CPt m_PrefSize; ///< Preferred size of this control
+
+ bool m_IsMouseOver; ///< True if the mouse is over this control
+ bool m_IsInvalidated; ///< True if this control needs to be redrawn
+ bool m_IsChildInvalidated; ///< True if a child of this control is invalidated.
+ bool m_IsVisible; ///< True if this control is to be visible
+ bool m_IsEnabled; ///< True if this control is enabled.
+ bool m_IsParentEnabled;
+ bool m_HasFocus;
+ bool m_IsMouseDown;
+ bool m_ShowTooltips; ///< Specifies whether or not tooltips should be shown
+ bool m_NeedsLayout; ///< True if this control needs to be layed out.
+ bool m_ChildrenNeedLayout; ///< True if my children need layout
+ SControlEventData
+ m_MouseWheelState; ///< Tracks whether this object cares about mouse wheel.
+
+ QString m_TooltipText; ///< Text to be displayed for tooltips
+
+ std::shared_ptr<CControlData> m_Focus; ///< Child control that has the focus.
+ std::shared_ptr<CControlData> m_MouseFocus; ///< Child control that got the mouse down.
+ CControlWindowListener
+ *m_WindowListener; ///< External listener for when this control is invalidated.
+
+ Q3DStudio::CString m_ControlName;
+ CMulticaster<CChildFocusListener *> m_FocusListeners; ///< Used for focus changes
+
+public:
+ CControlData(CControl &inControl);
+ ~CControlData();
+
+ CControl *GetControl();
+
+ CControl *GetParent();
+
+ void OnDraw(CRenderer *inRenderer, CRct &inDirtyRect, bool inIgnoreValidation = false);
+ void Draw(CRenderer *inRenderer);
+ void NotifyNotInClipRect();
+
+ CPt GetPosition() const;
+ void SetPosition(CPt inPosition);
+ void SetPosition(long inX, long inY);
+
+ CPt GetSize() const;
+ void SetSize(CPt inSize);
+ void SetSize(long inWidth, long inHeight);
+
+ CPt GetMinimumSize();
+ void SetMinimumSize(CPt inSize);
+
+ CPt GetMaximumSize();
+ void SetMaximumSize(CPt inSize);
+
+ CPt GetPreferredSize();
+ void SetPreferredSize(CPt inSize);
+
+ void SetAbsoluteSize(CPt inSize);
+
+ void SetMouseDown(bool inMouseDown);
+ void OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags);
+ void OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags);
+ void OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags);
+ bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags);
+ bool OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags);
+ void OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags);
+ void OnMouseRUp(CPt inPoint, Qt::KeyboardModifiers inFlags);
+ void OnMouseClick(CPt inPoint, Qt::KeyboardModifiers inFlags);
+ bool OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags);
+ bool OnMouseHover(CPt inPoint, Qt::KeyboardModifiers inFlags);
+ bool OnMouseWheel(CPt inPoint, long inAmount, Qt::KeyboardModifiers inFlags);
+ bool OnKeyDown(unsigned int inChar, Qt::KeyboardModifiers inFlags);
+ bool OnKeyUp(unsigned int inChar, Qt::KeyboardModifiers inFlags);
+ bool OnChar(const QString &inChar, Qt::KeyboardModifiers inFlags);
+ void OnLoseFocus();
+ void OnGainFocus();
+ bool CanGainFocus();
+ bool IsInFocus();
+ void OnTab();
+ void OnReverseTab();
+ void SetFocusToFirstAvailable();
+ void SetFocusToLastAvailable();
+ void ChildrenChanged();
+
+ // Mouse wheel event state.
+ void SetMouseWheelEnabled(bool inEnabled);
+ /**
+ Callback so we can update any event states to unknown
+ from ignoring forcing a refresh of hierarchy event information
+ the next time the event state is queried.
+ */
+ void OnHierarchyChanged();
+ /**
+ If our event state is unknown, force resolution by asking children what their
+ event state is. Else return our event state.
+ */
+ ControlEventState::Enum GetMouseWheelEventState();
+
+protected:
+ void UpdateMouseWheelEventState();
+ void ChildMouseWheelEventStateChanged(ControlEventState::Enum inNewState);
+ void SetMouseWheelEventState(ControlEventState::Enum inNewState);
+
+public:
+ CDropTarget *FindDropCandidate(CPt &inMousePoint, Qt::KeyboardModifiers inFlags,
+ EStudioObjectType objectType,
+ Q3DStudio::DocumentEditorFileType::Enum fileType);
+
+ void AddChild(CControl *inControl, CControl *inInsertBefore = NULL);
+ void RemoveChild(CControl *inControl);
+ void RemoveAllChildren();
+ long GetChildIndex(CControl *inChildControl);
+ CControl *FindChildByName(const Q3DStudio::CString &inName);
+
+ bool IsMouseOver() const;
+
+ bool HitTest(const CPt &inPoint) const;
+ bool IsInRect(const CRct &inRect) const;
+
+ void Invalidate(bool inInvalidate = true);
+ void InvalidateRect(const CRct &inRect);
+ bool IsInvalidated() const;
+
+ void OnChildInvalidated();
+ bool IsChildInvalidated() const;
+
+ void SetVisible(bool inIsVisible);
+ bool IsVisible() const;
+ void OnVisibleStateChange(bool inIsVisible);
+ void OnParentVisibleStateChanged(bool inIsVisible);
+
+ void SetParentEnabled(bool inParentEnabled);
+ void SetEnabled(bool inIsEnabled);
+ bool IsEnabled() const;
+ bool GetEnabledFlag();
+ void SetEnabledFlag(bool inIsEnabled);
+
+ void OnChildSizeChanged(CControl *inChild);
+ void ResetMinMaxPref();
+
+ void SetName(Q3DStudio::CString inName);
+ Q3DStudio::CString GetName();
+
+ void BeginDrawChildren(CRenderer *inRenderer);
+
+ long DoPopup(QMenu *inContextMenu, CPt inPoint);
+ void RemoveUberControl(CControl *inControl);
+ void OffsetPosition(CPt inOffset);
+
+ CPt GetGlobalPosition(CPt inChildPoint) const;
+ Qt3DSRenderDevice GetPlatformDevice();
+ bool IsChildPlatformDevice(Qt3DSRenderDevice inDevice);
+ void ShowMoveableWindow(CPt inLocation, Q3DStudio::CString inText, CRct inBoundingRct);
+ void HideMoveableWindow();
+ CControl *GetFirstChild();
+ bool HasFocus(CControl *inControl);
+ void GrabFocus(CControl *inControl);
+
+ CPt ClientToScreen(CPt inPoint);
+ CPt ScreenToClient(CPt inPoint);
+
+ void AddFocusListener(CChildFocusListener *inListener);
+ void RemoveFocusListener(CChildFocusListener *inListener);
+ void FireFocusEvent(bool inStatus);
+
+ void EnsureVisible(CRct inRect);
+ void EnsureVisible();
+
+ void OnParentChanged(CControl *inControl);
+
+ void NotifyParentNeedsLayout();
+ void MarkChildrenNeedLayout();
+ void MarkNeedsLayout();
+ // Tell this control that one of its children need to be layed out.
+ void SetLayout(CPt inSize, CPt inPosition);
+ void LayoutChildren();
+ void EnsureLayout();
+
+private:
+ static std::shared_ptr<CControlData> CreateControlData(CControl &inControl);
+ void ReleaseControl(); // set the control to null, remove our graph representation
+};
+}
+}
+
+#endif
diff --git a/src/Authoring/Qt3DStudio/Controls/ControlGraph.cpp b/src/Authoring/Qt3DStudio/Controls/ControlGraph.cpp
new file mode 100644
index 00000000..34b59b7c
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Controls/ControlGraph.cpp
@@ -0,0 +1,188 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "Qt3DSCommonPrecompile.h"
+#include "ControlGraph.h"
+#include "GraphImpl.h"
+#include "foundation/Qt3DSAssert.h"
+#include "Control.h"
+#include "ControlData.h"
+
+using namespace std;
+using namespace Q3DStudio;
+using namespace Q3DStudio::Graph;
+using namespace Q3DStudio::Control;
+using Q3DStudio::CString;
+
+namespace {
+typedef SGraphImpl<CControl *, std::shared_ptr<CControlData>> TGraphType;
+
+TGraphType g_ControlGraph;
+}
+
+namespace Q3DStudio {
+namespace Control {
+ namespace ControlGraph {
+
+ void AddNode(std::shared_ptr<CControlData> inData)
+ {
+ g_ControlGraph.AddRoot(inData->GetControl());
+ g_ControlGraph.SetData(inData->GetControl(), inData);
+ }
+
+ void RemoveNode(CControl &inData) { g_ControlGraph.RemoveChild(&inData, true); }
+
+ void AddChild(CControl &inParent, CControl &inChild, CControl *inNextSibling)
+ {
+ std::shared_ptr<CControlData> oldParent = GetParent(inChild);
+ TGraphType::TNodePtr theParent(g_ControlGraph.GetImpl(&inParent));
+
+ // It actually happens that sometimes inChild gets added with a sibling
+ // but the sibling hasn't actually been added yet.
+ if (inNextSibling != nullptr) {
+ TGraphType::TNodePtr theSibling(g_ControlGraph.GetImpl(inNextSibling));
+ if (theSibling->m_Parent == theParent)
+ g_ControlGraph.MoveBefore(&inChild, inNextSibling);
+ else
+ g_ControlGraph.AddChild(&inParent, &inChild, SGraphPosition::SEnd());
+ } else
+ g_ControlGraph.AddChild(&inParent, &inChild, SGraphPosition::SEnd());
+
+ if (!oldParent || oldParent->GetControl() != &inParent) {
+ inChild.OnParentChanged(&inParent);
+ if (oldParent)
+ oldParent->ChildrenChanged();
+ }
+ inChild.Invalidate();
+ inParent.ChildrenChanged();
+ }
+ // inParent is supplied for error checking purposes.
+ void RemoveChild(CControl &inParent, CControl &inChild)
+ {
+ inChild.OnParentChanged(nullptr);
+ g_ControlGraph.RemoveChild(&inParent, &inChild, false);
+ inChild.Invalidate();
+ inParent.ChildrenChanged();
+ }
+ void RemoveAllChildren(CControl &inParent)
+ {
+ TGraphType::TNodePtr theNode(g_ControlGraph.GetImpl(&inParent));
+ if (theNode == nullptr)
+ return;
+ while (theNode->m_Children.empty() == false) {
+ theNode->m_Children.back()->m_Data->OnParentChanged(nullptr);
+ theNode->m_Children.back()->m_Data->NotifyParentNeedsLayout();
+ g_ControlGraph.RemoveChild(&inParent, theNode->m_Children.back()->m_GraphableID,
+ false);
+ }
+ inParent.ChildrenChanged();
+ }
+ void MoveTo(CControl &inParent, CControl &inChild, const Graph::SGraphPosition &inPosition)
+ {
+ std::shared_ptr<CControlData> theOldParent(GetParent(inChild));
+ g_ControlGraph.MoveTo(&inParent, &inChild, inPosition);
+ if (!theOldParent || theOldParent->GetControl() != &inParent)
+ inChild.OnParentChanged(&inParent);
+ inChild.NotifyParentNeedsLayout();
+ inParent.MarkChildrenNeedLayout();
+ if (theOldParent) {
+ theOldParent->ChildrenChanged();
+ }
+ inParent.ChildrenChanged();
+ inChild.Invalidate();
+ }
+ long GetNumChildren(CControl &inControl)
+ {
+ return g_ControlGraph.GetChildCount(&inControl);
+ }
+
+ long GetChildIndex(CControl &inParent, CControl &inChild)
+ {
+ QT3DS_ASSERT(GetParent(inChild)->GetControl() == &inParent);
+
+ SGraphPosition thePos = g_ControlGraph.GetNodePosition(&inChild);
+ return thePos.GetIndex();
+ }
+
+ std::shared_ptr<CControlData> GetChild(CControl &inParent, long inIndex)
+ {
+ TGraphType::TNodePtr theNode(g_ControlGraph.GetImpl(&inParent));
+ if (theNode && inIndex < (long)theNode->m_Children.size() && inIndex > -1)
+ return theNode->m_Children[inIndex]->m_Data;
+ return std::shared_ptr<CControlData>();
+ }
+
+ std::shared_ptr<CControlData> GetParent(CControl &inControl)
+ {
+ TGraphType::TNodePtr theNode(g_ControlGraph.GetImpl(&inControl));
+ if (theNode && theNode->m_Parent)
+ return theNode->m_Parent->m_Data;
+ return std::shared_ptr<CControlData>();
+ }
+
+ // Dummy struct to hide graph implementation
+ struct SDummyGraphNode : public TGraphType::TNodeType
+ {
+ SDummyGraphNode(CControl *const &inIdentifier,
+ const std::shared_ptr<CControlData> &inNodeData =
+ std::shared_ptr<CControlData>())
+ : TGraphType::TNodeType(inIdentifier, inNodeData)
+ {
+ }
+ };
+
+ std::shared_ptr<CControlData> SIteratorBase::GetCurrent()
+ {
+ if (m_Children && m_Index < (long)m_Children->size())
+ return (*m_Children)[m_Index]->m_Data;
+
+ QT3DS_ASSERT(false);
+ return std::shared_ptr<CControlData>();
+ }
+
+ SReverseIterator GetRChildren(CControl &inControl)
+ {
+ TGraphType::TNodePtr theNode(g_ControlGraph.GetImpl(&inControl));
+ if (theNode)
+ return SReverseIterator(
+ theNode->m_Data,
+ reinterpret_cast<vector<SDummyGraphNode *> &>(theNode->m_Children));
+ return SReverseIterator();
+ }
+
+ SIterator GetChildren(CControl &inControl)
+ {
+ TGraphType::TNodePtr theNode(g_ControlGraph.GetImpl(&inControl));
+ if (theNode)
+ return SIterator(theNode->m_Data, reinterpret_cast<vector<SDummyGraphNode *> &>(
+ theNode->m_Children));
+ return SIterator();
+ }
+ }
+}
+}
diff --git a/src/Authoring/Qt3DStudio/Controls/ControlGraph.h b/src/Authoring/Qt3DStudio/Controls/ControlGraph.h
new file mode 100644
index 00000000..0dfe2b30
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Controls/ControlGraph.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#pragma once
+#ifndef CONTROLGRAPHH
+#define CONTROLGRAPHH
+#include "Multicaster.h"
+#include "ControlGraphIterators.h"
+
+class CControl;
+class CControlWindowListener;
+class CChildFocusListener;
+class CRenderer;
+
+namespace Q3DStudio {
+namespace Graph {
+
+ struct SGraphPosition; // GraphPosition.h"
+}
+
+namespace Control {
+ class ControlData;
+
+ namespace ControlGraph {
+ void AddNode(std::shared_ptr<CControlData> inData);
+ void RemoveNode(CControl &inData);
+ void AddChild(CControl &inParent, CControl &inChild, CControl *inNextSibling);
+ // inParent is supplied for error checking purposes.
+ void RemoveChild(CControl &inParent, CControl &inChild);
+ void RemoveAllChildren(CControl &inParent);
+ void MoveTo(CControl &inParent, CControl &inChild, const Graph::SGraphPosition &inPosition);
+ long GetNumChildren(CControl &inControl);
+ long GetChildIndex(CControl &inParent, CControl &inChild);
+ std::shared_ptr<CControlData> GetChild(CControl &inParent, long inIndex);
+ std::shared_ptr<CControlData> GetParent(CControl &inControl);
+
+ SReverseIterator GetRChildren(CControl &inControl);
+ SIterator GetChildren(CControl &inControl);
+ };
+}
+}
+
+#endif
diff --git a/src/Authoring/Qt3DStudio/Controls/ControlGraphIterators.h b/src/Authoring/Qt3DStudio/Controls/ControlGraphIterators.h
new file mode 100644
index 00000000..ae2ffcf6
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Controls/ControlGraphIterators.h
@@ -0,0 +1,156 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#pragma once
+#ifndef CONTROLGRAPHITERATORSH
+#define CONTROLGRAPHITERATORSH
+#include <vector>
+
+namespace Q3DStudio {
+namespace Control {
+ class CControlData;
+ using std::vector;
+
+ namespace ControlGraph {
+ struct SDummyGraphNode;
+
+ struct SIteratorBase
+ {
+ protected:
+ std::shared_ptr<CControlData> m_ControlData;
+ vector<SDummyGraphNode *> *m_Children;
+ long m_Index;
+
+ public:
+ SIteratorBase()
+ : m_Children(nullptr)
+ , m_Index(0)
+ {
+ }
+
+ SIteratorBase(std::shared_ptr<CControlData> data,
+ vector<SDummyGraphNode *> &inChildren)
+ : m_ControlData(data)
+ , m_Children(&inChildren)
+ , m_Index(0)
+ {
+ }
+
+ SIteratorBase(const SIteratorBase &inOther)
+ : m_ControlData(inOther.m_ControlData)
+ , m_Children(inOther.m_Children)
+ , m_Index(inOther.m_Index)
+ {
+ }
+
+ SIteratorBase &operator=(const SIteratorBase &inOther)
+ {
+ if (this != &inOther) {
+ m_ControlData = inOther.m_ControlData;
+ m_Children = inOther.m_Children;
+ m_Index = inOther.m_Index;
+ }
+ return *this;
+ }
+
+ bool operator==(const SIteratorBase &other) { return m_Index == other.m_Index; }
+ bool operator!=(const SIteratorBase &other) { return m_Index != other.m_Index; }
+
+ std::shared_ptr<CControlData> GetCurrent();
+
+ std::shared_ptr<CControlData> operator->() { return GetCurrent(); }
+ std::shared_ptr<CControlData> operator*() { return GetCurrent(); }
+ };
+
+ struct SReverseIterator : SIteratorBase
+ {
+ SReverseIterator() {}
+ SReverseIterator(std::shared_ptr<CControlData> data,
+ vector<SDummyGraphNode *> &inChildren)
+ : SIteratorBase(data, inChildren)
+ {
+ m_Index = (long)inChildren.size() - 1;
+ }
+ SReverseIterator(const SReverseIterator &inOther)
+ : SIteratorBase(inOther)
+ {
+ }
+ SReverseIterator &operator=(const SReverseIterator &inOther)
+ {
+ SIteratorBase::operator=(inOther);
+ return *this;
+ }
+
+ bool IsDone() { return m_Children == nullptr || m_Index < 0; }
+ bool HasNext() { return m_Children && m_Index > -1; }
+ SReverseIterator &operator++()
+ {
+ --m_Index;
+ return *this;
+ }
+ SReverseIterator &operator+=(long inAmount)
+ {
+ m_Index -= inAmount;
+ return *this;
+ }
+ };
+
+ struct SIterator : SIteratorBase
+ {
+ SIterator() {}
+ SIterator(std::shared_ptr<CControlData> data, vector<SDummyGraphNode *> &inChildren)
+ : SIteratorBase(data, inChildren)
+ {
+ }
+ SIterator(const SReverseIterator &inOther)
+ : SIteratorBase(inOther)
+ {
+ }
+ SIterator &operator=(const SIterator &inOther)
+ {
+ SIteratorBase::operator=(inOther);
+ return *this;
+ }
+
+ bool IsDone() { return m_Children == nullptr || m_Index >= (long)m_Children->size(); }
+ bool HasNext() { return m_Children && m_Index < (long)m_Children->size(); }
+ SIterator operator++()
+ {
+ ++m_Index;
+ return *this;
+ }
+ SIterator &operator+=(long inAmount)
+ {
+ m_Index += inAmount;
+ return *this;
+ }
+ };
+ }
+}
+}
+#endif \ No newline at end of file
diff --git a/src/Authoring/Qt3DStudio/Controls/OffscreenRenderer.cpp b/src/Authoring/Qt3DStudio/Controls/OffscreenRenderer.cpp
new file mode 100644
index 00000000..e30797f7
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Controls/OffscreenRenderer.cpp
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "Qt3DSCommonPrecompile.h"
+#include "OffscreenRenderer.h"
+#include "AppFonts.h"
+
+/**
+ * Constructor: Overrides a protected constructor on the base class. Sets up
+ * all the requirements so that this renderer is valid.
+ */
+COffscreenRenderer::COffscreenRenderer(const QRect &inClippingRect)
+ : CWinRenderer()
+{
+ m_pixmap = QPixmap(inClippingRect.size());
+ m_painter = new QPainter(&m_pixmap);
+ QFont font = CAppFonts::GetInstance()->GetNormalFont();
+ m_painter->setFont(font);
+
+ // Set up the specified clipping region. Renderer is now valid for use.
+ PushClippingRect(inClippingRect);
+}
+
+//=============================================================================
+/**
+ * Destructor
+ */
+COffscreenRenderer::~COffscreenRenderer()
+{
+ delete m_painter;
+ m_painter = nullptr;
+}
diff --git a/src/Authoring/Qt3DStudio/Controls/OffscreenRenderer.h b/src/Authoring/Qt3DStudio/Controls/OffscreenRenderer.h
new file mode 100644
index 00000000..dccd259f
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Controls/OffscreenRenderer.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#ifndef INCLUDED_OFFSCREEN_RENDERER_H
+#define INCLUDED_OFFSCREEN_RENDERER_H 1
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "WinRenderer.h"
+
+//=============================================================================
+/**
+ * Class for creating a renderer compatible with the current display, but that
+ * does not actually draw to the display. Provided so that you controls can
+ * query text size outside of their draw functions. This class could be
+ * further extended to provide offscreen drawing and blitting, though it's
+ * not currently set up to do so.
+ */
+class COffscreenRenderer : public CWinRenderer
+{
+public:
+ COffscreenRenderer(const QRect &inClippingRect);
+ virtual ~COffscreenRenderer();
+
+ QPixmap pixmap() const override { return m_pixmap;}
+
+protected:
+ QPixmap m_pixmap;
+};
+
+#endif // INCLUDED_OFFSCREEN_RENDERER_H
diff --git a/src/Authoring/Qt3DStudio/Controls/Renderer.cpp b/src/Authoring/Qt3DStudio/Controls/Renderer.cpp
new file mode 100644
index 00000000..5b0a6296
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Controls/Renderer.cpp
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "Qt3DSCommonPrecompile.h"
+
+#include "Renderer.h"
+
+#include <QtCore/qpoint.h>
+#include <QtCore/qrect.h>
+
+/**
+ * Draws the outline of a rectangle in the specified colors.
+ *
+ * @param inRect Rectangle to be outlined
+ * @param inTop Color of the top line
+ * @param inRight Color of the line on the right side
+ * @param inBottom Color of the line on the bottom
+ * @param inLeft Color of the line on the left side
+ */
+void CRenderer::DrawRectOutline(const QRect &inRect, const QColor &inTop, const QColor &inRight,
+ const QColor &inBottom, const QColor &inLeft)
+{
+ QPoint theUpperLeft(inRect.topLeft());
+ QPoint theUpperRight(inRect.topRight());
+ QPoint theLowerRight(inRect.bottomRight());
+ QPoint theLowerLeft(inRect.bottomLeft());
+
+ // Top
+ PushPen(inTop, 1);
+ MoveTo(theUpperLeft.x(), theUpperLeft.y());
+ LineTo(theUpperRight.x(), theUpperRight.y());
+ PopPen();
+
+ // Right
+ PushPen(inRight, 1);
+ LineTo(theLowerRight.x(), theLowerRight.y());
+ PopPen();
+
+ // Bottom
+ PushPen(inBottom, 1);
+ LineTo(theLowerLeft.x(), theLowerLeft.y());
+ PopPen();
+
+ // Left
+ PushPen(inLeft, 1);
+ LineTo(theUpperLeft.x(), theUpperLeft.y());
+ PopPen();
+}
diff --git a/src/Authoring/Qt3DStudio/Controls/Renderer.h b/src/Authoring/Qt3DStudio/Controls/Renderer.h
new file mode 100644
index 00000000..7ef77fe3
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Controls/Renderer.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_RENDERER_H
+#define INCLUDED_RENDERER_H 1
+
+#pragma once
+
+#include <QColor>
+#include <QPoint>
+
+#include "CColor.h"
+
+QT_BEGIN_NAMESPACE
+class QPainter;
+class QPixmap;
+class QRect;
+class QSize;
+class QString;
+QT_END_NAMESPACE
+
+class CRenderer
+{
+ typedef std::vector<QPoint> TTranslationList;
+
+public:
+ virtual ~CRenderer() {}
+
+ virtual QPainter* GetPainter() = 0;
+ virtual void FillSolidRect(const QRect &inCoordinates, const QColor &inColor) = 0;
+ virtual void FillRoundedRect(const QRect &inCoordinates, const QColor &inColor,
+ bool vertical) = 0;
+ virtual void MoveTo(const QPoint &inPoint) = 0;
+ virtual void MoveTo(long inX, long inY) = 0;
+ virtual void LineTo(const QPoint &inPoint) = 0;
+ virtual void LineTo(long inX, long inY) = 0;
+
+ virtual void PushPen(const QColor &inColor,
+ int inWidth = 1) = 0; //, UINT inStyle = PS_SOLID );
+ virtual void PopPen() = 0;
+ virtual void BitBltFrom(const QRect &inRect, CRenderer *inRenderer, long inXSrc, long inYSrc) = 0;
+
+ virtual void DrawText(float inX, float inY, const QString &inText) = 0;
+ virtual void DrawText(float inX, float inY, const QString &inText,
+ const QRect &inBoundingRect, const QColor &inColor = Qt::black) = 0;
+ virtual void DrawBoldText(float inX, float inY, const QString &inText,
+ const QRect &inBoundingRect, const QColor &inColor = Qt::black) = 0;
+
+ virtual QSize GetTextSize(const QString &inText) = 0;
+
+ virtual void DrawBitmap(const QPoint &inPos, const QPixmap &inImage) = 0;
+ virtual void Draw3dRect(const QRect &inRect, const QColor &inTopLeftColor,
+ const QColor &inBottomRightColor) = 0;
+ virtual void DrawRectOutline(const QRect &inRect, const QColor &inTop, const QColor &inRight,
+ const QColor &inBottom, const QColor &inLeft);
+ virtual void DrawGradientBitmap(const QRect &inRct, const QColor &inBeginColor, bool inInverted,
+ double inScalingFactor = .99) = 0;
+
+ virtual void DrawGradient(const QRect &inRect, const QColor &inBeginColor,
+ const QColor &inEndColor) = 0;
+
+ virtual void PushTranslation(const QPoint &inTranslation) = 0;
+ virtual void PopTranslation() = 0;
+ virtual QPoint GetTranslation() = 0;
+
+ virtual QRect GetClippingRect() = 0;
+ virtual void PushClippingRect(const QRect &inRect) = 0;
+ virtual void PushAbsoluteClippingRect(const QRect &inRect) = 0;
+ virtual void PopClippingRect() = 0;
+
+ virtual void FillHashed(const QRect &inRect, const QColor &inForeGroundColor) = 0;
+
+ virtual QPixmap pixmap() const = 0;
+
+protected:
+ QPoint m_Translation;
+ TTranslationList m_Translations;
+};
+#endif // INCLUDED_RENDERER_H
diff --git a/src/Authoring/Qt3DStudio/Controls/WidgetControl.cpp b/src/Authoring/Qt3DStudio/Controls/WidgetControl.cpp
new file mode 100644
index 00000000..207abed0
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Controls/WidgetControl.cpp
@@ -0,0 +1,243 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "WidgetControl.h"
+
+#include "Control.h"
+#include "DropSource.h"
+#include "IDragable.h"
+#include "OffscreenRenderer.h"
+#include "Pt.h"
+#include "Rct.h"
+#include "Qt3DSFile.h"
+
+#include <QtGui/qdrag.h>
+#include <QtGui/qevent.h>
+#include <QtGui/qpainter.h>
+#include <QtWidgets/qmenu.h>
+
+WidgetControl::WidgetControl(CControl *control, QWidget *parent)
+ : QWidget(parent)
+ , m_control(control)
+{
+ Q_ASSERT(control);
+ setControlSize(sizeHint());
+}
+
+WidgetControl::~WidgetControl()
+{
+}
+
+bool WidgetControl::event(QEvent *event)
+{
+ if (event->type() == QEvent::ShortcutOverride) {
+ QKeyEvent *ke = static_cast<QKeyEvent *>(event);
+ if (ke->key() == Qt::Key_C && ke->modifiers() == Qt::ControlModifier)
+ m_control->OnKeyDown(ke->key(), ke->modifiers());
+ }
+ return QWidget::event(event);
+}
+
+void WidgetControl::showEvent(QShowEvent *event)
+{
+ QWidget::showEvent(event);
+}
+
+void WidgetControl::paintEvent(QPaintEvent *event)
+{
+ QPainter painter(this);
+ const auto boundRect = QRect(QPoint(0,0), size());
+ CWinRenderer renderer(&painter, boundRect);
+ CRct rect(event->rect());
+ m_control->OnDraw(&renderer, rect, true);
+
+ QWidget::paintEvent(event);
+}
+
+void WidgetControl::resizeEvent(QResizeEvent *event)
+{
+ setControlSize(event->size());
+ QWidget::resizeEvent(event);
+}
+
+void WidgetControl::keyPressEvent(QKeyEvent *event)
+{
+ QWidget::keyPressEvent(event);
+ m_control->OnKeyDown(event->key(), event->modifiers());
+ m_control->OnChar(event->text(), event->modifiers());
+}
+
+void WidgetControl::keyReleaseEvent(QKeyEvent *event)
+{
+ m_control->OnKeyUp(event->key(), event->modifiers());
+ QWidget::keyReleaseEvent(event);
+}
+
+void WidgetControl::mousePressEvent(QMouseEvent *event)
+{
+ const auto pos = CPt(event->pos());
+ if (m_isLeftMouseDown)
+ m_control->OnMouseUp(pos, event->modifiers());
+
+ m_isLeftMouseDown = (event->button() == Qt::LeftButton);
+ if (m_isLeftMouseDown)
+ m_control->OnMouseDown(pos, event->modifiers());
+ else
+ m_control->OnMouseRDown(pos, event->modifiers());
+
+ setFocus();
+ QWidget::mousePressEvent(event);
+}
+
+void WidgetControl::mouseReleaseEvent(QMouseEvent *event)
+{
+ const auto pos = CPt(event->pos());
+ if (event->button() == Qt::LeftButton) {
+ m_isLeftMouseDown = false;
+ m_control->OnMouseUp(pos, event->modifiers());
+ } else {
+ m_control->OnMouseRUp(pos, event->modifiers());
+ }
+
+ QWidget::mouseReleaseEvent(event);
+}
+
+void WidgetControl::mouseMoveEvent(QMouseEvent *event)
+{
+ m_control->OnMouseMove(event->pos(), event->modifiers());
+ QWidget::mouseMoveEvent(event);
+}
+
+void WidgetControl::mouseDoubleClickEvent(QMouseEvent *event)
+{
+ // call QWidget handler first to not deliver OnMouseDown after OnMouseDoubleClick
+ QWidget::mouseDoubleClickEvent(event);
+ m_control->OnMouseDoubleClick(event->pos(), event->modifiers());
+}
+
+void WidgetControl::wheelEvent(QWheelEvent *event)
+{
+ m_control->OnMouseWheel(event->pos(), event->angleDelta().y(), event->modifiers());
+ QWidget::wheelEvent(event);
+}
+
+void WidgetControl::enterEvent(QEvent *event)
+{
+ setMouseTracking(true);
+ m_control->OnMouseHover(mapFromGlobal(QCursor::pos()), {});
+ QWidget::enterEvent(event);
+}
+
+void WidgetControl::leaveEvent(QEvent *event)
+{
+ setMouseTracking(false);
+ m_control->OnMouseOut(mapFromGlobal(QCursor::pos()), {});
+ QWidget::leaveEvent(event);
+}
+
+void WidgetControl::focusInEvent(QFocusEvent *event)
+{
+ m_control->OnGainFocus();
+ QWidget::focusInEvent(event);
+}
+
+void WidgetControl::focusOutEvent(QFocusEvent *event)
+{
+ if (!m_isContextMenuShown)
+ m_control->OnLoseFocus();
+ QWidget::focusOutEvent(event);
+}
+
+QSize WidgetControl::sizeHint() const
+{
+ const auto preferredSize = m_control->GetPreferredSize();
+ return QSize(preferredSize.x, preferredSize.y);
+}
+
+/*
+ * CPaletteManager::GetTimelineControl() needs a way of accessing
+ * the CControl inside the widget
+ */
+CControl *WidgetControl::getControl() const
+{
+ return m_control;
+}
+
+void WidgetControl::setControlSize(const QSize &size)
+{
+ m_control->SetSize(size.width(), size.height());
+}
+
+bool WidgetControl::OnDragWithin(CDropSource &inSource)
+{
+ bool theReturn = false;
+ CPt thePoint = inSource.GetCurrentPoint();
+ Qt::KeyboardModifiers theFlags = inSource.GetCurrentFlags();
+ CDropTarget *theDropTarget = m_control->FindDropCandidate(
+ thePoint, theFlags, static_cast<EStudioObjectType>(inSource.GetObjectType()),
+ static_cast<Q3DStudio::DocumentEditorFileType::Enum>(inSource.getFileType()));
+
+ if (theDropTarget) {
+ theReturn = theDropTarget->Accept(inSource);
+ delete theDropTarget;
+ }
+ return theReturn;
+}
+
+bool WidgetControl::OnDragReceive(CDropSource &inSource)
+{
+ bool theReturn = false;
+ CPt thePoint = inSource.GetCurrentPoint();
+ Qt::KeyboardModifiers theFlags = inSource.GetCurrentFlags();
+
+ CDropTarget *theDropTarget = m_control->FindDropCandidate(
+ thePoint, theFlags, static_cast<EStudioObjectType>(inSource.GetObjectType()),
+ static_cast<Q3DStudio::DocumentEditorFileType::Enum>(inSource.getFileType()));
+
+ if (theDropTarget) {
+ theReturn = theDropTarget->Drop(inSource);
+ delete theDropTarget;
+ }
+ return theReturn;
+}
+
+void WidgetControl::OnDragLeave()
+{
+ m_control->OnMouseMove(CPt(-1, -1), 0);
+}
+
+void WidgetControl::OnReflectMouse(CPt &inPoint, Qt::KeyboardModifiers inFlags)
+{
+ // Notify the control that the mouse moved
+ m_control->OnMouseMove(inPoint, inFlags /*CHotKeys::GetCurrentKeyModifiers( )*/);
+
+ // If the control invalidated because of a mouse event then we want to do an immediate redraw.
+ // this ensures consistent visible feedback.
+ if (m_control->IsChildInvalidated())
+ repaint();
+}
diff --git a/src/Authoring/Qt3DStudio/Controls/WidgetControl.h b/src/Authoring/Qt3DStudio/Controls/WidgetControl.h
new file mode 100644
index 00000000..277a2e17
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Controls/WidgetControl.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef WIDGETCONTROL_H
+#define WIDGETCONTROL_H
+
+#include "Control.h"
+#include "DropContainer.h"
+
+#include <QtWidgets/qwidget.h>
+
+class CRenderer;
+class WidgetControl;
+
+class WidgetControl : public QWidget, public CWinDropContainer
+{
+ Q_OBJECT
+public:
+ explicit WidgetControl(CControl *control, QWidget *parent = nullptr);
+ virtual ~WidgetControl();
+ void setContextMenuShown(bool shown) { m_isContextMenuShown = shown; }
+
+protected:
+ bool event(QEvent *event) override;
+ void showEvent(QShowEvent *event) override;
+ void paintEvent(QPaintEvent *event) override;
+ void resizeEvent(QResizeEvent *event) override;
+ void keyPressEvent(QKeyEvent *event) override;
+ void keyReleaseEvent(QKeyEvent *event) override;
+ void mousePressEvent(QMouseEvent *event) override;
+ void mouseReleaseEvent(QMouseEvent *event) override;
+ void mouseMoveEvent(QMouseEvent *event) override;
+ void mouseDoubleClickEvent(QMouseEvent *event) override;
+ void wheelEvent(QWheelEvent *event) override;
+ void enterEvent(QEvent *event) override;
+ void leaveEvent(QEvent *event) override;
+ void focusInEvent(QFocusEvent *event) override;
+ void focusOutEvent(QFocusEvent *event) override;
+
+public:
+ QSize sizeHint() const override;
+ CControl *getControl() const;
+
+protected:
+ bool OnDragWithin(CDropSource &inSource) override;
+ bool OnDragReceive(CDropSource &inSource) override;
+ void OnDragLeave() override;
+ void OnReflectMouse(CPt &inPoint, Qt::KeyboardModifiers inFlags) override;
+
+private:
+ void setControlSize(const QSize &size);
+
+ CControl *m_control;
+ bool m_isLeftMouseDown = false;
+ bool m_isContextMenuShown = false;
+};
+
+#endif // WIDGETCONTROL_H
diff --git a/src/Authoring/Qt3DStudio/Controls/WinRenderer.cpp b/src/Authoring/Qt3DStudio/Controls/WinRenderer.cpp
new file mode 100644
index 00000000..1fd98734
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Controls/WinRenderer.cpp
@@ -0,0 +1,518 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "Qt3DSCommonPrecompile.h"
+
+#include "WinRenderer.h"
+#include "MasterP.h"
+#include "CoreUtils.h"
+
+//=============================================================================
+/**
+ * Leaves the Renderer in an invalid state, only for subclasses.
+ * In order for this renderer to be valid, you must do two things: (1) you must
+ * create a CDC and set m_DC equal to it, and (2) you must call PushClippingRect.
+ */
+CWinRenderer::CWinRenderer()
+ : m_painter(nullptr)
+{
+}
+
+//=============================================================================
+/**
+ * Leaves the Renderer in an invalid state, only for subclasses.
+ * PushClippingRect must be called in order for this to become valid.
+ */
+CWinRenderer::CWinRenderer(QPainter *inDC)
+{
+ m_painter = inDC;
+}
+
+CWinRenderer::CWinRenderer(QPainter *inDC, const QRect &inClippingRect)
+{
+ m_painter = inDC;
+
+ PushClippingRect(inClippingRect);
+}
+
+CWinRenderer::~CWinRenderer()
+{
+ m_Pens.clear();
+}
+
+//=============================================================================
+/**
+ * Draws a rectangle and fills it with inColor.
+ * The rectangle has no border and is solid.
+ * The coordinates are converted to global space using the current translation.
+ * @param inCoordinates the coordinates of the rectangle.
+ * @param inColor the color of the rectangle to draw.
+ */
+void CWinRenderer::FillSolidRect(const QRect &inCoordinates, const QColor &inColor)
+{
+ QRect theRect(inCoordinates.topLeft() + m_Translation,
+ inCoordinates.size());
+
+ m_painter->fillRect(theRect, inColor);
+}
+
+//=============================================================================
+/**
+ * Draws a rounded rectangle (which actually is just a line) and fills it with inColor.
+ * The coordinates are converted to global space using the current translation.
+ * @param inCoordinates the coordinates of the rectangle.
+ * @param inColor the color of the rectangle to draw.
+ */
+void CWinRenderer::FillRoundedRect(const QRect &inCoordinates, const QColor &inColor,
+ bool vertical)
+{
+ QPen previousPen = m_painter->pen();
+ QRect theRect(inCoordinates.topLeft() + m_Translation, inCoordinates.size());
+ QPointF startPoint = (theRect.bottomLeft() + theRect.topLeft()) / 2.0;
+ QPointF endPoint = (theRect.bottomRight() + theRect.topRight()) / 2.0;
+ qreal lineWidth = theRect.bottom() - theRect.top() + 1.0;
+
+ if (vertical) {
+ lineWidth = theRect.right() - theRect.left() + 1.0;
+ startPoint = (theRect.topRight() + theRect.topLeft()) / 2.0;
+ endPoint = (theRect.bottomRight() + theRect.bottomLeft()) / 2.0;
+ }
+
+ m_painter->setPen(QPen(inColor, lineWidth, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
+ m_painter->drawLine(startPoint, endPoint);
+
+ // Restore previous pen
+ m_painter->setPen(previousPen);
+}
+
+//=============================================================================
+/**
+ * Move the pen to the position.
+ * This will put the pen at inPoint but will not draw a line there from the
+ * current location.
+ * @param inPoint the location to move to, in local coordinates.
+ */
+void CWinRenderer::MoveTo(const QPoint &inPoint)
+{
+ m_currentPos = inPoint + m_Translation;
+}
+
+//=============================================================================
+/**
+ * Move the pen to the position.
+ * This will put the pen to the point but will not draw a line there from the
+ * current location.
+ * @param inX the X location to move to, in local coordinates.
+ * @param inY the Y location to move to, in local coordinates.
+ */
+void CWinRenderer::MoveTo(long inX, long inY)
+{
+ MoveTo(QPoint(inX, inY));
+}
+
+//=============================================================================
+/**
+ * Draw a line from the current pen location to inPoint.
+ * This will draw a line to inPoint and move the current location of the pen
+ * to inPoint.
+ * @param inPoint the location to draw to, in local coordinates.
+ */
+void CWinRenderer::LineTo(const QPoint &inPoint)
+{
+ const QPoint point = inPoint + m_Translation;
+ m_painter->drawLine(m_currentPos, point);
+ m_painter->drawLine(point, QPoint(point.x(), point.y() + 1));
+ m_currentPos = point;
+}
+
+//=============================================================================
+/**
+ * Draw a line from the current pen location to the point.
+ * This will draw a line to the point and move the current location of the pen
+ * to inPoint.
+ * @param inX the X coordinate of the point to draw to, in local coordinates.
+ * @param inY the Y coordinate of the point to draw to, in local coordinates.
+ */
+void CWinRenderer::LineTo(long inX, long inY)
+{
+ LineTo(QPoint(inX, inY));
+}
+
+//=============================================================================
+/**
+ * Change the active pen color.
+ * This acts as a stack so that it does not interfere with previous components.
+ * Once the color is done being used PopPen should be called.
+ * @param inColor the color to make the current pen.
+ * @param inWidth the pen width, in pixels.
+ */
+void CWinRenderer::PushPen(const QColor &inColor, int inWidth)
+{
+ QPen thePen = GetPen(inColor, inWidth, Qt::SolidLine);
+
+ QPen theCurrentPen = m_painter->pen();
+ m_painter->setPen(thePen);
+ m_PenList.push_back(theCurrentPen);
+}
+
+void CWinRenderer::PopPen()
+{
+ QPen thePen = m_PenList.back();
+ m_PenList.pop_back();
+ m_painter->setPen(thePen);
+}
+
+//=============================================================================
+/**
+ * Copy the bits from another renderer into this one.
+ * This will copy the rect from inRenderer into this renderer.
+ * inRect will be offset by this renderer's current translation. inXSrc and inYSrc
+ * will be offset by inRenderer's current translation.
+ * @param inRect the position and size of the area to be copied into this renderer.
+ * @param inPixmap the renderer to copy from.
+ * @param xSrc the x location of the location to copy from in inRenderer.
+ * @param ySrc the y location of the location to copy from in inRenderer.
+ */
+void CWinRenderer::BitBltFrom(const QRect &inRect, CRenderer *inRenderer, long inXSrc, long inYSrc)
+{
+ const auto inTranslation = inRenderer->GetTranslation();
+ inXSrc += inTranslation.x();
+ inYSrc += inTranslation.y();
+
+ auto srcRect = inRect;
+ auto destRect = inRect;
+ destRect.translate(m_Translation);
+ srcRect.moveTo(inXSrc, inYSrc);
+ m_painter->save();
+ m_painter->setCompositionMode(QPainter::CompositionMode_DestinationOver);
+ m_painter->drawPixmap(destRect, inRenderer->pixmap(), srcRect);
+ m_painter->restore();
+}
+
+//=============================================================================
+/**
+ * Draws text out without clipping it.
+ * @param inPoint the point at which to draw the text. (upper left corner)
+ * @param inText the text to draw.
+ */
+void CWinRenderer::DrawText(float inX, float inY, const QString &inText)
+{
+ inX += m_Translation.x();
+ inY += m_Translation.y();
+ m_painter->drawText(QPointF(inX, inY), inText);
+}
+
+//=============================================================================
+/**
+ * Draws text out to a clipped rectangle.
+ * If any text occurs outside the bounding box then it will be clipped.
+ * @param inPoint the point at which to draw the text. (upper left corner)
+ * @param inText the text to draw.
+ * @param inBoundingBox the bounding box used to clip the text.
+ * @param inColor color to draw the text in
+ */
+void CWinRenderer::DrawText(float inX, float inY, const QString &inText,
+ const QRect &inBoundingBox, const QColor &inColor)
+{
+ inX += m_Translation.x();
+ inY += m_Translation.y();
+
+ QRectF rect(inBoundingBox);
+ rect.translate(inX, inY);
+ m_painter->save();
+ QPen pen(inColor);
+ m_painter->setPen(pen);
+ m_painter->drawText(rect, Qt::AlignLeft | Qt::AlignVCenter, inText);
+ m_painter->restore();
+}
+
+//=============================================================================
+/**
+ * Draws BOLD text out to a clipped rectangle.
+ * If any text occurs outside the bounding box then it will be clipped.
+ * @param inPoint the point at which to draw the text. (upper left corner)
+ * @param inText the text to draw.
+ * @param inBoundingBox the bounding box used to clip the text.
+ * @param inColor color to draw the text in
+ */
+void CWinRenderer::DrawBoldText(float inX, float inY, const QString &inText,
+ const QRect &inBoundingBox, const QColor &inColor)
+{
+ inX += m_Translation.x();
+ inY += m_Translation.y();
+
+ QRectF rect(inBoundingBox);
+ rect.translate(inX, inY);
+ m_painter->save();
+ QPen pen(inColor);
+ m_painter->setPen(pen);
+ QFont font = m_painter->font();
+ font.setBold(true);
+ m_painter->setFont(font);
+ m_painter->drawText(rect, Qt::AlignLeft | Qt::AlignVCenter, inText);
+ m_painter->restore();
+}
+
+//=============================================================================
+/**
+ * Gets the dimensions of the text string as it would be written out to the
+ * screen.
+ * @param inText the text to check the length on.
+ * @return the length of the text in pixels.
+ */
+QSize CWinRenderer::GetTextSize(const QString &inText)
+{
+ QFontMetrics fm = m_painter->fontMetrics();
+ return fm.size(Qt::TextSingleLine, inText);
+}
+
+//=============================================================================
+/**
+ * Draws a a three-dimensional rectangle with the top and left sides in the
+ * color specified by inTopLeftColor and the bottom and right sides in the color
+ * specified by inBottomRightColor.
+ *
+ * @param inRect The rectangle to draw
+ * @param inTopLeftColor Color for the top and left sides of the rect
+ * @param inBottomRightColor Color for the bottom and right sides of the rect
+ */
+void CWinRenderer::Draw3dRect(const QRect &inRect, const QColor &inTopLeftColor,
+ const QColor &inBottomRightColor)
+{
+ auto rect = inRect;
+ rect.translate(m_Translation);
+ m_painter->drawRect(rect);
+ m_painter->save();
+ m_painter->setPen(inTopLeftColor);
+ m_painter->drawLine(rect.topLeft(), rect.bottomLeft());
+ m_painter->drawLine(rect.topLeft(), rect.topRight());
+ m_painter->setPen(inBottomRightColor);
+ m_painter->drawLine(rect.bottomLeft(), rect.bottomRight());
+ m_painter->drawLine(rect.bottomRight(), rect.topRight());
+ m_painter->restore();
+}
+
+//==============================================================================
+/**
+ * DrawBitmap
+ *
+ * Draw a bitmap given a device context, position and HBITMAP handle.
+ *
+ * @param inDC Device context for drawing
+ * @param inPos CPoint position for drawing
+ * @param inBitmap Handle of the bitmap to draw
+ */
+//==============================================================================
+void CWinRenderer::DrawBitmap(const QPoint &inPos, const QPixmap &inImage)
+{
+ m_painter->save();
+ m_painter->setCompositionMode(QPainter::CompositionMode_SourceOver);
+ m_painter->drawPixmap(inPos + m_Translation, inImage);
+ m_painter->restore();;
+}
+
+void CWinRenderer::PushTranslation(const QPoint &inTranslation)
+{
+ m_Translation += inTranslation;
+
+ m_Translations.push_back(inTranslation);
+}
+
+void CWinRenderer::PopTranslation()
+{
+ QPoint thePreviousTranslation = m_Translations.back();
+ m_Translation -= thePreviousTranslation;
+
+ m_Translations.pop_back();
+}
+
+QPoint CWinRenderer::GetTranslation()
+{
+ return m_Translation;
+}
+
+QPainter* CWinRenderer::GetPainter()
+{
+ return m_painter;
+}
+
+//==============================================================================
+/**
+ * Get the current clipping rect.
+ * The clipping rect is the boundary of pixels that will be drawn to the DC.
+ * This can be used to not draw non-visible objects.
+ * @return the clipping rect in local coordinates.
+ */
+QRect CWinRenderer::GetClippingRect()
+{
+ QRect theClippingRect = m_painter->clipBoundingRect().toRect();
+ theClippingRect.translate(-m_Translation);
+
+ return theClippingRect;
+}
+
+//==============================================================================
+/**
+ * Push a clipping rect onto the stack of clipping rects.
+ * This will cause any drawing outside of the clipping rect to be ignored. The
+ * Control class also uses this to not draw objects outside of this rect.
+ * @param inClippingRect the new clipping rect, in local coordinates.
+ */
+void CWinRenderer::PushClippingRect(const QRect &inClippingRect)
+{
+ QRect clippingRect(inClippingRect);
+ clippingRect.translate(m_Translation);
+
+ const QRegion currentRegion = m_painter->clipRegion();
+ m_painter->setClipRect(clippingRect);
+
+ m_ClippingRegions.push_back(currentRegion);
+}
+
+//==============================================================================
+/**
+ * Pop the current clipping rect.
+ * This will change the clipping rect to use the one previous to the current
+ * one.
+ */
+void CWinRenderer::PopClippingRect()
+{
+ if (m_ClippingRegions.size() > 1) {
+ QRegion thePreviousRegion = m_ClippingRegions.back();
+ m_painter->setClipRegion(thePreviousRegion);
+ m_ClippingRegions.pop_back();
+ }
+}
+
+//==============================================================================
+/**
+ * DrawGradiantBitmap
+ *
+ * Draws a gradiant based on the begin color
+ *
+ * @param inRct Rct tof the control
+ * @param inBeginColor color to start with
+ * @param inInverted true if this is inverted
+ */
+void CWinRenderer::DrawGradientBitmap(const QRect &inRct, const QColor &inBeginColor, bool inInverted,
+ double inScalingFactor)
+{
+ QRect rect(inRct);
+ QRect theClippingRect = GetClippingRect();
+ rect &= theClippingRect;
+ rect.translate(m_Translation);
+
+ long theHeight = rect.height();
+ long theWidth = rect.width();
+
+ QImage theCompatibleBitmap(1, theHeight, QImage::Format_RGB32);
+
+ int theR = inBeginColor.red();
+ int theG = inBeginColor.green();
+ int theB = inBeginColor.blue();
+
+ double theExtraRModifier = inScalingFactor * (1.0 - (theR / 255.0));
+ double theExtraGModifier = inScalingFactor * (1.0 - (theG / 255.0));
+ double theExtraBModifier = inScalingFactor * (1.0 - (theB / 255.0));
+
+ for (long thePixel = 0; thePixel < theHeight; ++thePixel) {
+ double theNormPixel = (double)thePixel / (theHeight * 4.8);
+ double theCos = 1.0 / (theNormPixel * theNormPixel + 1.0);
+ double theRValue = (double)theR * (theCos + theExtraRModifier);
+ double theGValue = (double)theG * (theCos + theExtraGModifier);
+ double theBValue = (double)theB * (theCos + theExtraBModifier);
+
+ QColor theTempColor(::dtoi(theRValue), ::dtoi(theGValue), ::dtoi(theBValue));
+ if (inInverted) {
+ theCompatibleBitmap.setPixelColor(0, qMax(0l, theHeight - thePixel - 2), theTempColor);
+ } else {
+ theCompatibleBitmap.setPixelColor(0, thePixel, theTempColor);
+ }
+ theExtraRModifier *= 0.3;
+ theExtraGModifier *= 0.3;
+ theExtraBModifier *= 0.3;
+ }
+
+ m_painter->save();
+ m_painter->drawImage(QRect(rect.x(), rect.y(), theWidth, theHeight), theCompatibleBitmap);
+ m_painter->restore();
+}
+
+//=============================================================================
+/**
+ * Draw a gradient over inRect.
+ * This will blend horizontally across the rect from inBeginColor into inEndColor.
+ * This does linear interpolation.
+ * @param inRect the rect to draw on.
+ * @param inBeginColor the start (left most) color.
+ * @param inEndColor the final (right most) color.
+ */
+void CWinRenderer::DrawGradient(const QRect &inRect, const QColor &inBeginColor, const QColor &inEndColor)
+{
+ const QRect rect = inRect.translated(m_Translation);
+ QLinearGradient gradient(rect.topLeft(), rect.topRight());
+ gradient.setColorAt(0, inBeginColor);
+ gradient.setColorAt(1, inEndColor);
+
+ QBrush brush(gradient);
+ m_painter->fillRect(rect, brush);
+}
+
+void CWinRenderer::FillHashed(const QRect &inRect, const QColor &inForegroundColor)
+{
+ m_painter->save();
+
+ QBrush theBrush(inForegroundColor, Qt::BDiagPattern);
+ QPen pen(inForegroundColor);
+ m_painter->setPen(pen);
+ m_painter->setBrush(theBrush);
+ m_painter->drawRect(inRect.translated(m_Translation));
+
+ m_painter->restore();
+}
+
+QPen CWinRenderer::GetPen(const QColor &inColor, int inWidth, Qt::PenStyle inStyle)
+{
+ QPen thePen;
+ SPenInfo theInfo = { inColor, inWidth, inStyle };
+ TPenMap::iterator thePos = m_Pens.find(theInfo);
+ if (thePos != m_Pens.end()) {
+ thePen = thePos->second;
+ } else {
+ thePen.setColor(inColor);
+ thePen.setWidth(inWidth);
+ m_Pens[theInfo] = thePen;
+ }
+ return thePen;
+}
+
+QPixmap CWinRenderer::pixmap() const
+{
+ return {};
+}
diff --git a/src/Authoring/Qt3DStudio/Controls/WinRenderer.h b/src/Authoring/Qt3DStudio/Controls/WinRenderer.h
new file mode 100644
index 00000000..3c56145b
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Controls/WinRenderer.h
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_WIN_RENDERER_H
+#define INCLUDED_WIN_RENDERER_H 1
+
+#pragma once
+
+#include <vector>
+#include <map>
+
+#include "Pt.h"
+#include "Rct.h"
+#include "Renderer.h"
+
+#include <QPainter>
+#include <QRegion>
+
+QT_BEGIN_NAMESPACE
+class QPixmap;
+QT_END_NAMESPACE
+
+class CWinRenderer : public CRenderer
+{
+ typedef std::vector<QPen> TPenList;
+ typedef std::vector<QRegion> TClippingRegions;
+
+protected:
+ CWinRenderer(); ///< Leaves CRenderer in an invalid state, only for subclasses
+ CWinRenderer(QPainter *inDC); ///< Leaves CRenderer in an invalid state, only for subclasses
+
+public:
+ CWinRenderer(QPainter *inDC, const QRect &inClippingRect);
+ virtual ~CWinRenderer();
+
+ void FillSolidRect(const QRect &inCoordinates, const QColor &inColor) override;
+ void FillRoundedRect(const QRect &inCoordinates, const QColor &inColor,
+ bool vertical) override;
+
+ void MoveTo(const QPoint &inPoint) override;
+ void MoveTo(long inX, long inY) override;
+ void LineTo(const QPoint &inPoint) override;
+ void LineTo(long inX, long inY) override;
+
+ void PushPen(const QColor &inColor, int inWidth = 1) override;
+ void PopPen() override;
+ void BitBltFrom(const QRect &inRect, CRenderer *inRenderer, long inXSrc, long inYSrc) override;
+
+ void DrawText(float inX, float inY, const QString &inText) override;
+ void DrawText(float inX, float inY, const QString &inText,
+ const QRect &inBoundingRect, const QColor &inColor = Qt::black) override;
+ void DrawBoldText(float inX, float inY, const QString &inText,
+ const QRect &inBoundingRect, const QColor &inColor = Qt::black) override;
+
+ QSize GetTextSize(const QString &inText) override;
+
+ void DrawBitmap(const QPoint &inPos, const QPixmap &inImage) override;
+ void Draw3dRect(const QRect &inRect, const QColor &inTopLeftColor,
+ const QColor &inBottomRightColor) override;
+ void DrawGradientBitmap(const QRect &inRct, const QColor &inBeginColor, bool inInverted,
+ double inScalingFactor = .99) override;
+
+ void DrawGradient(const QRect &inRect, const QColor &inBeginColor, const QColor &inEndColor) override;
+
+ void PushTranslation(const QPoint &inTranslation) override;
+ void PopTranslation() override;
+ QPoint GetTranslation() override;
+
+ QRect GetClippingRect() override;
+ void PushClippingRect(const QRect &inRect) override;
+ void PopClippingRect() override;
+ void PushAbsoluteClippingRect(const QRect &) override {}
+ void FillHashed(const QRect &inRect, const QColor &inForeGroundColor) override;
+ QPainter *GetPainter() override;
+ QPen GetPen(const QColor &inColor, int inWidth, Qt::PenStyle inStyle);
+
+ QPixmap pixmap() const override;
+
+protected:
+ TPenList m_PenList;
+ TClippingRegions m_ClippingRegions;
+ QPainter *m_painter;
+ QPoint m_currentPos;
+
+protected:
+ struct SPenInfo
+ {
+ QColor Color;
+ long Width;
+ Qt::PenStyle Style;
+ };
+
+ class CPenInfoLessThan : public std::binary_function<const SPenInfo &, const SPenInfo &, bool>
+ {
+ public:
+ inline bool operator()(const SPenInfo &inValL, const SPenInfo &inValR) const
+ {
+ return memcmp(&inValL, &inValR, sizeof(SPenInfo)) < 0;
+ }
+ };
+
+ typedef std::map<SPenInfo, QPen, CPenInfoLessThan> TPenMap;
+ TPenMap m_Pens;
+};
+#endif // INCLUDED_WIN_RENDERER_H