-
-
-
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/html/style.css b/examples/html/style.css
new file mode 100644
index 0000000000..1625fd094f
--- /dev/null
+++ b/examples/html/style.css
@@ -0,0 +1,95 @@
+* {
+}
+
+body {
+ margin: 0;
+ padding: 0;
+
+ background-color: #efefef;
+ font-family: Sans-Serif;
+ font-size: 12px;
+
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+input {
+ line-height: 2;
+}
+
+.input-left {
+ display: inline-block;
+ width: 20px;
+}
+
+.color-box {
+ display: inline-block;
+ width: 20px;
+ height: 20px;
+ border: 1px solid black;
+ margin: 2px;
+ cursor: pointer;
+}
+
+.color-box.highlight {
+ width: 18px;
+ height: 18px;
+ border: 2px solid black;
+}
+
+.section-header {
+ background: #AAA;
+ border-bottom: 1px solid #CCC;
+ background-color: #333333;
+ color: #999;
+ padding: 4px;
+}
+
+.section-header label {
+ font-weight: bold;
+}
+
+.multi-property-section {
+}
+.property-section {
+ display: block;
+ margin: 10 10;
+ height: 30px;
+}
+
+.property-section label {
+ font-weight: bold;
+ vertical-align: middle;
+}
+
+.property-section span {
+ float: right;
+}
+
+.grid-section {
+ border-top: 1px solid #DDD;
+ background-color: #efefef;
+}
+
+input[type=button] {
+ cursor: pointer;
+ background-color: #608e96;
+ border-color: #608e96;
+ border-radius: 5px;
+ padding: 5px 10px;
+ border: 0;
+ color: #fff;
+ font-weight: bold;
+ margin: 0 2px;
+ margin-top: 5px;
+ font-size: .9em;
+}
+
+input.coord {
+ width: 6em;
+ height: 2em;
+}
diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js
index 22f75cb187..6733ccaf39 100644
--- a/examples/libraries/entitySelectionTool.js
+++ b/examples/libraries/entitySelectionTool.js
@@ -23,12 +23,13 @@ SelectionManager = (function() {
that.savedProperties = {};
- that.eventListener = null;
that.selections = [];
// These are selections that don't have a known ID yet
that.pendingSelections = [];
var pendingSelectionTimer = null;
+ var listeners = [];
+
that.localRotation = Quat.fromPitchYawRollDegrees(0, 0, 0);
that.localPosition = { x: 0, y: 0, z: 0 };
that.localDimensions = { x: 0, y: 0, z: 0 };
@@ -46,8 +47,8 @@ SelectionManager = (function() {
}
};
- that.setEventListener = function(func) {
- that.eventListener = func;
+ that.addEventListener = function(func) {
+ listeners.push(func);
};
that.hasSelection = function() {
@@ -187,8 +188,12 @@ SelectionManager = (function() {
SelectionDisplay.setSpaceMode(SPACE_WORLD);
}
- if (that.eventListener) {
- that.eventListener();
+ for (var i = 0; i < listeners.length; i++) {
+ try {
+ listeners[i]();
+ } catch (e) {
+ print("got exception");
+ }
}
};
diff --git a/examples/libraries/gridTool.js b/examples/libraries/gridTool.js
index 34e25d6733..d8b84babf9 100644
--- a/examples/libraries/gridTool.js
+++ b/examples/libraries/gridTool.js
@@ -31,6 +31,7 @@ Grid = function(opts) {
that.getMajorIncrement = function() { return minorGridSpacing * majorGridEvery; };
that.visible = false;
+ that.enabled = false;
that.getOrigin = function() {
return origin;
@@ -38,6 +39,11 @@ Grid = function(opts) {
that.getSnapToGrid = function() { return snapToGrid; };
+ that.setEnabled = function(enabled) {
+ that.enabled = enabled;
+ updateGrid();
+ }
+
that.setVisible = function(visible, noUpdate) {
that.visible = visible;
updateGrid();
@@ -127,7 +133,7 @@ Grid = function(opts) {
function updateGrid() {
Overlays.editOverlay(gridOverlay, {
position: { x: origin.y, y: origin.y, z: -origin.y },
- visible: that.visible,
+ visible: that.visible && that.enabled,
minorGridWidth: minorGridSpacing,
majorGridEvery: majorGridEvery,
color: gridColor,
@@ -159,7 +165,7 @@ GridTool = function(opts) {
var listeners = [];
var url = Script.resolvePath('html/gridControls.html');
- var webView = new WebWindow(url, 200, 280);
+ var webView = new WebWindow('Grid', url, 200, 280);
horizontalGrid.addListener(function(data) {
webView.eventBridge.emitScriptEvent(JSON.stringify(data));
@@ -174,6 +180,15 @@ GridTool = function(opts) {
for (var i = 0; i < listeners.length; i++) {
listeners[i](data);
}
+ } else if (data.type == "action") {
+ var action = data.action;
+ if (action == "moveToAvatar") {
+ grid.setPosition(MyAvatar.position);
+ } else if (action == "moveToSelection") {
+ var newPosition = selectionManager.worldPosition;
+ newPosition = Vec3.subtract(newPosition, { x: 0, y: selectionManager.worldDimensions.y * 0.5, z: 0 });
+ grid.setPosition(newPosition);
+ }
}
});
diff --git a/examples/newEditEntities.js b/examples/newEditEntities.js
index fefc3ca6da..cc3c0fceda 100644
--- a/examples/newEditEntities.js
+++ b/examples/newEditEntities.js
@@ -39,7 +39,7 @@ Script.include("libraries/gridTool.js");
var grid = Grid();
gridTool = GridTool({ horizontalGrid: grid });
-selectionManager.setEventListener(selectionDisplay.updateHandles);
+selectionManager.addEventListener(selectionDisplay.updateHandles);
var windowDimensions = Controller.getViewportDimensions();
var toolIconUrl = HIFI_PUBLIC_BUCKET + "images/tools/";
@@ -55,13 +55,11 @@ var wantEntityGlow = false;
var SPAWN_DISTANCE = 1;
var DEFAULT_DIMENSION = 0.20;
-var MENU_GRID_TOOL_ENABLED = 'Grid Tool';
var MENU_INSPECT_TOOL_ENABLED = "Inspect Tool";
var MENU_EASE_ON_FOCUS = "Ease Orientation on Focus";
var SETTING_INSPECT_TOOL_ENABLED = "inspectToolEnabled";
var SETTING_EASE_ON_FOCUS = "cameraEaseOnFocus";
-var SETTING_GRID_TOOL_ENABLED = 'GridToolEnabled';
var modelURLs = [
HIFI_PUBLIC_BUCKET + "models/entities/2-Terrain:%20Alder.fbx",
@@ -272,11 +270,15 @@ var toolBar = (function () {
isActive = !isActive;
if (!isActive) {
gridTool.setVisible(false);
+ grid.setEnabled(false);
+ propertiesTool.setVisible(false);
selectionManager.clearSelections();
cameraManager.disable();
} else {
cameraManager.enable();
- gridTool.setVisible(Menu.isOptionChecked(MENU_GRID_TOOL_ENABLED));
+ gridTool.setVisible(true);
+ grid.setEnabled(true);
+ propertiesTool.setVisible(true);
}
return true;
}
@@ -608,10 +610,6 @@ function setupModelMenus() {
Menu.addMenuItem({ menuName: "File", menuItemName: "Import Models", shortcutKey: "CTRL+META+I", afterItem: "Export Models" });
Menu.addMenuItem({ menuName: "Developer", menuItemName: "Debug Ryans Rotation Problems", isCheckable: true });
- Menu.addMenuItem({ menuName: "View", menuItemName: MENU_GRID_TOOL_ENABLED, afterItem: "Edit Entities Help...", isCheckable: true,
- isChecked: Settings.getValue(SETTING_GRID_TOOL_ENABLED) == 'true'});
- Menu.addMenuItem({ menuName: "View", menuItemName: MENU_INSPECT_TOOL_ENABLED, afterItem: MENU_GRID_TOOL_ENABLED,
- isCheckable: true, isChecked: Settings.getValue(SETTING_INSPECT_TOOL_ENABLED) == "true" });
Menu.addMenuItem({ menuName: "View", menuItemName: MENU_EASE_ON_FOCUS, afterItem: MENU_INSPECT_TOOL_ENABLED,
isCheckable: true, isChecked: Settings.getValue(SETTING_EASE_ON_FOCUS) == "true" });
}
@@ -636,8 +634,6 @@ function cleanupModelMenus() {
Menu.removeMenuItem("File", "Import Models");
Menu.removeMenuItem("Developer", "Debug Ryans Rotation Problems");
- Settings.setValue(SETTING_GRID_TOOL_ENABLED, Menu.isOptionChecked(MENU_GRID_TOOL_ENABLED));
- Menu.removeMenuItem("View", MENU_GRID_TOOL_ENABLED);
Menu.removeMenuItem("View", MENU_INSPECT_TOOL_ENABLED);
Menu.removeMenuItem("View", MENU_EASE_ON_FOCUS);
}
@@ -749,10 +745,6 @@ function handeMenuEvent(menuItem) {
}
} else if (menuItem == "Import Models") {
modelImporter.doImport();
- } else if (menuItem == MENU_GRID_TOOL_ENABLED) {
- if (isActive) {
- gridTool.setVisible(Menu.isOptionChecked(MENU_GRID_TOOL_ENABLED));
- }
}
tooltip.show(false);
}
@@ -911,3 +903,43 @@ function pushCommandForSelections(createdEntityData, deletedEntityData) {
}
UndoStack.pushCommand(applyEntityProperties, undoData, applyEntityProperties, redoData);
}
+
+PropertiesTool = function(opts) {
+ var that = {};
+
+ var url = Script.resolvePath('html/entityProperties.html');
+ var webView = new WebWindow('Entity Properties', url, 200, 280);
+
+ var visible = false;
+
+ webView.setVisible(visible);
+
+ that.setVisible = function(newVisible) {
+ visible = newVisible;
+ webView.setVisible(visible);
+ };
+
+ selectionManager.addEventListener(function() {
+ data = {
+ type: 'update',
+ };
+ if (selectionManager.hasSelection()) {
+ data.properties = Entities.getEntityProperties(selectionManager.selections[0]);
+ }
+ webView.eventBridge.emitScriptEvent(JSON.stringify(data));
+ });
+
+ webView.eventBridge.webEventReceived.connect(function(data) {
+ print(data);
+ data = JSON.parse(data);
+ if (data.type == "update") {
+ Entities.editEntity(selectionManager.selections[0], data.properties);
+ selectionManager._update();
+ }
+ });
+
+ return that;
+};
+
+propertiesTool = PropertiesTool();
+
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 5e158352bb..2ecf45922b 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -373,6 +373,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
// enable mouse tracking; otherwise, we only get drag events
_glWidget->setMouseTracking(true);
+ _toolWindow = new ToolWindow();
+ _toolWindow->setWindowFlags(_toolWindow->windowFlags() | Qt::WindowStaysOnTopHint);
+ _toolWindow->setWindowTitle("Tools");
+
// initialization continues in initializeGL when OpenGL context is ready
// Tell our voxel edit sender about our known jurisdictions
diff --git a/interface/src/Application.h b/interface/src/Application.h
index cba39317a5..d31833897f 100644
--- a/interface/src/Application.h
+++ b/interface/src/Application.h
@@ -82,6 +82,7 @@
#include "ui/overlays/Overlays.h"
#include "ui/ApplicationOverlay.h"
#include "ui/RunningScriptsWidget.h"
+#include "ui/ToolWindow.h"
#include "ui/VoxelImportDialog.h"
#include "voxels/VoxelFade.h"
#include "voxels/VoxelHideShowThread.h"
@@ -246,6 +247,8 @@ public:
void lockOctreeSceneStats() { _octreeSceneStatsLock.lockForRead(); }
void unlockOctreeSceneStats() { _octreeSceneStatsLock.unlock(); }
+ ToolWindow* getToolWindow() { return _toolWindow ; }
+
GeometryCache* getGeometryCache() { return &_geometryCache; }
AnimationCache* getAnimationCache() { return &_animationCache; }
TextureCache* getTextureCache() { return &_textureCache; }
@@ -459,6 +462,8 @@ private:
MainWindow* _window;
GLCanvas* _glWidget; // our GLCanvas has a couple extra features
+ ToolWindow* _toolWindow;
+
BandwidthMeter _bandwidthMeter;
QThread* _nodeThread;
diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp
index e0feb4e349..f7aabc8f06 100644
--- a/interface/src/Menu.cpp
+++ b/interface/src/Menu.cpp
@@ -247,6 +247,12 @@ Menu::Menu() :
_chatWindow = new ChatWindow(Application::getInstance()->getWindow());
#endif
+ addActionToQMenuAndActionHash(toolsMenu,
+ MenuOption::ToolWindow,
+ Qt::CTRL | Qt::ALT | Qt::Key_T,
+ this,
+ SLOT(toggleToolWindow()));
+
addActionToQMenuAndActionHash(toolsMenu,
MenuOption::Console,
Qt::CTRL | Qt::ALT | Qt::Key_J,
@@ -1464,6 +1470,11 @@ void Menu::toggleConsole() {
_jsConsole->setVisible(!_jsConsole->isVisible());
}
+void Menu::toggleToolWindow() {
+ QMainWindow* toolWindow = Application::getInstance()->getToolWindow();
+ toolWindow->setVisible(!toolWindow->isVisible());
+}
+
void Menu::audioMuteToggled() {
QAction *muteAction = _actionHash.value(MenuOption::MuteAudio);
if (muteAction) {
diff --git a/interface/src/Menu.h b/interface/src/Menu.h
index b745246780..8590d8580e 100644
--- a/interface/src/Menu.h
+++ b/interface/src/Menu.h
@@ -224,6 +224,7 @@ private slots:
void showScriptEditor();
void showChat();
void toggleConsole();
+ void toggleToolWindow();
void toggleChat();
void audioMuteToggled();
void displayNameLocationResponse(const QString& errorString);
@@ -490,6 +491,7 @@ namespace MenuOption {
const QString StringHair = "String Hair";
const QString SuppressShortTimings = "Suppress Timings Less than 10ms";
const QString TestPing = "Test Ping";
+ const QString ToolWindow = "Tool Window";
const QString TransmitterDrive = "Transmitter Drive";
const QString TurnWithHead = "Turn using Head";
const QString UploadAttachment = "Upload Attachment Model";
diff --git a/interface/src/scripting/WebWindowClass.cpp b/interface/src/scripting/WebWindowClass.cpp
index d280d8eecf..cc6f4fbfff 100644
--- a/interface/src/scripting/WebWindowClass.cpp
+++ b/interface/src/scripting/WebWindowClass.cpp
@@ -11,9 +11,13 @@
#include
#include
+#include
+#include
#include
#include
+#include
+#include "Application.h"
#include "WindowScriptingInterface.h"
#include "WebWindowClass.h"
@@ -28,29 +32,34 @@ void ScriptEventBridge::emitScriptEvent(const QString& data) {
emit scriptEventReceived(data);
}
-WebWindowClass::WebWindowClass(const QString& url, int width, int height)
+
+WebWindowClass::WebWindowClass(const QString& title, const QString& url, int width, int height)
: QObject(NULL),
- _window(new QWidget(NULL, Qt::Tool)),
_eventBridge(new ScriptEventBridge(this)) {
- QWebView* webView = new QWebView(_window);
+ ToolWindow* toolWindow = Application::getInstance()->getToolWindow();
+
+ _dockWidget = new QDockWidget(title, toolWindow);
+ _dockWidget->setFeatures(QDockWidget::DockWidgetMovable);
+ QWebView* webView = new QWebView(_dockWidget);
webView->page()->mainFrame()->addToJavaScriptWindowObject("EventBridge", _eventBridge);
webView->setUrl(url);
- QVBoxLayout* layout = new QVBoxLayout(_window);
- _window->setLayout(layout);
- layout->addWidget(webView);
- layout->setSpacing(0);
- layout->setContentsMargins(0, 0, 0, 0);
- _window->setGeometry(0, 0, width, height);
+ _dockWidget->setWidget(webView);
- connect(this, &WebWindowClass::destroyed, _window, &QWidget::deleteLater);
+ toolWindow->addDockWidget(Qt::RightDockWidgetArea, _dockWidget);
+
+ connect(this, &WebWindowClass::destroyed, _dockWidget, &QWidget::deleteLater);
}
WebWindowClass::~WebWindowClass() {
}
void WebWindowClass::setVisible(bool visible) {
- QMetaObject::invokeMethod(_window, "setVisible", Qt::BlockingQueuedConnection, Q_ARG(bool, visible));
+ if (visible) {
+ QMetaObject::invokeMethod(
+ Application::getInstance()->getToolWindow(), "setVisible", Qt::BlockingQueuedConnection, Q_ARG(bool, visible));
+ }
+ QMetaObject::invokeMethod(_dockWidget, "setVisible", Qt::BlockingQueuedConnection, Q_ARG(bool, visible));
}
QScriptValue WebWindowClass::constructor(QScriptContext* context, QScriptEngine* engine) {
@@ -59,8 +68,9 @@ QScriptValue WebWindowClass::constructor(QScriptContext* context, QScriptEngine*
QMetaObject::invokeMethod(WindowScriptingInterface::getInstance(), "doCreateWebWindow", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(WebWindowClass*, retVal),
Q_ARG(const QString&, file),
- Q_ARG(int, context->argument(1).toInteger()),
- Q_ARG(int, context->argument(2).toInteger()));
+ Q_ARG(QString, context->argument(1).toString()),
+ Q_ARG(int, context->argument(2).toInteger()),
+ Q_ARG(int, context->argument(3).toInteger()));
connect(engine, &QScriptEngine::destroyed, retVal, &WebWindowClass::deleteLater);
diff --git a/interface/src/scripting/WebWindowClass.h b/interface/src/scripting/WebWindowClass.h
index 7b77299774..ae0d14ae06 100644
--- a/interface/src/scripting/WebWindowClass.h
+++ b/interface/src/scripting/WebWindowClass.h
@@ -34,7 +34,7 @@ class WebWindowClass : public QObject {
Q_OBJECT
Q_PROPERTY(QObject* eventBridge READ getEventBridge)
public:
- WebWindowClass(const QString& url, int width, int height);
+ WebWindowClass(const QString& title, const QString& url, int width, int height);
~WebWindowClass();
static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine);
@@ -44,7 +44,7 @@ public slots:
ScriptEventBridge* getEventBridge() const { return _eventBridge; }
private:
- QWidget* _window;
+ QDockWidget* _dockWidget;
ScriptEventBridge* _eventBridge;
};
diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp
index 8c2066f253..8a79cad6e1 100644
--- a/interface/src/scripting/WindowScriptingInterface.cpp
+++ b/interface/src/scripting/WindowScriptingInterface.cpp
@@ -34,8 +34,8 @@ WindowScriptingInterface::WindowScriptingInterface() :
{
}
-WebWindowClass* WindowScriptingInterface::doCreateWebWindow(const QString& url, int width, int height) {
- return new WebWindowClass(url, width, height);
+WebWindowClass* WindowScriptingInterface::doCreateWebWindow(const QString& title, const QString& url, int width, int height) {
+ return new WebWindowClass(title, url, width, height);
}
QScriptValue WindowScriptingInterface::hasFocus() {
diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h
index 5529d31efd..0b320f23a1 100644
--- a/interface/src/scripting/WindowScriptingInterface.h
+++ b/interface/src/scripting/WindowScriptingInterface.h
@@ -78,7 +78,7 @@ private slots:
void nonBlockingFormAccepted() { _nonBlockingFormActive = false; _formResult = QDialog::Accepted; emit nonBlockingFormClosed(); }
void nonBlockingFormRejected() { _nonBlockingFormActive = false; _formResult = QDialog::Rejected; emit nonBlockingFormClosed(); }
- WebWindowClass* doCreateWebWindow(const QString& url, int width, int height);
+ WebWindowClass* doCreateWebWindow(const QString& title, const QString& url, int width, int height);
private:
WindowScriptingInterface();
diff --git a/interface/src/ui/ToolWindow.cpp b/interface/src/ui/ToolWindow.cpp
new file mode 100644
index 0000000000..1375ff1ea5
--- /dev/null
+++ b/interface/src/ui/ToolWindow.cpp
@@ -0,0 +1,82 @@
+//
+// ToolWindow.cpp
+// interface/src/ui
+//
+// Created by Ryan Huffman on 11/13/14.
+// Copyright 2014 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "Application.h"
+#include "ToolWindow.h"
+#include "UIUtil.h"
+
+const int DEFAULT_WIDTH = 300;
+
+ToolWindow::ToolWindow(QWidget* parent) :
+ QMainWindow(parent),
+ _hasShown(false),
+ _lastGeometry() {
+}
+
+bool ToolWindow::event(QEvent* event) {
+ QEvent::Type type = event->type();
+ if (type == QEvent::Show) {
+ if (!_hasShown) {
+ _hasShown = true;
+
+ QMainWindow* mainWindow = Application::getInstance()->getWindow();
+ QRect mainGeometry = mainWindow->geometry();
+
+ int titleBarHeight = UIUtil::getWindowTitleBarHeight(this);
+ int menuBarHeight = Menu::getInstance()->geometry().height();
+ int topMargin = titleBarHeight + menuBarHeight;
+
+ _lastGeometry = QRect(mainGeometry.topLeft().x(), mainGeometry.topLeft().y() + topMargin,
+ DEFAULT_WIDTH, mainGeometry.height() - topMargin);
+ }
+ setGeometry(_lastGeometry);
+ return true;
+ } else if (type == QEvent::Hide) {
+ _lastGeometry = geometry();
+ return true;
+ }
+
+ return QMainWindow::event(event);
+}
+
+void ToolWindow::onChildVisibilityUpdated(bool visible) {
+ if (visible) {
+ setVisible(true);
+ } else {
+ bool hasVisible = false;
+ QList dockWidgets = findChildren();
+ for (int i = 0; i < dockWidgets.count(); i++) {
+ if (dockWidgets[i]->isVisible()) {
+ hasVisible = true;
+ break;
+ }
+ }
+ setVisible(hasVisible);
+ }
+}
+
+void ToolWindow::addDockWidget(Qt::DockWidgetArea area, QDockWidget* dockWidget) {
+ QMainWindow::addDockWidget(area, dockWidget);
+
+ connect(dockWidget, &QDockWidget::visibilityChanged, this, &ToolWindow::onChildVisibilityUpdated);
+}
+
+void ToolWindow::addDockWidget(Qt::DockWidgetArea area, QDockWidget* dockWidget, Qt::Orientation orientation) {
+ QMainWindow::addDockWidget(area, dockWidget, orientation);
+
+ connect(dockWidget, &QDockWidget::visibilityChanged, this, &ToolWindow::onChildVisibilityUpdated);
+}
+
+void ToolWindow::removeDockWidget(QDockWidget* dockWidget) {
+ QMainWindow::removeDockWidget(dockWidget);
+
+ disconnect(dockWidget, &QDockWidget::visibilityChanged, this, &ToolWindow::onChildVisibilityUpdated);
+}
diff --git a/interface/src/ui/ToolWindow.h b/interface/src/ui/ToolWindow.h
new file mode 100644
index 0000000000..87b94d46df
--- /dev/null
+++ b/interface/src/ui/ToolWindow.h
@@ -0,0 +1,40 @@
+//
+// ToolWindow.h
+// interface/src/ui
+//
+// Created by Ryan Huffman on 11/13/14.
+// Copyright 2014 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#ifndef hifi_ToolWindow_h
+#define hifi_ToolWindow_h
+
+#include
+#include
+#include
+#include
+#include
+
+class ToolWindow : public QMainWindow {
+ Q_OBJECT
+public:
+ ToolWindow(QWidget* parent = NULL);
+
+ virtual bool event(QEvent* event);
+ virtual void addDockWidget(Qt::DockWidgetArea area, QDockWidget* dockWidget);
+ virtual void addDockWidget(Qt::DockWidgetArea area, QDockWidget* dockWidget, Qt::Orientation orientation);
+ virtual void removeDockWidget(QDockWidget* dockWidget);
+
+public slots:
+ void onChildVisibilityUpdated(bool visible);
+
+
+private:
+ bool _hasShown;
+ QRect _lastGeometry;
+};
+
+#endif // hifi_ToolWindow_h