Compare commits
6 Commits
main
...
new_osg_re
Author | SHA1 | Date | |
---|---|---|---|
2f52548074 | |||
ad02144014 | |||
32ed1bf037 | |||
c3bb7a8054 | |||
7effa0e8f4 | |||
7237c650a3 |
@ -1,41 +0,0 @@
|
|||||||
1.参数编辑时候崩溃bug。参数编辑窗口,添加,点击参数名称,在蓝色状态时候点击字母按键会崩溃。后续进行过某些操作就不会崩溃了。
|
|
||||||
解决方案
|
|
||||||
a、修改当前的crash(解决)
|
|
||||||
2.参数编辑,第一次生成matlabparam还是在workspace下,后续生成在release下,simmatlab文件需要保存在release下才能运行。参数文件和运行的.m文件路径需要统一
|
|
||||||
解决方案
|
|
||||||
a、放到想定空间所在的目录
|
|
||||||
|
|
||||||
3.窗口1的Report和窗口2的Report Table 展示的是不是同样的内容,如果是可以删除一个。需要在窗口1或2看的report时候通过窗口管理拖动实现。
|
|
||||||
解决方案
|
|
||||||
a、保留窗口2的Report Table (解决)
|
|
||||||
b、窗口2中的Report Table, 可以拖动变成dock模式添加到其他的窗口中
|
|
||||||
c、有缩放属性的控件,鼠标都显示为双箭头 (解决)
|
|
||||||
d、所有的窗口表头可以采用拖动的形式调整列的位置 (解决)
|
|
||||||
|
|
||||||
4.需要连续用到的操作、功能类似的放到一个大界面。这些不知道具体怎么分就需要讨论细分一下比如:
|
|
||||||
功能控制一样的:窗口管理和ui设置都是控制界面的放到同一个栏目
|
|
||||||
解决方案
|
|
||||||
a、窗口管理放到系统管理里面,点击按钮,弹出菜单可以勾选 (解决)
|
|
||||||
|
|
||||||
操作步骤连续的:①参数编辑②MatlabParam文件关联③SimMatlab关联④运行.m文件。这些放到一块方便操作
|
|
||||||
解决方案
|
|
||||||
a、暂时不动
|
|
||||||
|
|
||||||
5.关联文件时候更改文件的按键不太明显。
|
|
||||||
解决方案
|
|
||||||
a、属性控件文件选择按钮不明显 (解决)
|
|
||||||
b、属性控件中间的分割线能左右移动 (解决)
|
|
||||||
|
|
||||||
6.提供的轨迹文件是如何输入到dyt界面的,我们需要知道。
|
|
||||||
解决方案
|
|
||||||
a、下次发版带一个配置好的空间想定
|
|
||||||
|
|
||||||
7.属性、实体、report等这些窗口,加上稍微明显一点的边界,然后点击边界拖动时候改变窗口大小或者改变位置。就和桌面上的文件一样任意改变窗口大小和位置。
|
|
||||||
解决方案
|
|
||||||
a、界面美化,层次感 (解决)
|
|
||||||
b、鼠标拖动放大缩小之后,松开鼠标再次拖动无法缩小 (解决)
|
|
||||||
c、所有窗口都用dock形式,用户随意拖动放置到其他窗口中
|
|
||||||
d、窗口布局影响窗口位置
|
|
||||||
e、窗口会自动变大
|
|
||||||
f、report窗口能分离出来 (解决)
|
|
||||||
|
|
@ -9,7 +9,7 @@ SET(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|||||||
SET(CMAKE_INCLUDE_CURRENT_DIR ON)
|
SET(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
|
|
||||||
find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets LinguistTools REQUIRED)
|
find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets LinguistTools REQUIRED)
|
||||||
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets LinguistTools OpenGL REQUIRED)
|
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Gui Widgets LinguistTools OpenGL REQUIRED)
|
||||||
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Widgets LinguistTools DataVisualization Charts Network REQUIRED)
|
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Widgets LinguistTools DataVisualization Charts Network REQUIRED)
|
||||||
|
|
||||||
message("qt VERSION " ${QT_VERSION_MAJOR})
|
message("qt VERSION " ${QT_VERSION_MAJOR})
|
||||||
@ -85,8 +85,7 @@ INCLUDE_DIRECTORIES(
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
${Thirdparty}/spdlog/include
|
${Thirdparty}/spdlog/include
|
||||||
${Thirdparty}/breakpad/include
|
${Thirdparty}/breakpad/include
|
||||||
${Thirdparty}/3rdParty_x64/include
|
${Thirdparty}/3rdParty/include
|
||||||
${Thirdparty}/OpenSceneGraph-3.6.5/include
|
|
||||||
${Thirdparty}/TritonSDK/PublicHeaders
|
${Thirdparty}/TritonSDK/PublicHeaders
|
||||||
${Thirdparty}/matlab/include
|
${Thirdparty}/matlab/include
|
||||||
# ${Thirdparty}/Python39/include
|
# ${Thirdparty}/Python39/include
|
||||||
@ -94,8 +93,7 @@ INCLUDE_DIRECTORIES(
|
|||||||
|
|
||||||
LINK_DIRECTORIES(
|
LINK_DIRECTORIES(
|
||||||
${Thirdparty}/spdlog/lib
|
${Thirdparty}/spdlog/lib
|
||||||
${Thirdparty}/3rdParty_x64/lib
|
${Thirdparty}/3rdParty/lib
|
||||||
${Thirdparty}/OpenSceneGraph-3.6.5/lib
|
|
||||||
${Thirdparty}/matlab/lib/win64/microsoft
|
${Thirdparty}/matlab/lib/win64/microsoft
|
||||||
${Thirdparty}/TritonSDK/lib/vc143/x64
|
${Thirdparty}/TritonSDK/lib/vc143/x64
|
||||||
# ${Thirdparty}/Python39/libs
|
# ${Thirdparty}/Python39/libs
|
||||||
@ -146,6 +144,7 @@ target_link_libraries(
|
|||||||
${PROJECT_NAME}
|
${PROJECT_NAME}
|
||||||
PRIVATE
|
PRIVATE
|
||||||
Qt${QT_VERSION_MAJOR}::Core
|
Qt${QT_VERSION_MAJOR}::Core
|
||||||
|
Qt${QT_VERSION_MAJOR}::Gui
|
||||||
Qt${QT_VERSION_MAJOR}::Widgets
|
Qt${QT_VERSION_MAJOR}::Widgets
|
||||||
Qt${QT_VERSION_MAJOR}::Charts
|
Qt${QT_VERSION_MAJOR}::Charts
|
||||||
Qt${QT_VERSION_MAJOR}::DataVisualization
|
Qt${QT_VERSION_MAJOR}::DataVisualization
|
||||||
@ -165,8 +164,10 @@ target_link_libraries(
|
|||||||
osgParticle
|
osgParticle
|
||||||
osgSim
|
osgSim
|
||||||
osgWidget
|
osgWidget
|
||||||
osgText
|
|
||||||
osgEarth
|
osgEarth
|
||||||
|
osgEarthUtil
|
||||||
|
osgEarthAnnotation
|
||||||
|
osgEarthTriton
|
||||||
Triton-MT-DLL
|
Triton-MT-DLL
|
||||||
libeng
|
libeng
|
||||||
libmx
|
libmx
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
<file>res/sys_icon.png</file>
|
<file>res/sys_icon.png</file>
|
||||||
<file>res/sys_down.png</file>
|
<file>res/sys_down.png</file>
|
||||||
<file>res/sys_up.png</file>
|
<file>res/sys_up.png</file>
|
||||||
<file>res/select_file.ico</file>
|
|
||||||
<file>res/default/menu_new_file.png</file>
|
<file>res/default/menu_new_file.png</file>
|
||||||
<file>res/default/menu_open_file.png</file>
|
<file>res/default/menu_open_file.png</file>
|
||||||
<file>res/default/menu_save_file.png</file>
|
<file>res/default/menu_save_file.png</file>
|
||||||
@ -24,7 +23,6 @@
|
|||||||
<file>res/default/menu_setting_restore.png</file>
|
<file>res/default/menu_setting_restore.png</file>
|
||||||
<file>res/default/menu_setting.png</file>
|
<file>res/default/menu_setting.png</file>
|
||||||
<file>res/default/menu_uisetting.png</file>
|
<file>res/default/menu_uisetting.png</file>
|
||||||
<file>res/default/menu_window_manager.png</file>
|
|
||||||
</qresource>
|
</qresource>
|
||||||
<qresource prefix="/qss">
|
<qresource prefix="/qss">
|
||||||
</qresource>
|
</qresource>
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#include "CrashHandler.h"
|
#include "CrashHandler.h"
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
@ -110,3 +112,4 @@ void TestCrash() {
|
|||||||
volatile int* a = (int*)(nullptr);
|
volatile int* a = (int*)(nullptr);
|
||||||
*a = 1;
|
*a = 1;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#if 0
|
||||||
bool InstallCrashHandler();
|
bool InstallCrashHandler();
|
||||||
void TestCrash();
|
void TestCrash();
|
||||||
|
#endif
|
||||||
|
@ -84,8 +84,7 @@ void RecourceHelper::Init() {
|
|||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
const QString transName = QString("./%1_%2.qm").arg(appName, QLocale().name());
|
const QString transName = QString("./%1_%2.qm").arg(appName, QLocale().name());
|
||||||
#else
|
#else
|
||||||
const QString appDirPath = QApplication::applicationDirPath();
|
const QString transName = QString("./translations/%1_%2.qm").arg(appName, QLocale().name());
|
||||||
const QString transName = QString("%1/translations/%2_%3.qm").arg(appDirPath, appName, QLocale().name());
|
|
||||||
#endif
|
#endif
|
||||||
qDebug() << transName;
|
qDebug() << transName;
|
||||||
bool success = trans_.load(transName);
|
bool success = trans_.load(transName);
|
||||||
|
@ -293,7 +293,3 @@ QDockWidget DockTitleWidget QPushButton::menu-indicator,
|
|||||||
QDockWidget DockTitleWidget QToolButton::menu-indicator {
|
QDockWidget DockTitleWidget QToolButton::menu-indicator {
|
||||||
image: none;
|
image: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
QListWidget {
|
|
||||||
border: none;
|
|
||||||
}
|
|
@ -322,7 +322,3 @@ QDockWidget DockTitleWidget QPushButton::menu-indicator,
|
|||||||
QDockWidget DockTitleWidget QToolButton::menu-indicator {
|
QDockWidget DockTitleWidget QToolButton::menu-indicator {
|
||||||
image: none;
|
image: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
QListWidget {
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#include "effects/ConeWave.h"
|
#include "effects/ConeWave.h"
|
||||||
/*
|
|
||||||
#include <osg/BlendFunc>
|
#include <osg/BlendFunc>
|
||||||
#include <osg/Material>
|
#include <osg/Material>
|
||||||
#include <osg/Texture2D>
|
#include <osg/Texture2D>
|
||||||
@ -10,49 +10,10 @@
|
|||||||
#include <osg/Shader>
|
#include <osg/Shader>
|
||||||
#include <osg/Program>
|
#include <osg/Program>
|
||||||
#include <osg/Uniform>
|
#include <osg/Uniform>
|
||||||
#include <osg/Depth>
|
|
||||||
#include <osgEarth/Registry>
|
|
||||||
|
|
||||||
class WaveSurfaceCallback : public osg::NodeCallback {
|
|
||||||
public:
|
|
||||||
WaveSurfaceCallback() : timeElapsed(0.0f) {}
|
|
||||||
|
|
||||||
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) {
|
|
||||||
timeElapsed += (nv->getFrameStamp()->getSimulationTime() - SimulationTime);
|
|
||||||
|
|
||||||
// 获取并更新geometry的顶点
|
|
||||||
osg::Geode* geode = dynamic_cast<osg::Geode*>(node);
|
|
||||||
if (geode) {
|
|
||||||
osg::Geometry* geometry = dynamic_cast<osg::Geometry*>(geode->getDrawable(0));
|
|
||||||
if (geometry) {
|
|
||||||
osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray());
|
|
||||||
if (vertices) {
|
|
||||||
// 更新顶点位置来模拟波动
|
|
||||||
float amplitude = 2.0f;
|
|
||||||
float frequency = 1.0f;
|
|
||||||
for (unsigned int i = 0; i < vertices->size(); ++i) {
|
|
||||||
osg::Vec3f& vertex = (*vertices)[i];
|
|
||||||
vertex.z() = amplitude * sin(frequency * (vertex.x() + timeElapsed));
|
|
||||||
}
|
|
||||||
geometry->setVertexArray(vertices);
|
|
||||||
geometry->dirtyBound(); // 更新几何体边界
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 继续遍历场景图
|
|
||||||
traverse(node, nv);
|
|
||||||
SimulationTime = nv->getFrameStamp()->getSimulationTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
float timeElapsed;
|
|
||||||
double SimulationTime;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
ConeWave::ConeWave() {
|
ConeWave::ConeWave() {
|
||||||
osgEarth::Registry::shaderGenerator().run(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -66,10 +27,6 @@ void ConeWave::Render(double dt) {
|
|||||||
|
|
||||||
void ConeWave::InitGeode() {
|
void ConeWave::InitGeode() {
|
||||||
CreateTexturedCone(this);
|
CreateTexturedCone(this);
|
||||||
//getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
|
||||||
//getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON);
|
|
||||||
//getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
|
|
||||||
//setCullingActive(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConeWave::Destory() {
|
void ConeWave::Destory() {
|
||||||
@ -81,7 +38,7 @@ void ConeWave::SetHeight(float height) {
|
|||||||
if (cone_) {
|
if (cone_) {
|
||||||
cone_->setHeight(height_);
|
cone_->setHeight(height_);
|
||||||
}
|
}
|
||||||
// coneDrawable_->build();
|
coneDrawable_->build();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConeWave::SetRadius(float radius) {
|
void ConeWave::SetRadius(float radius) {
|
||||||
@ -89,7 +46,7 @@ void ConeWave::SetRadius(float radius) {
|
|||||||
if (cone_) {
|
if (cone_) {
|
||||||
cone_->setRadius(radius);
|
cone_->setRadius(radius);
|
||||||
}
|
}
|
||||||
// coneDrawable_->build();
|
coneDrawable_->build();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConeWave::SetBaseColor(const osg::Vec4& color) {
|
void ConeWave::SetBaseColor(const osg::Vec4& color) {
|
||||||
@ -114,69 +71,14 @@ void ConeWave::SetLevelHeight(float height) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ConeWave::CreateTexturedCone(osg::Geode* geode) {
|
void ConeWave::CreateTexturedCone(osg::Geode* geode) {
|
||||||
// cone_ = new osg::Cone(osg::Vec3(0, 0, 0.), radius_, height_);
|
cone_ = new osg::Cone(osg::Vec3(0, 0, 0.), radius_, height_);
|
||||||
// osg::TessellationHints* tesselate = new osg::TessellationHints;
|
osg::TessellationHints* tesselate = new osg::TessellationHints;
|
||||||
// tesselate->setCreateBottom(false);
|
tesselate->setCreateBottom(false);
|
||||||
// tesselate->setCreateBackFace(false);
|
tesselate->setCreateBackFace(false);
|
||||||
// coneDrawable_ = new osg::ShapeDrawable(cone_, tesselate);
|
coneDrawable_ = new osg::ShapeDrawable(cone_, tesselate);
|
||||||
// geode->addDrawable(coneDrawable_);
|
addDrawable(coneDrawable_);
|
||||||
// coneDrawable_->setColor(baseColor_);
|
|
||||||
// osg::StateSet* ss = coneDrawable_->getOrCreateStateSet();
|
|
||||||
// //stateset->setRenderBinDetails(120, "OSGEARTH_SCREEN_SPACE_LAYOUT_BIN");
|
|
||||||
// ss->setRenderBinDetails(120, "RenderBin");
|
|
||||||
// osg::ref_ptr<osg::BlendFunc> bf = new osg::BlendFunc();
|
|
||||||
// ss->setAttributeAndModes(bf, osg::StateAttribute::ON);
|
|
||||||
// ss->setMode(GL_CULL_FACE, osg::StateAttribute::ON);
|
|
||||||
|
|
||||||
|
|
||||||
osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry();
|
|
||||||
|
|
||||||
// 创建顶点数组
|
|
||||||
osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
|
|
||||||
|
|
||||||
int rows = 20, cols=20;
|
|
||||||
for (unsigned int i = 0; i < rows; ++i) {
|
|
||||||
for (unsigned int j = 0; j < cols; ++j) {
|
|
||||||
// 坐标
|
|
||||||
float x = (float)i / (rows - 1) * 100;
|
|
||||||
float y = (float)j / (cols - 1) * 100;
|
|
||||||
vertices->push_back(osg::Vec3f(x, y, 0.0f));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
geometry->setVertexArray(vertices);
|
|
||||||
|
|
||||||
// 生成索引来连接顶点
|
|
||||||
osg::ref_ptr<osg::DrawElementsUShort> indices = new osg::DrawElementsUShort(osg::PrimitiveSet::QUADS);
|
|
||||||
for (unsigned int i = 0; i < rows - 1; ++i) {
|
|
||||||
for (unsigned int j = 0; j < cols - 1; ++j) {
|
|
||||||
unsigned short bottomLeft = i * cols + j;
|
|
||||||
unsigned short bottomRight = bottomLeft + 1;
|
|
||||||
unsigned short topLeft = (i + 1) * cols + j;
|
|
||||||
unsigned short topRight = topLeft + 1;
|
|
||||||
|
|
||||||
indices->push_back(bottomLeft);
|
|
||||||
indices->push_back(bottomRight);
|
|
||||||
indices->push_back(topRight);
|
|
||||||
indices->push_back(topLeft);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
geometry->addPrimitiveSet(indices);
|
|
||||||
|
|
||||||
// 创建表面颜色
|
|
||||||
osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array;
|
|
||||||
colors->push_back(osg::Vec4(0.0f, 0.0f, 1.0f, 1.0f)); // 蓝色
|
|
||||||
|
|
||||||
geometry->setColorArray(colors);
|
|
||||||
geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
|
|
||||||
|
|
||||||
// 添加geometry到geode
|
|
||||||
geode->addDrawable(geometry);
|
|
||||||
geode->setUpdateCallback(new WaveSurfaceCallback());
|
|
||||||
return;
|
|
||||||
|
|
||||||
static const char* vertSource = {
|
static const char* vertSource = {
|
||||||
"#version 330\n"
|
|
||||||
"varying vec3 pos;\n"
|
"varying vec3 pos;\n"
|
||||||
"void main()\n"
|
"void main()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
@ -187,7 +89,6 @@ void ConeWave::CreateTexturedCone(osg::Geode* geode) {
|
|||||||
"}\n"
|
"}\n"
|
||||||
};
|
};
|
||||||
static const char* fragSource = {
|
static const char* fragSource = {
|
||||||
"#version 330\n"
|
|
||||||
"uniform float num; \n"
|
"uniform float num; \n"
|
||||||
"uniform float height; \n"
|
"uniform float height; \n"
|
||||||
"uniform vec4 baseColor;\n"
|
"uniform vec4 baseColor;\n"
|
||||||
@ -215,309 +116,21 @@ void ConeWave::CreateTexturedCone(osg::Geode* geode) {
|
|||||||
fragmentShader->setShaderSource(fragSource);
|
fragmentShader->setShaderSource(fragSource);
|
||||||
|
|
||||||
osg::StateSet* stateset = coneDrawable_->getOrCreateStateSet();
|
osg::StateSet* stateset = coneDrawable_->getOrCreateStateSet();
|
||||||
// osg::ref_ptr<osg::Material> mat = new osg::Material;
|
stateset->setRenderBinDetails(120, "OSGEARTH_SCREEN_SPACE_LAYOUT_BIN");
|
||||||
// //设置正面散射颜色
|
osg::ref_ptr<osg::BlendFunc> blendFunc = new osg::BlendFunc();
|
||||||
// mat->setDiffuse(osg::Material::FRONT, osg::Vec4(1.0, 0.0, 0.0, 0.3));//1.0, 0.0, 0.0, 0.3
|
stateset->setAttributeAndModes(blendFunc, osg::StateAttribute::ON);
|
||||||
// //设置正面镜面颜色
|
osg::ref_ptr<osg::Program> program = new osg::Program();
|
||||||
// mat->setSpecular(osg::Material::FRONT, osg::Vec4(1.0, 0.0, 0.0, 0.3));//1.0, 0.0, 0.0, 0.3
|
program->addShader(vertexShader);
|
||||||
//
|
program->addShader(fragmentShader);
|
||||||
// geode->getOrCreateStateSet()->setAttribute(mat);
|
|
||||||
stateset->setMode(GL_BLEND, osg::StateAttribute::ON);
|
|
||||||
stateset->setMode(GL_RESCALE_NORMAL, osg::StateAttribute::ON);
|
|
||||||
// stateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
|
|
||||||
stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
|
||||||
|
|
||||||
//设置渲染顺序 仿真模型被波束遮盖 ,1000000-指的是若有1000000个Node 则此节点最后一个被渲染
|
baseColorUniform_ = new osg::Uniform("baseColor", baseColor_);
|
||||||
// //stateset->setRenderBinDetails(120, "OSGEARTH_SCREEN_SPACE_LAYOUT_BIN");
|
stateset->setMode(GL_CULL_FACE, osg::StateAttribute::ON);
|
||||||
stateset->setRenderBinDetails(10, "RenderBin");
|
stateset->addUniform(baseColorUniform_);
|
||||||
// osg::ref_ptr<osg::BlendFunc> blendFunc = new osg::BlendFunc();
|
stateset->setAttributeAndModes(program, osg::StateAttribute::ON);
|
||||||
// stateset->setAttributeAndModes(blendFunc, osg::StateAttribute::ON);
|
|
||||||
// osg::ref_ptr<osg::Program> program = new osg::Program();
|
|
||||||
// program->addShader(vertexShader);
|
|
||||||
// program->addShader(fragmentShader);
|
|
||||||
//
|
|
||||||
// baseColorUniform_ = new osg::Uniform("baseColor", baseColor_);
|
|
||||||
// stateset->setMode(GL_CULL_FACE, osg::StateAttribute::ON);
|
|
||||||
// stateset->addUniform(baseColorUniform_);
|
|
||||||
// // stateset->setAttributeAndModes(program, osg::StateAttribute::ON);
|
|
||||||
// // stateset->setAttributeAndModes(new osg::Depth(osg::Depth::LESS, 0.0, 1.0, false));
|
|
||||||
//
|
|
||||||
// levelCountUniform_ = new osg::Uniform("num", float(levelCount_));
|
|
||||||
// levelHeightUniform_ = new osg::Uniform("height", levelHeight_);
|
|
||||||
|
|
||||||
// stateset->addUniform(levelCountUniform_);
|
levelCountUniform_ = new osg::Uniform("num", float(levelCount_));
|
||||||
// stateset->addUniform(levelHeightUniform_.get());
|
levelHeightUniform_ = new osg::Uniform("height", levelHeight_);
|
||||||
|
|
||||||
|
stateset->addUniform(levelCountUniform_);
|
||||||
|
stateset->addUniform(levelHeightUniform_.get());
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
#include <osg/Geode>
|
|
||||||
#include <osg/Geometry>
|
|
||||||
#include <osg/Material>
|
|
||||||
#include <osgFX/Outline>
|
|
||||||
#include <osgFX/Scribe>
|
|
||||||
#include <osg/MatrixTransform>
|
|
||||||
#include <osgEarth/Ellipsoid>
|
|
||||||
|
|
||||||
#include "scene/SceneContent.h"
|
|
||||||
|
|
||||||
class WaveBeamConeCallBack : public osg::NodeCallback {
|
|
||||||
public:
|
|
||||||
WaveBeamConeCallBack();
|
|
||||||
~WaveBeamConeCallBack();
|
|
||||||
|
|
||||||
virtual void operator() (osg::Node *node, osg::NodeVisitor *nv);
|
|
||||||
public:
|
|
||||||
double m_latitude;
|
|
||||||
double m_longitude;
|
|
||||||
double m_height;
|
|
||||||
bool m_ifDynamic;
|
|
||||||
|
|
||||||
double m_angle;
|
|
||||||
double m_length;
|
|
||||||
osg::Vec4 m_color;
|
|
||||||
osg::Vec4 m_lineColor;
|
|
||||||
double m_lineWidth;
|
|
||||||
|
|
||||||
osg::ref_ptr<osg::Geode> m_geode;
|
|
||||||
osg::ref_ptr<osg::Geometry> m_geom;
|
|
||||||
osg::ref_ptr<osg::Vec4Array> m_colorArray;
|
|
||||||
osg::ref_ptr<osg::Vec3Array> m_pointVector;
|
|
||||||
osg::ref_ptr<osgFX::Scribe> m_nodeFX;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
WaveBeamConeCallBack::WaveBeamConeCallBack() {
|
|
||||||
m_latitude = 0.0;
|
|
||||||
m_longitude = 0.0;
|
|
||||||
m_height = -6371000;
|
|
||||||
m_ifDynamic = false;
|
|
||||||
|
|
||||||
m_angle = 20.0;
|
|
||||||
m_length = 100000;
|
|
||||||
m_color = osg::Vec4(1, 0, 0, 0.5);
|
|
||||||
m_lineColor = osg::Vec4(1.0, 0.0, 0.0, 1.0);
|
|
||||||
m_lineWidth = 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
WaveBeamConeCallBack::~WaveBeamConeCallBack() {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void WaveBeamConeCallBack::operator()(osg::Node *node, osg::NodeVisitor *nv) {
|
|
||||||
if (m_ifDynamic == false)
|
|
||||||
return;
|
|
||||||
//std::cout << "WaveBeamConeCallBack info=" << m_latitude << "," << m_longitude << "," << m_height << std::endl;
|
|
||||||
osg::MatrixTransform* mtCone = dynamic_cast<osg::MatrixTransform*>(node);
|
|
||||||
if (mtCone != NULL) {
|
|
||||||
osg::MatrixTransform* mtR = dynamic_cast<osg::MatrixTransform*>(mtCone->getParent(0));
|
|
||||||
osg::MatrixTransform* mt = dynamic_cast<osg::MatrixTransform*>(mtR->getParent(0));
|
|
||||||
|
|
||||||
//osg::Matrix m = osg::computeWorldToLocal(mtCone->getParentalNodePaths().at(0));
|
|
||||||
osg::Matrix m = osg::Matrix::inverse(mt->getMatrix()*mtR->getMatrix());
|
|
||||||
osg::Matrix mTarget;
|
|
||||||
double x, y, z;
|
|
||||||
osg::EllipsoidModel em;
|
|
||||||
em.convertLatLongHeightToXYZ(osg::DegreesToRadians(m_latitude),
|
|
||||||
osg::DegreesToRadians(m_longitude),
|
|
||||||
m_height, x, y, z);
|
|
||||||
|
|
||||||
mTarget.setTrans(x, y, z);
|
|
||||||
osg::Matrix mConeRate = osg::Matrix::rotate(osg::Vec3d(0, 1, 0), (mTarget*m).getTrans());
|
|
||||||
mtCone->setMatrix(mConeRate);//mTarget*m
|
|
||||||
|
|
||||||
//更改cone的形状----------------------------------------
|
|
||||||
double length = (mTarget*m).getTrans().length();
|
|
||||||
|
|
||||||
double angle = osg::DegreesToRadians(m_angle);
|
|
||||||
double radius = std::tan(angle*0.5) * length;
|
|
||||||
int splitCount = 20;
|
|
||||||
double angleStep = osg::PI * 2.0 / splitCount;
|
|
||||||
|
|
||||||
//侧面
|
|
||||||
for (int i = 1; i <= splitCount + 1; i++) {
|
|
||||||
double tempAngle = (i - 1)*angleStep;
|
|
||||||
osg::Vec3 pos(radius * cos(tempAngle), length, radius * sin(tempAngle) + 3);
|
|
||||||
m_pointVector->at(i) = pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_pointVector->at(splitCount + 2) = osg::Vec3(0, length, 0);
|
|
||||||
|
|
||||||
//底面
|
|
||||||
for (int i = splitCount + 3; i <= splitCount + 3 + splitCount; i++) {
|
|
||||||
double tempAngle = (i - splitCount - 3) *angleStep;
|
|
||||||
osg::Vec3 pos(radius * cos(tempAngle), length, radius * sin(tempAngle) + 3);
|
|
||||||
m_pointVector->at(i) = pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_geom->dirtyBound();
|
|
||||||
m_geom->dirtyDisplayList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ConeWave::ConeWave() {
|
|
||||||
}
|
|
||||||
|
|
||||||
ConeWave::~ConeWave() {
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConeWave::clearSelf() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConeWave::Render(double dt)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConeWave::createWaveBeamCone(osg::MatrixTransform* node, double angle, double length,
|
|
||||||
osg::Vec4 color, osg::Vec4 lineColor, double lineWidth) {
|
|
||||||
double angleD = osg::DegreesToRadians(angle);
|
|
||||||
double radius = std::tan(angleD*0.5) * length;
|
|
||||||
int splitCount = 20;
|
|
||||||
double angleStep = osg::PI * 2.0 / splitCount;
|
|
||||||
|
|
||||||
|
|
||||||
osg::ref_ptr<osg::Geode> geode = new osg::Geode();
|
|
||||||
osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;
|
|
||||||
osg::ref_ptr<osg::Vec3Array> vertex = new osg::Vec3Array;
|
|
||||||
osg::ref_ptr<osg::Vec3Array> normal = new osg::Vec3Array;
|
|
||||||
osg::ref_ptr<osg::DrawElementsUInt> drawElemUInt = new osg::DrawElementsUInt(GL_TRIANGLE_FAN);
|
|
||||||
osg::ref_ptr<osg::DrawElementsUInt> drawElemUInt2 = new osg::DrawElementsUInt(GL_TRIANGLE_FAN);
|
|
||||||
geom->setVertexArray(vertex);
|
|
||||||
geom->setNormalArray(normal);
|
|
||||||
geode->addDrawable(geom);
|
|
||||||
|
|
||||||
vertex->push_back(osg::Vec3(0, 0, 0));
|
|
||||||
drawElemUInt->push_back(0);
|
|
||||||
normal->push_back(osg::Vec3(0, -1, 0));
|
|
||||||
|
|
||||||
//侧面
|
|
||||||
for (int i = 0; i <= splitCount; i++) {
|
|
||||||
double tempAngle = i*angleStep;
|
|
||||||
osg::Vec3 pos(radius * cos(tempAngle), length, radius * sin(tempAngle) + 3);
|
|
||||||
vertex->push_back(osg::Vec3(pos));
|
|
||||||
|
|
||||||
pos.normalize();
|
|
||||||
normal->push_back(pos);
|
|
||||||
drawElemUInt->push_back(i + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
//底面
|
|
||||||
int indexBegin = vertex->size();
|
|
||||||
vertex->push_back(osg::Vec3(0, length, 0));
|
|
||||||
drawElemUInt2->push_back(indexBegin);
|
|
||||||
normal->push_back(osg::Vec3(0, 1, 0));
|
|
||||||
for (int i = 0; i <= splitCount; i++) {
|
|
||||||
double tempAngle = i*angleStep;
|
|
||||||
osg::Vec3 pos(radius * cos(tempAngle), length, radius * sin(tempAngle) + 3);
|
|
||||||
vertex->push_back(osg::Vec3(pos));
|
|
||||||
|
|
||||||
normal->push_back(osg::Vec3(0, 1, 0));
|
|
||||||
drawElemUInt2->push_back(indexBegin + i + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
geom->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
|
|
||||||
geom->addPrimitiveSet(drawElemUInt);
|
|
||||||
geom->addPrimitiveSet(drawElemUInt2);
|
|
||||||
|
|
||||||
//创建材质对象
|
|
||||||
osg::ref_ptr<osg::Material> mat = new osg::Material;
|
|
||||||
//设置正面散射颜色
|
|
||||||
mat->setDiffuse(osg::Material::FRONT, osg::Vec4(1.0, 1.0, 0.0, 0.3));//1.0, 0.0, 0.0, 0.3
|
|
||||||
//设置正面镜面颜色
|
|
||||||
mat->setSpecular(osg::Material::FRONT, osg::Vec4(1.0, 0.0, 0.0, 0.3));//1.0, 0.0, 0.0, 0.3
|
|
||||||
|
|
||||||
geode->getOrCreateStateSet()->setAttribute(mat.get());
|
|
||||||
geode->getOrCreateStateSet()->setMode(GL_RESCALE_NORMAL, osg::StateAttribute::ON);
|
|
||||||
//设置透明效果
|
|
||||||
geode->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON);
|
|
||||||
geode->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
|
|
||||||
geode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
|
||||||
|
|
||||||
//设置渲染顺序 仿真模型被波束遮盖 ,1000000-指的是若有1000000个Node 则此节点最后一个被渲染
|
|
||||||
geode->getOrCreateStateSet()->setRenderBinDetails(12, "RenderBin");
|
|
||||||
|
|
||||||
osg::ref_ptr<osg::MatrixTransform> mtCone = new osg::MatrixTransform;
|
|
||||||
// mtCone->addChild(nodeFX);
|
|
||||||
|
|
||||||
//给callback中赋值
|
|
||||||
WaveBeamConeCallBack* coneCallBack = new WaveBeamConeCallBack;
|
|
||||||
coneCallBack->m_angle = angle;
|
|
||||||
coneCallBack->m_length = length;
|
|
||||||
coneCallBack->m_color = color;
|
|
||||||
coneCallBack->m_lineColor = lineColor;
|
|
||||||
coneCallBack->m_lineWidth = lineWidth;
|
|
||||||
|
|
||||||
coneCallBack->m_geode = geode;
|
|
||||||
coneCallBack->m_geom = geom;
|
|
||||||
coneCallBack->m_pointVector = vertex;
|
|
||||||
|
|
||||||
//添加到模型中
|
|
||||||
// osg::MatrixTransform* mtR = dynamic_cast<osg::MatrixTransform*>(node->getChild(0));
|
|
||||||
// osg::MatrixTransform* mtS = dynamic_cast<osg::MatrixTransform*>(mtR->getChild(0));
|
|
||||||
// mtR->addChild(mtCone);
|
|
||||||
_waveBeamCone = mtCone;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConeWave::changeWaveBeamConeTarget(double latitude, double longitude, double height, bool ifDynamic) {
|
|
||||||
WaveBeamConeCallBack* coneCallBack = dynamic_cast<WaveBeamConeCallBack*>(_waveBeamCone->getUpdateCallback());
|
|
||||||
if (coneCallBack != NULL) {
|
|
||||||
coneCallBack->m_ifDynamic = ifDynamic;
|
|
||||||
coneCallBack->m_latitude = latitude;
|
|
||||||
coneCallBack->m_longitude = longitude;
|
|
||||||
coneCallBack->m_height = height;
|
|
||||||
|
|
||||||
if (ifDynamic == false) {
|
|
||||||
osg::MatrixTransform* mtCone = _waveBeamCone;
|
|
||||||
|
|
||||||
osg::MatrixTransform* mtR = dynamic_cast<osg::MatrixTransform*>(mtCone->getParent(0));
|
|
||||||
osg::MatrixTransform* mt = dynamic_cast<osg::MatrixTransform*>(mtR->getParent(0));
|
|
||||||
|
|
||||||
//osg::Matrix m = osg::computeWorldToLocal(mtCone->getParentalNodePaths().at(0));
|
|
||||||
osg::Matrix m = osg::Matrix::inverse(mt->getMatrix()*mtR->getMatrix());
|
|
||||||
osg::Matrix mTarget;
|
|
||||||
double x, y, z;
|
|
||||||
osg::EllipsoidModel em;
|
|
||||||
em.convertLatLongHeightToXYZ(osg::DegreesToRadians(latitude),
|
|
||||||
osg::DegreesToRadians(longitude),
|
|
||||||
height, x, y, z);
|
|
||||||
|
|
||||||
mTarget.setTrans(x, y, z);
|
|
||||||
osg::Matrix mConeRate = osg::Matrix::rotate(osg::Vec3d(0, 1, 0), (mTarget*m).getTrans());
|
|
||||||
|
|
||||||
mtCone->setMatrix(mConeRate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConeWave::changeWaveBeamConeAppearance( osg::Vec4 color, osg::Vec4 lineColor, double lineWidth) {
|
|
||||||
WaveBeamConeCallBack* coneCallBack = dynamic_cast<WaveBeamConeCallBack*>(_waveBeamCone->getUpdateCallback());
|
|
||||||
if (coneCallBack != NULL) {
|
|
||||||
coneCallBack->m_color = color;
|
|
||||||
coneCallBack->m_lineColor = lineColor;
|
|
||||||
coneCallBack->m_lineWidth = lineWidth;
|
|
||||||
|
|
||||||
//创建材质对象
|
|
||||||
osg::ref_ptr<osg::Material> mat = new osg::Material;
|
|
||||||
//设置正面散射颜色
|
|
||||||
mat->setDiffuse(osg::Material::FRONT, color);//1.0, 0.0, 0.0, 0.3
|
|
||||||
//设置正面镜面颜色
|
|
||||||
mat->setSpecular(osg::Material::FRONT, color);//1.0, 0.0, 0.0, 0.3
|
|
||||||
coneCallBack->m_geode->getOrCreateStateSet()->setAttribute(mat.get());
|
|
||||||
|
|
||||||
if (lineWidth < 0.1) {
|
|
||||||
_waveBeamCone->addChild(coneCallBack->m_geode);
|
|
||||||
_waveBeamCone->removeChild(coneCallBack->m_nodeFX);
|
|
||||||
} else {
|
|
||||||
_waveBeamCone->removeChild(coneCallBack->m_geode);
|
|
||||||
_waveBeamCone->addChild(coneCallBack->m_nodeFX);
|
|
||||||
|
|
||||||
coneCallBack->m_nodeFX->setWireframeColor(lineColor);
|
|
||||||
coneCallBack->m_nodeFX->setWireframeLineWidth(lineWidth);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
/*
|
|
||||||
#include <osg/Matrix>
|
#include <osg/Matrix>
|
||||||
#include <osg/Array>
|
#include <osg/Array>
|
||||||
#include <osg/Geometry>
|
#include <osg/Geometry>
|
||||||
@ -62,36 +62,3 @@ private:
|
|||||||
float radius_{ 10.0f };
|
float radius_{ 10.0f };
|
||||||
};
|
};
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <osg/Node>
|
|
||||||
#include <osg/Geode>
|
|
||||||
#include <osg/MatrixTransform>
|
|
||||||
#include "viewer/UpdateRenderStd.h"
|
|
||||||
|
|
||||||
//三维实体的圆锥波束
|
|
||||||
|
|
||||||
class ConeWave : public osg::Geode
|
|
||||||
, public UpdateRenderStd {
|
|
||||||
public:
|
|
||||||
ConeWave();
|
|
||||||
~ConeWave();
|
|
||||||
|
|
||||||
void clearSelf() ;
|
|
||||||
void Render(double dt) override;
|
|
||||||
|
|
||||||
void createWaveBeamCone(osg::MatrixTransform* node,double angle, double length, osg::Vec4 color, osg::Vec4 lineColor, double lineWidth);
|
|
||||||
|
|
||||||
void changeWaveBeamConeTarget(/*osg::MatrixTransform* mt,*/ double latitude, double longitude, double height, bool ifDynamic);
|
|
||||||
|
|
||||||
void changeWaveBeamConeAppearance(osg::Vec4 color, osg::Vec4 lineColor, double lineWidth);
|
|
||||||
|
|
||||||
osg::ref_ptr<osg::MatrixTransform> getWaveBeamCone() {
|
|
||||||
return _waveBeamCone;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
osg::ref_ptr<osg::MatrixTransform> _waveBeamCone;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -13,8 +13,8 @@
|
|||||||
|
|
||||||
ConeWaveComponent::ConeWaveComponent(SceneComponent* parent)
|
ConeWaveComponent::ConeWaveComponent(SceneComponent* parent)
|
||||||
: SceneComponent(parent) {
|
: SceneComponent(parent) {
|
||||||
// coneWave_ = new ConeWave();
|
coneWave_ = new ConeWave();
|
||||||
// coneWave_->InitGeode();
|
coneWave_->InitGeode();
|
||||||
|
|
||||||
colorMap_[1] = osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f);
|
colorMap_[1] = osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
colorMap_[2] = osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f);
|
colorMap_[2] = osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
@ -22,7 +22,7 @@ ConeWaveComponent::ConeWaveComponent(SceneComponent* parent)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ConeWaveComponent::~ConeWaveComponent() {
|
ConeWaveComponent::~ConeWaveComponent() {
|
||||||
// coneWave_->Destory();
|
coneWave_->Destory();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ConeWaveComponent::GetTypeName() {
|
std::string ConeWaveComponent::GetTypeName() {
|
||||||
@ -84,48 +84,46 @@ void ConeWaveComponent::Update(double dt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ConeWaveComponent::SetHeight(float height) {
|
void ConeWaveComponent::SetHeight(float height) {
|
||||||
// coneWave_->SetHeight(height);
|
coneWave_->SetHeight(height);
|
||||||
// if (nullptr != mt_) {
|
if (nullptr != mt_) {
|
||||||
// mt_->setMatrix(osg::Matrix::translate(osg::Vec3(0.0f, 0.0f, -coneWave_->GetHeght() * 0.75f)));
|
mt_->setMatrix(osg::Matrix::translate(osg::Vec3(0.0f, 0.0f, -coneWave_->GetHeght() * 0.75f)));
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float ConeWaveComponent::GetHeight() const {
|
float ConeWaveComponent::GetHeight() const {
|
||||||
return 0;// coneWave_->GetHeght();
|
return coneWave_->GetHeght();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConeWaveComponent::SetRadius(float radius) {
|
void ConeWaveComponent::SetRadius(float radius) {
|
||||||
// coneWave_->SetRadius(radius);
|
coneWave_->SetRadius(radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
float ConeWaveComponent::GetRadius() const {
|
float ConeWaveComponent::GetRadius() const {
|
||||||
return 0;// return coneWave_->GetRadius();
|
return coneWave_->GetRadius();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConeWaveComponent::SetLevelCount(int count) {
|
void ConeWaveComponent::SetLevelCount(int count) {
|
||||||
// coneWave_->SetLevelCount(count);
|
coneWave_->SetLevelCount(count);
|
||||||
}
|
}
|
||||||
|
|
||||||
float ConeWaveComponent::GetLevelCount() const {
|
float ConeWaveComponent::GetLevelCount() const {
|
||||||
return 0; // return coneWave_->GetLevelCount();
|
return coneWave_->GetLevelCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConeWaveComponent::SetLevelHeight(float height) {
|
void ConeWaveComponent::SetLevelHeight(float height) {
|
||||||
// coneWave_->SetLevelHeight(height);
|
coneWave_->SetLevelHeight(height);
|
||||||
}
|
}
|
||||||
|
|
||||||
float ConeWaveComponent::GetLevelHeight() const {
|
float ConeWaveComponent::GetLevelHeight() const {
|
||||||
// return coneWave_->GetLevelHeihgt();
|
return coneWave_->GetLevelHeihgt();
|
||||||
return 0.0f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConeWaveComponent::SetBaseColor(const osg::Vec4& color) {
|
void ConeWaveComponent::SetBaseColor(const osg::Vec4& color) {
|
||||||
// coneWave_->SetBaseColor(color);
|
coneWave_->SetBaseColor(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
const osg::Vec4 ConeWaveComponent::GetBaseColor() const {
|
const osg::Vec4 ConeWaveComponent::GetBaseColor() const {
|
||||||
// return coneWave_->GetBaseColor();
|
return coneWave_->GetBaseColor();
|
||||||
return osg::Vec4();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConeWaveComponent::SetColor1(const osg::Vec4& color) {
|
void ConeWaveComponent::SetColor1(const osg::Vec4& color) {
|
||||||
@ -172,7 +170,7 @@ void ConeWaveComponent::AddToRender() {
|
|||||||
void ConeWaveComponent::Initialize() {
|
void ConeWaveComponent::Initialize() {
|
||||||
mt_ = new osg::MatrixTransform;
|
mt_ = new osg::MatrixTransform;
|
||||||
mt_->addChild(coneWave_);
|
mt_->addChild(coneWave_);
|
||||||
// mt_->setMatrix(osg::Matrix::translate(osg::Vec3(0.0f, 0.0f, -coneWave_->GetHeght() * 0.75f)));
|
mt_->setMatrix(osg::Matrix::translate(osg::Vec3(0.0f, 0.0f, -coneWave_->GetHeght() * 0.75f)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConeWaveComponent::UpdateEvent() {
|
void ConeWaveComponent::UpdateEvent() {
|
||||||
@ -200,7 +198,7 @@ void ConeWaveComponent::UpdateEvent() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
osg::Vec4& color = colorMap_[currentStatus_];
|
osg::Vec4& color = colorMap_[currentStatus_];
|
||||||
// coneWave_->SetBaseColor(color);
|
coneWave_->SetBaseColor(color);
|
||||||
coneWave_->setNodeMask(0xff);
|
coneWave_->setNodeMask(0xff);
|
||||||
|
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ void PathComponent::Begin() {
|
|||||||
int num = std::min(steps.size(), transforms.size());
|
int num = std::min(steps.size(), transforms.size());
|
||||||
for (int index = 0; index < num; ++index) {
|
for (int index = 0; index < num; ++index) {
|
||||||
const Transform& transform = transforms[index];
|
const Transform& transform = transforms[index];
|
||||||
osg::AnimationPath::ControlPoint controlPoint(transform.GetLocation() /*+ osg::Vec3(index * 10, 0, 0)*/,
|
osg::AnimationPath::ControlPoint controlPoint(transform.GetLocation() + osg::Vec3(index * 10, 0, 0),
|
||||||
OsgUtils::HPRToQuat(transform.GetRotation() + osg::Vec3(0, 0, -90.0)), transform.GetScale());
|
OsgUtils::HPRToQuat(transform.GetRotation() + osg::Vec3(0, 0, -90.0)), transform.GetScale());
|
||||||
animationPath_->insert(steps[index], controlPoint);
|
animationPath_->insert(steps[index], controlPoint);
|
||||||
}
|
}
|
||||||
|
@ -1,513 +0,0 @@
|
|||||||
#include "entities/ScutcheonComponent.h"
|
|
||||||
|
|
||||||
#include <osgViewer/Renderer>
|
|
||||||
|
|
||||||
|
|
||||||
Scutcheon::Scutcheon() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Scutcheon::Scutcheon(const QString& titleText, osg::ref_ptr<osg::MatrixTransform> targetObj) :
|
|
||||||
osgWidget::Box("Scutcheon", osgWidget::Box::VERTICAL),
|
|
||||||
mTargetObj(targetObj),
|
|
||||||
mIndex(0),
|
|
||||||
mIsVisible(true),
|
|
||||||
mIsItemVisible(true),
|
|
||||||
mIsMouseDrag(false),
|
|
||||||
mIsMousePush(false) {
|
|
||||||
|
|
||||||
getBackground()->setColor(1.0, 1.0, 1.0, 0.5);
|
|
||||||
setEventMask(osgWidget::EVENT_ALL);
|
|
||||||
attachMoveCallback();
|
|
||||||
|
|
||||||
mTitleText = titleText;
|
|
||||||
addLabelTitle(titleText);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Scutcheon::~Scutcheon() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void Scutcheon::addLabelTitle(const QString& titleText) {
|
|
||||||
|
|
||||||
osg::ref_ptr<osgWidget::Label> labelTitle = new osgWidget::Label("labelTitle");
|
|
||||||
labelTitle->setFont(FONT_TEXT);
|
|
||||||
labelTitle->setFontSize(14);
|
|
||||||
labelTitle->setFontColor(1.0f, 1.0f, 0.0f, 1.0f);
|
|
||||||
labelTitle->setColor(1.0f, 1.0f, 1.0f, 0.3f);
|
|
||||||
labelTitle->addSize(128.0f, 32.0f);
|
|
||||||
//labelTitle->setEventMask(osgWidget::EVENT_MOUSE_DRAG);
|
|
||||||
//labelTitle->addCallback(new osgWidget::Callback(&osgScutcheon::callbackMousePush, this, osgWidget::EVENT_MOUSE_DRAG));
|
|
||||||
|
|
||||||
//labelTitle->setShadow(0.08f);
|
|
||||||
labelTitle->setCanFill(true);
|
|
||||||
labelTitle->setImage(TITLE_IMAGE);
|
|
||||||
labelTitle->setTexCoord(0.0f, 0.0f, osgWidget::Widget::LOWER_LEFT);
|
|
||||||
labelTitle->setTexCoord(1.0f, 0.0f, osgWidget::Widget::LOWER_RIGHT);
|
|
||||||
labelTitle->setTexCoord(1.0f, 1.0f, osgWidget::Widget::UPPER_RIGHT);
|
|
||||||
labelTitle->setTexCoord(0.0f, 1.0f, osgWidget::Widget::UPPER_LEFT);
|
|
||||||
osgText::String labelString = TextCodecUtils::QStringToOsgTextString(titleText);
|
|
||||||
labelTitle->setLabel(labelString);
|
|
||||||
addWidget(labelTitle);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Scutcheon::addLabelItem(const QString& labelText) {
|
|
||||||
++mIndex;
|
|
||||||
ScutcheonMenu* labelItem = new ScutcheonMenu(labelText, this);
|
|
||||||
labelItem->setIndex(mIndex);
|
|
||||||
mLabelItemManager.push_back(labelItem);
|
|
||||||
addWidget(labelItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Scutcheon::addLabelItem(ScutcheonMenu& labelItem) {
|
|
||||||
++mIndex;
|
|
||||||
labelItem.setIndex(mIndex);
|
|
||||||
mLabelItemManager.push_back(&labelItem);
|
|
||||||
if (mIsItemVisible) {
|
|
||||||
addWidget(&labelItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void Scutcheon::moveLabelItem() {
|
|
||||||
int x = this->getX();
|
|
||||||
int y = this->getY();
|
|
||||||
|
|
||||||
for (int i = 0; i < mLabelItemManager.size(); ++i) {
|
|
||||||
ScutcheonMenu* labelItem = mLabelItemManager.at(i);
|
|
||||||
labelItem->moveTo(x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Scutcheon::callbackMouseDrag(osgWidget::Event& ev) {
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Scutcheon::mouseDrag(double, double, const osgWidget::WindowManager*) {
|
|
||||||
qDebug() << "osgScutcheon mouseDrag called";
|
|
||||||
mIsMouseDrag = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Scutcheon::mousePush(double, double, const osgWidget::WindowManager*) {
|
|
||||||
mIsMousePush = true;
|
|
||||||
qDebug() << "osgScutcheon mousePush called" << mIsMousePush << ":" << mTitleText;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Scutcheon::mouseRelease(double, double, const osgWidget::WindowManager*) {
|
|
||||||
qDebug() << "osgScutcheon mouseRelease called" << mIsMouseDrag << ":" << mTitleText;
|
|
||||||
|
|
||||||
if (!mIsMouseDrag) {
|
|
||||||
if (mIsMousePush && mIsItemVisible) {
|
|
||||||
std::vector<osg::ref_ptr<ScutcheonMenu> >::const_iterator it;
|
|
||||||
for (it = mLabelItemManager.begin(); it != mLabelItemManager.end(); ++it) {
|
|
||||||
(*it)->getChildMenu()->hide();
|
|
||||||
this->removeWidget((*it));
|
|
||||||
qDebug() << "item removed!" << (*it)->getIndex();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (this->getNumChildren() <= mLabelItemManager.size()) {
|
|
||||||
std::vector<osg::ref_ptr<ScutcheonMenu> >::const_iterator it;
|
|
||||||
for (it = mLabelItemManager.begin(); it != mLabelItemManager.end(); ++it) {
|
|
||||||
this->addWidget((*it));
|
|
||||||
qDebug() << "item added!" << (*it)->getIndex();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mIsItemVisible = !mIsItemVisible;
|
|
||||||
}
|
|
||||||
mIsMousePush = false;
|
|
||||||
mIsMouseDrag = false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<osg::ref_ptr<ScutcheonMenu> > Scutcheon::getLabelItemManager() const {
|
|
||||||
return mLabelItemManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Scutcheon::onMouseEvent(const osgGA::GUIEventAdapter& ea, osgViewer::Viewer* viewer) {
|
|
||||||
int etype = ea.getEventType();
|
|
||||||
if (etype == ea.FRAME) {
|
|
||||||
if (mTargetObj) {
|
|
||||||
osg::Vec3 position = mTargetObj->getMatrix().getTrans() + osg::Vec3d(0, 0, 0);
|
|
||||||
osgViewer::Renderer* renderer = dynamic_cast<osgViewer::Renderer*>(viewer->getCamera()->getRenderer());
|
|
||||||
osg::Vec3 renderPos;
|
|
||||||
renderer->getSceneView(0)->projectObjectIntoWindow(position, renderPos);
|
|
||||||
|
|
||||||
float x = this->getX();
|
|
||||||
float y = this->getY();
|
|
||||||
float w = this->getWidth();
|
|
||||||
float h = this->getHeight();
|
|
||||||
|
|
||||||
float offset = 0.0;
|
|
||||||
osg::Vec3 stPt(x + 0.5 * w, y + 0.5 * h, 0);
|
|
||||||
if (stPt.y()- renderPos.y()>0.5*h)
|
|
||||||
{
|
|
||||||
stPt[1] = stPt.y()-0.5*h+offset;
|
|
||||||
}
|
|
||||||
else if (stPt.y()- renderPos.y()<-0.5*h)
|
|
||||||
{
|
|
||||||
stPt[1] = stPt.y()+0.5*h+offset;
|
|
||||||
}
|
|
||||||
if (stPt.x()- renderPos.x()>0.5*w)
|
|
||||||
{
|
|
||||||
stPt[0] = stPt.x()-0.5*w-offset;
|
|
||||||
}
|
|
||||||
else if (stPt.x()- renderPos.x()<-0.5*w)
|
|
||||||
{
|
|
||||||
stPt[0] = stPt.x()+0.5*w-offset;
|
|
||||||
}
|
|
||||||
setPos(renderPos + osg::Vec3d(50, 50, 50));
|
|
||||||
createLine(stPt, renderPos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((etype == ea.PUSH) && ea.getButtonMask() == ea.LEFT_MOUSE_BUTTON) {
|
|
||||||
if (mIsMousePush) {
|
|
||||||
//qDebug() << "mousePush called" ;
|
|
||||||
m_LBDownPt.set(ea.getX(), ea.getY(), 0);
|
|
||||||
m_LastPt = m_LBDownPt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((etype == ea.DRAG)) {
|
|
||||||
//qDebug() << "mouseDrag called" ;
|
|
||||||
if (mIsMouseDrag) {
|
|
||||||
osg::Vec3 pt(ea.getX() - m_LastPt[0], ea.getY() - m_LastPt[1], 0);
|
|
||||||
setOffset(m_offset + pt);
|
|
||||||
m_LastPt.set(ea.getX(), ea.getY(), 0);
|
|
||||||
ea.setHandled(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((etype == ea.RELEASE)) {
|
|
||||||
//qDebug() << "mouseDrag release" ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Scutcheon::setPos(osg::Vec3 pos) {
|
|
||||||
m_pos = pos;
|
|
||||||
pos = m_pos + m_offset;
|
|
||||||
this->setOrigin(pos.x(), pos.y());
|
|
||||||
this->update();
|
|
||||||
moveLabelItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Scutcheon::setOffset(osg::Vec3 offset) {
|
|
||||||
m_offset = offset;
|
|
||||||
offset = m_pos + m_offset;
|
|
||||||
this->setOrigin(offset.x(), offset.y());
|
|
||||||
this->update();
|
|
||||||
moveLabelItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
osg::ref_ptr<osg::MatrixTransform> Scutcheon::getTargetObject() {
|
|
||||||
return mTargetObj;
|
|
||||||
}
|
|
||||||
int Scutcheon::getItemCount() {
|
|
||||||
return mLabelItemManager.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Scutcheon::setVisibility(bool b) {
|
|
||||||
mIsVisible = b;
|
|
||||||
if (mIsVisible) {
|
|
||||||
this->show();
|
|
||||||
m_line->setNodeMask(1);
|
|
||||||
} else {
|
|
||||||
this->hide();
|
|
||||||
m_line->setNodeMask(0);
|
|
||||||
for (int i = 0; i < mLabelItemManager.size(); i++) {
|
|
||||||
mLabelItemManager.at(i)->getChildMenu()->hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void Scutcheon::createLine(const osg::Vec3& startPt, const osg::Vec3& endPt) {
|
|
||||||
if (NULL == m_line) {
|
|
||||||
m_line = new osg::Geometry;
|
|
||||||
osg::Vec3Array* vertices = new osg::Vec3Array;
|
|
||||||
vertices->push_back(startPt);
|
|
||||||
vertices->push_back(endPt);
|
|
||||||
m_line->setVertexArray(vertices);
|
|
||||||
|
|
||||||
osg::Vec3Array* normals = new osg::Vec3Array;
|
|
||||||
normals->push_back(osg::Vec3(0.0f, 0.0f, 1.0f));
|
|
||||||
m_line->setNormalArray(normals);
|
|
||||||
m_line->setNormalBinding(osg::Geometry::BIND_OVERALL);
|
|
||||||
|
|
||||||
osg::Vec4Array* colors = new osg::Vec4Array;
|
|
||||||
|
|
||||||
colors->push_back(osg::Vec4(1.0, 1.0, 0.0, 1.0));
|
|
||||||
m_line->setColorArray(colors);
|
|
||||||
m_line->setColorBinding(osg::Geometry::BIND_OVERALL);
|
|
||||||
|
|
||||||
m_line->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP, 0, 2));
|
|
||||||
m_line->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON);
|
|
||||||
//m_line->getOrCreateStateSet()->setAttributeAndModes(new osg::LineWidth(1.0f),osg::StateAttribute::ON);
|
|
||||||
m_line->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
|
|
||||||
osg::Geode* geode = new osg::Geode();
|
|
||||||
geode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
|
||||||
geode->addDrawable(m_line);
|
|
||||||
//this->addChild(geode);
|
|
||||||
this->getWindowManager()->addChild(geode);
|
|
||||||
} else {
|
|
||||||
osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(m_line->getVertexArray());
|
|
||||||
(*vertices)[0].set(startPt.x(), startPt.y(), 0.0);
|
|
||||||
(*vertices)[1].set(endPt.x(), endPt.y(), 0.0);
|
|
||||||
vertices->dirty();
|
|
||||||
m_line->setVertexArray(vertices);
|
|
||||||
m_line->dirtyDisplayList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////
|
|
||||||
/// \brief osgScutcheonManager::osgScutcheonManager
|
|
||||||
/// 标牌管理器
|
|
||||||
/// ///////////////////////////////////////////////////////////
|
|
||||||
ScutcheonManager* ScutcheonManager::m_pInstance = NULL;
|
|
||||||
ScutcheonManager::ScutcheonManager(osgViewer::Viewer* pViewer, osg::Group* pScreneRoot) {
|
|
||||||
m_bVisible = true;
|
|
||||||
|
|
||||||
|
|
||||||
mWindowManager = new osgWidget::WindowManager(pViewer, 50.0f, 50.0f, 1, /*0xF0000000*/
|
|
||||||
osgWidget::WindowManager::WM_PICK_DEBUG);
|
|
||||||
osg::Camera* camera = mWindowManager->createParentOrthoCamera();
|
|
||||||
pScreneRoot->addChild(camera);
|
|
||||||
|
|
||||||
/*pViewer->addEventHandler(new osgWidget::MouseHandler(mWindowManager));
|
|
||||||
pViewer->addEventHandler(new osgWidget::KeyboardHandler(mWindowManager));
|
|
||||||
pViewer->addEventHandler(new osgWidget::ResizeHandler(mWindowManager, camera));
|
|
||||||
pViewer->addEventHandler(new osgWidget::CameraSwitchHandler(mWindowManager, camera));*/
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ScutcheonManager::~ScutcheonManager() {
|
|
||||||
m_bGUIStoped = true;
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
ScutcheonManager* ScutcheonManager::instance() {
|
|
||||||
if (NULL == m_pInstance) {
|
|
||||||
//osgViewer::Viewer* getOSGViewer(){ return m_pViewer; }
|
|
||||||
//osg::Group* getRoot(){ return m_pRoot.get(); }
|
|
||||||
/* m_pInstance = new osgScutcheonManager(GraphicsView::instance()->getOSGViewer(),
|
|
||||||
GraphicsView::instance()->getRoot());
|
|
||||||
GraphicsView::instance()->getOSGViewer()->addEventHandler(m_pInstance);*/
|
|
||||||
}
|
|
||||||
return m_pInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScutcheonManager::destroy() {
|
|
||||||
if (NULL != m_pInstance) {
|
|
||||||
delete m_pInstance;
|
|
||||||
m_pInstance = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ScutcheonManager::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) {
|
|
||||||
if (m_bStopGUI) {
|
|
||||||
m_bGUIStoped = true;
|
|
||||||
} else {
|
|
||||||
osgViewer::Viewer* viewer = dynamic_cast<osgViewer::Viewer*>(&aa);
|
|
||||||
int nCount = m_LabelList.size();
|
|
||||||
for (int i = 0; i < nCount; i++) {
|
|
||||||
m_LabelList[i]->onMouseEvent(ea, viewer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ScutcheonManager::addLabel(Scutcheon* label) {
|
|
||||||
m_bVisible = true;
|
|
||||||
if (label == NULL) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
lock(true);
|
|
||||||
// while (!m_bStopGUI) QThread::sleep(100);
|
|
||||||
int nCount = m_LabelList.size();
|
|
||||||
for (int i = 0; i < nCount; i++) {
|
|
||||||
if (m_LabelList[i] == label) {
|
|
||||||
lock(false);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mWindowManager->addChild(label);
|
|
||||||
mWindowManager->resizeAllWindows();
|
|
||||||
m_LabelList.push_back(label);
|
|
||||||
|
|
||||||
lock(false);
|
|
||||||
return m_LabelList.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
int ScutcheonManager::delLabel(Scutcheon*& label) {
|
|
||||||
lock(true);
|
|
||||||
while (!m_bStopGUI) QThread::sleep(100);
|
|
||||||
for (std::vector<Scutcheon*>::iterator vit = m_LabelList.begin(); vit != m_LabelList.end(); vit++) {
|
|
||||||
if ((*vit) == label) {
|
|
||||||
m_LabelList.erase(vit);
|
|
||||||
//label->setVisibility(false);
|
|
||||||
delete label;
|
|
||||||
label = NULL;
|
|
||||||
lock(false);
|
|
||||||
return m_LabelList.size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lock(false);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ScutcheonManager::delLabel(osg::MatrixTransform* tethernode) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScutcheonManager::clear() {
|
|
||||||
lock(true);
|
|
||||||
//while (!m_bGUIStoped) Sleep(200);
|
|
||||||
while (m_LabelList.size() > 0) {
|
|
||||||
Scutcheon* back = m_LabelList.back();
|
|
||||||
delLabel(back);
|
|
||||||
}
|
|
||||||
lock(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScutcheonManager::lock(bool b) {
|
|
||||||
if (b) {
|
|
||||||
m_bStopGUI = true;
|
|
||||||
m_bGUIStoped = false;
|
|
||||||
} else {
|
|
||||||
m_bStopGUI = false;
|
|
||||||
m_bGUIStoped = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
osg::ref_ptr<osgWidget::WindowManager> ScutcheonManager::getWindowManager() const {
|
|
||||||
return mWindowManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
ScutcheonMenu::ScutcheonMenu(const QString& label, osg::ref_ptr<Scutcheon> parentMenu) :
|
|
||||||
osgWidget::Label("menu1"),
|
|
||||||
mChildMenu(NULL),
|
|
||||||
mParentMenu(parentMenu),
|
|
||||||
mHasChildMenu(false),
|
|
||||||
mIndex(0),
|
|
||||||
mMenuItemCount(0) {
|
|
||||||
initLabel(label);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScutcheonMenu::addChildMenu(const QString& menuText) {
|
|
||||||
ImageLabel* childMenuContent = new ImageLabel(menuText);
|
|
||||||
if (mChildMenu == NULL) {
|
|
||||||
mChildMenu = new osgWidget::Box("childMenu", osgWidget::Box::VERTICAL, true);
|
|
||||||
mChildMenu->addWidget(childMenuContent);
|
|
||||||
mMenuItemManager.push_back(childMenuContent);
|
|
||||||
mChildMenu->getBackground()->setColor(1.0f, 1.0f, 1.0f, 0.6f);
|
|
||||||
mChildMenu->resize();
|
|
||||||
mChildMenu->hide();
|
|
||||||
mHasChildMenu = true;
|
|
||||||
//mParentMenu->addChild(mChildMenu);
|
|
||||||
mParentMenu->getWindowManager()->addChild(mChildMenu.get());
|
|
||||||
|
|
||||||
} else {
|
|
||||||
mChildMenu->addWidget(childMenuContent);
|
|
||||||
mMenuItemManager.push_back(childMenuContent);
|
|
||||||
}
|
|
||||||
|
|
||||||
++mMenuItemCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScutcheonMenu::updateChildMenuText(int index, QString labelText) {
|
|
||||||
if (index >= 0 && index < getMenuItemCount()) {
|
|
||||||
//mMenuItemManager.at(index)->setLabelText(labelText);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScutcheonMenu::initLabel(const QString& labelText) {
|
|
||||||
setFont(FONT_TEXT);
|
|
||||||
setFontSize(15);
|
|
||||||
setFontColor(0.0f, 0.0f, 1.0f, 1.0f);
|
|
||||||
addSize(128.0f, 32.0f);
|
|
||||||
setColor(1.0f, 1.0f, 0.0f, 0.6f);
|
|
||||||
//setShadow(0.08f);
|
|
||||||
setCanFill(true);
|
|
||||||
setEventMask(osgWidget::EVENT_ALL);
|
|
||||||
setImage(ITEM_IAMGE);
|
|
||||||
setTexCoord(0.0f, 0.0f, osgWidget::Widget::LOWER_LEFT);
|
|
||||||
setTexCoord(1.0f, 0.0f, osgWidget::Widget::LOWER_RIGHT);
|
|
||||||
setTexCoord(1.0f, 1.0f, osgWidget::Widget::UPPER_RIGHT);
|
|
||||||
setTexCoord(0.0f, 1.0f, osgWidget::Widget::UPPER_LEFT);
|
|
||||||
osgText::String labelString = TextCodecUtils::QStringToOsgTextString(labelText);
|
|
||||||
setLabel(labelString);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScutcheonMenu::hideOtherChildMenu() {
|
|
||||||
for (int i = 0; i < mParentMenu->getLabelItemManager().size(); i++) {
|
|
||||||
osg::ref_ptr<ScutcheonMenu> childItem = mParentMenu->getLabelItemManager().at(i);
|
|
||||||
if (childItem->getChildMenu() != mChildMenu) {
|
|
||||||
childItem->getChildMenu()->hide();
|
|
||||||
}
|
|
||||||
qDebug() << "hideOtherChildMenu";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScutcheonMenu::hideAllChildMenu(osgWidget::WindowManager* wm) {
|
|
||||||
osgWidget::Window* tmp = 0;
|
|
||||||
unsigned int count = wm->getNumChildren();
|
|
||||||
for (unsigned int i = 0; i < count; ++i) {
|
|
||||||
tmp = dynamic_cast<osgWidget::Window*>(wm->getChild(i));
|
|
||||||
if (tmp) {
|
|
||||||
QString name = QString::fromStdString(tmp->getName());
|
|
||||||
if (tmp != mChildMenu.get() && name == "childMenu") {
|
|
||||||
if (tmp->isVisible()) {
|
|
||||||
tmp->hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ScutcheonMenu::mousePush(double, double, const osgWidget::WindowManager* wm) {
|
|
||||||
hideOtherChildMenu();
|
|
||||||
//hideAllChildMenu(mParentMenu->getWindowManager());
|
|
||||||
|
|
||||||
if (!mChildMenu->isVisible()) {
|
|
||||||
mChildMenu->show();
|
|
||||||
qDebug() << "hideOtherChildMenu show";
|
|
||||||
} else {
|
|
||||||
mChildMenu->hide();
|
|
||||||
qDebug() << "hideOtherChildMenu hide";
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImageLabel::ImageLabel(const QString& labelText) : osgWidget::Label("menu1") {
|
|
||||||
setFont(FONT_TEXT);
|
|
||||||
setFontSize(13);
|
|
||||||
setFontColor(0.0f, 0.2f, 1.0f, 1.0f);
|
|
||||||
addSize(128.0f, 32.0f);
|
|
||||||
setColor(1.0f, 1.0f, 1.0f, 0.6f);
|
|
||||||
//setPadding(1.0f);
|
|
||||||
//setShadow(0.08f);
|
|
||||||
setCanFill(true);
|
|
||||||
setEventMask(osgWidget::EVENT_ALL);
|
|
||||||
setImage(ITEM_IAMGE);
|
|
||||||
|
|
||||||
setLabelText(labelText);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImageLabel::setLabelText(QString labelText) {
|
|
||||||
setAlignHorizontal(osgWidget::Widget::HA_LEFT);
|
|
||||||
setTexCoord(0.0f, 0.0f, osgWidget::Widget::LOWER_LEFT);
|
|
||||||
setTexCoord(1.0f, 0.0f, osgWidget::Widget::LOWER_RIGHT);
|
|
||||||
setTexCoord(1.0f, 1.0f, osgWidget::Widget::UPPER_RIGHT);
|
|
||||||
setTexCoord(0.0f, 1.0f, osgWidget::Widget::UPPER_LEFT);
|
|
||||||
|
|
||||||
osgText::String labelString = TextCodecUtils::QStringToOsgTextString(labelText);
|
|
||||||
setLabel(labelString);
|
|
||||||
}
|
|
@ -1,255 +0,0 @@
|
|||||||
/**
|
|
||||||
* @brief 标牌
|
|
||||||
* @author hph
|
|
||||||
* @date 2018/07/07
|
|
||||||
*/
|
|
||||||
#ifndef OSGSCUTCHEON_H
|
|
||||||
#define OSGSCUTCHEON_H
|
|
||||||
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <iostream>
|
|
||||||
#include <sstream>
|
|
||||||
#include <QDebug>
|
|
||||||
#include <QTextCodec>
|
|
||||||
#include <QVector>
|
|
||||||
#include <QThread>
|
|
||||||
|
|
||||||
#include <osgWidget/Box>
|
|
||||||
#include <osgWidget/Label>
|
|
||||||
#include <osgWidget/WindowManager>
|
|
||||||
|
|
||||||
#include "utils/TextCodecUtil.h"
|
|
||||||
|
|
||||||
#define FONT_TEXT "fonts/simhei.ttf"
|
|
||||||
#define TITLE_IMAGE "../publish/data/texture/mark/label_title.png"
|
|
||||||
#define ITEM_IAMGE "../publish/data/texture/mark/label_normal_01.png"
|
|
||||||
|
|
||||||
class ScutcheonMenu;
|
|
||||||
class ImageLabel;
|
|
||||||
|
|
||||||
class Scutcheon : public osgWidget::Box {
|
|
||||||
public:
|
|
||||||
Scutcheon();
|
|
||||||
Scutcheon(const QString& titleText, osg::ref_ptr<osg::MatrixTransform> targetObj);
|
|
||||||
~Scutcheon();
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
void addLabelTitle(const QString& titleText);
|
|
||||||
void addLabelItem(const QString& labelText);
|
|
||||||
void addLabelItem(ScutcheonMenu& labelItem);
|
|
||||||
|
|
||||||
void hideOtherLabelItem();
|
|
||||||
void moveLabelItem();
|
|
||||||
|
|
||||||
void createLine(const osg::Vec3& startPt = osg::Vec3(0, 0, 0), const osg::Vec3& endPt = osg::Vec3(0, 0, 0));
|
|
||||||
|
|
||||||
void onMouseEvent(const osgGA::GUIEventAdapter& ea, osgViewer::Viewer* viewer);
|
|
||||||
|
|
||||||
osg::Geometry* getLine() const {
|
|
||||||
return m_line;
|
|
||||||
}
|
|
||||||
|
|
||||||
int getItemCount();
|
|
||||||
|
|
||||||
void setVisibility(bool b);
|
|
||||||
bool getVisibility() {
|
|
||||||
return mIsVisible;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setPos(osg::Vec3 pos);
|
|
||||||
void setOffset(osg::Vec3 offset);
|
|
||||||
|
|
||||||
osg::ref_ptr<osg::MatrixTransform> getTargetObject();
|
|
||||||
std::vector<osg::ref_ptr<ScutcheonMenu> > getLabelItemManager() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool callbackMouseDrag(osgWidget::Event& ev);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool mouseDrag(double, double, const osgWidget::WindowManager*);
|
|
||||||
bool mousePush(double, double, const osgWidget::WindowManager*);
|
|
||||||
bool mouseRelease(double, double, const osgWidget::WindowManager*);
|
|
||||||
|
|
||||||
public:
|
|
||||||
QString mTitleText;
|
|
||||||
std::vector<osg::ref_ptr<ScutcheonMenu> > mLabelItemManager;
|
|
||||||
|
|
||||||
int mIndex;
|
|
||||||
|
|
||||||
osg::ref_ptr<osg::MatrixTransform> mTargetObj;
|
|
||||||
osg::ref_ptr<osg::Geometry> m_line;
|
|
||||||
|
|
||||||
bool mIsVisible;
|
|
||||||
bool mIsItemVisible;
|
|
||||||
bool mIsMousePush;
|
|
||||||
bool mIsMouseDrag;
|
|
||||||
|
|
||||||
|
|
||||||
osg::Vec3 m_pos;
|
|
||||||
osg::Vec3 m_offset;
|
|
||||||
|
|
||||||
osg::Vec3 m_LastPt;
|
|
||||||
osg::Vec3 m_LBDownPt;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ScutcheonManager : public osgGA::GUIEventHandler {
|
|
||||||
protected:
|
|
||||||
ScutcheonManager(osgViewer::Viewer* pViewer, osg::Group* pScreneRoot);
|
|
||||||
~ScutcheonManager();
|
|
||||||
|
|
||||||
public:
|
|
||||||
static ScutcheonManager* instance();
|
|
||||||
static void destroy();
|
|
||||||
bool handle(const osgGA::GUIEventAdapter&, osgGA::GUIActionAdapter&);
|
|
||||||
int addLabel(Scutcheon* label);
|
|
||||||
int delLabel(Scutcheon*& label);
|
|
||||||
int delLabel(osg::MatrixTransform* tethernode);
|
|
||||||
void clear();
|
|
||||||
void lock(bool b);
|
|
||||||
|
|
||||||
void setVisibility(bool b);
|
|
||||||
void setVisibilityByID(unsigned int ID, bool b);
|
|
||||||
bool getVisibilityByID(unsigned int ID);
|
|
||||||
bool getVisibility() const {
|
|
||||||
return m_bVisible;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setLabelTxtColor(const osg::Vec4f& color);
|
|
||||||
void setLabelBgColor(const osg::Vec4f& color);
|
|
||||||
const osg::Vec4f& getLabelTxtColor() const {
|
|
||||||
return m_clrTxt;
|
|
||||||
}
|
|
||||||
const osg::Vec4f& getLabelBgColor() const {
|
|
||||||
return m_clrBg;
|
|
||||||
}
|
|
||||||
|
|
||||||
osg::ref_ptr<osgWidget::WindowManager> getWindowManager() const;
|
|
||||||
public:
|
|
||||||
static ScutcheonManager* m_pInstance;
|
|
||||||
osg::ref_ptr<osgWidget::WindowManager> mWindowManager;
|
|
||||||
//osgWidget::WindowManager* mWindowManager;
|
|
||||||
std::vector<Scutcheon*> m_LabelList;
|
|
||||||
bool m_bStopGUI;
|
|
||||||
bool m_bGUIStoped;
|
|
||||||
bool m_bVisible;
|
|
||||||
osg::Vec4f m_clrTxt;
|
|
||||||
osg::Vec4f m_clrBg;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class ScutcheonMenu : public osgWidget::Label {
|
|
||||||
public:
|
|
||||||
ScutcheonMenu(const QString& label, osg::ref_ptr<Scutcheon> parentMenu);
|
|
||||||
|
|
||||||
void addChildMenu(const QString& menuText);
|
|
||||||
|
|
||||||
void updateChildMenuText(int index, QString labelText);
|
|
||||||
|
|
||||||
void initLabel(const QString& labelText);
|
|
||||||
|
|
||||||
void setIndex(int index) {
|
|
||||||
mIndex = index;
|
|
||||||
}
|
|
||||||
|
|
||||||
void moveTo(int parentX, int parentY) {
|
|
||||||
if (mChildMenu) {
|
|
||||||
mChildMenu->setOrigin(parentX + 128.0, parentY + 32.0 * mIndex);
|
|
||||||
mChildMenu->update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isHasChildMenu() {
|
|
||||||
return mHasChildMenu;
|
|
||||||
}
|
|
||||||
|
|
||||||
osg::ref_ptr<osgWidget::Window> getChildMenu() {
|
|
||||||
return mChildMenu;
|
|
||||||
}
|
|
||||||
|
|
||||||
int getIndex() {
|
|
||||||
return mIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
int getMenuItemCount() {
|
|
||||||
return mMenuItemManager.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
void hideOtherChildMenu();
|
|
||||||
|
|
||||||
void hideAllChildMenu(osgWidget::WindowManager* wm);
|
|
||||||
|
|
||||||
void managed(osgWidget::WindowManager* wm) {
|
|
||||||
osgWidget::Label::managed(wm);
|
|
||||||
if (mChildMenu) {
|
|
||||||
mChildMenu->hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void positioned() {
|
|
||||||
osgWidget::Label::positioned();
|
|
||||||
if (mChildMenu) {
|
|
||||||
//qDebug() << "mChildMenu not NULL!!" << mIndex;
|
|
||||||
mChildMenu->setOrigin(mParentMenu->getX() + 128.0, mParentMenu->getY() + 32.0 * mIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool mousePush(double, double, const osgWidget::WindowManager* wm);
|
|
||||||
|
|
||||||
bool mouseEnter(double, double, const osgWidget::WindowManager*) {
|
|
||||||
setColor(1.0f, 1.0f, 1.0f, 0.3f);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool mouseLeave(double, double, const osgWidget::WindowManager*) {
|
|
||||||
setColor(1.0f, 1.0f, 1.0f, 0.6f);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
QVector<osg::ref_ptr<ImageLabel> > mMenuItemManager;
|
|
||||||
|
|
||||||
private:
|
|
||||||
osg::ref_ptr<osgWidget::Box> mChildMenu;
|
|
||||||
osg::ref_ptr<Scutcheon> mParentMenu;
|
|
||||||
|
|
||||||
int mIndex;
|
|
||||||
int mMenuItemCount;
|
|
||||||
bool mHasChildMenu;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class ImageLabel : public osgWidget::Label {
|
|
||||||
public:
|
|
||||||
ImageLabel(const QString& labelText);
|
|
||||||
|
|
||||||
void setLabelText(QString labelText);
|
|
||||||
|
|
||||||
bool mousePush(double, double, const osgWidget::WindowManager*) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool mouseDrag(double, double, const osgWidget::WindowManager*) {
|
|
||||||
//osg::notify(osg::NOTICE) << _name << " > mouseDrag called" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool mouseEnter(double, double, const osgWidget::WindowManager*) {
|
|
||||||
//setColor(1.0f, 1.0f, 1.0f, 1.0f);
|
|
||||||
setFontColor(0.0f, 0.0f, 1.0f, 1.0f);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool mouseLeave(double, double, const osgWidget::WindowManager*) {
|
|
||||||
//setColor(1.0f, 1.0f, 1.0f, 0.8f);
|
|
||||||
setFontColor(0.0f, 0.2f, 1.0f, 1.0f);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool mouseOver(double, double, const osgWidget::WindowManager*) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // OSGSCUTCHEON_H
|
|
731
src/main.cpp
731
src/main.cpp
@ -1,3 +1,4 @@
|
|||||||
|
#if 0
|
||||||
#include "app/Application.h"
|
#include "app/Application.h"
|
||||||
|
|
||||||
#include "common/SpdLogger.h"
|
#include "common/SpdLogger.h"
|
||||||
@ -5,15 +6,21 @@
|
|||||||
#include "common/CrashHandler.h"
|
#include "common/CrashHandler.h"
|
||||||
|
|
||||||
#include "ui/MainFrame.h"
|
#include "ui/MainFrame.h"
|
||||||
|
#include "viewer/OSGEnv.h"
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
SpdLogger logger("logs/log.txt", 5);
|
SpdLogger logger("logs/log.txt", 5);
|
||||||
|
|
||||||
|
if (!OSGEnv::init()) {
|
||||||
|
LOG_ERROR("OSGEnv::init() failed!");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
Application::setAttribute(Qt::AA_EnableHighDpiScaling);
|
Application::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||||
|
|
||||||
Application app(argc, argv);
|
Application app(argc, argv);
|
||||||
app.setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
|
app.setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
|
||||||
//InstallCrashHandler();
|
InstallCrashHandler();
|
||||||
|
|
||||||
RecourceHelper::ChangeSkin("default");
|
RecourceHelper::ChangeSkin("default");
|
||||||
|
|
||||||
@ -23,5 +30,727 @@ int main(int argc, char* argv[]) {
|
|||||||
mainWindow.showMaximized();
|
mainWindow.showMaximized();
|
||||||
|
|
||||||
ret = app.exec();
|
ret = app.exec();
|
||||||
|
OSGEnv::destroy();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
//
|
||||||
|
//#include <osgDB/ReadFile>
|
||||||
|
//
|
||||||
|
//#include <osgWidget/Util>
|
||||||
|
//#include <osgWidget/WindowManager>
|
||||||
|
//#include <osgWidget/Frame>
|
||||||
|
//#include <osgWidget/Box>
|
||||||
|
//
|
||||||
|
//const unsigned int MASK_2D = 0xF0000000;
|
||||||
|
//
|
||||||
|
//// NOTE: THIS IS JUST A TEMPORARY HACK! :) This functionality will all eventually be
|
||||||
|
//// encapsulate into another class in osgWidget proper.
|
||||||
|
//bool scrollWindow(osgWidget::Event& ev) {
|
||||||
|
// // The first thing we need to do is make sure we have a Frame object...
|
||||||
|
// osgWidget::Frame* frame = dynamic_cast<osgWidget::Frame*>(ev.getWindow());
|
||||||
|
//
|
||||||
|
// if (!frame) return false;
|
||||||
|
//
|
||||||
|
// // And now we need to make sure our Frame has a valid internal EmbeddedWindow widget.
|
||||||
|
// osgWidget::Window::EmbeddedWindow* ew =
|
||||||
|
// dynamic_cast<osgWidget::Window::EmbeddedWindow*>(frame->getEmbeddedWindow())
|
||||||
|
// ;
|
||||||
|
//
|
||||||
|
// if (!ew) return false;
|
||||||
|
//
|
||||||
|
// // Lets get the visible area so that we can use it to make sure our scrolling action
|
||||||
|
// // is necessary in the first place.
|
||||||
|
// const osgWidget::Quad& va = ew->getWindow()->getVisibleArea();
|
||||||
|
//
|
||||||
|
// // The user wants to scroll up; make sure that the visible area's Y origin isn't already
|
||||||
|
// // at 0.0f, 0.0f.
|
||||||
|
// if (ev.getWindowManager()->isMouseScrollingUp() && va[1] != 0.0f)
|
||||||
|
// ew->getWindow()->addVisibleArea(0, -20)
|
||||||
|
// ;
|
||||||
|
//
|
||||||
|
// else if (va[1] <= (ew->getWindow()->getHeight() - ew->getHeight()))
|
||||||
|
// ew->getWindow()->addVisibleArea(0, 20)
|
||||||
|
// ;
|
||||||
|
//
|
||||||
|
// // We need to manually call update to make sure the visible area scissoring is done
|
||||||
|
// // properly.
|
||||||
|
// frame->update();
|
||||||
|
//
|
||||||
|
// return true;
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//bool changeTheme(osgWidget::Event& ev) {
|
||||||
|
// std::string theme;
|
||||||
|
//
|
||||||
|
// if (ev.key == osgGA::GUIEventAdapter::KEY_Right)
|
||||||
|
// theme = "osgWidget/theme-1.png"
|
||||||
|
// ;
|
||||||
|
//
|
||||||
|
// else if (ev.key == osgGA::GUIEventAdapter::KEY_Left)
|
||||||
|
// theme = "osgWidget/theme-2.png"
|
||||||
|
// ;
|
||||||
|
//
|
||||||
|
// else return false;
|
||||||
|
//
|
||||||
|
// osgWidget::Frame* frame = dynamic_cast<osgWidget::Frame*>(ev.getWindow());
|
||||||
|
//
|
||||||
|
// if (!frame) return false;
|
||||||
|
//
|
||||||
|
// // This is just one way to access all our Widgets; we could just as well have used:
|
||||||
|
// //
|
||||||
|
// // for(osgWidget::Frame::Iterator i = frame.begin(); i != frame.end() i++) {}
|
||||||
|
// //
|
||||||
|
// // ...and it have worked, too.
|
||||||
|
// for (unsigned int row = 0; row < 3; row++) {
|
||||||
|
// for (unsigned int col = 0; col < 3; col++) {
|
||||||
|
// frame->getByRowCol(row, col)->setImage(theme);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return true;
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//int main(int, char**) {
|
||||||
|
// osgViewer::Viewer viewer;
|
||||||
|
//
|
||||||
|
// osgWidget::WindowManager* wm = new osgWidget::WindowManager(
|
||||||
|
// &viewer,
|
||||||
|
// 1280.0f,
|
||||||
|
// 1024.0f,
|
||||||
|
// MASK_2D,
|
||||||
|
// osgWidget::WindowManager::WM_PICK_DEBUG
|
||||||
|
// //osgWidget::WindowManager::WM_NO_INVERT_Y
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// std::string baes("D:/Project/DYTSrouce/bin/Release/data/");
|
||||||
|
// osgWidget::Frame* frame = osgWidget::Frame::createSimpleFrameFromTheme(
|
||||||
|
// "frame",
|
||||||
|
// osgDB::readRefImageFile(baes + "osgWidget/theme.png"),
|
||||||
|
// 40.0f,
|
||||||
|
// 40.0f,
|
||||||
|
// osgWidget::Frame::FRAME_ALL
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// frame->getBackground()->setColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
//
|
||||||
|
// // This is our Transformers box. :)
|
||||||
|
// osgWidget::Box* box = new osgWidget::Box("images", osgWidget::Box::VERTICAL);
|
||||||
|
// osgWidget::Widget* img1 = new osgWidget::Widget("im1", 512.0f, 512.0f);
|
||||||
|
// osgWidget::Widget* img2 = new osgWidget::Widget("im2", 512.0f, 512.0f);
|
||||||
|
// osgWidget::Widget* img3 = new osgWidget::Widget("im3", 512.0f, 512.0f);
|
||||||
|
// osgWidget::Widget* img4 = new osgWidget::Widget("im4", 512.0f, 512.0f);
|
||||||
|
//
|
||||||
|
// const std::string image1 = "D:/Project/DYTSrouce/bin/Release/resources/northarrow/_n.png";
|
||||||
|
// img1->setImage(image1, true);
|
||||||
|
// img2->setImage(baes + "osgWidget/scrolled2.jpg", true);
|
||||||
|
// img3->setImage(baes + "osgWidget/scrolled3.jpg", true);
|
||||||
|
// img4->setImage(baes + "osgWidget/scrolled4.jpg", true);
|
||||||
|
//
|
||||||
|
// img1->setMinimumSize(10.0f, 10.0f);
|
||||||
|
// img2->setMinimumSize(10.0f, 10.0f);
|
||||||
|
// img3->setMinimumSize(10.0f, 10.0f);
|
||||||
|
// img4->setMinimumSize(10.0f, 10.0f);
|
||||||
|
//
|
||||||
|
// box->addWidget(img1);
|
||||||
|
// box->addWidget(img2);
|
||||||
|
// box->addWidget(img3);
|
||||||
|
// box->addWidget(img4);
|
||||||
|
// box->setEventMask(osgWidget::EVENT_NONE);
|
||||||
|
//
|
||||||
|
// //frame->getEmbeddedWindow()->setWindow(box);
|
||||||
|
// frame->setWindow(box);
|
||||||
|
// frame->getEmbeddedWindow()->setColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
// frame->resize(300.0f, 300.0f);
|
||||||
|
// frame->addCallback(new osgWidget::Callback(&scrollWindow, osgWidget::EVENT_MOUSE_SCROLL));
|
||||||
|
// frame->addCallback(new osgWidget::Callback(&changeTheme, osgWidget::EVENT_KEY_DOWN));
|
||||||
|
//
|
||||||
|
// wm->addChild(frame);
|
||||||
|
//
|
||||||
|
// return osgWidget::createExample(viewer, wm);
|
||||||
|
//}
|
||||||
|
#ifdef QT_VERSION
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QMainWindow>
|
||||||
|
#include <QOpenGLWidget>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QWheelEvent>
|
||||||
|
#include <QDesktopWidget>
|
||||||
|
#include <QScreen>
|
||||||
|
#include <QtGlobal>
|
||||||
|
#include <QWindow>
|
||||||
|
|
||||||
|
#include <osg/ref_ptr>
|
||||||
|
#include <osgViewer/GraphicsWindow>
|
||||||
|
#include <osgViewer/Viewer>
|
||||||
|
#include <osg/Camera>
|
||||||
|
#include <osg/ShapeDrawable>
|
||||||
|
#include <osg/StateSet>
|
||||||
|
#include <osg/Material>
|
||||||
|
#include <osgGA/EventQueue>
|
||||||
|
#include <osgGA/TrackballManipulator>
|
||||||
|
#include <osgDB/ReadFile>
|
||||||
|
#include <osgEarth/MapNode>
|
||||||
|
#include <osgEarthUtil/Sky>
|
||||||
|
#include <osgEarthUtil/Ephemeris>
|
||||||
|
#include <osgEarthUtil/EarthManipulator>
|
||||||
|
//#include <osgEarth/GLUtils>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "viewer/OSGEnv.h"
|
||||||
|
|
||||||
|
class QtOSGWidget : public QOpenGLWidget {
|
||||||
|
public:
|
||||||
|
QtOSGWidget(qreal scaleX, qreal scaleY, QWidget* parent = 0)
|
||||||
|
: QOpenGLWidget(parent)
|
||||||
|
//, _mGraphicsWindow(new osgViewer::GraphicsWindowEmbedded(this->x(), this->y(),
|
||||||
|
//this->width(), this->height()))
|
||||||
|
, _mViewer(new osgViewer::Viewer)
|
||||||
|
, m_scaleX(scaleX)
|
||||||
|
, m_scaleY(scaleY) {
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::DisplaySettings> ds = osg::DisplaySettings::instance();
|
||||||
|
osg::ref_ptr<osg::GraphicsContext::Traits> traits
|
||||||
|
= new osg::GraphicsContext::Traits(ds);
|
||||||
|
traits->x = 0;
|
||||||
|
traits->y = 0;
|
||||||
|
traits->width = width();
|
||||||
|
traits->height = height();
|
||||||
|
traits->alpha = ds->getMinimumNumAlphaBits();
|
||||||
|
traits->stencil = ds->getMinimumNumStencilBits();
|
||||||
|
traits->sampleBuffers = ds->getMultiSamples();
|
||||||
|
traits->samples = ds->getNumMultiSamples();
|
||||||
|
traits->windowDecoration = false;
|
||||||
|
traits->doubleBuffer = true;
|
||||||
|
traits->sharedContext = nullptr;
|
||||||
|
traits->setInheritedWindowPixelFormat = true;
|
||||||
|
|
||||||
|
//_mGraphicsWindow = new osgViewer::GraphicsWindowEmbedded(0, 0, width(), height());
|
||||||
|
_mGraphicsWindow = new osgViewer::GraphicsWindowEmbedded(traits);
|
||||||
|
|
||||||
|
//osg::Cylinder* cylinder = new osg::Cylinder(osg::Vec3(0.f, 0.f, 0.f), 0.25f, 0.5f);
|
||||||
|
//osg::ShapeDrawable* sd = new osg::ShapeDrawable(cylinder);
|
||||||
|
//sd->setColor(osg::Vec4(0.8f, 0.5f, 0.2f, 1.f));
|
||||||
|
//osg::Geode* geode = new osg::Geode;
|
||||||
|
//geode->addDrawable(sd);
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::Node> node = osgDB::readNodeFile("D:/Project/DYT/Tool/TritonSample/TritonSample/triton.earth");
|
||||||
|
if (!node.valid())
|
||||||
|
return ;
|
||||||
|
|
||||||
|
// If the node doesn't contain a MapNode (earth file), bail out:
|
||||||
|
auto mapNode = osgEarth::MapNode::get(node);
|
||||||
|
if (!mapNode)
|
||||||
|
return ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
auto sky = osgEarth::Util::SkyNode::create();
|
||||||
|
//auto parent = mapNode->getParent(0);
|
||||||
|
sky->addChild(mapNode);
|
||||||
|
//parent->addChild(sky);
|
||||||
|
//parent->removeChild(mapNode);
|
||||||
|
|
||||||
|
|
||||||
|
sky->setAtmosphereVisible(true);
|
||||||
|
sky->setSunVisible(true);
|
||||||
|
sky->setMoonVisible(true);
|
||||||
|
sky->setStarsVisible(true);
|
||||||
|
|
||||||
|
sky->setDateTime(osgEarth::DateTime(2024, 12, 24, 6));
|
||||||
|
//sky->setSimulationTimeTracksDateTime(true);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//#ifndef OSG_GL3_AVAILABLE
|
||||||
|
// // If your OSG is build with a GL2 profile, install our custom realize op
|
||||||
|
// // to get all the shaders working:
|
||||||
|
// _mViewer->setRealizeOperation(new osgEarth::GL3RealizeOperation());
|
||||||
|
//#endif
|
||||||
|
// _mViewer->realize();
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// _mViewer->setCameraManipulator(new osgEarth::Util::EarthManipulator());
|
||||||
|
|
||||||
|
osg::Camera* camera = new osg::Camera;
|
||||||
|
camera->setViewport(0, 0, this->width(), this->height());
|
||||||
|
//camera->setClearColor(osg::Vec4(0.9f, 0.9f, 1.f, 1.f));
|
||||||
|
float aspectRatio = static_cast<float>(this->width()) / static_cast<float>(this->height());
|
||||||
|
camera->setProjectionMatrixAsPerspective(30.f, aspectRatio, 1.f, 1000.f);
|
||||||
|
camera->setGraphicsContext(_mGraphicsWindow);
|
||||||
|
|
||||||
|
_mViewer->setCamera(camera);
|
||||||
|
//_mViewer->setSceneData(geode);
|
||||||
|
_mViewer->setSceneData(sky);
|
||||||
|
sky->attach(_mViewer);
|
||||||
|
osgGA::TrackballManipulator* manipulator = new osgGA::TrackballManipulator;
|
||||||
|
manipulator->setAllowThrow(false);
|
||||||
|
this->setMouseTracking(true);
|
||||||
|
_mViewer->setCameraManipulator(manipulator);
|
||||||
|
|
||||||
|
_mViewer->getDatabasePager()->setUnrefImageDataAfterApplyPolicy(true, false);
|
||||||
|
//_mViewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);
|
||||||
|
//_mViewer->setRealizeOperation(new osgEarth::GL3RealizeOperation());
|
||||||
|
//_mViewer->realize();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
virtual ~QtOSGWidget() {}
|
||||||
|
|
||||||
|
void setScale(qreal X, qreal Y) {
|
||||||
|
m_scaleX = X;
|
||||||
|
m_scaleY = Y;
|
||||||
|
this->resizeGL(this->width(), this->height());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
virtual void paintGL() {
|
||||||
|
_mViewer->frame();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void resizeGL(int width, int height) {
|
||||||
|
this->getEventQueue()->windowResize(this->x() * m_scaleX, this->y() * m_scaleY, width * m_scaleX, height * m_scaleY);
|
||||||
|
_mGraphicsWindow->resized(this->x() * m_scaleX, this->y() * m_scaleY, width * m_scaleX, height * m_scaleY);
|
||||||
|
osg::Camera* camera = _mViewer->getCamera();
|
||||||
|
camera->setViewport(0, 0, this->width() * m_scaleX, this->height() * m_scaleY);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void initializeGL() {
|
||||||
|
//osg::Geode* geode = dynamic_cast<osg::Geode*>(_mViewer->getSceneData());
|
||||||
|
//osg::StateSet* stateSet = geode->getOrCreateStateSet();
|
||||||
|
//osg::Material* material = new osg::Material;
|
||||||
|
//material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
|
||||||
|
//stateSet->setAttributeAndModes(material, osg::StateAttribute::ON);
|
||||||
|
//stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
|
||||||
|
|
||||||
|
// osg::ref_ptr<osg::Node> node = osgDB::readNodeFile("D:/Project/DYT/Tool/TritonSample/TritonSample/triton.earth");
|
||||||
|
// if (!node.valid())
|
||||||
|
// return ;
|
||||||
|
//
|
||||||
|
// // If the node doesn't contain a MapNode (earth file), bail out:
|
||||||
|
// auto mapNode = osgEarth::MapNode::get(node);
|
||||||
|
// if (!mapNode)
|
||||||
|
// return ;
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// auto sky = osgEarth::SkyNode::create();
|
||||||
|
// //auto parent = mapNode->getParent(0);
|
||||||
|
// sky->addChild(mapNode);
|
||||||
|
// //parent->addChild(sky);
|
||||||
|
// //parent->removeChild(mapNode);
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// sky->setAtmosphereVisible(true);
|
||||||
|
// sky->setSunVisible(true);
|
||||||
|
// sky->setMoonVisible(true);
|
||||||
|
// sky->setStarsVisible(true);
|
||||||
|
//
|
||||||
|
// sky->setDateTime(osgEarth::DateTime(2024, 12, 24, 6));
|
||||||
|
// sky->setSimulationTimeTracksDateTime(true);
|
||||||
|
//
|
||||||
|
// _mViewer->setSceneData(sky);
|
||||||
|
//
|
||||||
|
//#ifndef OSG_GL3_AVAILABLE
|
||||||
|
// // If your OSG is build with a GL2 profile, install our custom realize op
|
||||||
|
// // to get all the shaders working:
|
||||||
|
// _mViewer->setRealizeOperation(new osgEarth::GL3RealizeOperation());
|
||||||
|
//#endif
|
||||||
|
// _mViewer->realize();
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// _mViewer->setCameraManipulator(new osgEarth::Util::EarthManipulator());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void mouseMoveEvent(QMouseEvent* event) {
|
||||||
|
this->getEventQueue()->mouseMotion(event->x() * m_scaleX, event->y() * m_scaleY);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void mousePressEvent(QMouseEvent* event) {
|
||||||
|
unsigned int button = 0;
|
||||||
|
switch (event->button()) {
|
||||||
|
case Qt::LeftButton:
|
||||||
|
button = 1;
|
||||||
|
break;
|
||||||
|
case Qt::MiddleButton:
|
||||||
|
button = 2;
|
||||||
|
break;
|
||||||
|
case Qt::RightButton:
|
||||||
|
button = 3;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this->getEventQueue()->mouseButtonPress(event->x() * m_scaleX, event->y() * m_scaleY, button);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void mouseReleaseEvent(QMouseEvent* event) {
|
||||||
|
unsigned int button = 0;
|
||||||
|
switch (event->button()) {
|
||||||
|
case Qt::LeftButton:
|
||||||
|
button = 1;
|
||||||
|
break;
|
||||||
|
case Qt::MiddleButton:
|
||||||
|
button = 2;
|
||||||
|
break;
|
||||||
|
case Qt::RightButton:
|
||||||
|
button = 3;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this->getEventQueue()->mouseButtonRelease(event->x() * m_scaleX, event->y() * m_scaleY, button);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void wheelEvent(QWheelEvent* event) {
|
||||||
|
int delta = event->delta();
|
||||||
|
osgGA::GUIEventAdapter::ScrollingMotion motion = delta > 0 ?
|
||||||
|
osgGA::GUIEventAdapter::SCROLL_UP : osgGA::GUIEventAdapter::SCROLL_DOWN;
|
||||||
|
this->getEventQueue()->mouseScroll(motion);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool event(QEvent* event) {
|
||||||
|
bool handled = QOpenGLWidget::event(event);
|
||||||
|
this->update();
|
||||||
|
return handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
osgGA::EventQueue* getEventQueue() const {
|
||||||
|
osgGA::EventQueue* eventQueue = _mGraphicsWindow->getEventQueue();
|
||||||
|
return eventQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::ref_ptr<osgViewer::GraphicsWindowEmbedded> _mGraphicsWindow;
|
||||||
|
osg::ref_ptr<osgViewer::Viewer> _mViewer;
|
||||||
|
qreal m_scaleX, m_scaleY;
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
QApplication qapp(argc, argv);
|
||||||
|
OSGEnv::init();
|
||||||
|
|
||||||
|
QMainWindow window;
|
||||||
|
QtOSGWidget* widget = new QtOSGWidget(1, 1, &window);
|
||||||
|
window.setCentralWidget(widget);
|
||||||
|
window.show();
|
||||||
|
|
||||||
|
return qapp.exec();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <osgViewer/Viewer>
|
||||||
|
#include <osgDB/FileNameUtils>
|
||||||
|
#include <osgDB/ReadFile>
|
||||||
|
#include <osgEarth/NodeUtils>
|
||||||
|
#include <osgEarth/LineDrawable>
|
||||||
|
#include <osgEarth/Registry>
|
||||||
|
#include <osgEarthUtil/EarthManipulator>
|
||||||
|
#include <osgEarthUtil/ExampleResources>
|
||||||
|
#include <osgEarthUtil/Controls>
|
||||||
|
#include <osgEarthTriton/TritonAPIWrapper>
|
||||||
|
#include <osgEarthTriton/TritonCallback>
|
||||||
|
#include <osgEarthTriton/TritonOptions>
|
||||||
|
#include <osgEarthTriton/TritonLayer>
|
||||||
|
#include <osgEarthAnnotation/AnnotationLayer>
|
||||||
|
#include <osgEarthAnnotation/PlaceNode>
|
||||||
|
#include <osgEarthAnnotation/GeoPositionNode>
|
||||||
|
|
||||||
|
#define LC "[osgearth_triton] "
|
||||||
|
|
||||||
|
using namespace osgEarth;
|
||||||
|
using namespace osgEarth::Util;
|
||||||
|
using namespace osgEarth::Triton;
|
||||||
|
using namespace osgEarth::Annotation;
|
||||||
|
namespace ui = osgEarth::Util::Controls;
|
||||||
|
|
||||||
|
struct Settings {
|
||||||
|
optional<double> chop;
|
||||||
|
optional<double> seaState;
|
||||||
|
optional<float> alpha;
|
||||||
|
osg::observer_ptr<TritonLayer> tritonLayer;
|
||||||
|
|
||||||
|
void apply(Environment& env, Ocean& ocean) {
|
||||||
|
if (chop.isSet()) {
|
||||||
|
ocean.SetChoppiness(chop.get());
|
||||||
|
chop.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seaState.isSet()) {
|
||||||
|
env.SimulateSeaState(seaState.get(), 0.0);
|
||||||
|
seaState.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::ref_ptr<TritonLayer> layer;
|
||||||
|
if (alpha.isSet() && tritonLayer.lock(layer)) {
|
||||||
|
layer->setOpacity(alpha.value());
|
||||||
|
alpha.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class TritonCallback : public osgEarth::Triton::Callback {
|
||||||
|
public:
|
||||||
|
TritonCallback(Settings& settings) : _settings(settings) {}
|
||||||
|
|
||||||
|
void onInitialize(Environment& env, Ocean& ocean) {
|
||||||
|
//todo
|
||||||
|
}
|
||||||
|
|
||||||
|
void onDrawOcean(Environment& env, Ocean& ocean) {
|
||||||
|
_settings.apply(env, ocean);
|
||||||
|
}
|
||||||
|
|
||||||
|
Settings& _settings;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct App {
|
||||||
|
App() {
|
||||||
|
tritonLayer = NULL;
|
||||||
|
map = NULL;
|
||||||
|
const double lon = -118.5406, lat = 32.7838;
|
||||||
|
|
||||||
|
anchor.set(
|
||||||
|
SpatialReference::get("wgs84"), lon, lat, 0.0,
|
||||||
|
ALTMODE_ABSOLUTE);
|
||||||
|
|
||||||
|
isect = new Triton::TritonIntersections();
|
||||||
|
}
|
||||||
|
|
||||||
|
Map* map;
|
||||||
|
TritonLayer* tritonLayer;
|
||||||
|
Settings settings;
|
||||||
|
osg::ref_ptr<Triton::TritonIntersections> isect;
|
||||||
|
AnnotationLayer* labels;
|
||||||
|
AnnotationLayer* normals;
|
||||||
|
LineDrawable* normalDrawable;
|
||||||
|
GeoPoint anchor;
|
||||||
|
|
||||||
|
void addTriton() {
|
||||||
|
// Create TritonNode from TritonOptions
|
||||||
|
osgEarth::Triton::TritonOptions tritonOptions;
|
||||||
|
tritonOptions.user() = "my_user_name";
|
||||||
|
tritonOptions.licenseCode() = "my_license_code";
|
||||||
|
tritonOptions.maxAltitude() = 100000;
|
||||||
|
tritonOptions.useHeightMap() = true;
|
||||||
|
|
||||||
|
const char* ev_t = ::getenv("TRITON_PATH");
|
||||||
|
if (ev_t) {
|
||||||
|
tritonOptions.resourcePath() = osgDB::concatPaths(
|
||||||
|
std::string(ev_t),
|
||||||
|
"Resources");
|
||||||
|
|
||||||
|
OE_INFO << LC
|
||||||
|
<< "Setting resource path to << " << tritonOptions.resourcePath().get()
|
||||||
|
<< std::endl;
|
||||||
|
} else {
|
||||||
|
OE_WARN << LC
|
||||||
|
<< "No resource path! Triton might not initialize properly. "
|
||||||
|
<< "Consider setting the TRITON_PATH environment variable."
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
tritonLayer = new TritonLayer(tritonOptions, new TritonCallback(settings));
|
||||||
|
map->addLayer(tritonLayer);
|
||||||
|
settings.tritonLayer = tritonLayer;
|
||||||
|
|
||||||
|
tritonLayer->addIntersections(isect.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeTriton() {
|
||||||
|
if (tritonLayer)
|
||||||
|
map->removeLayer(tritonLayer);
|
||||||
|
tritonLayer = 0L;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addBuoyancyTest(osg::Node* model) {
|
||||||
|
//labels = new AnnotationLayer();
|
||||||
|
//map->addLayer(labels);
|
||||||
|
|
||||||
|
normals = new AnnotationLayer();
|
||||||
|
map->addLayer(normals);
|
||||||
|
|
||||||
|
// geometry for a unit normal vector
|
||||||
|
normalDrawable = new LineDrawable(GL_LINES);
|
||||||
|
normalDrawable->setColor(osg::Vec4(1, 1, 0, 1));
|
||||||
|
normalDrawable->pushVertex(osg::Vec3(0, 0, 0));
|
||||||
|
normalDrawable->pushVertex(osg::Vec3(0, 0, 10));
|
||||||
|
normalDrawable->pushVertex(osg::Vec3(-2, 0, 0.5));
|
||||||
|
normalDrawable->pushVertex(osg::Vec3(2, 0, 0.5));
|
||||||
|
normalDrawable->pushVertex(osg::Vec3(0, -2, 0.5));
|
||||||
|
normalDrawable->pushVertex(osg::Vec3(0, 2, 0.5));
|
||||||
|
normalDrawable->finish();
|
||||||
|
|
||||||
|
// a single shared anchor point for the intersection set:
|
||||||
|
isect->setAnchor(anchor);
|
||||||
|
|
||||||
|
// generate a bunch of local points around the anchor:
|
||||||
|
for (int x = -50; x <= 50; x += 25) {
|
||||||
|
for (int y = -50; y <= 50; y += 25) {
|
||||||
|
isect->addLocalPoint(osg::Vec3d(x, y, 0));
|
||||||
|
|
||||||
|
// a label communicating the wave height:
|
||||||
|
//PlaceNode* label = new PlaceNode();
|
||||||
|
//label->setDynamic(true);
|
||||||
|
//label->setPosition(anchor);
|
||||||
|
//label->setIconImage(image);
|
||||||
|
//label->setText("-");
|
||||||
|
//labels->getGroup()->addChild(label);
|
||||||
|
|
||||||
|
// a normal vector and optional model:
|
||||||
|
GeoPositionNode* normal = new GeoPositionNode();
|
||||||
|
normal->setDynamic(true);
|
||||||
|
normal->getPositionAttitudeTransform()->addChild(normalDrawable);
|
||||||
|
if (model)
|
||||||
|
normal->getPositionAttitudeTransform()->addChild(model);
|
||||||
|
normal->setPosition(anchor);
|
||||||
|
normals->getGroup()->addChild(normal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//ScreenSpaceLayout::setDeclutteringEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateBuoyancyTest() {
|
||||||
|
for (unsigned i = 0; i < isect->getHeights().size(); ++i) {
|
||||||
|
osg::Vec3d local = isect->getInput()[i];
|
||||||
|
local.z() = isect->getHeights()[i];
|
||||||
|
|
||||||
|
//PlaceNode* label = dynamic_cast<PlaceNode*>(labels->getGroup()->getChild(i));
|
||||||
|
//label->getPositionAttitudeTransform()->setPosition(local);
|
||||||
|
//label->setText(Stringify()<<std::setprecision(2)<<local.z());
|
||||||
|
|
||||||
|
GeoPositionNode* normalNode = dynamic_cast<GeoPositionNode*>(normals->getGroup()->getChild(i));
|
||||||
|
normalNode->getPositionAttitudeTransform()->setPosition(local);
|
||||||
|
osg::Quat q;
|
||||||
|
q.makeRotate(osg::Vec3d(0, 0, 1), isect->getNormals()[i]);
|
||||||
|
normalNode->getPositionAttitudeTransform()->setAttitude(q);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
App s_app;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T> struct Set : public ui::ControlEventHandler {
|
||||||
|
optional<T>& _var;
|
||||||
|
Set(optional<T>& var) : _var(var) {}
|
||||||
|
void onValueChanged(ui::Control*, double value) {
|
||||||
|
_var = value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Toggle : public ui::ControlEventHandler {
|
||||||
|
void onValueChanged(ui::Control*, bool value) {
|
||||||
|
if (s_app.tritonLayer)
|
||||||
|
s_app.removeTriton();
|
||||||
|
else
|
||||||
|
s_app.addTriton();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Container* createUI() {
|
||||||
|
VBox* box = new VBox();
|
||||||
|
box->setBackColor(0, 0, 0, 0.5);
|
||||||
|
Grid* grid = box->addControl(new Grid());
|
||||||
|
int r = 0;
|
||||||
|
grid->setControl(0, r, new LabelControl("Chop"));
|
||||||
|
grid->setControl(1, r, new HSliderControl(0, 3, 0, new Set<double>(s_app.settings.chop)));
|
||||||
|
++r;
|
||||||
|
grid->setControl(0, r, new LabelControl("Sea State"));
|
||||||
|
grid->setControl(1, r, new HSliderControl(0, 12, 5, new Set<double>(s_app.settings.seaState)));
|
||||||
|
++r;
|
||||||
|
grid->setControl(0, r, new LabelControl("Alpha"));
|
||||||
|
grid->setControl(1, r, new HSliderControl(0, 1.0, 1.0, new Set<float>(s_app.settings.alpha)));
|
||||||
|
++r;
|
||||||
|
grid->setControl(0, r, new LabelControl("Toggle"));
|
||||||
|
grid->setControl(1, r, new CheckBoxControl(true, new Toggle()));
|
||||||
|
|
||||||
|
grid->getControl(1, r - 1)->setHorizFill(true, 200);
|
||||||
|
|
||||||
|
return box;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
usage(const char* name) {
|
||||||
|
OE_DEBUG
|
||||||
|
<< "\nUsage: " << name << " file.earth" << std::endl
|
||||||
|
<< osgEarth::Util::MapNodeHelper().usage() << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char** argv) {
|
||||||
|
osg::ArgumentParser arguments(&argc, argv);
|
||||||
|
|
||||||
|
// help?
|
||||||
|
if (arguments.read("--help"))
|
||||||
|
return usage(argv[0]);
|
||||||
|
|
||||||
|
//osg::Node* model = 0L;
|
||||||
|
std::string filename = "D:/Project/DYT/Tool/TritonSample/TritonSample/triton.earth";
|
||||||
|
osg::ref_ptr<osg::Node> node = osgDB::readNodeFile(filename);
|
||||||
|
//if (arguments.read("--model", filename)) {
|
||||||
|
// model = osgDB::readRefNodeFile(filename).release();
|
||||||
|
// Registry::shaderGenerator().run(model);
|
||||||
|
//}
|
||||||
|
osg::ref_ptr<MapNode> mapNode = MapNode::get(node.get());
|
||||||
|
|
||||||
|
|
||||||
|
// create a viewer:
|
||||||
|
osgViewer::Viewer viewer(arguments);
|
||||||
|
|
||||||
|
// Tell the database pager to not modify the unref settings
|
||||||
|
viewer.getDatabasePager()->setUnrefImageDataAfterApplyPolicy(false, false);
|
||||||
|
|
||||||
|
// install our default manipulator (do this before calling load)
|
||||||
|
EarthManipulator* manip = new EarthManipulator();
|
||||||
|
viewer.setCameraManipulator(manip);
|
||||||
|
|
||||||
|
// load an earth file, and support all or our example command-line options
|
||||||
|
// and earth file <external> tags
|
||||||
|
//osg::Group* node = osgEarth::Util::MapNodeHelper().load(arguments, &viewer, createUI());
|
||||||
|
osg::Group* root = new osg::Group();
|
||||||
|
root->addChild(node);
|
||||||
|
if (root) {
|
||||||
|
viewer.getCamera()->setNearFarRatio(0.00002);
|
||||||
|
viewer.getCamera()->setSmallFeatureCullingPixelSize(-1.0f);
|
||||||
|
|
||||||
|
viewer.setSceneData(node);
|
||||||
|
|
||||||
|
s_app.map = MapNode::get(node)->getMap();
|
||||||
|
|
||||||
|
s_app.addTriton();
|
||||||
|
//s_app.addBuoyancyTest(model);
|
||||||
|
|
||||||
|
// Zoom the camera to our area of interest:
|
||||||
|
Viewpoint vp;
|
||||||
|
vp.heading() = 25.0f;
|
||||||
|
vp.pitch() = -25;
|
||||||
|
vp.range() = 400.0;
|
||||||
|
vp.focalPoint() = s_app.anchor;
|
||||||
|
manip->setViewpoint(vp);
|
||||||
|
|
||||||
|
#ifdef OSG_GL3_AVAILABLE
|
||||||
|
if (viewer) {
|
||||||
|
viewer->setRealizeOperation(new GL3RealizeOperation());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
while (!viewer.done()) {
|
||||||
|
viewer.frame();
|
||||||
|
s_app.updateBuoyancyTest();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return usage(argv[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 527 B |
Binary file not shown.
Before Width: | Height: | Size: 1.1 KiB |
@ -7,7 +7,7 @@
|
|||||||
#include <osg/LightSource>
|
#include <osg/LightSource>
|
||||||
#include <osgDB/ReadFile>
|
#include <osgDB/ReadFile>
|
||||||
#include <osgEarth/GLUtils>
|
#include <osgEarth/GLUtils>
|
||||||
#include <osgEarth/EarthManipulator>
|
#include <osgEarthUtil/EarthManipulator>
|
||||||
|
|
||||||
#include <osgShadow/ShadowedScene>
|
#include <osgShadow/ShadowedScene>
|
||||||
#include <osgShadow/ViewDependentShadowMap>
|
#include <osgShadow/ViewDependentShadowMap>
|
||||||
@ -21,8 +21,6 @@
|
|||||||
#include "viewer/OsgCameraManipulator.h"
|
#include "viewer/OsgCameraManipulator.h"
|
||||||
#include "scene/ScaleBarHandler.h"
|
#include "scene/ScaleBarHandler.h"
|
||||||
|
|
||||||
#include "effects/ConeWave.h"
|
|
||||||
|
|
||||||
const osgEarth::SpatialReference* g_srs_{ nullptr };
|
const osgEarth::SpatialReference* g_srs_{ nullptr };
|
||||||
|
|
||||||
|
|
||||||
@ -31,7 +29,6 @@ OEScene::OEScene() {
|
|||||||
const std::string& basePath = RecourceHelper::Get().GetBasePath().toStdString();
|
const std::string& basePath = RecourceHelper::Get().GetBasePath().toStdString();
|
||||||
pathList.push_back(basePath + "/resources/earth/");
|
pathList.push_back(basePath + "/resources/earth/");
|
||||||
pathList.push_back(basePath + "/resources/textures/");
|
pathList.push_back(basePath + "/resources/textures/");
|
||||||
root_ = new osg::Group;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -43,8 +40,12 @@ void OEScene::InitEventHandle(class OsgView* view) {
|
|||||||
|
|
||||||
//view->GetView()->addEventHandler(new osgEarth::Util::EarthManipulator());
|
//view->GetView()->addEventHandler(new osgEarth::Util::EarthManipulator());
|
||||||
|
|
||||||
view->GetView()->addEventHandler(new osgViewer::HelpHandler);
|
InitEventHandle(view->GetView());
|
||||||
view->GetView()->addEventHandler(new osgViewer::StatsHandler);
|
}
|
||||||
|
|
||||||
|
void OEScene::InitEventHandle(osgViewer::View* view) {
|
||||||
|
view->addEventHandler(new osgViewer::HelpHandler);
|
||||||
|
view->addEventHandler(new osgViewer::StatsHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OEScene::AttachView(OsgView* view) {
|
void OEScene::AttachView(OsgView* view) {
|
||||||
@ -53,37 +54,51 @@ void OEScene::AttachView(OsgView* view) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::Node* rootNode = view->GetView()->getSceneData();
|
|
||||||
if (nullptr != rootNode) {
|
//AttachView(view->GetView());
|
||||||
int parantCount = rootNode->getNumParents();
|
|
||||||
for (int i = 0; i < parantCount; ++i) {
|
|
||||||
rootNode->getParent(i)->removeChild(rootNode);
|
|
||||||
}
|
|
||||||
root_->addChild(rootNode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
view->GetView()->setSceneData(root_);
|
void OEScene::AttachView(osgViewer::Viewer* view) {
|
||||||
|
|
||||||
earthRootNode_ = osgDB::readNodeFile("triton.earth");
|
earthRootNode_ = osgDB::readNodeFile("triton.earth");
|
||||||
dyt_check(nullptr != earthRootNode_);
|
if (!earthRootNode_) {
|
||||||
|
LOG_ERROR("read earth node(triton.earth) failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
logarithmicDepthBuffer_ = std::make_unique<osgEarth::Util::LogarithmicDepthBuffer>();
|
logarithmicDepthBuffer_ = std::make_unique<osgEarth::Util::LogarithmicDepthBuffer>();
|
||||||
|
|
||||||
earthMapNode_ = osgEarth::MapNode::get(earthRootNode_);
|
earthMapNode_ = osgEarth::MapNode::get(earthRootNode_);
|
||||||
dyt_check(nullptr != earthMapNode_);
|
|
||||||
LOG_INFO("earth map node get success: {}", earthMapNode_.valid());
|
LOG_INFO("earth map node get success: {}", earthMapNode_.valid());
|
||||||
g_srs_ = earthMapNode_->getMapSRS();
|
|
||||||
|
|
||||||
entityRoot_ = new osg::Group;
|
entityRoot_ = new osg::Group;
|
||||||
root_->addChild(entityRoot_);
|
if (earthMapNode_) {
|
||||||
|
earthMapNode_->addChild(entityRoot_);
|
||||||
|
g_srs_ = earthMapNode_->getMapSRS();
|
||||||
|
dyt_check(nullptr != g_srs_);
|
||||||
|
}
|
||||||
|
|
||||||
skyDome_ = osgEarth::SkyNode::create();
|
skyDome_ = osgEarth::Util::SkyNode::create();
|
||||||
if (!earthMapNode_) {
|
if (!earthMapNode_) {
|
||||||
LOG_WARN("eart map node is nullptr");
|
LOG_WARN("eart map node is nullptr");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
root_->addChild(skyDome_);
|
|
||||||
skyDome_->addChild(earthMapNode_);
|
skyDome_->addChild(earthMapNode_);
|
||||||
skyDome_->attach(view->GetView());
|
|
||||||
|
osg::Node* node = view->getSceneData();
|
||||||
|
if (nullptr == node) {
|
||||||
|
LOG_INFO("view scene data is nullptr, root valid:{}", skyDome_.valid());
|
||||||
|
view->setSceneData(skyDome_);
|
||||||
|
} else {
|
||||||
|
osg::Group* group = node->asGroup();
|
||||||
|
if (nullptr != group) {
|
||||||
|
LOG_INFO("node is group");
|
||||||
|
group->addChild(skyDome_);
|
||||||
|
} else {
|
||||||
|
LOG_INFO("node is not group");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
skyDome_->attach(view);
|
||||||
|
|
||||||
skyDome_->setAtmosphereVisible(true);
|
skyDome_->setAtmosphereVisible(true);
|
||||||
skyDome_->setSunVisible(true);
|
skyDome_->setSunVisible(true);
|
||||||
@ -91,21 +106,9 @@ void OEScene::AttachView(OsgView* view) {
|
|||||||
skyDome_->setStarsVisible(true);
|
skyDome_->setStarsVisible(true);
|
||||||
|
|
||||||
skyDome_->setDateTime(osgEarth::DateTime(2024, 12, 24, 3));
|
skyDome_->setDateTime(osgEarth::DateTime(2024, 12, 24, 3));
|
||||||
skyDome_->setSimulationTimeTracksDateTime(true);
|
//skyDome_->setSimulationTimeTracksDateTime(true);
|
||||||
|
|
||||||
logarithmicDepthBuffer_->install(view->GetView()->getCamera());
|
logarithmicDepthBuffer_->install(view->getCamera());
|
||||||
|
|
||||||
ConeWave* coneWave = new ConeWave;
|
|
||||||
|
|
||||||
osgEarth::GeoTransform *geo = new osgEarth::GeoTransform;
|
|
||||||
entityRoot_->addChild(geo);
|
|
||||||
|
|
||||||
osgEarth::GeoPoint pos(g_srs_, 120.000000,25.000000,600.000000);
|
|
||||||
geo->setPosition(pos);
|
|
||||||
coneWave->createWaveBeamCone(geo, 45, 6000, osg::Vec4(1.0, 0.0, 0.0, 0.3),
|
|
||||||
osg::Vec4(1.0, 1.0, 0.0, 0.3), 30);
|
|
||||||
osg::MatrixTransform* mt =coneWave->getWaveBeamCone();
|
|
||||||
geo->addChild(mt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OEScene::DetachView(OsgView* view) {
|
void OEScene::DetachView(OsgView* view) {
|
||||||
@ -157,7 +160,7 @@ osg::ref_ptr<osg::TextureCubeMap> OEScene::LoadCubeMapTextures(const std::string
|
|||||||
}
|
}
|
||||||
|
|
||||||
osg::Group* OEScene::GetData() {
|
osg::Group* OEScene::GetData() {
|
||||||
return root_;
|
return earthMapNode_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,9 +4,10 @@
|
|||||||
#include <osg/TextureCubeMap>
|
#include <osg/TextureCubeMap>
|
||||||
|
|
||||||
#include <osgText/Text>
|
#include <osgText/Text>
|
||||||
#include <osgEarth/ModelNode>
|
#include <osgEarth/MapNode>
|
||||||
#include <osgEarth/Sky>
|
#include <osgEarthUtil/Sky>
|
||||||
#include <osgEarth/LogarithmicDepthBuffer>
|
#include <osgEarthUtil/LogarithmicDepthBuffer>
|
||||||
|
#include <osgViewer/Viewer>
|
||||||
|
|
||||||
//#include "scene/SkyDome.h"
|
//#include "scene/SkyDome.h"
|
||||||
|
|
||||||
@ -20,7 +21,9 @@ class OEScene : public osg::Referenced {
|
|||||||
public:
|
public:
|
||||||
OEScene();
|
OEScene();
|
||||||
void InitEventHandle(OsgView* view);
|
void InitEventHandle(OsgView* view);
|
||||||
|
void InitEventHandle(osgViewer::View* view);
|
||||||
void AttachView(OsgView* view);
|
void AttachView(OsgView* view);
|
||||||
|
void AttachView(osgViewer::Viewer* view);
|
||||||
void DetachView(OsgView* view);
|
void DetachView(OsgView* view);
|
||||||
|
|
||||||
osg::ref_ptr<osg::TextureCubeMap> LoadCubeMapTextures(const std::string& dir);
|
osg::ref_ptr<osg::TextureCubeMap> LoadCubeMapTextures(const std::string& dir);
|
||||||
@ -33,7 +36,7 @@ public:
|
|||||||
osg::Group* GetData();
|
osg::Group* GetData();
|
||||||
|
|
||||||
inline osg::Group* GetScene(void) {
|
inline osg::Group* GetScene(void) {
|
||||||
return root_.get();
|
return earthMapNode_.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
osgEarth::MapNode* GetMapNode(void) const {
|
osgEarth::MapNode* GetMapNode(void) const {
|
||||||
@ -46,11 +49,10 @@ public:
|
|||||||
OESceneUI* GetOrCreateSceneUI();
|
OESceneUI* GetOrCreateSceneUI();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
osg::ref_ptr<osg::Group> root_;
|
|
||||||
osg::ref_ptr<osg::Node> earthRootNode_;
|
osg::ref_ptr<osg::Node> earthRootNode_;
|
||||||
osg::ref_ptr<osgEarth::MapNode> earthMapNode_;
|
osg::ref_ptr<osgEarth::MapNode> earthMapNode_;
|
||||||
osg::ref_ptr<osg::Group> entityRoot_;
|
osg::ref_ptr<osg::Group> entityRoot_;
|
||||||
osg::ref_ptr<osgEarth::SkyNode> skyDome_;
|
osg::ref_ptr<osgEarth::Util::SkyNode> skyDome_;
|
||||||
std::unique_ptr<osgEarth::Util::LogarithmicDepthBuffer> logarithmicDepthBuffer_;
|
std::unique_ptr<osgEarth::Util::LogarithmicDepthBuffer> logarithmicDepthBuffer_;
|
||||||
osg::ref_ptr<OESceneUI> sceneUI_;
|
osg::ref_ptr<OESceneUI> sceneUI_;
|
||||||
};
|
};
|
||||||
|
@ -1,114 +0,0 @@
|
|||||||
/* -*-c++-*- */
|
|
||||||
/* osgEarth - Geospatial SDK for OpenSceneGraph
|
|
||||||
* Copyright 2020 Pelican Mapping
|
|
||||||
* http://osgearth.org
|
|
||||||
*
|
|
||||||
* osgEarth is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
#include "TritonAPIWrapper.h"
|
|
||||||
#include <Triton.h>
|
|
||||||
|
|
||||||
#define LC "[TritonAPI] "
|
|
||||||
|
|
||||||
using namespace osgEarth::Triton;
|
|
||||||
|
|
||||||
#define SETGET_EXPLICIT(NS, SETTER, GETTER, TYPE) \
|
|
||||||
void NS :: SETTER (TYPE value) { HANDLE-> SETTER (value); } \
|
|
||||||
TYPE NS :: GETTER () const { return HANDLE -> GETTER (); }
|
|
||||||
|
|
||||||
#define SETGET(NS, FUNC, TYPE) \
|
|
||||||
SETGET_EXPLICIT(NS, Set##FUNC, Get##FUNC, TYPE)
|
|
||||||
|
|
||||||
#define TOVEC3(X) ::Triton::Vector3(X.x(),X.y(),X.z())
|
|
||||||
#define FROMVEC3(X) osg::Vec3(X.x,X.y,X.z)
|
|
||||||
|
|
||||||
//................................
|
|
||||||
#undef HANDLE
|
|
||||||
#define HANDLE ((::Triton::BreakingWavesParameters*)_handle)
|
|
||||||
|
|
||||||
SETGET(BreakingWavesParameters, Steepness, float);
|
|
||||||
SETGET(BreakingWavesParameters, Wavelength, float);
|
|
||||||
|
|
||||||
//................................
|
|
||||||
#undef HANDLE
|
|
||||||
#define HANDLE ((::Triton::Environment*)_handle)
|
|
||||||
|
|
||||||
BreakingWavesParameters Environment::GetBreakingWavesParameters() const {
|
|
||||||
return BreakingWavesParameters((uintptr_t)&HANDLE->GetBreakingWavesParameters());
|
|
||||||
}
|
|
||||||
void Environment::SetDirectionalLight(const osg::Vec3& dir, const osg::Vec3& color) {
|
|
||||||
HANDLE->SetDirectionalLight(TOVEC3(dir), TOVEC3(color));
|
|
||||||
}
|
|
||||||
osg::Vec3 Environment::GetLightDirection() const {
|
|
||||||
const ::Triton::Vector3& v = HANDLE->GetLightDirection();
|
|
||||||
return FROMVEC3(v);
|
|
||||||
}
|
|
||||||
osg::Vec3 Environment::GetDirectionalLightColor() const {
|
|
||||||
const ::Triton::Vector3& v = HANDLE->GetDirectionalLightColor();
|
|
||||||
return FROMVEC3(v);
|
|
||||||
}
|
|
||||||
void Environment::SetAmbientLight(const osg::Vec3& color) {
|
|
||||||
HANDLE->SetAmbientLight(TOVEC3(color));
|
|
||||||
}
|
|
||||||
osg::Vec3 Environment::GetAmbientLightColor() const {
|
|
||||||
const ::Triton::Vector3& v = HANDLE->GetAmbientLightColor();
|
|
||||||
return FROMVEC3(v);
|
|
||||||
}
|
|
||||||
void Environment::SimulateSeaState(double bscale, double winddir) {
|
|
||||||
HANDLE->SimulateSeaState(bscale, winddir);
|
|
||||||
}
|
|
||||||
void Environment::SetAboveWaterVisibility(double visibility, osg::Vec3 fog_color) {
|
|
||||||
HANDLE->SetAboveWaterVisibility(visibility, TOVEC3(fog_color));
|
|
||||||
}
|
|
||||||
void Environment::GetAboveWaterVisibility(double &visibility, osg::Vec3 &fog_color) const {
|
|
||||||
::Triton::Vector3 triton_fog_col;
|
|
||||||
HANDLE->GetAboveWaterVisibility(visibility, triton_fog_col);
|
|
||||||
fog_color = FROMVEC3(triton_fog_col);
|
|
||||||
}
|
|
||||||
void Environment::SetEnvironmentMap(GLuint cubeMap, const osg::Matrixd &textureMatrix) {
|
|
||||||
::Triton::Matrix3 triton_tex_mat(
|
|
||||||
textureMatrix(0, 0), textureMatrix(0, 1), textureMatrix(0, 2),
|
|
||||||
textureMatrix(1, 0), textureMatrix(1, 1), textureMatrix(1, 2),
|
|
||||||
textureMatrix(2, 0), textureMatrix(2, 1), textureMatrix(2, 2));
|
|
||||||
::Triton::TextureHandle tex_handle = (::Triton::TextureHandle)(static_cast<size_t>(cubeMap));
|
|
||||||
HANDLE->SetEnvironmentMap(tex_handle, triton_tex_mat);
|
|
||||||
}
|
|
||||||
GLuint Environment::GetEnvironmentMap() const {
|
|
||||||
::Triton::TextureHandle tex_handle = HANDLE->GetEnvironmentMap();
|
|
||||||
return static_cast<GLuint>((size_t)tex_handle);
|
|
||||||
}
|
|
||||||
osg::Matrixd Environment::GetEnvironmentMapMatrix() const {
|
|
||||||
::Triton::Matrix3 m = HANDLE->GetEnvironmentMapMatrix();
|
|
||||||
osg::Matrixd env_map_matrix(
|
|
||||||
m.elem[0][0], m.elem[0][1], m.elem[0][2], 0,
|
|
||||||
m.elem[1][0], m.elem[1][1], m.elem[1][2], 0,
|
|
||||||
m.elem[2][0], m.elem[2][1], m.elem[2][2], 0,
|
|
||||||
0, 0, 0, 1);
|
|
||||||
return env_map_matrix;
|
|
||||||
}
|
|
||||||
SETGET(Environment, SunIntensity, float);
|
|
||||||
|
|
||||||
//................................
|
|
||||||
#undef HANDLE
|
|
||||||
#define HANDLE ((::Triton::Ocean*)_handle)
|
|
||||||
|
|
||||||
SETGET(Ocean, Choppiness, float);
|
|
||||||
//SETGET(Ocean, MaximumWavePeriod, double);
|
|
||||||
SETGET_EXPLICIT(Ocean, EnableSpray, SprayEnabled, bool);
|
|
||||||
SETGET_EXPLICIT(Ocean, EnableGodRays, GodRaysEnabled, bool);
|
|
||||||
SETGET(Ocean, GodRaysFade, float);
|
|
||||||
|
|
||||||
void Ocean::EnableWireframe(bool wireframe) { HANDLE->EnableWireframe(wireframe); }
|
|
||||||
void Ocean::SetQuality(OceanQuality value) { HANDLE->SetQuality((::Triton::OceanQuality)value); }
|
|
||||||
OceanQuality Ocean::GetQuality() const { return (OceanQuality)HANDLE->GetQuality(); }
|
|
@ -1,112 +0,0 @@
|
|||||||
/* -*-c++-*- */
|
|
||||||
/* osgEarth - Geospatial SDK for OpenSceneGraph
|
|
||||||
* Copyright 2020 Pelican Mapping
|
|
||||||
* http://osgearth.org
|
|
||||||
*
|
|
||||||
* osgEarth is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
#ifndef OSGEARTH_TRITON_API_WRAPPER
|
|
||||||
#define OSGEARTH_TRITON_API_WRAPPER 1
|
|
||||||
|
|
||||||
//#include "Common"
|
|
||||||
#include <osg/Vec3>
|
|
||||||
#include <osg/Matrix>
|
|
||||||
#include <osg/GL>
|
|
||||||
#include <stdint.h> // for uintptr_t
|
|
||||||
|
|
||||||
namespace osgEarth {
|
|
||||||
namespace Util {
|
|
||||||
class OceanNode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace osgEarth { namespace Triton
|
|
||||||
{
|
|
||||||
/** Enumerates the ocean quality settings used in Ocean::SetQuality() */
|
|
||||||
enum OceanQuality {
|
|
||||||
GOOD,
|
|
||||||
BETTER,
|
|
||||||
BEST
|
|
||||||
};
|
|
||||||
|
|
||||||
class BreakingWavesParameters
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void SetSteepness(float);
|
|
||||||
float GetSteepness() const;
|
|
||||||
|
|
||||||
void SetWavelength(float);
|
|
||||||
float GetWavelength() const;
|
|
||||||
|
|
||||||
public:
|
|
||||||
BreakingWavesParameters(uintptr_t handle) : _handle(handle) { }
|
|
||||||
uintptr_t _handle;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Environment
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void SetDirectionalLight(const osg::Vec3& dir, const osg::Vec3& color);
|
|
||||||
osg::Vec3 GetLightDirection() const;
|
|
||||||
osg::Vec3 GetDirectionalLightColor() const;
|
|
||||||
|
|
||||||
void SetAmbientLight(const osg::Vec3& color);
|
|
||||||
osg::Vec3 GetAmbientLightColor() const;
|
|
||||||
|
|
||||||
void SetSunIntensity(float intensity);
|
|
||||||
float GetSunIntensity() const;
|
|
||||||
|
|
||||||
BreakingWavesParameters GetBreakingWavesParameters() const;
|
|
||||||
|
|
||||||
void SimulateSeaState(double bs, double winddir);
|
|
||||||
|
|
||||||
void SetAboveWaterVisibility(double visibility, osg::Vec3 fog_color);
|
|
||||||
void GetAboveWaterVisibility(double &visibility, osg::Vec3 &fog_color) const;
|
|
||||||
|
|
||||||
void SetEnvironmentMap(GLuint id, const osg::Matrixd &textureMatrix = osg::Matrixd());
|
|
||||||
GLuint GetEnvironmentMap() const;
|
|
||||||
osg::Matrixd GetEnvironmentMapMatrix() const;
|
|
||||||
public:
|
|
||||||
Environment(uintptr_t handle) : _handle(handle) { }
|
|
||||||
uintptr_t _handle;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Ocean
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void SetChoppiness(float);
|
|
||||||
float GetChoppiness() const;
|
|
||||||
|
|
||||||
void EnableWireframe(bool wireframe);
|
|
||||||
|
|
||||||
void SetQuality(OceanQuality value);
|
|
||||||
OceanQuality GetQuality() const;
|
|
||||||
|
|
||||||
void EnableSpray(bool enabled);
|
|
||||||
bool SprayEnabled() const;
|
|
||||||
|
|
||||||
void EnableGodRays(bool enabled);
|
|
||||||
bool GodRaysEnabled() const;
|
|
||||||
|
|
||||||
void SetGodRaysFade(float fadeAmount);
|
|
||||||
float GetGodRaysFade() const;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Ocean(uintptr_t handle) : _handle(handle) { }
|
|
||||||
uintptr_t _handle;
|
|
||||||
};
|
|
||||||
|
|
||||||
} } // namespace osgEarth::SilverLining
|
|
||||||
|
|
||||||
#endif // OSGEARTH_TRITON_API_WRAPPER
|
|
@ -1,39 +0,0 @@
|
|||||||
/* -*-c++-*- */
|
|
||||||
/* osgEarth - Geospatial SDK for OpenSceneGraph
|
|
||||||
* Copyright 2020 Pelican Mapping
|
|
||||||
* http://osgearth.org
|
|
||||||
*
|
|
||||||
* osgEarth is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
#ifndef OSGEARTH_TRITON_CALLBACK_H
|
|
||||||
#define OSGEARTH_TRITON_CALLBACK_H 1
|
|
||||||
|
|
||||||
#include "TritonAPIWrapper.h"
|
|
||||||
|
|
||||||
namespace osgEarth { namespace Triton
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* A callback that lets you execute code in the proper context.
|
|
||||||
*/
|
|
||||||
class Callback : public osg::Referenced
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual void onInitialize(Environment& env, Ocean& ocean) { }
|
|
||||||
|
|
||||||
virtual void onDrawOcean(Environment& env, Ocean& ocean) { }
|
|
||||||
};
|
|
||||||
|
|
||||||
} } // namespace osgEarth::Triton
|
|
||||||
|
|
||||||
#endif // OSGEARTH_TRITON_CALLBACK_H
|
|
@ -1,229 +0,0 @@
|
|||||||
/* -*-c++-*- */
|
|
||||||
/* osgEarth - Geospatial SDK for OpenSceneGraph
|
|
||||||
* Copyright 2020 Pelican Mapping
|
|
||||||
* http://osgearth.org
|
|
||||||
*
|
|
||||||
* osgEarth is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
#include "TritonContext.h"
|
|
||||||
#include <osg/GLExtensions>
|
|
||||||
#include <osg/Math>
|
|
||||||
#include <osgDB/FileNameUtils>
|
|
||||||
#include <osgEarth/SpatialReference>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <QApplication>
|
|
||||||
|
|
||||||
#define LC "[TritonContext] "
|
|
||||||
|
|
||||||
using namespace osgEarth::Triton;
|
|
||||||
|
|
||||||
|
|
||||||
TritonContext::TritonContext(const TritonLayer::Options& options) :
|
|
||||||
_options ( options ),
|
|
||||||
_initAttempted ( false ),
|
|
||||||
_initFailed ( false ),
|
|
||||||
_resourceLoader ( 0L ),
|
|
||||||
_environment ( 0L ),
|
|
||||||
_environmentWrapper ( 0L ),
|
|
||||||
_ocean ( 0L ),
|
|
||||||
_oceanWrapper ( 0L )
|
|
||||||
{
|
|
||||||
//nop
|
|
||||||
}
|
|
||||||
|
|
||||||
TritonContext::~TritonContext()
|
|
||||||
{
|
|
||||||
if (_oceanWrapper)
|
|
||||||
delete _oceanWrapper;
|
|
||||||
|
|
||||||
if (_environmentWrapper)
|
|
||||||
delete _environmentWrapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TritonContext::setSRS(const osgEarth::SpatialReference* srs)
|
|
||||||
{
|
|
||||||
_srs = srs;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TritonContext::setCallback(Callback* callback)
|
|
||||||
{
|
|
||||||
_callback = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
TritonContext::passHeightMapToTriton() const
|
|
||||||
{
|
|
||||||
return _options.useHeightMap() == true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
TritonContext::getHeightMapSize() const
|
|
||||||
{
|
|
||||||
return osg::clampBetween(_options.heightMapSize().get(), 64u, 2048u);
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string&
|
|
||||||
TritonContext::getMaskLayerName() const
|
|
||||||
{
|
|
||||||
return _options.maskLayer().externalLayerName().get();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TritonContext::initialize(osg::RenderInfo& renderInfo)
|
|
||||||
{
|
|
||||||
if ( !_initAttempted && !_initFailed )
|
|
||||||
{
|
|
||||||
// lock/double-check:
|
|
||||||
std::lock_guard<std::mutex> excl(_initMutex);
|
|
||||||
if ( !_initAttempted && !_initFailed )
|
|
||||||
{
|
|
||||||
_initAttempted = true;
|
|
||||||
|
|
||||||
std::string resourcePath = _options.resourcePath().get();
|
|
||||||
if (resourcePath.empty() && ::getenv("TRITON_PATH"))
|
|
||||||
{
|
|
||||||
resourcePath = osgDB::concatPaths(::getenv("TRITON_PATH"), "Resources");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( resourcePath.empty() )
|
|
||||||
{
|
|
||||||
const QString dir = QString("%1/TritonResources").arg(QApplication::applicationDirPath());
|
|
||||||
resourcePath = dir.toStdString();
|
|
||||||
}
|
|
||||||
|
|
||||||
_resourceLoader = new ::Triton::ResourceLoader(resourcePath.c_str());
|
|
||||||
|
|
||||||
_environment = new ::Triton::Environment();
|
|
||||||
|
|
||||||
_environmentWrapper = new Environment((uintptr_t)_environment);
|
|
||||||
|
|
||||||
_environment->SetLicenseCode(
|
|
||||||
_options.user()->c_str(),
|
|
||||||
_options.licenseCode()->c_str() );
|
|
||||||
|
|
||||||
// "WGS84" is used to represent any ellipsoid.
|
|
||||||
::Triton::CoordinateSystem cs =
|
|
||||||
_srs->isGeographic() ? ::Triton::WGS84_ZUP :
|
|
||||||
::Triton::FLAT_ZUP;
|
|
||||||
|
|
||||||
// Set the ellipsoid to match the one in our map's SRS.
|
|
||||||
if ( _srs->isGeographic() )
|
|
||||||
{
|
|
||||||
const Ellipsoid& ellipsoid = _srs->getEllipsoid();
|
|
||||||
|
|
||||||
std::string eqRadius = Stringify() << ellipsoid.getRadiusEquator();
|
|
||||||
std::string poRadius = Stringify() << ellipsoid.getRadiusPolar();
|
|
||||||
|
|
||||||
_environment->SetConfigOption( "equatorial-earth-radius-meters", eqRadius.c_str() );
|
|
||||||
_environment->SetConfigOption( "polar-earth-radius-meters", poRadius.c_str() );
|
|
||||||
}
|
|
||||||
|
|
||||||
//_environment->SetConfigOption("avoid-opengl-stalls", "yes");
|
|
||||||
//_environment->SetConfigOption("fft-texture-update-frame-delayed", "yes");
|
|
||||||
|
|
||||||
float openGLVersion = osg::getGLVersionNumber();
|
|
||||||
enum ::Triton::Renderer tritonOpenGlVersion = ::Triton::OPENGL_2_0;
|
|
||||||
#ifndef OSG_GL_FIXED_FUNCTION_AVAILABLE
|
|
||||||
if( openGLVersion >= 4.1 )
|
|
||||||
tritonOpenGlVersion = ::Triton::OPENGL_4_1;
|
|
||||||
else if( openGLVersion >= 4.0 )
|
|
||||||
tritonOpenGlVersion = ::Triton::OPENGL_4_0;
|
|
||||||
else if( openGLVersion >= 3.2 )
|
|
||||||
tritonOpenGlVersion = ::Triton::OPENGL_3_2;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
::Triton::EnvironmentError err = _environment->Initialize(
|
|
||||||
cs,
|
|
||||||
tritonOpenGlVersion,
|
|
||||||
_resourceLoader );
|
|
||||||
|
|
||||||
if ( err == ::Triton::SUCCEEDED )
|
|
||||||
{
|
|
||||||
::Triton::WindFetch wf;
|
|
||||||
wf.SetWind( 10.0, 0.0 );
|
|
||||||
_environment->AddWindFetch( wf );
|
|
||||||
|
|
||||||
_ocean = ::Triton::Ocean::Create(
|
|
||||||
_environment,
|
|
||||||
::Triton::JONSWAP,
|
|
||||||
true ); // enableHeightTests - activated GetHeight for intersections
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( _ocean )
|
|
||||||
{
|
|
||||||
_oceanWrapper = new Ocean((uintptr_t)_ocean);
|
|
||||||
|
|
||||||
// fire init callback if available
|
|
||||||
if (_callback.valid())
|
|
||||||
{
|
|
||||||
_callback->onInitialize(getEnvironmentWrapper(), getOceanWrapper());
|
|
||||||
}
|
|
||||||
|
|
||||||
OE_INFO << LC << "Triton initialized OK!" << std::endl;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_initFailed = true;
|
|
||||||
OE_WARN << LC << "Triton initialization failed- err=" << err << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
TritonContext::intersect(const osg::Vec3d& start, const osg::Vec3d& dir, float& out_height, osg::Vec3f& out_normal) const
|
|
||||||
{
|
|
||||||
::Triton::Vector3 p(start.ptr());
|
|
||||||
::Triton::Vector3 d(dir.ptr());
|
|
||||||
::Triton::Vector3 normal;
|
|
||||||
bool ok = _ocean->GetHeight(p, d, out_height, normal);
|
|
||||||
out_normal.set(normal.x, normal.y, normal.z);
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TritonContext::resizeGLObjectBuffers(unsigned maxSize)
|
|
||||||
{
|
|
||||||
osg::Object::resizeGLObjectBuffers(maxSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TritonContext::releaseGLObjects(osg::State* state) const
|
|
||||||
{
|
|
||||||
osg::Object::releaseGLObjects(state);
|
|
||||||
|
|
||||||
OE_DEBUG << LC << "Triton shutting down - releasing GL resources\n";
|
|
||||||
if (state)
|
|
||||||
{
|
|
||||||
if ( _ocean )
|
|
||||||
{
|
|
||||||
delete _ocean;
|
|
||||||
_ocean = 0L;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( _environment )
|
|
||||||
{
|
|
||||||
delete _environment;
|
|
||||||
_environment = 0L;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( _resourceLoader )
|
|
||||||
{
|
|
||||||
delete _resourceLoader;
|
|
||||||
_resourceLoader = 0L;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,115 +0,0 @@
|
|||||||
/* -*-c++-*- */
|
|
||||||
/* osgEarth - Geospatial SDK for OpenSceneGraph
|
|
||||||
* Copyright 2020 Pelican Mapping
|
|
||||||
* http://osgearth.org
|
|
||||||
*
|
|
||||||
* osgEarth is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
#ifndef OSGEARTH_TRITON_CONTEXT_H
|
|
||||||
#define OSGEARTH_TRITON_CONTEXT_H
|
|
||||||
|
|
||||||
#include <Triton.h>
|
|
||||||
#include <Camera.h> // Triton
|
|
||||||
#include "TritonLayer.h"
|
|
||||||
#include "TritonAPIWrapper.h"
|
|
||||||
#include "TritonCallback.h"
|
|
||||||
#include <osg/Referenced>
|
|
||||||
#include <osg/Light>
|
|
||||||
#include <osgEarth/Threading>
|
|
||||||
|
|
||||||
namespace osgEarth {
|
|
||||||
class SpatialReference;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace osgEarth { namespace Triton
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Contains all the Triton SDK handles.
|
|
||||||
*/
|
|
||||||
class TritonContext : public osg::Object
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
META_Object(osgEarth, TritonContext);
|
|
||||||
|
|
||||||
TritonContext(const TritonLayer::Options&);
|
|
||||||
|
|
||||||
/** Sets the spatial reference system of the map */
|
|
||||||
void setSRS(const osgEarth::SpatialReference* srs);
|
|
||||||
|
|
||||||
/** Sets the user callback */
|
|
||||||
void setCallback(Callback* callback);
|
|
||||||
Callback* getCallback() const { return _callback.get(); }
|
|
||||||
|
|
||||||
public: // accessors
|
|
||||||
|
|
||||||
bool ready() const { return _initAttempted && !_initFailed; }
|
|
||||||
|
|
||||||
/** Spatial reference of the map */
|
|
||||||
const osgEarth::SpatialReference* getSRS() const { return _srs.get(); }
|
|
||||||
|
|
||||||
void initialize(osg::RenderInfo& renderInfo);
|
|
||||||
|
|
||||||
bool intersect(const osg::Vec3d& start, const osg::Vec3d& dir, float& out_height, osg::Vec3f& out_normal) const;
|
|
||||||
|
|
||||||
::Triton::Environment* getEnvironment() { return _environment; }
|
|
||||||
Environment& getEnvironmentWrapper() const { return *_environmentWrapper; }
|
|
||||||
|
|
||||||
::Triton::Ocean* getOcean() { return _ocean; }
|
|
||||||
Ocean& getOceanWrapper() const { return *_oceanWrapper; }
|
|
||||||
|
|
||||||
bool passHeightMapToTriton() const;
|
|
||||||
|
|
||||||
int getHeightMapSize() const;
|
|
||||||
|
|
||||||
const std::string& getMaskLayerName() const;
|
|
||||||
|
|
||||||
public: // osg::Object
|
|
||||||
|
|
||||||
void resizeGLObjectBuffers(unsigned maxSize);
|
|
||||||
|
|
||||||
/** If State is non-zero, this function releases any associated OpenGL objects for
|
|
||||||
* the specified graphics context. Otherwise, releases OpenGL objects
|
|
||||||
* for all graphics contexts. */
|
|
||||||
void releaseGLObjects(osg::State* state) const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
virtual ~TritonContext();
|
|
||||||
|
|
||||||
// hidden ctors (for META_Object)
|
|
||||||
TritonContext() { }
|
|
||||||
TritonContext(const TritonContext&, const osg::CopyOp&) { }
|
|
||||||
|
|
||||||
private:
|
|
||||||
TritonLayer::Options _options;
|
|
||||||
|
|
||||||
bool _initAttempted;
|
|
||||||
bool _initFailed;
|
|
||||||
std::mutex _initMutex;
|
|
||||||
|
|
||||||
osg::ref_ptr<const osgEarth::SpatialReference> _srs;
|
|
||||||
|
|
||||||
mutable ::Triton::ResourceLoader* _resourceLoader;
|
|
||||||
mutable ::Triton::Environment* _environment;
|
|
||||||
mutable ::Triton::Ocean* _ocean;
|
|
||||||
|
|
||||||
Environment* _environmentWrapper;
|
|
||||||
Ocean* _oceanWrapper;
|
|
||||||
|
|
||||||
osg::ref_ptr<Callback> _callback;
|
|
||||||
};
|
|
||||||
|
|
||||||
} } // namespace osgEarth::Triton
|
|
||||||
|
|
||||||
#endif // OSGEARTH_TRITON_CONTEXT_H
|
|
@ -1,330 +0,0 @@
|
|||||||
/* -*-c++-*- */
|
|
||||||
/* osgEarth - Geospatial SDK for OpenSceneGraph
|
|
||||||
* Copyright 2020 Pelican Mapping
|
|
||||||
* http://osgearth.org
|
|
||||||
*
|
|
||||||
* osgEarth is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
#include "TritonContext.h"
|
|
||||||
#include "TritonDrawable.h"
|
|
||||||
#include "TritonHeightMap.h"
|
|
||||||
#include <Version.h>
|
|
||||||
#include <osg/MatrixTransform>
|
|
||||||
#include <osg/FrameBufferObject>
|
|
||||||
#include <osg/Depth>
|
|
||||||
|
|
||||||
#include <osgEarth/SpatialReference>
|
|
||||||
#include <osgEarth/VirtualProgram>
|
|
||||||
#include <osgEarth/MapNode>
|
|
||||||
#include <osgEarth/TerrainEngineNode>
|
|
||||||
#include <osgEarth/Random>
|
|
||||||
#include <osgEarth/GLUtils>
|
|
||||||
|
|
||||||
#undef LC
|
|
||||||
#define LC "[TritonDrawable] "
|
|
||||||
|
|
||||||
//#define DEBUG_HEIGHTMAP
|
|
||||||
|
|
||||||
using namespace osgEarth::Triton;
|
|
||||||
|
|
||||||
|
|
||||||
TritonDrawable::TritonDrawable(TritonContext* TRITON) :
|
|
||||||
_TRITON(TRITON)
|
|
||||||
{
|
|
||||||
// call this to ensure draw() gets called every frame.
|
|
||||||
setSupportsDisplayList( false );
|
|
||||||
setUseVertexBufferObjects( false );
|
|
||||||
|
|
||||||
// dynamic variance prevents update/cull overlap when drawing this
|
|
||||||
setDataVariance( osg::Object::DYNAMIC );
|
|
||||||
|
|
||||||
_wgs84 = SpatialReference::get("wgs84");
|
|
||||||
_ecef = _wgs84->getGeocentricSRS();
|
|
||||||
}
|
|
||||||
|
|
||||||
TritonDrawable::~TritonDrawable()
|
|
||||||
{
|
|
||||||
//nop
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TritonDrawable::setMaskLayer(const osgEarth::ImageLayer* layer)
|
|
||||||
{
|
|
||||||
_maskLayer = layer;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TritonDrawable::setHeightMapGenerator(TritonHeightMap* value)
|
|
||||||
{
|
|
||||||
_heightMapGenerator = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TritonDrawable::setPlanarReflectionMap(osg::Texture2D* map)
|
|
||||||
{
|
|
||||||
_planarReflectionMap = map;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TritonDrawable::setPlanarReflectionProjection(osg::RefMatrix* proj)
|
|
||||||
{
|
|
||||||
_planarReflectionProjection = proj;
|
|
||||||
}
|
|
||||||
|
|
||||||
osg::BoundingBox
|
|
||||||
TritonDrawable::computeBoundingBox() const
|
|
||||||
{
|
|
||||||
return osg::BoundingBox();
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
// Wrapper around Ocean->GetShaderObject() to account for API changes from Triton 3.x to 4.x
|
|
||||||
GLint
|
|
||||||
getOceanShader(::Triton::Ocean* ocean, ::Triton::Shaders shaderProgram, void* context, const ::Triton::Camera* camera)
|
|
||||||
{
|
|
||||||
#if (TRITON_MAJOR_VERSION >= 4)
|
|
||||||
return (GLint)ocean->GetShaderObject( shaderProgram, context, camera );
|
|
||||||
#else
|
|
||||||
return (GLint)ocean->GetShaderObject( shaderProgram );
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TritonDrawable::drawImplementation(osg::RenderInfo& renderInfo) const
|
|
||||||
{
|
|
||||||
OE_GL_ZONE;
|
|
||||||
|
|
||||||
osg::State* state = renderInfo.getState();
|
|
||||||
|
|
||||||
state->disableAllVertexArrays();
|
|
||||||
|
|
||||||
_TRITON->initialize( renderInfo );
|
|
||||||
if ( !_TRITON->ready() )
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Configure the height map generator.
|
|
||||||
// If configuration fails, attempt to continue without a heightmap.
|
|
||||||
if (_heightMapGenerator.valid())
|
|
||||||
{
|
|
||||||
bool configOK = _heightMapGenerator->configure(_TRITON->getHeightMapSize(), *state);
|
|
||||||
if (configOK == false)
|
|
||||||
{
|
|
||||||
_heightMapGenerator = 0L;
|
|
||||||
OE_WARN << LC << "Failed to establish a legal FBO configuration; disabling height map generator!" << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
::Triton::Environment* environment = _TRITON->getEnvironment();
|
|
||||||
|
|
||||||
// Find or create the Triton camera for this OSG camera:
|
|
||||||
CameraLocal& local = _local.get(renderInfo.getCurrentCamera());
|
|
||||||
if (local._tritonCam == 0L)
|
|
||||||
{
|
|
||||||
local._tritonCam = environment->CreateCamera();
|
|
||||||
local._tritonCam->SetName(renderInfo.getCurrentCamera()->getName().c_str());
|
|
||||||
}
|
|
||||||
::Triton::Camera* tritonCam = local._tritonCam;
|
|
||||||
|
|
||||||
auto cid = GLUtils::getSharedContextID(*state);
|
|
||||||
osgEarth::NativeProgramAdapterCollection& adapters = _adapters[cid];
|
|
||||||
if ( adapters.empty() )
|
|
||||||
{
|
|
||||||
OE_DEBUG << LC << "Initializing Triton program adapters" << std::endl;
|
|
||||||
const std::vector<const char*> prefixes = { "osg_", "oe_" };
|
|
||||||
adapters.push_back( new osgEarth::NativeProgramAdapter(state, getOceanShader(_TRITON->getOcean(), ::Triton::WATER_SURFACE, 0L, tritonCam), prefixes, "WATER_SURFACE"));
|
|
||||||
adapters.push_back( new osgEarth::NativeProgramAdapter(state, getOceanShader(_TRITON->getOcean(), ::Triton::WATER_SURFACE_PATCH, 0L, tritonCam), prefixes, "WATER_SURFACE_PATCH"));
|
|
||||||
adapters.push_back( new osgEarth::NativeProgramAdapter(state, getOceanShader(_TRITON->getOcean(), ::Triton::GOD_RAYS, 0L, tritonCam), prefixes, "GOD_RAYS"));
|
|
||||||
adapters.push_back( new osgEarth::NativeProgramAdapter(state, getOceanShader(_TRITON->getOcean(), ::Triton::SPRAY_PARTICLES, 0L, tritonCam), prefixes, "SPRAY_PARTICLES"));
|
|
||||||
adapters.push_back( new osgEarth::NativeProgramAdapter(state, getOceanShader(_TRITON->getOcean(), ::Triton::WAKE_SPRAY_PARTICLES, 0L, tritonCam), prefixes, "WAKE_SPRAY_PARTICLES"));
|
|
||||||
#if 0
|
|
||||||
// In older Triton (3.91), this line causes problems in Core profile and prevents the ocean from drawing. In newer Triton (4.01),
|
|
||||||
// this line causes a crash because there is no context passed in to GetShaderObject(), resulting in multiple NULL references.
|
|
||||||
adapters.push_back( new osgEarth::NativeProgramAdapter(state, getOceanShader(_TRITON->getOcean(), ::Triton::WATER_DECALS, 0L, tritonCam), prefixes, "WATER_DECALS"));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
adapters.apply( state );
|
|
||||||
|
|
||||||
|
|
||||||
// Pass the final view and projection matrices into Triton.
|
|
||||||
if ( environment )
|
|
||||||
{
|
|
||||||
tritonCam->SetCameraMatrix(state->getModelViewMatrix().ptr());
|
|
||||||
tritonCam->SetProjectionMatrix(state->getProjectionMatrix().ptr());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate sea level based on the camera:
|
|
||||||
if (_verticalDatum.valid())
|
|
||||||
{
|
|
||||||
GeoPoint cam(_ecef, osg::Vec3d(0, 0, 0) * state->getInitialInverseViewMatrix(), ALTMODE_ABSOLUTE);
|
|
||||||
cam.transformInPlace(_wgs84);
|
|
||||||
auto msl = _verticalDatum->hae2msl(cam.y(), cam.x(), 0.0);
|
|
||||||
environment->SetSeaLevel(-msl);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_heightMapGenerator.valid())
|
|
||||||
{
|
|
||||||
GLint texName;
|
|
||||||
osg::Matrix hMM;
|
|
||||||
if (_heightMapGenerator->getTextureAndMatrix(renderInfo, texName, hMM))
|
|
||||||
{
|
|
||||||
// copy the OSG matrix to a Triton matrix:
|
|
||||||
::Triton::Matrix4 texMat(
|
|
||||||
hMM(0, 0), hMM(0, 1), hMM(0, 2), hMM(0, 3),
|
|
||||||
hMM(1, 0), hMM(1, 1), hMM(1, 2), hMM(1, 3),
|
|
||||||
hMM(2, 0), hMM(2, 1), hMM(2, 2), hMM(2, 3),
|
|
||||||
hMM(3, 0), hMM(3, 1), hMM(3, 2), hMM(3, 3));
|
|
||||||
|
|
||||||
environment->SetHeightMap((::Triton::TextureHandle)texName, texMat, 0L, tritonCam);
|
|
||||||
|
|
||||||
//OE_DEBUG << LC << "Updating height map, FN=" << renderInfo.getState()->getFrameStamp()->getFrameNumber() << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
state->dirtyAllVertexArrays();
|
|
||||||
|
|
||||||
// Now light and draw the ocean:
|
|
||||||
if ( environment )
|
|
||||||
{
|
|
||||||
// User pre-draw callback:
|
|
||||||
if (_TRITON->getCallback())
|
|
||||||
{
|
|
||||||
_TRITON->getCallback()->onDrawOcean(
|
|
||||||
_TRITON->getEnvironmentWrapper(),
|
|
||||||
_TRITON->getOceanWrapper());
|
|
||||||
}
|
|
||||||
|
|
||||||
osg::Light* light = renderInfo.getView() ? renderInfo.getView()->getLight() : NULL;
|
|
||||||
|
|
||||||
// This is the light attached to View so there are no transformations above..
|
|
||||||
// But in general case you would need to accumulate all transforms above the light into this matrix
|
|
||||||
osg::Matrix lightLocalToWorldMatrix = osg::Matrix::identity();
|
|
||||||
|
|
||||||
// If you don't know where the sun lightsource is attached and don't know its local to world matrix you may use
|
|
||||||
// following elaborate scheme to grab the light source while drawing Triton ocean:
|
|
||||||
// - Install cull callback to catch CullVisitor and record pointer to its associated RenderStage
|
|
||||||
// I was hoping RenderStage can be found from renderInfo in drawImplementation but I didn't figure how ...
|
|
||||||
// - When TritonDrawable::drawImplementation is called all lights will be already applied to OpenGL
|
|
||||||
// then just find proper infinite directional light by scanning renderStage->PositionalStateContainer.
|
|
||||||
// - Note that we canot scan for the lights inside cull because they may not be traversed before Triton drawable
|
|
||||||
// - When you found interesting ligt source that can work as Sun, read its modelview matrix and lighting params
|
|
||||||
// Multiply light position by ( modelview * inverse camera view ) and pass this to Triton with lighting colors
|
|
||||||
|
|
||||||
if ( light && light->getPosition().w() == 0 )
|
|
||||||
{
|
|
||||||
osg::Vec4 ambient = light->getAmbient();
|
|
||||||
osg::Vec4 diffuse = light->getDiffuse();
|
|
||||||
osg::Vec4 position = light->getPosition();
|
|
||||||
|
|
||||||
// Compute light position/direction in the world
|
|
||||||
position = position * lightLocalToWorldMatrix;
|
|
||||||
|
|
||||||
// Diffuse direction and color
|
|
||||||
environment->SetDirectionalLight(
|
|
||||||
::Triton::Vector3( position[0], position[1], position[2] ),
|
|
||||||
::Triton::Vector3( diffuse[0], diffuse[1], diffuse[2] ) );
|
|
||||||
|
|
||||||
// Sun-based ambient value:
|
|
||||||
osg::Vec3d up = osg::Vec3d(0,0,0) * renderInfo.getCurrentCamera()->getInverseViewMatrix();
|
|
||||||
up.normalize();
|
|
||||||
osg::Vec3d pos3 = osg::Vec3d(position.x(), position.y(), position.z());
|
|
||||||
pos3.normalize();
|
|
||||||
float dot = osg::clampAbove(up*pos3, 0.0); dot*=dot;
|
|
||||||
float sunAmbient = (float)osg::clampBetween( dot, 0.0f, 0.88f );
|
|
||||||
float fa = osg::maximum(sunAmbient, ambient[0]);
|
|
||||||
|
|
||||||
// Ambient color based on the zenith color in the cube map
|
|
||||||
environment->SetAmbientLight( ::Triton::Vector3(fa, fa, fa) );
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
environment->SetDirectionalLight( ::Triton::Vector3(0,0,1), ::Triton::Vector3(1,1,1) );
|
|
||||||
environment->SetAmbientLight( ::Triton::Vector3(0.88f, 0.88f, 0.88f) );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( _cubeMap.valid() )
|
|
||||||
{
|
|
||||||
// Build transform from our cube map orientation space to native Triton orientation
|
|
||||||
// See worldToCubeMap function used in SkyBox to orient sky texture so that sky is up and earth is down
|
|
||||||
osg::Matrix m = osg::Matrix::rotate( osg::PI_2, osg::X_AXIS ); // = worldToCubeMap
|
|
||||||
|
|
||||||
::Triton::Matrix3 transformFromYUpToZUpCubeMapCoords(
|
|
||||||
m(0,0), m(0,1), m(0,2),
|
|
||||||
m(1,0), m(1,1), m(1,2),
|
|
||||||
m(2,0), m(2,1), m(2,2) );
|
|
||||||
|
|
||||||
// Grab the cube map from our sky box and give it to Triton to use as an _environment map
|
|
||||||
// GLenum texture = renderInfo.getState()->getLastAppliedTextureAttribute( _stage, osg::StateAttribute::TEXTURE );
|
|
||||||
environment->SetEnvironmentMap(
|
|
||||||
(::Triton::TextureHandle)_cubeMap->getTextureObject(cid)->id(),
|
|
||||||
transformFromYUpToZUpCubeMapCoords );
|
|
||||||
|
|
||||||
if( _planarReflectionMap.valid() && _planarReflectionProjection.valid() )
|
|
||||||
{
|
|
||||||
osg::Matrix & p = *_planarReflectionProjection;
|
|
||||||
|
|
||||||
::Triton::Matrix3 planarProjection(
|
|
||||||
p(0,0), p(0,1), p(0,2),
|
|
||||||
p(1,0), p(1,1), p(1,2),
|
|
||||||
p(2,0), p(2,1), p(2,2) );
|
|
||||||
|
|
||||||
environment->SetPlanarReflectionMap(
|
|
||||||
(::Triton::TextureHandle)_planarReflectionMap->getTextureObject(cid)->id(),
|
|
||||||
planarProjection,
|
|
||||||
0.125 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw the ocean for the current time sample
|
|
||||||
if ( _TRITON->getOcean() )
|
|
||||||
{
|
|
||||||
osg::GLExtensions* ext = osg::GLExtensions::Get(cid, true);
|
|
||||||
|
|
||||||
bool writeDepth = true;
|
|
||||||
const osg::Depth* depth = static_cast<const osg::Depth*>(state->getLastAppliedAttribute(osg::StateAttribute::DEPTH));
|
|
||||||
if (depth)
|
|
||||||
writeDepth = depth->getWriteMask();
|
|
||||||
|
|
||||||
double simTime = renderInfo.getView()->getFrameStamp()->getSimulationTime();
|
|
||||||
simTime = fmod(simTime, 86400.0);
|
|
||||||
|
|
||||||
_TRITON->getOcean()->Draw(
|
|
||||||
simTime,
|
|
||||||
writeDepth, // depth writes
|
|
||||||
true, // draw water
|
|
||||||
true, // draw particles
|
|
||||||
NULL, // optional context
|
|
||||||
tritonCam);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Put GL back in a state that won't confuse the OSG state tracking:
|
|
||||||
state->dirtyAllVertexArrays();
|
|
||||||
state->dirtyAllAttributes();
|
|
||||||
state->dirtyAllModes();
|
|
||||||
|
|
||||||
#ifndef OSG_GL_FIXED_FUNCTION_AVAILABLE
|
|
||||||
// Keep OSG from reapplying GL_LIGHTING on next state change after dirtyAllModes().
|
|
||||||
state->setModeValidity(GL_LIGHTING, false);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Keep an eye on this.
|
|
||||||
// I had to remove something similar in another module (Rex engine) because it was causing
|
|
||||||
// positional attributes (like clip planes) to re-apply with an incorrect MVM. -gw
|
|
||||||
state->apply();
|
|
||||||
}
|
|
@ -1,102 +0,0 @@
|
|||||||
/* -*-c++-*- */
|
|
||||||
/* osgEarth - Geospatial SDK for OpenSceneGraph
|
|
||||||
* Copyright 2020 Pelican Mapping
|
|
||||||
* http://osgearth.org
|
|
||||||
*
|
|
||||||
* osgEarth is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
#ifndef OSGEARTH_TRITON_DRAWABLE_H
|
|
||||||
#define OSGEARTH_TRITON_DRAWABLE_H
|
|
||||||
|
|
||||||
#include <osg/Drawable>
|
|
||||||
#include <osg/RenderInfo>
|
|
||||||
#include <osg/TextureCubeMap>
|
|
||||||
#include <osg/Version>
|
|
||||||
#include <osg/Texture2D>
|
|
||||||
#include <osg/buffered_value>
|
|
||||||
|
|
||||||
#include <osgEarth/Terrain>
|
|
||||||
#include <osgEarth/NativeProgramAdapter>
|
|
||||||
#include <osgEarth/ImageLayer>
|
|
||||||
#include <osgEarth/VerticalDatum>
|
|
||||||
|
|
||||||
const unsigned int TRITON_OCEAN_MASK = 0x4; // 0100
|
|
||||||
|
|
||||||
namespace osgEarth { namespace Triton
|
|
||||||
{
|
|
||||||
class TritonContext;
|
|
||||||
class TritonHeightMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom drawable for rendering the Triton ocean effects
|
|
||||||
*/
|
|
||||||
class TritonDrawable : public osg::Drawable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
TritonDrawable(TritonContext* TRITON);
|
|
||||||
|
|
||||||
//! Layer to use as an ocean rendering mask
|
|
||||||
void setMaskLayer(const osgEarth::ImageLayer* maskLayer);
|
|
||||||
|
|
||||||
//! Height map generator to use to mask out the ocean where the
|
|
||||||
//! terrain has positive elevation
|
|
||||||
void setHeightMapGenerator(TritonHeightMap* heightMap);
|
|
||||||
|
|
||||||
//! Vertical datum to use to calculate sea level
|
|
||||||
void setVerticalDatum(VerticalDatum* value) {
|
|
||||||
_verticalDatum = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Gets the Triton Camera associated with an osg Camera
|
|
||||||
::Triton::Camera* getTritonCam(const osg::Camera* cam) {
|
|
||||||
return _local.get(cam)._tritonCam;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setPlanarReflectionMap(osg::Texture2D* map);
|
|
||||||
|
|
||||||
void setPlanarReflectionProjection(osg::RefMatrix* proj);
|
|
||||||
|
|
||||||
public: // osg::Drawable
|
|
||||||
|
|
||||||
void drawImplementation(osg::RenderInfo& ri) const override;
|
|
||||||
|
|
||||||
osg::BoundingBox computeBoundingBox() const override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual ~TritonDrawable();
|
|
||||||
|
|
||||||
osg::observer_ptr<TritonContext> _TRITON;
|
|
||||||
osg::observer_ptr<const osgEarth::ImageLayer> _maskLayer;
|
|
||||||
osg::ref_ptr<osg::TextureCubeMap> _cubeMap;
|
|
||||||
|
|
||||||
osg::ref_ptr<osg::Texture2D> _planarReflectionMap;
|
|
||||||
osg::ref_ptr<osg::RefMatrix> _planarReflectionProjection;
|
|
||||||
|
|
||||||
mutable osg::ref_ptr<TritonHeightMap> _heightMapGenerator;
|
|
||||||
|
|
||||||
osg::ref_ptr<VerticalDatum> _verticalDatum;
|
|
||||||
osg::ref_ptr<const SpatialReference> _wgs84, _ecef;
|
|
||||||
|
|
||||||
mutable osg::buffered_object<osgEarth::NativeProgramAdapterCollection> _adapters;
|
|
||||||
|
|
||||||
struct CameraLocal
|
|
||||||
{
|
|
||||||
::Triton::Camera* _tritonCam = nullptr;
|
|
||||||
};
|
|
||||||
mutable PerObjectFastMap<const osg::Camera*, CameraLocal> _local;
|
|
||||||
};
|
|
||||||
|
|
||||||
} } // namespace osgEarth::Triton
|
|
||||||
|
|
||||||
#endif // OSGEARTH_TRITON_DRAWABLE_H
|
|
@ -1,434 +0,0 @@
|
|||||||
/* -*-c++-*- */
|
|
||||||
/* osgEarth - Geospatial SDK for OpenSceneGraph
|
|
||||||
* Copyright 2020 Pelican Mapping
|
|
||||||
* http://osgearth.org
|
|
||||||
*
|
|
||||||
* osgEarth is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
#include "TritonHeightMap.h"
|
|
||||||
#include "TritonContext.h"
|
|
||||||
#include <osgEarth/CullingUtils>
|
|
||||||
#include <osgEarth/VirtualProgram>
|
|
||||||
#include <osgEarth/TerrainEngineNode>
|
|
||||||
#include <osgEarth/Utils>
|
|
||||||
|
|
||||||
#define LC "[TritonHeightMap] "
|
|
||||||
|
|
||||||
using namespace osgEarth::Triton;
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
const char* vertexShader =
|
|
||||||
"#pragma import_defines(OE_TRITON_MASK_MATRIX);\n"
|
|
||||||
|
|
||||||
"// terrain SDK:\n"
|
|
||||||
"float oe_terrain_getElevation(); \n"
|
|
||||||
|
|
||||||
"out float oe_triton_elev;\n"
|
|
||||||
|
|
||||||
"#ifdef OE_TRITON_MASK_MATRIX\n"
|
|
||||||
"out vec2 maskCoords;\n"
|
|
||||||
"uniform mat4 OE_TRITON_MASK_MATRIX;\n"
|
|
||||||
"vec4 oe_layer_tilec;\n"
|
|
||||||
"#endif\n"
|
|
||||||
|
|
||||||
"void oe_triton_setupHeightMap(inout vec4 unused) \n"
|
|
||||||
"{ \n"
|
|
||||||
" oe_triton_elev = oe_terrain_getElevation(); \n"
|
|
||||||
"#ifdef OE_TRITON_MASK_MATRIX\n"
|
|
||||||
" maskCoords = (OE_TRITON_MASK_MATRIX * oe_layer_tilec).st;\n"
|
|
||||||
"#endif\n"
|
|
||||||
"} \n";
|
|
||||||
|
|
||||||
// The fragment shader simply takes the texture index that we generated
|
|
||||||
// in the vertex shader and does a texture lookup. In this case we're
|
|
||||||
// just wholesale replacing the color, so if the map had any existing
|
|
||||||
// imagery, this will overwrite it.
|
|
||||||
|
|
||||||
const char* fragmentShader =
|
|
||||||
"#pragma import_defines(OE_TRITON_MASK_SAMPLER);\n"
|
|
||||||
|
|
||||||
"in float oe_triton_elev;\n"
|
|
||||||
|
|
||||||
"#ifdef OE_TRITON_MASK_SAMPLER\n"
|
|
||||||
"in vec2 maskCoords;\n"
|
|
||||||
"uniform sampler2D OE_TRITON_MASK_SAMPLER;\n"
|
|
||||||
"#endif\n"
|
|
||||||
|
|
||||||
"out vec4 out_height; \n"
|
|
||||||
|
|
||||||
"void oe_triton_drawHeightMap(inout vec4 unused) \n"
|
|
||||||
"{ \n"
|
|
||||||
#ifdef DEBUG_HEIGHTMAP
|
|
||||||
// Map to black = -500m, white = +500m
|
|
||||||
" float nHeight = clamp(oe_triton_elev / 1000.0 + 0.5, 0.0, 1.0);\n"
|
|
||||||
#else
|
|
||||||
" float nHeight = oe_triton_elev;\n"
|
|
||||||
|
|
||||||
"#ifdef OE_TRITON_MASK_SAMPLER\n"
|
|
||||||
" float mask = texture(OE_TRITON_MASK_SAMPLER, maskCoords).a;\n"
|
|
||||||
" nHeight *= mask; \n"
|
|
||||||
"#endif\n"
|
|
||||||
|
|
||||||
#endif
|
|
||||||
" out_height = vec4( nHeight, 0.0, 0.0, 1.0 ); \n"
|
|
||||||
"} \n";
|
|
||||||
|
|
||||||
struct TerrainDirtyCallback : public osgEarth::TerrainCallback
|
|
||||||
{
|
|
||||||
osg::observer_ptr<TritonHeightMap> _hm;
|
|
||||||
TerrainDirtyCallback(TritonHeightMap* hm) : _hm(hm) { }
|
|
||||||
void onTileUpdate(const osgEarth::TileKey&, osg::Node*, osgEarth::TerrainCallbackContext&)
|
|
||||||
{
|
|
||||||
osg::ref_ptr<TritonHeightMap> hm;
|
|
||||||
if (_hm.lock(hm))
|
|
||||||
hm->dirty();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
TritonHeightMap::TritonHeightMap() :
|
|
||||||
_texSize(0u),
|
|
||||||
_internalFormat((GLint)0),
|
|
||||||
_sourceFormat((GLenum)0)
|
|
||||||
{
|
|
||||||
setCullingActive(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
TritonHeightMap::~TritonHeightMap()
|
|
||||||
{
|
|
||||||
osgEarth::TerrainEngineNode* t = dynamic_cast<osgEarth::TerrainEngineNode*>(_terrain.get());
|
|
||||||
if (t)
|
|
||||||
{
|
|
||||||
t->getTerrain()->removeTerrainCallback(static_cast<TerrainDirtyCallback*>(_terrainCallback.get()));
|
|
||||||
_terrainCallback = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TritonHeightMap::setTerrain(osg::Node* node)
|
|
||||||
{
|
|
||||||
_terrain = node;
|
|
||||||
|
|
||||||
osgEarth::TerrainEngineNode* t = dynamic_cast<osgEarth::TerrainEngineNode*>(node);
|
|
||||||
if (t)
|
|
||||||
{
|
|
||||||
TerrainDirtyCallback* cb = new TerrainDirtyCallback(this);
|
|
||||||
t->getTerrain()->addTerrainCallback(cb);
|
|
||||||
_terrainCallback = cb;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TritonHeightMap::setMaskLayer(const osgEarth::ImageLayer* layer)
|
|
||||||
{
|
|
||||||
_maskLayer = layer;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TritonHeightMap::SetDirty::operator()(CameraLocal& local)
|
|
||||||
{
|
|
||||||
local._mvpw.makeIdentity();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TritonHeightMap::dirty()
|
|
||||||
{
|
|
||||||
SetDirty setDirty;
|
|
||||||
_local.forEach(setDirty);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
TritonHeightMap::configure(unsigned texSize, osg::State& state)
|
|
||||||
{
|
|
||||||
bool result = true;
|
|
||||||
|
|
||||||
if (_texSize == 0u)
|
|
||||||
{
|
|
||||||
// first time through, single-lane and set up FBO parameters.
|
|
||||||
static std::mutex s_mutex;
|
|
||||||
std::lock_guard<std::mutex> lock(s_mutex);
|
|
||||||
|
|
||||||
if (_texSize == 0u)
|
|
||||||
{
|
|
||||||
_texSize = texSize;
|
|
||||||
if (!getBestFBOConfig(state, _internalFormat, _sourceFormat))
|
|
||||||
{
|
|
||||||
result = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
struct Format {
|
|
||||||
Format(GLint i, GLenum s, const std::string& n) :
|
|
||||||
internalFormat(i), sourceFormat(s), name(n) { }
|
|
||||||
GLint internalFormat;
|
|
||||||
GLenum sourceFormat;
|
|
||||||
std::string name;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
TritonHeightMap::getBestFBOConfig(osg::State& state, GLint& out_internalFormat, GLenum& out_sourceFormat)
|
|
||||||
{
|
|
||||||
#ifdef GL_LUMINANCE_FLOAT16_ATI
|
|
||||||
# define GL_LUMINANCE_FLOAT16_ATI 0x881E
|
|
||||||
#endif
|
|
||||||
|
|
||||||
std::vector<Format> formats;
|
|
||||||
|
|
||||||
#ifdef GL_R16F
|
|
||||||
formats.push_back(Format(GL_R16F, GL_RED, "GL_R16F"));
|
|
||||||
#endif
|
|
||||||
#ifdef GL_LUMINANCE16F_ARB
|
|
||||||
formats.push_back(Format(GL_LUMINANCE16F_ARB, GL_LUMINANCE, "GL_LUMINANCE16F_ARB"));
|
|
||||||
#endif
|
|
||||||
#ifdef GL_LUMINANCE_FLOAT16_ATI
|
|
||||||
formats.push_back(Format(GL_LUMINANCE_FLOAT16_ATI, GL_LUMINANCE, "GL_LUMINANCE_FLOAT16_ATI"));
|
|
||||||
#endif
|
|
||||||
#ifdef GL_R32F
|
|
||||||
formats.push_back(Format(GL_R32F, GL_RED, "GL_R32F"));
|
|
||||||
#endif
|
|
||||||
#ifdef GL_LUMINANCE32F_ARB
|
|
||||||
formats.push_back(Format(GL_LUMINANCE32F_ARB, GL_LUMINANCE, "GL_LUMINANCE32F_ARB"));
|
|
||||||
#endif
|
|
||||||
#ifdef GL_RGB16F_ARB
|
|
||||||
formats.push_back(Format(GL_RGB16F_ARB, GL_RGB, "GL_RGB16F_ARB"));
|
|
||||||
#endif
|
|
||||||
#ifdef GL_RGBA16F_ARB
|
|
||||||
formats.push_back(Format(GL_RGBA16F_ARB, GL_RGBA, "GL_RGBA16F_ARB"));
|
|
||||||
#endif
|
|
||||||
#ifdef GL_RGB32F_ARB
|
|
||||||
formats.push_back(Format(GL_RGB32F_ARB, GL_RGB, "GL_RGB32F_ARB"));
|
|
||||||
#endif
|
|
||||||
#ifdef GL_RGBA32F_ARB
|
|
||||||
formats.push_back(Format(GL_RGBA32F_ARB, GL_RGBA, "GL_RGBA32F_ARB"));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
auto cid = GLUtils::getSharedContextID(state);
|
|
||||||
osg::GLExtensions* ext = osg::GLExtensions::Get(cid, true);
|
|
||||||
|
|
||||||
osg::State::CheckForGLErrors check = state.getCheckForGLErrors();
|
|
||||||
state.setCheckForGLErrors(state.NEVER_CHECK_GL_ERRORS);
|
|
||||||
|
|
||||||
bool found = false;
|
|
||||||
|
|
||||||
for(int i=0; i<formats.size() && !found; ++i)
|
|
||||||
{
|
|
||||||
const Format& format = formats[i];
|
|
||||||
|
|
||||||
osg::ref_ptr<osg::Texture2D> tex = new osg::Texture2D();
|
|
||||||
tex->setTextureSize(1, 1);
|
|
||||||
tex->setInternalFormat( format.internalFormat );
|
|
||||||
tex->setSourceFormat ( format.sourceFormat );
|
|
||||||
|
|
||||||
osg::ref_ptr<osg::FrameBufferObject> fbo = new osg::FrameBufferObject();
|
|
||||||
fbo->setAttachment( osg::Camera::COLOR_BUFFER0, osg::FrameBufferAttachment(tex.get()) );
|
|
||||||
|
|
||||||
fbo->apply( state );
|
|
||||||
|
|
||||||
GLenum status = ext->glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
|
|
||||||
|
|
||||||
fbo->releaseGLObjects( &state );
|
|
||||||
tex->releaseGLObjects( &state );
|
|
||||||
|
|
||||||
if ( status == GL_FRAMEBUFFER_COMPLETE_EXT )
|
|
||||||
{
|
|
||||||
out_internalFormat = format.internalFormat;
|
|
||||||
out_sourceFormat = format.sourceFormat;
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
state.setCheckForGLErrors(check);
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
TritonHeightMap::isConfigurationComplete() const
|
|
||||||
{
|
|
||||||
return
|
|
||||||
_texSize > 0u &&
|
|
||||||
_internalFormat != (GLint)0 &&
|
|
||||||
_sourceFormat != (GLenum)0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TritonHeightMap::setup(CameraLocal& local, const std::string& name)
|
|
||||||
{
|
|
||||||
// make sure the FBO params are configured:
|
|
||||||
if (!isConfigurationComplete())
|
|
||||||
return;
|
|
||||||
|
|
||||||
local._frameNum = 0u;
|
|
||||||
|
|
||||||
local._tex = new osg::Texture2D();
|
|
||||||
local._tex->setName(Stringify() << "Triton HM (" << name << ")");
|
|
||||||
local._tex->setTextureSize(_texSize, _texSize);
|
|
||||||
local._tex->setInternalFormat( _internalFormat );
|
|
||||||
local._tex->setSourceFormat( _sourceFormat );
|
|
||||||
local._tex->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR);
|
|
||||||
local._tex->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::LINEAR);
|
|
||||||
|
|
||||||
// Triton prob doesn't need this but it's good practice
|
|
||||||
if (_sourceFormat == GL_RED)
|
|
||||||
{
|
|
||||||
local._tex->setSwizzle(osg::Vec4i(GL_RED, GL_RED, GL_RED, GL_ONE));
|
|
||||||
}
|
|
||||||
|
|
||||||
local._rtt = new osg::Camera();
|
|
||||||
local._rtt->setName(local._tex->getName());
|
|
||||||
local._rtt->setReferenceFrame(osg::Transform::ABSOLUTE_RF_INHERIT_VIEWPOINT);
|
|
||||||
local._rtt->setClearMask(GL_COLOR_BUFFER_BIT); //GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
|
||||||
local._rtt->setClearColor(osg::Vec4(-1000.0, -1000.0, -1000.0, 1.0f));
|
|
||||||
local._rtt->setViewport(0, 0, _texSize, _texSize);
|
|
||||||
local._rtt->setRenderOrder(osg::Camera::PRE_RENDER);
|
|
||||||
local._rtt->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
|
|
||||||
local._rtt->setImplicitBufferAttachmentMask(0, 0);
|
|
||||||
local._rtt->attach(osg::Camera::COLOR_BUFFER0, local._tex.get());
|
|
||||||
//local._rtt->setCullMask( ~TRITON_OCEAN_MASK );
|
|
||||||
local._rtt->setAllowEventFocus(false);
|
|
||||||
local._rtt->setDrawBuffer(GL_FRONT);
|
|
||||||
local._rtt->setReadBuffer(GL_FRONT);
|
|
||||||
local._rtt->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
|
|
||||||
|
|
||||||
// TODO: create this once and just re-use it for all RTT cameras
|
|
||||||
osg::StateSet* rttSS = local._rtt->getOrCreateStateSet();
|
|
||||||
|
|
||||||
osgEarth::VirtualProgram* rttVP = osgEarth::VirtualProgram::getOrCreate(rttSS);
|
|
||||||
rttVP->setName("Triton Height Map");
|
|
||||||
rttVP->setFunction( "oe_triton_setupHeightMap", vertexShader, VirtualProgram::LOCATION_VERTEX_MODEL);
|
|
||||||
rttVP->setFunction( "oe_triton_drawHeightMap", fragmentShader, VirtualProgram::LOCATION_FRAGMENT_OUTPUT);
|
|
||||||
rttVP->setInheritShaders(false);
|
|
||||||
|
|
||||||
osg::StateAttribute::OverrideValue off = osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE;
|
|
||||||
rttSS->setDefine("OE_IS_DEPTH_CAMERA");
|
|
||||||
rttSS->setDefine("OE_TERRAIN_RENDER_IMAGERY", off);
|
|
||||||
rttSS->setDefine("OE_TERRAIN_RENDER_NORMAL_MAP", off);
|
|
||||||
rttSS->setDefine("OE_TERRAIN_BLEND_IMAGERY", off);
|
|
||||||
rttSS->setDefine("OE_TERRAIN_MORPH_GEOMETRY", off);
|
|
||||||
|
|
||||||
osg::ref_ptr<const osgEarth::ImageLayer> maskLayer;
|
|
||||||
if (_maskLayer.lock(maskLayer))
|
|
||||||
{
|
|
||||||
rttSS->setDefine("OE_TRITON_MASK_SAMPLER", maskLayer->getSharedTextureUniformName());
|
|
||||||
rttSS->setDefine("OE_TRITON_MASK_MATRIX", maskLayer->getSharedTextureMatrixUniformName());
|
|
||||||
OE_DEBUG << LC << "Using mask layer \"" << maskLayer->getName() << "\", sampler=" << maskLayer->getSharedTextureUniformName() << ", matrix=" << maskLayer->getSharedTextureMatrixUniformName() << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_terrain.valid())
|
|
||||||
{
|
|
||||||
local._rtt->addChild(_terrain.get());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
OE_WARN << LC << "Illegal: no terrain set (must call setTerrain)" << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MAXABS4(A,B,C,D) \
|
|
||||||
osg::maximum(fabs(A), osg::maximum(fabs(B), osg::maximum(fabs(C),fabs(D))))
|
|
||||||
|
|
||||||
void
|
|
||||||
TritonHeightMap::update(CameraLocal& local, const osg::Camera* cam, osgEarth::Horizon* horizon)
|
|
||||||
{
|
|
||||||
osg::Vec3d eye = osg::Vec3d(0,0,0) * cam->getInverseViewMatrix();
|
|
||||||
|
|
||||||
double hd = horizon->getDistanceToVisibleHorizon();
|
|
||||||
|
|
||||||
local._rtt->setProjectionMatrix(osg::Matrix::ortho(-hd, hd, -hd, hd, 1.0, eye.length()));
|
|
||||||
local._rtt->setViewMatrixAsLookAt(eye, osg::Vec3d(0.0,0.0,0.0), osg::Vec3d(0.0,0.0,1.0));
|
|
||||||
|
|
||||||
static const osg::Matrixd scaleBias(
|
|
||||||
0.5, 0.0, 0.0, 0.0,
|
|
||||||
0.0, 0.5, 0.0, 0.0,
|
|
||||||
0.0, 0.0, 0.5, 0.0,
|
|
||||||
0.5, 0.5, 0.5, 1.0);
|
|
||||||
|
|
||||||
// Matrix that Triton will use to position the heightmap for sampling.
|
|
||||||
local._texMatrix = local._rtt->getViewMatrix() * local._rtt->getProjectionMatrix() * scaleBias;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TritonHeightMap::traverse(osg::NodeVisitor& nv)
|
|
||||||
{
|
|
||||||
if (nv.getVisitorType() == nv.CULL_VISITOR)
|
|
||||||
{
|
|
||||||
osgUtil::CullVisitor* cv = osgEarth::Culling::asCullVisitor(nv);
|
|
||||||
const osg::Camera* camera = cv->getCurrentCamera();
|
|
||||||
if (camera)
|
|
||||||
{
|
|
||||||
CameraLocal& local = _local.get(camera);
|
|
||||||
|
|
||||||
if (isConfigurationComplete())
|
|
||||||
{
|
|
||||||
// create the RTT for this camera on first encounter:
|
|
||||||
if (!local._rtt.valid())
|
|
||||||
{
|
|
||||||
setup(local, camera->getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
// only update when the MVPW changes.
|
|
||||||
if (local._mvpw != *cv->getMVPW())
|
|
||||||
{
|
|
||||||
// update the RTT based on the current camera:
|
|
||||||
osg::ref_ptr<Horizon> horizon;
|
|
||||||
ObjectStorage::get(&nv, horizon);
|
|
||||||
update(local, camera, horizon);
|
|
||||||
|
|
||||||
// finally, traverse the camera to build the height map.
|
|
||||||
local._rtt->accept(nv);
|
|
||||||
|
|
||||||
local._frameNum = nv.getFrameStamp()->getFrameNumber();
|
|
||||||
local._mvpw = *cv->getMVPW();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//OE_DEBUG << LC << "Configuration not yet complete..." << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
TritonHeightMap::getTextureAndMatrix(osg::RenderInfo& ri, GLint& out_texName, osg::Matrix& out_matrix)
|
|
||||||
{
|
|
||||||
if (!isConfigurationComplete())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
CameraLocal& local = _local.get(ri.getCurrentCamera());
|
|
||||||
if (!local._tex.valid())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// did the texture change?
|
|
||||||
//OE_DEBUG << "FN=" << ri.getState()->getFrameStamp()->getFrameNumber() << "; localFN=" << local._frameNum << std::endl;
|
|
||||||
|
|
||||||
if (ri.getState()->getFrameStamp()->getFrameNumber() > local._frameNum)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
auto cid = GLUtils::getSharedContextID(*ri.getState());
|
|
||||||
osg::Texture::TextureObject* obj = local._tex->getTextureObject(cid);
|
|
||||||
if (!obj)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
out_texName = obj->id();
|
|
||||||
out_matrix = local._texMatrix;
|
|
||||||
return true;
|
|
||||||
}
|
|
@ -1,109 +0,0 @@
|
|||||||
/* -*-c++-*- */
|
|
||||||
/* osgEarth - Geospatial SDK for OpenSceneGraph
|
|
||||||
* Copyright 2020 Pelican Mapping
|
|
||||||
* http://osgearth.org
|
|
||||||
*
|
|
||||||
* osgEarth is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
#ifndef OSGEARTH_TRITON_HEIGHT_MAP
|
|
||||||
#define OSGEARTH_TRITON_HEIGHT_MAP 1
|
|
||||||
|
|
||||||
#include <osgEarth/Containers>
|
|
||||||
#include <osgEarth/ImageLayer>
|
|
||||||
#include <osg/Node>
|
|
||||||
#include <osg/Camera>
|
|
||||||
#include <osg/Texture2D>
|
|
||||||
|
|
||||||
namespace osgEarth {
|
|
||||||
class Horizon;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace osgEarth { namespace Triton
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Creates a height map that Triton can use to mask out the ocean where
|
|
||||||
* the terrain is above sea level.
|
|
||||||
*/
|
|
||||||
class TritonHeightMap : public osg::Node
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
TritonHeightMap();
|
|
||||||
|
|
||||||
//! Sets the root of the terrain scene graph
|
|
||||||
void setTerrain(osg::Node*);
|
|
||||||
|
|
||||||
//! Sets the masking layer
|
|
||||||
void setMaskLayer(const osgEarth::ImageLayer* layer);
|
|
||||||
|
|
||||||
//! Configure the generator; return success t/f
|
|
||||||
bool configure(unsigned texSize, osg::State& state);
|
|
||||||
|
|
||||||
//! Fetch the heightmap texture and matrix generated for a camera.
|
|
||||||
bool getTextureAndMatrix(osg::RenderInfo&, GLint& out_texName, osg::Matrix& out_matrix);
|
|
||||||
|
|
||||||
//! Mark all height maps (for all cameras) for regeneration
|
|
||||||
void dirty();
|
|
||||||
|
|
||||||
public: // osg::Node
|
|
||||||
|
|
||||||
void traverse(osg::NodeVisitor&);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
virtual ~TritonHeightMap();
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
struct CameraLocal
|
|
||||||
{
|
|
||||||
osg::ref_ptr<osg::Camera> _rtt;
|
|
||||||
osg::ref_ptr<osg::Texture2D> _tex;
|
|
||||||
osg::Matrix _texMatrix;
|
|
||||||
osg::Matrix _mvpw;
|
|
||||||
unsigned _frameNum;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef osgEarth::PerObjectFastMap<const osg::Camera*, CameraLocal> Locals;
|
|
||||||
|
|
||||||
struct SetDirty : public Locals::Functor
|
|
||||||
{
|
|
||||||
void operator()(CameraLocal&);
|
|
||||||
};
|
|
||||||
|
|
||||||
//! Sets up an RTT camera for the first time
|
|
||||||
void setup(CameraLocal& local, const std::string& name);
|
|
||||||
|
|
||||||
//! Updates an RTT camera for the new view/projection matrices of the camera
|
|
||||||
void update(CameraLocal& local, const osg::Camera*, osgEarth::Horizon*);
|
|
||||||
|
|
||||||
//! Whether FBO configuration has happened yet
|
|
||||||
bool isConfigurationComplete() const;
|
|
||||||
|
|
||||||
//! Figures out the best FBO format on this GPU
|
|
||||||
static bool getBestFBOConfig(osg::State& state, GLint& internalFormat, GLenum& sourceFormat);
|
|
||||||
|
|
||||||
|
|
||||||
Locals _local;
|
|
||||||
osg::observer_ptr<osg::Node> _terrain;
|
|
||||||
unsigned _texSize;
|
|
||||||
GLint _internalFormat;
|
|
||||||
GLenum _sourceFormat;
|
|
||||||
osg::observer_ptr<const osgEarth::ImageLayer> _maskLayer;
|
|
||||||
osg::ref_ptr<osg::Referenced> _terrainCallback;
|
|
||||||
};
|
|
||||||
|
|
||||||
} } // namespace osgEarth::Triton
|
|
||||||
|
|
||||||
#endif // OSGEARTH_TRITON_HEIGHT_MAP
|
|
@ -1,51 +0,0 @@
|
|||||||
/* -*-c++-*- */
|
|
||||||
/* osgEarth - Geospatial SDK for OpenSceneGraph
|
|
||||||
* Copyright 2020 Pelican Mapping
|
|
||||||
* http://osgearth.org
|
|
||||||
*
|
|
||||||
* osgEarth is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
#include "TritonIntersections.h"
|
|
||||||
|
|
||||||
using namespace osgEarth;
|
|
||||||
using namespace osgEarth::Triton;
|
|
||||||
|
|
||||||
TritonIntersections::TritonIntersections() :
|
|
||||||
_maxRange(1.0, Units::KILOMETERS)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TritonIntersections::setAnchor(const GeoPoint& value)
|
|
||||||
{
|
|
||||||
_anchor = value;
|
|
||||||
|
|
||||||
// zero out the other stuff:
|
|
||||||
_anchor.z() = 0.0;
|
|
||||||
_anchor.altitudeMode() = ALTMODE_ABSOLUTE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TritonIntersections::addLocalPoint(const osg::Vec3d& p)
|
|
||||||
{
|
|
||||||
_input.push_back(p);
|
|
||||||
_heights.resize(_input.size());
|
|
||||||
_normals.resize(_input.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TritonIntersections::setMaxRange(const Distance& range)
|
|
||||||
{
|
|
||||||
_maxRange = range;
|
|
||||||
}
|
|
@ -1,72 +0,0 @@
|
|||||||
/* -*-c++-*- */
|
|
||||||
/* osgEarth - Geospatial SDK for OpenSceneGraph
|
|
||||||
* Copyright 2020 Pelican Mapping
|
|
||||||
* http://osgearth.org
|
|
||||||
*
|
|
||||||
* osgEarth is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
#ifndef OSGEARTH_TRITON_INTERSECTIONS
|
|
||||||
#define OSGEARTH_TRITON_INTERSECTIONS 1
|
|
||||||
|
|
||||||
#include <osgEarth/VisibleLayer>
|
|
||||||
#include <osgEarth/ImageLayer>
|
|
||||||
#include "TritonCallback.h"
|
|
||||||
|
|
||||||
namespace osgEarth { namespace Triton
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Pass this structure to TritonLayer and it will automatically
|
|
||||||
* populate the results with ocean wave intersections (local coordinates
|
|
||||||
* and normals.)
|
|
||||||
*/
|
|
||||||
class TritonIntersections : public osg::Referenced
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
//! Construct an empty set
|
|
||||||
TritonIntersections();
|
|
||||||
|
|
||||||
//! Anchor point for intersectsions in this set. Only the X and Y
|
|
||||||
//! components are used. Any local points you add to this set will
|
|
||||||
//! be in the local coordinate system (LTP) around this anchor point.
|
|
||||||
void setAnchor(const GeoPoint& p);
|
|
||||||
|
|
||||||
//! Adds a point to the intersection set. The point should be in the
|
|
||||||
//! local coordinate system of the anchor point.
|
|
||||||
void addLocalPoint(const osg::Vec3d& p);
|
|
||||||
|
|
||||||
//! Maximum range at which to perform intersections. Beyond this
|
|
||||||
//! range Triton will skip this set. Default is 2km.
|
|
||||||
void setMaxRange(const Distance& value);
|
|
||||||
const Distance& getMaxRange() const { return _maxRange; }
|
|
||||||
|
|
||||||
//! Vector of input local points added by addLocalPoint.
|
|
||||||
const std::vector<osg::Vec3d>& getInput() const { return _input; }
|
|
||||||
|
|
||||||
//! Vector of heights resulting from the intersection tests.
|
|
||||||
const std::vector<float>& getHeights() const { return _heights; }
|
|
||||||
|
|
||||||
//! Vector of normals resulting from the intersection tests.
|
|
||||||
const std::vector<osg::Vec3d>& getNormals() const { return _normals; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
GeoPoint _anchor;
|
|
||||||
std::vector<osg::Vec3d> _input;
|
|
||||||
std::vector<float> _heights;
|
|
||||||
std::vector<osg::Vec3d> _normals;
|
|
||||||
Distance _maxRange;
|
|
||||||
friend class TritonLayerNode;
|
|
||||||
};
|
|
||||||
} }
|
|
||||||
|
|
||||||
#endif // OSGEARTH_TRITON_INTERSECTIONS
|
|
@ -1,386 +0,0 @@
|
|||||||
/* -*-c++-*- */
|
|
||||||
/* osgEarth - Geospatial SDK for OpenSceneGraph
|
|
||||||
* Copyright 2020 Pelican Mapping
|
|
||||||
* http://osgearth.org
|
|
||||||
*
|
|
||||||
* osgEarth is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
#include "TritonLayer.h"
|
|
||||||
#include "TritonContext.h"
|
|
||||||
#include "TritonDrawable.h"
|
|
||||||
#include "TritonHeightMap.h"
|
|
||||||
#include "TritonCallback.h"
|
|
||||||
|
|
||||||
#include <osgEarth/MapNode>
|
|
||||||
#include <osgEarth/ImageLayer>
|
|
||||||
#include <osgEarth/NodeUtils>
|
|
||||||
#include <osgEarth/ElevationLOD>
|
|
||||||
#include <osgEarth/TerrainEngineNode>
|
|
||||||
#include <osgEarth/VerticalDatum>
|
|
||||||
|
|
||||||
#include <osgUtil/CullVisitor>
|
|
||||||
|
|
||||||
#define LC "[TritonLayer] "
|
|
||||||
|
|
||||||
using namespace osgEarth::Triton;
|
|
||||||
|
|
||||||
namespace osgEarth { namespace Triton
|
|
||||||
{
|
|
||||||
class TritonLayerNode : public osg::Group
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
TritonLayerNode(osgEarth::Triton::TritonLayer* layer,
|
|
||||||
LayerReference<osgEarth::ImageLayer>& mask) :
|
|
||||||
_tritonLayer(layer),
|
|
||||||
_maskLayer(mask),
|
|
||||||
_callback(0L),
|
|
||||||
_needsMapNode(true)
|
|
||||||
{
|
|
||||||
// To detect the map node:
|
|
||||||
ADJUST_UPDATE_TRAV_COUNT(this, +1);
|
|
||||||
|
|
||||||
// Disable bounds culling
|
|
||||||
setCullingActive(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
~TritonLayerNode()
|
|
||||||
{
|
|
||||||
//nop
|
|
||||||
}
|
|
||||||
|
|
||||||
void setUserCallback(osgEarth::Triton::Callback* callback)
|
|
||||||
{
|
|
||||||
_callback = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dirty()
|
|
||||||
{
|
|
||||||
create();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** MapNode to use; will be discovered automatically if not set here */
|
|
||||||
void setMapNode(osgEarth::MapNode* mapNode)
|
|
||||||
{
|
|
||||||
if (!mapNode)
|
|
||||||
{
|
|
||||||
this->removeChildren(0, this->getNumChildren());
|
|
||||||
_drawable = 0L;
|
|
||||||
_TRITON = 0L;
|
|
||||||
_needsMapNode = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_mapNode = mapNode;
|
|
||||||
create();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void create()
|
|
||||||
{
|
|
||||||
this->removeChildren(0, this->getNumChildren());
|
|
||||||
_drawable = 0L;
|
|
||||||
|
|
||||||
osg::ref_ptr<osgEarth::MapNode> mapNode;
|
|
||||||
if (!_mapNode.lock(mapNode))
|
|
||||||
return;
|
|
||||||
|
|
||||||
const osgEarth::Map* map = mapNode->getMap();
|
|
||||||
|
|
||||||
// create an object to house Triton data and resources.
|
|
||||||
if (!_TRITON.valid())
|
|
||||||
_TRITON = new TritonContext(_tritonLayer->options());
|
|
||||||
|
|
||||||
if (map)
|
|
||||||
_TRITON->setSRS(map->getSRS());
|
|
||||||
|
|
||||||
if (_callback.valid())
|
|
||||||
_TRITON->setCallback(_callback.get());
|
|
||||||
|
|
||||||
TritonDrawable* drawable = new TritonDrawable(_TRITON.get());
|
|
||||||
_drawable = drawable;
|
|
||||||
_drawable->setNodeMask(TRITON_OCEAN_MASK);
|
|
||||||
drawable->setMaskLayer(_maskLayer.getLayer());
|
|
||||||
this->addChild(_drawable);
|
|
||||||
|
|
||||||
// Place in the depth-sorted bin and set a rendering order.
|
|
||||||
// We want Triton to render after the terrain.
|
|
||||||
_drawable->getOrCreateStateSet()->setRenderBinDetails(
|
|
||||||
_tritonLayer->getRenderBinNumber(),
|
|
||||||
"DepthSortedBin");
|
|
||||||
|
|
||||||
// Install a vdatum for sea level calculations:
|
|
||||||
auto vdatum = VerticalDatum::get(_tritonLayer->options().vdatum().value());
|
|
||||||
if (vdatum)
|
|
||||||
drawable->setVerticalDatum(vdatum);
|
|
||||||
|
|
||||||
// If the user requested a height map, install it now.
|
|
||||||
// Configuration of the height map generator will take place later when
|
|
||||||
// we have a valid graphics context.
|
|
||||||
if (_tritonLayer->getUseHeightMap() == true)
|
|
||||||
{
|
|
||||||
TritonHeightMap* heightMapGen = new TritonHeightMap();
|
|
||||||
heightMapGen->setTerrain(mapNode->getTerrainEngine()->getNode());
|
|
||||||
if (_maskLayer.getLayer())
|
|
||||||
heightMapGen->setMaskLayer(_maskLayer.getLayer());
|
|
||||||
this->addChild(heightMapGen);
|
|
||||||
drawable->setHeightMapGenerator(heightMapGen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void traverse(osg::NodeVisitor& nv)
|
|
||||||
{
|
|
||||||
if (nv.getVisitorType() == nv.UPDATE_VISITOR)
|
|
||||||
{
|
|
||||||
// Find a MapNode in the traversal path if necessary:
|
|
||||||
if (_needsMapNode)
|
|
||||||
{
|
|
||||||
osgEarth::MapNode* mapNode = osgEarth::findInNodePath<osgEarth::MapNode>(nv);
|
|
||||||
if (mapNode)
|
|
||||||
{
|
|
||||||
setMapNode(mapNode);
|
|
||||||
_needsMapNode = false;
|
|
||||||
ADJUST_UPDATE_TRAV_COUNT(this, -1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (nv.getVisitorType() == nv.CULL_VISITOR && _drawable && _TRITON.valid() && _TRITON->getOcean())
|
|
||||||
{
|
|
||||||
// Update any intersections.
|
|
||||||
// For now this is running in the CULL traversal, which is not ideal.
|
|
||||||
// However the Triton Ocean::GetHeight method requires a pointer to the Triton "camera"
|
|
||||||
// and under our framework this is only available in CULL or DRAW.
|
|
||||||
// Running the intersection in eithe CULL or DRAW will result in a frame
|
|
||||||
// incoherency w.r.t the Triton update() call that updates the ocean state.
|
|
||||||
::Triton::Ocean* ocean = _TRITON->getOcean();
|
|
||||||
|
|
||||||
// Find the TritonCam associated with this osg Cam
|
|
||||||
osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(&nv);
|
|
||||||
::Triton::Camera* tritonCam = static_cast<TritonDrawable*>(_drawable)->getTritonCam(cv->getCurrentCamera());
|
|
||||||
|
|
||||||
osg::Vec3d eye = osg::Vec3d(0,0,0) * cv->getCurrentCamera()->getInverseViewMatrix();
|
|
||||||
|
|
||||||
for(std::vector<osg::ref_ptr<TritonIntersections> >::iterator i = _isect.begin();
|
|
||||||
i != _isect.end();
|
|
||||||
++i)
|
|
||||||
{
|
|
||||||
TritonIntersections* ir = i->get();
|
|
||||||
|
|
||||||
// allocate enough space for the output:
|
|
||||||
ir->_input.resize(ir->_input.size());
|
|
||||||
ir->_normals.resize(ir->_input.size());
|
|
||||||
|
|
||||||
osg::Matrix local2world;
|
|
||||||
ir->_anchor.createLocalToWorld(local2world);
|
|
||||||
|
|
||||||
// Make sure it's in range so as not to waste cycles:
|
|
||||||
osg::Vec3d anchor = osg::Vec3d(0,0,0) * local2world;
|
|
||||||
double m = ir->getMaxRange().as(Units::METERS);
|
|
||||||
if ((eye-anchor).length2() > (m))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
osg::Matrix world2local;
|
|
||||||
world2local.invert(local2world);
|
|
||||||
|
|
||||||
for(unsigned i=0; i<ir->_input.size(); ++i)
|
|
||||||
{
|
|
||||||
const osg::Vec3d& local = ir->_input[i];
|
|
||||||
|
|
||||||
// transform the ray to world coordinates
|
|
||||||
osg::Vec3d start = local * local2world;
|
|
||||||
osg::Vec3d dir = osg::Matrix::transform3x3(local2world, osg::Vec3d(0,0,1));
|
|
||||||
|
|
||||||
// intersect the ocean
|
|
||||||
float& out_height = ir->_heights[i];
|
|
||||||
::Triton::Vector3 out_normalT;
|
|
||||||
|
|
||||||
bool ok = ocean->GetHeight(
|
|
||||||
::Triton::Vector3(start.x(), start.y(), start.z()),
|
|
||||||
::Triton::Vector3(dir.x(), dir.y(), dir.z()),
|
|
||||||
out_height,
|
|
||||||
out_normalT,
|
|
||||||
true, // visualCorrelation
|
|
||||||
true, // includeWakes
|
|
||||||
true, // highResolution
|
|
||||||
true, // threadSafe,
|
|
||||||
0L, // intersectionPoint,
|
|
||||||
true, // autoFlip
|
|
||||||
tritonCam);
|
|
||||||
|
|
||||||
if (ok)
|
|
||||||
{
|
|
||||||
// populate the output data in local coordinates
|
|
||||||
osg::Vec3d& normal = ir->_normals[i];
|
|
||||||
normal.set(out_normalT.x, out_normalT.y, out_normalT.z);
|
|
||||||
normal = osg::Matrix::transform3x3(normal, world2local);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// todo...what?
|
|
||||||
OE_WARN << "GetHeight returned false dude" << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
osg::Group::traverse(nv);
|
|
||||||
}
|
|
||||||
|
|
||||||
osg::ref_ptr<TritonContext> _TRITON;
|
|
||||||
osg::Drawable* _drawable;
|
|
||||||
LayerReference<osgEarth::ImageLayer>& _maskLayer;
|
|
||||||
osg::observer_ptr<osgEarth::MapNode> _mapNode;
|
|
||||||
osg::observer_ptr<osgEarth::Triton::TritonLayer> _tritonLayer;
|
|
||||||
osg::ref_ptr<Callback> _callback;
|
|
||||||
bool _needsMapNode;
|
|
||||||
std::vector<osg::ref_ptr<TritonIntersections> > _isect;
|
|
||||||
|
|
||||||
};
|
|
||||||
} }
|
|
||||||
|
|
||||||
//........................................................................
|
|
||||||
|
|
||||||
void
|
|
||||||
TritonLayer::Options::fromConfig(const osgEarth::Config& conf)
|
|
||||||
{
|
|
||||||
conf.get("user", _user);
|
|
||||||
conf.get("license_code", _licenseCode);
|
|
||||||
conf.get("resource_path", _resourcePath);
|
|
||||||
conf.get("use_height_map", _useHeightMap);
|
|
||||||
conf.get("height_map_size", _heightMapSize);
|
|
||||||
conf.get("render_bin_number", _renderBinNumber);
|
|
||||||
conf.get("max_altitude", _maxAltitude);
|
|
||||||
conf.get("vdatum", vdatum());
|
|
||||||
maskLayer().get(conf, "mask_layer");
|
|
||||||
}
|
|
||||||
|
|
||||||
osgEarth::Config
|
|
||||||
TritonLayer::Options::getConfig() const
|
|
||||||
{
|
|
||||||
osgEarth::Config conf = osgEarth::VisibleLayer::Options::getConfig();
|
|
||||||
conf.set("user", _user);
|
|
||||||
conf.set("license_code", _licenseCode);
|
|
||||||
conf.set("resource_path", _resourcePath);
|
|
||||||
conf.set("use_height_map", _useHeightMap);
|
|
||||||
conf.set("height_map_size", _heightMapSize);
|
|
||||||
conf.set("render_bin_number", _renderBinNumber);
|
|
||||||
conf.set("max_altitude", _maxAltitude);
|
|
||||||
conf.set("vdatum", vdatum());
|
|
||||||
maskLayer().set(conf, "mask_layer");
|
|
||||||
|
|
||||||
return conf;
|
|
||||||
}
|
|
||||||
|
|
||||||
//........................................................................
|
|
||||||
|
|
||||||
/** Register this layer so it can be used in an earth file */
|
|
||||||
namespace osgEarth { namespace Triton
|
|
||||||
{
|
|
||||||
REGISTER_OSGEARTH_LAYER(triton, TritonLayer);
|
|
||||||
REGISTER_OSGEARTH_LAYER(triton_ocean, TritonLayer);
|
|
||||||
} }
|
|
||||||
|
|
||||||
OE_LAYER_PROPERTY_IMPL(TritonLayer, std::string, UserName, user);
|
|
||||||
OE_LAYER_PROPERTY_IMPL(TritonLayer, std::string, LicenseCode, licenseCode);
|
|
||||||
OE_LAYER_PROPERTY_IMPL(TritonLayer, std::string, ResourcePath, resourcePath);
|
|
||||||
OE_LAYER_PROPERTY_IMPL(TritonLayer, bool, UseHeightMap, useHeightMap);
|
|
||||||
OE_LAYER_PROPERTY_IMPL(TritonLayer, unsigned, HeightMapSize, heightMapSize);
|
|
||||||
OE_LAYER_PROPERTY_IMPL(TritonLayer, int, RenderBinNumber, renderBinNumber);
|
|
||||||
OE_LAYER_PROPERTY_IMPL(TritonLayer, float, MaxAltitude, maxAltitude);
|
|
||||||
OE_LAYER_PROPERTY_IMPL(TritonLayer, std::string, VerticalDatum, vdatum);
|
|
||||||
|
|
||||||
void
|
|
||||||
TritonLayer::init()
|
|
||||||
{
|
|
||||||
super::init();
|
|
||||||
|
|
||||||
_seaLevel = 0.0f;
|
|
||||||
|
|
||||||
// Trick to force the VisibleLayer to install its opacity shader,
|
|
||||||
// which a modified Triton user-functions.glsl shader needs in order to control
|
|
||||||
// sea surface opacity.
|
|
||||||
float opacity = getOpacity();
|
|
||||||
setOpacity(0.0f);
|
|
||||||
setOpacity(opacity);
|
|
||||||
|
|
||||||
this->setName("Triton");
|
|
||||||
setRenderType(RENDERTYPE_CUSTOM);
|
|
||||||
|
|
||||||
ElevationLOD* lod = new ElevationLOD();
|
|
||||||
_root = lod;
|
|
||||||
if (options().maxAltitude().isSet())
|
|
||||||
{
|
|
||||||
OE_DEBUG << LC << "Setting max altitude = " << options().maxAltitude().get() << std::endl;
|
|
||||||
lod->setMaxElevation(options().maxAltitude().get());
|
|
||||||
}
|
|
||||||
|
|
||||||
_tritonNode = new TritonLayerNode(this, options().maskLayer());
|
|
||||||
_root->addChild(_tritonNode.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TritonLayer::setUserCallback(Callback* callback)
|
|
||||||
{
|
|
||||||
static_cast<TritonLayerNode*>(_tritonNode.get())->setUserCallback(callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
osg::Node*
|
|
||||||
TritonLayer::getNode() const
|
|
||||||
{
|
|
||||||
return _root.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TritonLayer::setMaskLayer(osgEarth::ImageLayer* maskLayer)
|
|
||||||
{
|
|
||||||
options().maskLayer().setLayer(maskLayer);
|
|
||||||
static_cast<TritonLayerNode*>(_tritonNode.get())->dirty();
|
|
||||||
}
|
|
||||||
|
|
||||||
osgEarth::ImageLayer*
|
|
||||||
TritonLayer::getMaskLayer() const
|
|
||||||
{
|
|
||||||
return options().maskLayer().getLayer();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TritonLayer::addedToMap(const osgEarth::Map* map)
|
|
||||||
{
|
|
||||||
VisibleLayer::addedToMap(map);
|
|
||||||
options().maskLayer().addedToMap(map);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TritonLayer::removedFromMap(const osgEarth::Map* map)
|
|
||||||
{
|
|
||||||
VisibleLayer::removedFromMap(map);
|
|
||||||
options().maskLayer().removedFromMap(map);
|
|
||||||
setMaskLayer(0L);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TritonLayer::addIntersections(TritonIntersections* value)
|
|
||||||
{
|
|
||||||
TritonLayerNode* node = static_cast<TritonLayerNode*>(_tritonNode.get());
|
|
||||||
node->_isect.push_back(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
osgEarth::Config
|
|
||||||
TritonLayer::getConfig() const
|
|
||||||
{
|
|
||||||
osgEarth::Config c = osgEarth::VisibleLayer::getConfig();
|
|
||||||
return c;
|
|
||||||
}
|
|
@ -1,125 +0,0 @@
|
|||||||
/* -*-c++-*- */
|
|
||||||
/* osgEarth - Geospatial SDK for OpenSceneGraph
|
|
||||||
* Copyright 2020 Pelican Mapping
|
|
||||||
* http://osgearth.org
|
|
||||||
*
|
|
||||||
* osgEarth is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
#ifndef OSGEARTH_TRITON_LAYER
|
|
||||||
#define OSGEARTH_TRITON_LAYER 1
|
|
||||||
|
|
||||||
#include <osgEarth/VisibleLayer>
|
|
||||||
#include <osgEarth/LayerReference>
|
|
||||||
#include <osgEarth/ImageLayer>
|
|
||||||
#include "TritonCallback.h"
|
|
||||||
#include "TritonIntersections.h"
|
|
||||||
|
|
||||||
namespace osgEarth { namespace Triton
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Node that roots the Triton adapter.
|
|
||||||
*/
|
|
||||||
class TritonLayer : public osgEarth::VisibleLayer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
class Options : public osgEarth::VisibleLayer::Options {
|
|
||||||
public:
|
|
||||||
META_LayerOptions(osgEarth, Options, osgEarth::VisibleLayer::Options);
|
|
||||||
OE_OPTION(std::string, user);
|
|
||||||
OE_OPTION(std::string, licenseCode);
|
|
||||||
OE_OPTION(std::string, resourcePath);
|
|
||||||
OE_OPTION(bool, useHeightMap, true);
|
|
||||||
OE_OPTION(unsigned, heightMapSize, 1024);
|
|
||||||
OE_OPTION(int, renderBinNumber, 12);
|
|
||||||
OE_OPTION(float, maxAltitude, 50000.0f);
|
|
||||||
OE_OPTION(std::string, vdatum, "egm96");
|
|
||||||
OE_OPTION_LAYER(osgEarth::ImageLayer, maskLayer);
|
|
||||||
virtual Config getConfig() const;
|
|
||||||
private:
|
|
||||||
void fromConfig(const Config& conf);
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
META_Layer(osgEarth, TritonLayer, Options, osgEarth::VisibleLayer, triton);
|
|
||||||
|
|
||||||
//! Sets the user callback that's invoked when Triton start up
|
|
||||||
void setUserCallback(Triton::Callback* callback);
|
|
||||||
|
|
||||||
//! User name for license
|
|
||||||
void setUserName(const std::string& value);
|
|
||||||
const std::string& getUserName() const;
|
|
||||||
|
|
||||||
//! License code
|
|
||||||
void setLicenseCode(const std::string& value);
|
|
||||||
const std::string& getLicenseCode() const;
|
|
||||||
|
|
||||||
//! Triton resource path
|
|
||||||
void setResourcePath(const std::string& value);
|
|
||||||
const std::string& getResourcePath() const;
|
|
||||||
|
|
||||||
//! Whether to use a height map to fade out the ocean at the coastline
|
|
||||||
void setUseHeightMap(const bool& value);
|
|
||||||
const bool& getUseHeightMap() const;
|
|
||||||
|
|
||||||
//! Size in texels of the height map (each dimension)
|
|
||||||
void setHeightMapSize(const unsigned& value);
|
|
||||||
const unsigned& getHeightMapSize() const;
|
|
||||||
|
|
||||||
//! Render bin number to use for the ocean rendering
|
|
||||||
void setRenderBinNumber(const int& value);
|
|
||||||
const int& getRenderBinNumber() const;
|
|
||||||
|
|
||||||
//! Masking layer for the ocean
|
|
||||||
void setMaskLayer(osgEarth::ImageLayer* maskLayer);
|
|
||||||
osgEarth::ImageLayer* getMaskLayer() const;
|
|
||||||
|
|
||||||
//! Maximum visibility altitude
|
|
||||||
void setMaxAltitude(const float& value);
|
|
||||||
const float& getMaxAltitude() const;
|
|
||||||
|
|
||||||
//! Vertical datum to use to calculate sea level
|
|
||||||
void setVerticalDatum(const std::string& value);
|
|
||||||
const std::string& getVerticalDatum() const;
|
|
||||||
|
|
||||||
//! Adds an intersection set.
|
|
||||||
//! Each frame, Triton will perform intersections against the ocean surface
|
|
||||||
//! (including the waves) and populate the set with the results.
|
|
||||||
void addIntersections(TritonIntersections*);
|
|
||||||
|
|
||||||
public: // Layer
|
|
||||||
|
|
||||||
virtual osg::Node* getNode() const;
|
|
||||||
|
|
||||||
//! Serialize
|
|
||||||
virtual Config getConfig() const;
|
|
||||||
|
|
||||||
protected: // Layer
|
|
||||||
|
|
||||||
virtual void init();
|
|
||||||
|
|
||||||
virtual void addedToMap(const class osgEarth::Map*);
|
|
||||||
|
|
||||||
virtual void removedFromMap(const class osgEarth::Map*);
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
osg::ref_ptr<osg::Group> _root;
|
|
||||||
osg::ref_ptr<osg::Node> _tritonNode;
|
|
||||||
float _seaLevel;
|
|
||||||
float _opacity;
|
|
||||||
};
|
|
||||||
|
|
||||||
} } // namespace osgEarth::Triton
|
|
||||||
|
|
||||||
#endif // OSGEARTH_TRITON_LAYER
|
|
@ -17,7 +17,7 @@ BackGroundWidget::BackGroundWidget(const std::string& name,
|
|||||||
//osg::Image *image = ImageUtils::readImage(fileName);
|
//osg::Image *image = ImageUtils::readImage(fileName);
|
||||||
|
|
||||||
LOG_INFO("setimage, {}", fileName);
|
LOG_INFO("setimage, {}", fileName);
|
||||||
setImage(fileName, false);
|
setImage(fileName, true);
|
||||||
|
|
||||||
setTexCoord(0.0f, 0.0f, osgWidget::Widget::LOWER_LEFT);
|
setTexCoord(0.0f, 0.0f, osgWidget::Widget::LOWER_LEFT);
|
||||||
setTexCoord(1.0f, 0.0f, osgWidget::Widget::LOWER_RIGHT);
|
setTexCoord(1.0f, 0.0f, osgWidget::Widget::LOWER_RIGHT);
|
||||||
|
@ -27,8 +27,6 @@ void OESceneUI::InitUI(OsgViewUI* ui) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
|
||||||
|
|
||||||
compositeWidgetManager_ = new CompositeWidgetManager();
|
compositeWidgetManager_ = new CompositeWidgetManager();
|
||||||
compositeWidgetManager_->AttachViewUI(ui);
|
compositeWidgetManager_->AttachViewUI(ui);
|
||||||
zoomManager_ = new ZoomManager();
|
zoomManager_ = new ZoomManager();
|
||||||
@ -45,9 +43,6 @@ void OESceneUI::InitUI(OsgViewUI* ui) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void OESceneUI::OnResize(double width, double height) {
|
void OESceneUI::OnResize(double width, double height) {
|
||||||
|
|
||||||
return;
|
|
||||||
|
|
||||||
dyt_check(compositeWidgetManager_);
|
dyt_check(compositeWidgetManager_);
|
||||||
dyt_check(zoomManager_);
|
dyt_check(zoomManager_);
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ QueryElevationWidget::QueryElevationWidget(OEScene* oeScene)
|
|||||||
, oeScene_(oeScene) {
|
, oeScene_(oeScene) {
|
||||||
LOG_INFO("actor self={}", spdlog::fmt_lib::ptr(this));
|
LOG_INFO("actor self={}", spdlog::fmt_lib::ptr(this));
|
||||||
|
|
||||||
label_ = new ColorLabel(GetElevationString(0, 0, 0).c_str());
|
label_ = new ColorLabel("Pick me!");
|
||||||
addWidget(label_);
|
addWidget(label_);
|
||||||
getBackground()->setColor(0.0f, 0.0f, 0.0f, 0.3f);
|
getBackground()->setColor(0.0f, 0.0f, 0.0f, 0.3f);
|
||||||
}
|
}
|
||||||
@ -51,7 +51,10 @@ void QueryElevationWidget::OnUpdateGeoPoint(double x, double y, double z) {
|
|||||||
// x 保存小数点后6位 c++14
|
// x 保存小数点后6位 c++14
|
||||||
dyt_check(nullptr != label_);
|
dyt_check(nullptr != label_);
|
||||||
|
|
||||||
label_->setLabel(GetElevationString(x, y, z));
|
QString info = QObject::tr("longitude:") + QString::number(x, 'f', 6) + ", "
|
||||||
|
+ QString::fromLocal8Bit("latitude:") + QString::number(y, 'f', 6) + ", "
|
||||||
|
+ QString::fromLocal8Bit("altitude:") + QString::number(z, 'f', 6);
|
||||||
|
label_->setLabel(info.toLocal8Bit().constData());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,14 +63,6 @@ void QueryElevationWidget::ResetCanvasPosition(double width, double height) {
|
|||||||
label_->setSize(width, 20);
|
label_->setSize(width, 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string QueryElevationWidget::GetElevationString(double x, double y, double z) {
|
|
||||||
QString info = QObject::tr("longitude:") + QString::number(x, 'f', 6) + ", "
|
|
||||||
+ QObject::tr("latitude:") + QString::number(y, 'f', 6) + ", "
|
|
||||||
+ QObject::tr("altitude:") + QString::number(z, 'f', 6);
|
|
||||||
return std::string(info.toLocal8Bit().constData());
|
|
||||||
}
|
|
||||||
|
|
||||||
QueryElevationWidget::QueryElevationEventHandler::QueryElevationEventHandler(
|
QueryElevationWidget::QueryElevationEventHandler::QueryElevationEventHandler(
|
||||||
osgEarth::MapNode* mapNode, QueryElevationWidget* widget)
|
osgEarth::MapNode* mapNode, QueryElevationWidget* widget)
|
||||||
: osgGA::GUIEventHandler()
|
: osgGA::GUIEventHandler()
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <osgGA/GUIEventHandler>
|
#include <osgGA/GUIEventHandler>
|
||||||
#include <osgWidget/Box>
|
#include <osgWidget/Box>
|
||||||
#include <osgWidget/Label>
|
#include <osgWidget/Label>
|
||||||
@ -28,9 +28,6 @@ public:
|
|||||||
void OnUpdateGeoPoint(double x, double y, double z);
|
void OnUpdateGeoPoint(double x, double y, double z);
|
||||||
void ResetCanvasPosition(double width, double height);
|
void ResetCanvasPosition(double width, double height);
|
||||||
|
|
||||||
private:
|
|
||||||
std::string GetElevationString(double x, double y, double z);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class OEScene* oeScene_;
|
class OEScene* oeScene_;
|
||||||
osg::ref_ptr<osgWidget::Label> label_;
|
osg::ref_ptr<osgWidget::Label> label_;
|
||||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
647
src/ui/AdvDock/DockAreaTabBar.cpp
Normal file
647
src/ui/AdvDock/DockAreaTabBar.cpp
Normal file
@ -0,0 +1,647 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
** Qt Advanced Docking System
|
||||||
|
** Copyright (C) 2017 Uwe Kindler
|
||||||
|
**
|
||||||
|
** This library is free software; you can redistribute it and/or
|
||||||
|
** modify it under the terms of the GNU Lesser General Public
|
||||||
|
** License as published by the Free Software Foundation; either
|
||||||
|
** version 2.1 of the License, or (at your option) any later version.
|
||||||
|
**
|
||||||
|
** This library is distributed in the hope that it will be useful,
|
||||||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
** Lesser General Public License for more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU Lesser General Public
|
||||||
|
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
/// \file DockAreaTabBar.cpp
|
||||||
|
/// \author Uwe Kindler
|
||||||
|
/// \date 24.08.2018
|
||||||
|
/// \brief Implementation of CDockAreaTabBar class
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// INCLUDES
|
||||||
|
//============================================================================
|
||||||
|
#include "FloatingDragPreview.h"
|
||||||
|
#include "DockAreaTabBar.h"
|
||||||
|
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QScrollBar>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QBoxLayout>
|
||||||
|
#include <QApplication>
|
||||||
|
|
||||||
|
#include "FloatingDockContainer.h"
|
||||||
|
#include "DockAreaWidget.h"
|
||||||
|
#include "DockOverlay.h"
|
||||||
|
#include "DockManager.h"
|
||||||
|
#include "DockWidget.h"
|
||||||
|
#include "DockWidgetTab.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
|
||||||
|
namespace ads
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Private data class of CDockAreaTabBar class (pimpl)
|
||||||
|
*/
|
||||||
|
struct DockAreaTabBarPrivate
|
||||||
|
{
|
||||||
|
CDockAreaTabBar* _this;
|
||||||
|
QPoint DragStartMousePos;
|
||||||
|
CDockAreaWidget* DockArea;
|
||||||
|
IFloatingWidget* FloatingWidget = nullptr;
|
||||||
|
QWidget* TabsContainerWidget;
|
||||||
|
QBoxLayout* TabsLayout;
|
||||||
|
int CurrentIndex = -1;
|
||||||
|
eDragState DragState = DraggingInactive;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private data constructor
|
||||||
|
*/
|
||||||
|
DockAreaTabBarPrivate(CDockAreaTabBar* _public);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update tabs after current index changed or when tabs are removed.
|
||||||
|
* The function reassigns the stylesheet to update the tabs
|
||||||
|
*/
|
||||||
|
void updateTabs();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test function for current drag state
|
||||||
|
*/
|
||||||
|
bool isDraggingState(eDragState dragState) const
|
||||||
|
{
|
||||||
|
return this->DragState == dragState;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// struct DockAreaTabBarPrivate
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
DockAreaTabBarPrivate::DockAreaTabBarPrivate(CDockAreaTabBar* _public) :
|
||||||
|
_this(_public)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void DockAreaTabBarPrivate::updateTabs()
|
||||||
|
{
|
||||||
|
// Set active TAB and update all other tabs to be inactive
|
||||||
|
for (int i = 0; i < _this->count(); ++i)
|
||||||
|
{
|
||||||
|
auto TabWidget = _this->tab(i);
|
||||||
|
if (!TabWidget)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == CurrentIndex)
|
||||||
|
{
|
||||||
|
TabWidget->show();
|
||||||
|
TabWidget->setActiveTab(true);
|
||||||
|
_this->ensureWidgetVisible(TabWidget);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TabWidget->setActiveTab(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockAreaTabBar::CDockAreaTabBar(CDockAreaWidget* parent) :
|
||||||
|
QScrollArea(parent),
|
||||||
|
d(new DockAreaTabBarPrivate(this))
|
||||||
|
{
|
||||||
|
d->DockArea = parent;
|
||||||
|
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
||||||
|
setFrameStyle(QFrame::NoFrame);
|
||||||
|
setWidgetResizable(true);
|
||||||
|
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||||
|
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||||
|
|
||||||
|
d->TabsContainerWidget = new QWidget();
|
||||||
|
d->TabsContainerWidget->setObjectName("tabsContainerWidget");
|
||||||
|
setWidget(d->TabsContainerWidget);
|
||||||
|
|
||||||
|
d->TabsLayout = new QBoxLayout(QBoxLayout::LeftToRight);
|
||||||
|
d->TabsLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
d->TabsLayout->setSpacing(0);
|
||||||
|
d->TabsLayout->addStretch(1);
|
||||||
|
d->TabsContainerWidget->setLayout(d->TabsLayout);
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockAreaTabBar::~CDockAreaTabBar()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaTabBar::wheelEvent(QWheelEvent* Event)
|
||||||
|
{
|
||||||
|
Event->accept();
|
||||||
|
const int direction = Event->angleDelta().y();
|
||||||
|
if (direction < 0)
|
||||||
|
{
|
||||||
|
horizontalScrollBar()->setValue(horizontalScrollBar()->value() + 20);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
horizontalScrollBar()->setValue(horizontalScrollBar()->value() - 20);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaTabBar::mousePressEvent(QMouseEvent* ev)
|
||||||
|
{
|
||||||
|
if (ev->button() == Qt::LeftButton)
|
||||||
|
{
|
||||||
|
ev->accept();
|
||||||
|
d->DragStartMousePos = ev->pos();
|
||||||
|
d->DragState = DraggingMousePressed;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Super::mousePressEvent(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaTabBar::mouseReleaseEvent(QMouseEvent* ev)
|
||||||
|
{
|
||||||
|
if (ev->button() == Qt::LeftButton)
|
||||||
|
{
|
||||||
|
ADS_PRINT("CDockAreaTabBar::mouseReleaseEvent");
|
||||||
|
ev->accept();
|
||||||
|
auto CurrentDragState = d->DragState;
|
||||||
|
d->DragStartMousePos = QPoint();
|
||||||
|
d->DragState = DraggingInactive;
|
||||||
|
if (DraggingFloatingWidget == CurrentDragState)
|
||||||
|
{
|
||||||
|
d->FloatingWidget->finishDragging();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Super::mouseReleaseEvent(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaTabBar::mouseMoveEvent(QMouseEvent* ev)
|
||||||
|
{
|
||||||
|
Super::mouseMoveEvent(ev);
|
||||||
|
if (!(ev->buttons() & Qt::LeftButton) || d->isDraggingState(DraggingInactive))
|
||||||
|
{
|
||||||
|
d->DragState = DraggingInactive;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// move floating window
|
||||||
|
if (d->isDraggingState(DraggingFloatingWidget))
|
||||||
|
{
|
||||||
|
d->FloatingWidget->moveFloating();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this is the last dock area in a dock container it does not make
|
||||||
|
// sense to move it to a new floating widget and leave this one
|
||||||
|
// empty
|
||||||
|
if (d->DockArea->dockContainer()->isFloating()
|
||||||
|
&& d->DockArea->dockContainer()->visibleDockAreaCount() == 1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If one single dock widget in this area is not floatable then the whole
|
||||||
|
// area is not floatable
|
||||||
|
if (!d->DockArea->features().testFlag(CDockWidget::DockWidgetFloatable))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DragDistance = (d->DragStartMousePos - ev->pos()).manhattanLength();
|
||||||
|
if (DragDistance >= CDockManager::startDragDistance())
|
||||||
|
{
|
||||||
|
ADS_PRINT("CTabsScrollArea::startFloating");
|
||||||
|
startFloating(d->DragStartMousePos);
|
||||||
|
auto Overlay = d->DockArea->dockManager()->containerOverlay();
|
||||||
|
Overlay->setAllowedAreas(OuterDockAreas);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaTabBar::mouseDoubleClickEvent(QMouseEvent *event)
|
||||||
|
{
|
||||||
|
// If this is the last dock area in a dock container it does not make
|
||||||
|
// sense to move it to a new floating widget and leave this one
|
||||||
|
// empty
|
||||||
|
if (d->DockArea->dockContainer()->isFloating() && d->DockArea->dockContainer()->dockAreaCount() == 1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!d->DockArea->features().testFlag(CDockWidget::DockWidgetFloatable))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
makeAreaFloating(event->pos(), DraggingInactive);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
IFloatingWidget* CDockAreaTabBar::makeAreaFloating(const QPoint& Offset, eDragState DragState)
|
||||||
|
{
|
||||||
|
QSize Size = d->DockArea->size();
|
||||||
|
d->DragState = DragState;
|
||||||
|
bool OpaqueUndocking = CDockManager::configFlags().testFlag(CDockManager::OpaqueUndocking) ||
|
||||||
|
(DraggingFloatingWidget != DragState);
|
||||||
|
CFloatingDockContainer* FloatingDockContainer = nullptr;
|
||||||
|
IFloatingWidget* FloatingWidget;
|
||||||
|
if (OpaqueUndocking)
|
||||||
|
{
|
||||||
|
FloatingWidget = FloatingDockContainer = new CFloatingDockContainer(d->DockArea);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto w = new CFloatingDragPreview(d->DockArea);
|
||||||
|
connect(w, &CFloatingDragPreview::draggingCanceled, [=]()
|
||||||
|
{
|
||||||
|
d->DragState = DraggingInactive;
|
||||||
|
});
|
||||||
|
FloatingWidget = w;
|
||||||
|
}
|
||||||
|
|
||||||
|
FloatingWidget->startFloating(Offset, Size, DragState, nullptr);
|
||||||
|
if (FloatingDockContainer)
|
||||||
|
{
|
||||||
|
auto TopLevelDockWidget = FloatingDockContainer->topLevelDockWidget();
|
||||||
|
if (TopLevelDockWidget)
|
||||||
|
{
|
||||||
|
TopLevelDockWidget->emitTopLevelChanged(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FloatingWidget;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaTabBar::startFloating(const QPoint& Offset)
|
||||||
|
{
|
||||||
|
d->FloatingWidget = makeAreaFloating(Offset, DraggingFloatingWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaTabBar::setCurrentIndex(int index)
|
||||||
|
{
|
||||||
|
if (index == d->CurrentIndex)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index < -1 || index > (count() - 1))
|
||||||
|
{
|
||||||
|
qWarning() << Q_FUNC_INFO << "Invalid index" << index;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit currentChanging(index);
|
||||||
|
d->CurrentIndex = index;
|
||||||
|
d->updateTabs();
|
||||||
|
emit currentChanged(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
int CDockAreaTabBar::count() const
|
||||||
|
{
|
||||||
|
// The tab bar contains a stretch item as last item
|
||||||
|
return d->TabsLayout->count() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void CDockAreaTabBar::insertTab(int Index, CDockWidgetTab* Tab)
|
||||||
|
{
|
||||||
|
d->TabsLayout->insertWidget(Index, Tab);
|
||||||
|
connect(Tab, SIGNAL(clicked()), this, SLOT(onTabClicked()));
|
||||||
|
connect(Tab, SIGNAL(closeRequested()), this, SLOT(onTabCloseRequested()));
|
||||||
|
connect(Tab, SIGNAL(closeOtherTabsRequested()), this, SLOT(onCloseOtherTabsRequested()));
|
||||||
|
connect(Tab, SIGNAL(moved(const QPoint&)), this, SLOT(onTabWidgetMoved(const QPoint&)));
|
||||||
|
Tab->installEventFilter(this);
|
||||||
|
emit tabInserted(Index);
|
||||||
|
if (Index <= d->CurrentIndex)
|
||||||
|
{
|
||||||
|
setCurrentIndex(d->CurrentIndex + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void CDockAreaTabBar::removeTab(CDockWidgetTab* Tab)
|
||||||
|
{
|
||||||
|
if (!count())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ADS_PRINT("CDockAreaTabBar::removeTab ");
|
||||||
|
int NewCurrentIndex = currentIndex();
|
||||||
|
int RemoveIndex = d->TabsLayout->indexOf(Tab);
|
||||||
|
if (count() == 1)
|
||||||
|
{
|
||||||
|
NewCurrentIndex = -1;
|
||||||
|
}
|
||||||
|
if (NewCurrentIndex > RemoveIndex)
|
||||||
|
{
|
||||||
|
NewCurrentIndex--;
|
||||||
|
}
|
||||||
|
else if (NewCurrentIndex == RemoveIndex)
|
||||||
|
{
|
||||||
|
NewCurrentIndex = -1;
|
||||||
|
// First we walk to the right to search for the next visible tab
|
||||||
|
for (int i = (RemoveIndex + 1); i < count(); ++i)
|
||||||
|
{
|
||||||
|
if (tab(i)->isVisibleTo(this))
|
||||||
|
{
|
||||||
|
NewCurrentIndex = i - 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is no visible tab right to this tab then we walk to
|
||||||
|
// the left to find a visible tab
|
||||||
|
if (NewCurrentIndex < 0)
|
||||||
|
{
|
||||||
|
for (int i = (RemoveIndex - 1); i >= 0; --i)
|
||||||
|
{
|
||||||
|
if (tab(i)->isVisibleTo(this))
|
||||||
|
{
|
||||||
|
NewCurrentIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
emit removingTab(RemoveIndex);
|
||||||
|
d->TabsLayout->removeWidget(Tab);
|
||||||
|
Tab->disconnect(this);
|
||||||
|
Tab->removeEventFilter(this);
|
||||||
|
ADS_PRINT("NewCurrentIndex " << NewCurrentIndex);
|
||||||
|
if (NewCurrentIndex != d->CurrentIndex)
|
||||||
|
{
|
||||||
|
setCurrentIndex(NewCurrentIndex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
d->updateTabs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
int CDockAreaTabBar::currentIndex() const
|
||||||
|
{
|
||||||
|
return d->CurrentIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
CDockWidgetTab* CDockAreaTabBar::currentTab() const
|
||||||
|
{
|
||||||
|
if (d->CurrentIndex < 0)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return qobject_cast<CDockWidgetTab*>(d->TabsLayout->itemAt(d->CurrentIndex)->widget());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void CDockAreaTabBar::onTabClicked()
|
||||||
|
{
|
||||||
|
CDockWidgetTab* Tab = qobject_cast<CDockWidgetTab*>(sender());
|
||||||
|
if (!Tab)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int index = d->TabsLayout->indexOf(Tab);
|
||||||
|
if (index < 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setCurrentIndex(index);
|
||||||
|
emit tabBarClicked(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void CDockAreaTabBar::onTabCloseRequested()
|
||||||
|
{
|
||||||
|
CDockWidgetTab* Tab = qobject_cast<CDockWidgetTab*>(sender());
|
||||||
|
int Index = d->TabsLayout->indexOf(Tab);
|
||||||
|
closeTab(Index);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void CDockAreaTabBar::onCloseOtherTabsRequested()
|
||||||
|
{
|
||||||
|
auto Sender = qobject_cast<CDockWidgetTab*>(sender());
|
||||||
|
for (int i = 0; i < count(); ++i)
|
||||||
|
{
|
||||||
|
auto Tab = tab(i);
|
||||||
|
if (Tab->isClosable() && !Tab->isHidden() && Tab != Sender)
|
||||||
|
{
|
||||||
|
// If the dock widget is deleted with the closeTab() call, its tab
|
||||||
|
// it will no longer be in the layout, and thus the index needs to
|
||||||
|
// be updated to not skip any tabs
|
||||||
|
int Offset = Tab->dockWidget()->features().testFlag(
|
||||||
|
CDockWidget::DockWidgetDeleteOnClose) ? 1 : 0;
|
||||||
|
closeTab(i);
|
||||||
|
|
||||||
|
// If the the dock widget blocks closing, i.e. if the flag
|
||||||
|
// CustomCloseHandling is set, and the dock widget is still open,
|
||||||
|
// then we do not need to correct the index
|
||||||
|
if (Tab->dockWidget()->isClosed())
|
||||||
|
{
|
||||||
|
i -= Offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
CDockWidgetTab* CDockAreaTabBar::tab(int Index) const
|
||||||
|
{
|
||||||
|
if (Index >= count() || Index < 0)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return qobject_cast<CDockWidgetTab*>(d->TabsLayout->itemAt(Index)->widget());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void CDockAreaTabBar::onTabWidgetMoved(const QPoint& GlobalPos)
|
||||||
|
{
|
||||||
|
CDockWidgetTab* MovingTab = qobject_cast<CDockWidgetTab*>(sender());
|
||||||
|
if (!MovingTab)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fromIndex = d->TabsLayout->indexOf(MovingTab);
|
||||||
|
auto MousePos = mapFromGlobal(GlobalPos);
|
||||||
|
int toIndex = -1;
|
||||||
|
// Find tab under mouse
|
||||||
|
for (int i = 0; i < count(); ++i)
|
||||||
|
{
|
||||||
|
CDockWidgetTab* DropTab = tab(i);
|
||||||
|
if (DropTab == MovingTab || !DropTab->isVisibleTo(this)
|
||||||
|
|| !DropTab->geometry().contains(MousePos))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
toIndex = d->TabsLayout->indexOf(DropTab);
|
||||||
|
if (toIndex == fromIndex)
|
||||||
|
{
|
||||||
|
toIndex = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toIndex < 0)
|
||||||
|
{
|
||||||
|
toIndex = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now check if the mouse is behind the last tab
|
||||||
|
if (toIndex < 0)
|
||||||
|
{
|
||||||
|
if (MousePos.x() > tab(count() - 1)->geometry().right())
|
||||||
|
{
|
||||||
|
ADS_PRINT("after all tabs");
|
||||||
|
toIndex = count() - 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
toIndex = fromIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
d->TabsLayout->removeWidget(MovingTab);
|
||||||
|
d->TabsLayout->insertWidget(toIndex, MovingTab);
|
||||||
|
if (toIndex >= 0)
|
||||||
|
{
|
||||||
|
ADS_PRINT("tabMoved from " << fromIndex << " to " << toIndex);
|
||||||
|
emit tabMoved(fromIndex, toIndex);
|
||||||
|
setCurrentIndex(toIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void CDockAreaTabBar::closeTab(int Index)
|
||||||
|
{
|
||||||
|
if (Index < 0 || Index >= count())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Tab = tab(Index);
|
||||||
|
if (Tab->isHidden())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//Tab->hide();
|
||||||
|
emit tabCloseRequested(Index);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
bool CDockAreaTabBar::eventFilter(QObject *watched, QEvent *event)
|
||||||
|
{
|
||||||
|
bool Result = Super::eventFilter(watched, event);
|
||||||
|
CDockWidgetTab* Tab = qobject_cast<CDockWidgetTab*>(watched);
|
||||||
|
if (!Tab)
|
||||||
|
{
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (event->type())
|
||||||
|
{
|
||||||
|
case QEvent::Hide:
|
||||||
|
emit tabClosed(d->TabsLayout->indexOf(Tab)); break;
|
||||||
|
case QEvent::Show:
|
||||||
|
emit tabOpened(d->TabsLayout->indexOf(Tab)); break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
bool CDockAreaTabBar::isTabOpen(int Index) const
|
||||||
|
{
|
||||||
|
if (Index < 0 || Index >= count())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !tab(Index)->isHidden();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
QSize CDockAreaTabBar::minimumSizeHint() const
|
||||||
|
{
|
||||||
|
QSize Size = sizeHint();
|
||||||
|
Size.setWidth(Super::minimumSizeHint().width());// this defines the minimum width of a dock area
|
||||||
|
return Size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
QSize CDockAreaTabBar::sizeHint() const
|
||||||
|
{
|
||||||
|
QSize Size = Super::sizeHint();
|
||||||
|
Size.setHeight(d->TabsContainerWidget->sizeHint().height());
|
||||||
|
return Size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
eDragState CDockAreaTabBar::dragState() const
|
||||||
|
{
|
||||||
|
return d->DragState;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ads
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// EOF DockAreaTabBar.cpp
|
247
src/ui/AdvDock/DockAreaTabBar.h
Normal file
247
src/ui/AdvDock/DockAreaTabBar.h
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
#ifndef DockAreaTabBarH
|
||||||
|
#define DockAreaTabBarH
|
||||||
|
/*******************************************************************************
|
||||||
|
** Qt Advanced Docking System
|
||||||
|
** Copyright (C) 2017 Uwe Kindler
|
||||||
|
**
|
||||||
|
** This library is free software; you can redistribute it and/or
|
||||||
|
** modify it under the terms of the GNU Lesser General Public
|
||||||
|
** License as published by the Free Software Foundation; either
|
||||||
|
** version 2.1 of the License, or (at your option) any later version.
|
||||||
|
**
|
||||||
|
** This library is distributed in the hope that it will be useful,
|
||||||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
** Lesser General Public License for more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU Lesser General Public
|
||||||
|
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
/// \file DockAreaTabBar.h
|
||||||
|
/// \author Uwe Kindler
|
||||||
|
/// \date 24.08.2018
|
||||||
|
/// \brief Declaration of CDockAreaTabBar class
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// INCLUDES
|
||||||
|
//============================================================================
|
||||||
|
#include <QScrollArea>
|
||||||
|
|
||||||
|
#include "ads_globals.h"
|
||||||
|
|
||||||
|
namespace ads
|
||||||
|
{
|
||||||
|
class CDockAreaWidget;
|
||||||
|
class CDockWidgetTab;
|
||||||
|
struct DockAreaTabBarPrivate;
|
||||||
|
class CDockAreaTitleBar;
|
||||||
|
class CFloatingDockContainer;
|
||||||
|
class IFloatingWidget;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom tabbar implementation for tab area that is shown on top of a
|
||||||
|
* dock area widget.
|
||||||
|
* The tabbar displays the tab widgets of the contained dock widgets.
|
||||||
|
* We cannot use QTabBar here because it does a lot of fancy animations
|
||||||
|
* that will crash the application if a tab is removed while the animation
|
||||||
|
* has not finished. And we need to remove a tab, if the user drags a
|
||||||
|
* a dock widget out of a group of tabbed widgets
|
||||||
|
*/
|
||||||
|
class CDockAreaTabBar : public QScrollArea
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
DockAreaTabBarPrivate* d; ///< private data (pimpl)
|
||||||
|
friend struct DockAreaTabBarPrivate;
|
||||||
|
friend class CDockAreaTitleBar;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onTabClicked();
|
||||||
|
void onTabCloseRequested();
|
||||||
|
void onCloseOtherTabsRequested();
|
||||||
|
void onTabWidgetMoved(const QPoint& GlobalPos);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void wheelEvent(QWheelEvent* Event) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores mouse position to detect dragging
|
||||||
|
*/
|
||||||
|
virtual void mousePressEvent(QMouseEvent* ev) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores mouse position to detect dragging
|
||||||
|
*/
|
||||||
|
virtual void mouseReleaseEvent(QMouseEvent* ev) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts floating the complete docking area including all dock widgets,
|
||||||
|
* if it is not the last dock area in a floating widget
|
||||||
|
*/
|
||||||
|
virtual void mouseMoveEvent(QMouseEvent* ev) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Double clicking the title bar also starts floating of the complete area
|
||||||
|
*/
|
||||||
|
virtual void mouseDoubleClickEvent(QMouseEvent *event) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts floating
|
||||||
|
*/
|
||||||
|
void startFloating(const QPoint& Offset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the dock area floating
|
||||||
|
*/
|
||||||
|
IFloatingWidget* makeAreaFloating(const QPoint& Offset, eDragState DragState);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current drag state
|
||||||
|
*/
|
||||||
|
eDragState dragState() const;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
using Super = QScrollArea;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default Constructor
|
||||||
|
*/
|
||||||
|
CDockAreaTabBar(CDockAreaWidget* parent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Virtual Destructor
|
||||||
|
*/
|
||||||
|
virtual ~CDockAreaTabBar();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts the given dock widget tab at the given position.
|
||||||
|
* Inserting a new tab at an index less than or equal to the current index
|
||||||
|
* will increment the current index, but keep the current tab.
|
||||||
|
*/
|
||||||
|
void insertTab(int Index, CDockWidgetTab* Tab);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the given DockWidgetTab from the tabbar
|
||||||
|
*/
|
||||||
|
void removeTab(CDockWidgetTab* Tab);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of tabs in this tabbar
|
||||||
|
*/
|
||||||
|
int count() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current index or -1 if no tab is selected
|
||||||
|
*/
|
||||||
|
int currentIndex() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current tab or a nullptr if no tab is selected.
|
||||||
|
*/
|
||||||
|
CDockWidgetTab* currentTab() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the tab with the given index
|
||||||
|
*/
|
||||||
|
CDockWidgetTab* tab(int Index) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters the tab widget events
|
||||||
|
*/
|
||||||
|
virtual bool eventFilter(QObject *watched, QEvent *event) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function returns true if the tab is open, that means if it is
|
||||||
|
* visible to the user. If the function returns false, the tab is
|
||||||
|
* closed
|
||||||
|
*/
|
||||||
|
bool isTabOpen(int Index) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides the minimumSizeHint() function of QScrollArea
|
||||||
|
* The minimumSizeHint() is bigger than the sizeHint () for the scroll
|
||||||
|
* area because even if the scrollbars are invisible, the required speace
|
||||||
|
* is reserved in the minimumSizeHint(). This override simply returns
|
||||||
|
* sizeHint();
|
||||||
|
*/
|
||||||
|
virtual QSize minimumSizeHint() const override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function provides a sizeHint that matches the height of the
|
||||||
|
* internal viewport.
|
||||||
|
*/
|
||||||
|
virtual QSize sizeHint() const override;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
/**
|
||||||
|
* This property sets the index of the tab bar's visible tab
|
||||||
|
*/
|
||||||
|
void setCurrentIndex(int Index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function will close the tab given in Index param.
|
||||||
|
* Closing a tab means, the tab will be hidden, it will not be removed
|
||||||
|
*/
|
||||||
|
void closeTab(int Index);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
/**
|
||||||
|
* This signal is emitted when the tab bar's current tab is about to be changed. The new
|
||||||
|
* current has the given index, or -1 if there isn't a new one.
|
||||||
|
*/
|
||||||
|
void currentChanging(int Index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted when the tab bar's current tab changes. The new
|
||||||
|
* current has the given index, or -1 if there isn't a new one
|
||||||
|
*/
|
||||||
|
void currentChanged(int Index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted when user clicks on a tab
|
||||||
|
*/
|
||||||
|
void tabBarClicked(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted when the close button on a tab is clicked.
|
||||||
|
* The index is the index that should be closed.
|
||||||
|
*/
|
||||||
|
void tabCloseRequested(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted if a tab has been closed
|
||||||
|
*/
|
||||||
|
void tabClosed(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted if a tab has been opened.
|
||||||
|
* A tab is opened if it has been made visible
|
||||||
|
*/
|
||||||
|
void tabOpened(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted when the tab has moved the tab at index position
|
||||||
|
* from to index position to.
|
||||||
|
*/
|
||||||
|
void tabMoved(int from, int to);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted, just before the tab with the given index is
|
||||||
|
* removed
|
||||||
|
*/
|
||||||
|
void removingTab(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted if a tab has been inserted
|
||||||
|
*/
|
||||||
|
void tabInserted(int index);
|
||||||
|
}; // class CDockAreaTabBar
|
||||||
|
} // namespace ads
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
#endif // DockAreaTabBarH
|
||||||
|
|
386
src/ui/AdvDock/DockAreaTitleBar.cpp
Normal file
386
src/ui/AdvDock/DockAreaTitleBar.cpp
Normal file
@ -0,0 +1,386 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
** Qt Advanced Docking System
|
||||||
|
** Copyright (C) 2017 Uwe Kindler
|
||||||
|
**
|
||||||
|
** This library is free software; you can redistribute it and/or
|
||||||
|
** modify it under the terms of the GNU Lesser General Public
|
||||||
|
** License as published by the Free Software Foundation; either
|
||||||
|
** version 2.1 of the License, or (at your option) any later version.
|
||||||
|
**
|
||||||
|
** This library is distributed in the hope that it will be useful,
|
||||||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
** Lesser General Public License for more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU Lesser General Public
|
||||||
|
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
/// \file DockAreaTitleBar.cpp
|
||||||
|
/// \author Uwe Kindler
|
||||||
|
/// \date 12.10.2018
|
||||||
|
/// \brief Implementation of CDockAreaTitleBar class
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// INCLUDES
|
||||||
|
//============================================================================
|
||||||
|
#include "DockAreaTitleBar.h"
|
||||||
|
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QToolButton>
|
||||||
|
#include <QBoxLayout>
|
||||||
|
#include <QStyle>
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QScrollArea>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
#include "ads_globals.h"
|
||||||
|
#include "FloatingDockContainer.h"
|
||||||
|
#include "DockAreaWidget.h"
|
||||||
|
#include "DockOverlay.h"
|
||||||
|
#include "DockManager.h"
|
||||||
|
#include "DockWidget.h"
|
||||||
|
#include "DockWidgetTab.h"
|
||||||
|
#include "DockAreaTabBar.h"
|
||||||
|
#include "IconProvider.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace ads
|
||||||
|
{
|
||||||
|
using tTileBarButton = QToolButton;
|
||||||
|
/**
|
||||||
|
* Private data class of CDockAreaTitleBar class (pimpl)
|
||||||
|
*/
|
||||||
|
struct DockAreaTitleBarPrivate
|
||||||
|
{
|
||||||
|
CDockAreaTitleBar* _this;
|
||||||
|
tTileBarButton* TabsMenuButton;
|
||||||
|
tTileBarButton* UndockButton;
|
||||||
|
tTileBarButton* CloseButton;
|
||||||
|
QBoxLayout* TopLayout;
|
||||||
|
CDockAreaWidget* DockArea;
|
||||||
|
CDockAreaTabBar* TabBar;
|
||||||
|
bool MenuOutdated = true;
|
||||||
|
QMenu* TabsMenu;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private data constructor
|
||||||
|
*/
|
||||||
|
DockAreaTitleBarPrivate(CDockAreaTitleBar* _public);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the title bar close and menu buttons
|
||||||
|
*/
|
||||||
|
void createButtons();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the internal TabBar
|
||||||
|
*/
|
||||||
|
void createTabBar();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience function for DockManager access
|
||||||
|
*/
|
||||||
|
CDockManager* dockManager() const
|
||||||
|
{
|
||||||
|
return DockArea->dockManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the given config flag is set
|
||||||
|
*/
|
||||||
|
bool testConfigFlag(CDockManager::eConfigFlag Flag) const
|
||||||
|
{
|
||||||
|
return CDockManager::configFlags().testFlag(Flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to set title bar button icons depending on operating
|
||||||
|
* system and to avoid duplicated code. On windows the standard icons
|
||||||
|
* are blurry since Qt 5.11 so we need to do some additional steps.
|
||||||
|
* If the global IconPovider of the dockmanager provides a custom
|
||||||
|
* Icon for the given CustomIconId, the this icon will be used.
|
||||||
|
*/
|
||||||
|
void setTitleBarButtonIcon(tTileBarButton* Button, QStyle::StandardPixmap StandarPixmap,
|
||||||
|
ads::eIcon CustomIconId)
|
||||||
|
{
|
||||||
|
// First we try to use custom icons if available
|
||||||
|
QIcon Icon = CDockManager::iconProvider().customIcon(CustomIconId);
|
||||||
|
if (!Icon.isNull())
|
||||||
|
{
|
||||||
|
Button->setIcon(Icon);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
Button->setIcon(_this->style()->standardIcon(StandarPixmap));
|
||||||
|
#else
|
||||||
|
QPixmap normalPixmap = _this->style()->standardPixmap(StandarPixmap, 0, Button);
|
||||||
|
Icon.addPixmap(internal::createTransparentPixmap(normalPixmap, 0.25), QIcon::Disabled);
|
||||||
|
Icon.addPixmap(normalPixmap, QIcon::Normal);
|
||||||
|
Button->setIcon(Icon);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
};// struct DockAreaTitleBarPrivate
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
DockAreaTitleBarPrivate::DockAreaTitleBarPrivate(CDockAreaTitleBar* _public) :
|
||||||
|
_this(_public)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void DockAreaTitleBarPrivate::createButtons()
|
||||||
|
{
|
||||||
|
QSizePolicy ButtonSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
|
||||||
|
// Tabs menu button
|
||||||
|
TabsMenuButton = new tTileBarButton();
|
||||||
|
TabsMenuButton->setObjectName("tabsMenuButton");
|
||||||
|
TabsMenuButton->setAutoRaise(true);
|
||||||
|
TabsMenuButton->setPopupMode(QToolButton::InstantPopup);
|
||||||
|
setTitleBarButtonIcon(TabsMenuButton, QStyle::SP_TitleBarUnshadeButton, ads::DockAreaMenuIcon);
|
||||||
|
QMenu* TabsMenu = new QMenu(TabsMenuButton);
|
||||||
|
#ifndef QT_NO_TOOLTIP
|
||||||
|
TabsMenu->setToolTipsVisible(true);
|
||||||
|
#endif
|
||||||
|
_this->connect(TabsMenu, SIGNAL(aboutToShow()), SLOT(onTabsMenuAboutToShow()));
|
||||||
|
TabsMenuButton->setMenu(TabsMenu);
|
||||||
|
#ifndef QT_NO_TOOLTIP
|
||||||
|
TabsMenuButton->setToolTip(QObject::tr("List all tabs"));
|
||||||
|
#endif
|
||||||
|
TabsMenuButton->setSizePolicy(ButtonSizePolicy);
|
||||||
|
TopLayout->addWidget(TabsMenuButton, 0);
|
||||||
|
_this->connect(TabsMenuButton->menu(), SIGNAL(triggered(QAction*)),
|
||||||
|
SLOT(onTabsMenuActionTriggered(QAction*)));
|
||||||
|
|
||||||
|
|
||||||
|
// Undock button
|
||||||
|
UndockButton = new tTileBarButton();
|
||||||
|
UndockButton->setObjectName("undockButton");
|
||||||
|
UndockButton->setAutoRaise(true);
|
||||||
|
#ifndef QT_NO_TOOLTIP
|
||||||
|
UndockButton->setToolTip(QObject::tr("Detach Group"));
|
||||||
|
#endif
|
||||||
|
setTitleBarButtonIcon(UndockButton, QStyle::SP_TitleBarNormalButton, ads::DockAreaUndockIcon);
|
||||||
|
UndockButton->setSizePolicy(ButtonSizePolicy);
|
||||||
|
TopLayout->addWidget(UndockButton, 0);
|
||||||
|
_this->connect(UndockButton, SIGNAL(clicked()), SLOT(onUndockButtonClicked()));
|
||||||
|
|
||||||
|
|
||||||
|
// Close button
|
||||||
|
CloseButton = new tTileBarButton();
|
||||||
|
CloseButton->setObjectName("closeButton");
|
||||||
|
CloseButton->setAutoRaise(true);
|
||||||
|
setTitleBarButtonIcon(CloseButton, QStyle::SP_TitleBarCloseButton, ads::DockAreaCloseIcon);
|
||||||
|
#ifndef QT_NO_TOOLTIP
|
||||||
|
if (testConfigFlag(CDockManager::DockAreaCloseButtonClosesTab))
|
||||||
|
{
|
||||||
|
CloseButton->setToolTip(QObject::tr("Close Active Tab"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CloseButton->setToolTip(QObject::tr("Close Group"));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
CloseButton->setSizePolicy(ButtonSizePolicy);
|
||||||
|
CloseButton->setIconSize(QSize(16, 16));
|
||||||
|
if (testConfigFlag(CDockManager::DockAreaHasCloseButton))
|
||||||
|
{
|
||||||
|
TopLayout->addWidget(CloseButton, 0);
|
||||||
|
}
|
||||||
|
_this->connect(CloseButton, SIGNAL(clicked()), SLOT(onCloseButtonClicked()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void DockAreaTitleBarPrivate::createTabBar()
|
||||||
|
{
|
||||||
|
TabBar = new CDockAreaTabBar(DockArea);
|
||||||
|
TopLayout->addWidget(TabBar);
|
||||||
|
_this->connect(TabBar, SIGNAL(tabClosed(int)), SLOT(markTabsMenuOutdated()));
|
||||||
|
_this->connect(TabBar, SIGNAL(tabOpened(int)), SLOT(markTabsMenuOutdated()));
|
||||||
|
_this->connect(TabBar, SIGNAL(tabInserted(int)), SLOT(markTabsMenuOutdated()));
|
||||||
|
_this->connect(TabBar, SIGNAL(removingTab(int)), SLOT(markTabsMenuOutdated()));
|
||||||
|
_this->connect(TabBar, SIGNAL(tabMoved(int, int)), SLOT(markTabsMenuOutdated()));
|
||||||
|
_this->connect(TabBar, SIGNAL(currentChanged(int)), SLOT(onCurrentTabChanged(int)));
|
||||||
|
_this->connect(TabBar, SIGNAL(tabBarClicked(int)), SIGNAL(tabBarClicked(int)));
|
||||||
|
|
||||||
|
TabBar->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
|
_this->connect(TabBar, SIGNAL(customContextMenuRequested(const QPoint&)),
|
||||||
|
SLOT(showContextMenu(const QPoint&)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockAreaTitleBar::CDockAreaTitleBar(CDockAreaWidget* parent) :
|
||||||
|
QFrame(parent),
|
||||||
|
d(new DockAreaTitleBarPrivate(this))
|
||||||
|
{
|
||||||
|
d->DockArea = parent;
|
||||||
|
|
||||||
|
setObjectName("dockAreaTitleBar");
|
||||||
|
d->TopLayout = new QBoxLayout(QBoxLayout::LeftToRight);
|
||||||
|
d->TopLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
d->TopLayout->setSpacing(0);
|
||||||
|
setLayout(d->TopLayout);
|
||||||
|
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||||
|
|
||||||
|
d->createTabBar();
|
||||||
|
d->createButtons();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockAreaTitleBar::~CDockAreaTitleBar()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockAreaTabBar* CDockAreaTitleBar::tabBar() const
|
||||||
|
{
|
||||||
|
return d->TabBar;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaTitleBar::markTabsMenuOutdated()
|
||||||
|
{
|
||||||
|
d->MenuOutdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaTitleBar::onTabsMenuAboutToShow()
|
||||||
|
{
|
||||||
|
if (!d->MenuOutdated)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenu* menu = d->TabsMenuButton->menu();
|
||||||
|
menu->clear();
|
||||||
|
for (int i = 0; i < d->TabBar->count(); ++i)
|
||||||
|
{
|
||||||
|
if (!d->TabBar->isTabOpen(i))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto Tab = d->TabBar->tab(i);
|
||||||
|
QAction* Action = menu->addAction(Tab->icon(), Tab->text());
|
||||||
|
#ifndef QT_NO_TOOLTIP
|
||||||
|
Action->setToolTip(Tab->toolTip());
|
||||||
|
#endif
|
||||||
|
Action->setData(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
d->MenuOutdated = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaTitleBar::onCloseButtonClicked()
|
||||||
|
{
|
||||||
|
ADS_PRINT("CDockAreaTitleBar::onCloseButtonClicked");
|
||||||
|
if (d->testConfigFlag(CDockManager::DockAreaCloseButtonClosesTab))
|
||||||
|
{
|
||||||
|
d->TabBar->closeTab(d->TabBar->currentIndex());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
d->DockArea->closeArea();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaTitleBar::onUndockButtonClicked()
|
||||||
|
{
|
||||||
|
if (d->DockArea->features().testFlag(CDockWidget::DockWidgetFloatable))
|
||||||
|
{
|
||||||
|
d->TabBar->makeAreaFloating(mapFromGlobal(QCursor::pos()), DraggingInactive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaTitleBar::onTabsMenuActionTriggered(QAction* Action)
|
||||||
|
{
|
||||||
|
int Index = Action->data().toInt();
|
||||||
|
d->TabBar->setCurrentIndex(Index);
|
||||||
|
emit tabBarClicked(Index);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaTitleBar::onCurrentTabChanged(int Index)
|
||||||
|
{
|
||||||
|
if (Index < 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d->testConfigFlag(CDockManager::DockAreaCloseButtonClosesTab))
|
||||||
|
{
|
||||||
|
CDockWidget* DockWidget = d->TabBar->tab(Index)->dockWidget();
|
||||||
|
d->CloseButton->setEnabled(DockWidget->features().testFlag(CDockWidget::DockWidgetClosable));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QAbstractButton* CDockAreaTitleBar::button(TitleBarButton which) const
|
||||||
|
{
|
||||||
|
switch (which)
|
||||||
|
{
|
||||||
|
case TitleBarButtonTabsMenu: return d->TabsMenuButton;
|
||||||
|
case TitleBarButtonUndock: return d->UndockButton;
|
||||||
|
case TitleBarButtonClose: return d->CloseButton;
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaTitleBar::setVisible(bool Visible)
|
||||||
|
{
|
||||||
|
Super::setVisible(Visible);
|
||||||
|
markTabsMenuOutdated();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaTitleBar::showContextMenu(const QPoint& pos)
|
||||||
|
{
|
||||||
|
if (d->TabBar->dragState() == DraggingFloatingWidget)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenu Menu(this);
|
||||||
|
auto Action = Menu.addAction(tr("Detach Area"), this, SLOT(onUndockButtonClicked()));
|
||||||
|
Action->setEnabled(d->DockArea->features().testFlag(CDockWidget::DockWidgetFloatable));
|
||||||
|
Menu.addSeparator();
|
||||||
|
Action = Menu.addAction(tr("Close Area"), this, SLOT(onCloseButtonClicked()));
|
||||||
|
Action->setEnabled(d->DockArea->features().testFlag(CDockWidget::DockWidgetClosable));
|
||||||
|
Menu.addAction(tr("Close Other Areas"), d->DockArea, SLOT(closeOtherAreas()));
|
||||||
|
Menu.exec(mapToGlobal(pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace ads
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// EOF DockAreaTitleBar.cpp
|
112
src/ui/AdvDock/DockAreaTitleBar.h
Normal file
112
src/ui/AdvDock/DockAreaTitleBar.h
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
#ifndef DockAreaTitleBarH
|
||||||
|
#define DockAreaTitleBarH
|
||||||
|
/*******************************************************************************
|
||||||
|
** Qt Advanced Docking System
|
||||||
|
** Copyright (C) 2017 Uwe Kindler
|
||||||
|
**
|
||||||
|
** This library is free software; you can redistribute it and/or
|
||||||
|
** modify it under the terms of the GNU Lesser General Public
|
||||||
|
** License as published by the Free Software Foundation; either
|
||||||
|
** version 2.1 of the License, or (at your option) any later version.
|
||||||
|
**
|
||||||
|
** This library is distributed in the hope that it will be useful,
|
||||||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
** Lesser General Public License for more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU Lesser General Public
|
||||||
|
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
/// \file DockAreaTitleBar.h
|
||||||
|
/// \author Uwe Kindler
|
||||||
|
/// \date 12.10.2018
|
||||||
|
/// \brief Declaration of CDockAreaTitleBar class
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// INCLUDES
|
||||||
|
//============================================================================
|
||||||
|
#include <QFrame>
|
||||||
|
|
||||||
|
#include "ads_globals.h"
|
||||||
|
|
||||||
|
class QAbstractButton;
|
||||||
|
|
||||||
|
namespace ads
|
||||||
|
{
|
||||||
|
class CDockAreaTabBar;
|
||||||
|
class CDockAreaWidget;
|
||||||
|
struct DockAreaTitleBarPrivate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Title bar of a dock area.
|
||||||
|
* The title bar contains a tabbar with all tabs for a dock widget group and
|
||||||
|
* with a tabs menu button, a undock button and a close button.
|
||||||
|
*/
|
||||||
|
class CDockAreaTitleBar : public QFrame
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
DockAreaTitleBarPrivate* d; ///< private data (pimpl)
|
||||||
|
friend struct DockAreaTitleBarPrivate;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onTabsMenuAboutToShow();
|
||||||
|
void onCloseButtonClicked();
|
||||||
|
void onUndockButtonClicked();
|
||||||
|
void onTabsMenuActionTriggered(QAction* Action);
|
||||||
|
void onCurrentTabChanged(int Index);
|
||||||
|
void showContextMenu(const QPoint& pos);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
/**
|
||||||
|
* Call this slot to tell the title bar that it should update the tabs menu
|
||||||
|
* the next time it is shown.
|
||||||
|
*/
|
||||||
|
void markTabsMenuOutdated();
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
using Super = QFrame;
|
||||||
|
/**
|
||||||
|
* Default Constructor
|
||||||
|
*/
|
||||||
|
CDockAreaTitleBar(CDockAreaWidget* parent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Virtual Destructor
|
||||||
|
*/
|
||||||
|
virtual ~CDockAreaTitleBar();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the pointer to the tabBar()
|
||||||
|
*/
|
||||||
|
CDockAreaTabBar* tabBar() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the button corresponding to the given title bar button identifier
|
||||||
|
*/
|
||||||
|
QAbstractButton* button(TitleBarButton which) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks the tabs menu outdated before it calls its base class
|
||||||
|
* implementation
|
||||||
|
*/
|
||||||
|
virtual void setVisible(bool Visible) override;
|
||||||
|
|
||||||
|
|
||||||
|
signals:
|
||||||
|
/**
|
||||||
|
* This signal is emitted if a tab in the tab bar is clicked by the user
|
||||||
|
* or if the user clicks on a tab item in the title bar tab menu.
|
||||||
|
*/
|
||||||
|
void tabBarClicked(int index);
|
||||||
|
}; // class name
|
||||||
|
}
|
||||||
|
// namespace ads
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
#endif // DockAreaTitleBarH
|
846
src/ui/AdvDock/DockAreaWidget.cpp
Normal file
846
src/ui/AdvDock/DockAreaWidget.cpp
Normal file
@ -0,0 +1,846 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
** Qt Advanced Docking System
|
||||||
|
** Copyright (C) 2017 Uwe Kindler
|
||||||
|
**
|
||||||
|
** This library is free software; you can redistribute it and/or
|
||||||
|
** modify it under the terms of the GNU Lesser General Public
|
||||||
|
** License as published by the Free Software Foundation; either
|
||||||
|
** version 2.1 of the License, or (at your option) any later version.
|
||||||
|
**
|
||||||
|
** This library is distributed in the hope that it will be useful,
|
||||||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
** Lesser General Public License for more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU Lesser General Public
|
||||||
|
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
/// \file DockAreaWidget.cpp
|
||||||
|
/// \author Uwe Kindler
|
||||||
|
/// \date 24.02.2017
|
||||||
|
/// \brief Implementation of CDockAreaWidget class
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// INCLUDES
|
||||||
|
//============================================================================
|
||||||
|
#include "DockWidgetTab.h"
|
||||||
|
#include "DockAreaWidget.h"
|
||||||
|
|
||||||
|
#include <QStackedLayout>
|
||||||
|
#include <QScrollBar>
|
||||||
|
#include <QScrollArea>
|
||||||
|
#include <QWheelEvent>
|
||||||
|
#include <QStyle>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QSplitter>
|
||||||
|
#include <QXmlStreamWriter>
|
||||||
|
#include <QVector>
|
||||||
|
#include <QList>
|
||||||
|
|
||||||
|
|
||||||
|
#include "DockContainerWidget.h"
|
||||||
|
#include "DockWidget.h"
|
||||||
|
#include "FloatingDockContainer.h"
|
||||||
|
#include "DockManager.h"
|
||||||
|
#include "DockOverlay.h"
|
||||||
|
#include "DockAreaTabBar.h"
|
||||||
|
#include "DockSplitter.h"
|
||||||
|
#include "DockAreaTitleBar.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
|
||||||
|
namespace ads
|
||||||
|
{
|
||||||
|
static const char* const INDEX_PROPERTY = "index";
|
||||||
|
static const char* const ACTION_PROPERTY = "action";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dock area layout mimics stack layout but only inserts the current
|
||||||
|
* widget into the internal QLayout object.
|
||||||
|
* \warning Only the current widget has a parent. All other widgets
|
||||||
|
* do not have a parent. That means, a widget that is in this layout may
|
||||||
|
* return nullptr for its parent() function if it is not the current widget.
|
||||||
|
*/
|
||||||
|
class CDockAreaLayout
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
QBoxLayout* m_ParentLayout;
|
||||||
|
QList<QWidget*> m_Widgets;
|
||||||
|
int m_CurrentIndex = -1;
|
||||||
|
QWidget* m_CurrentWidget = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Creates an instance with the given parent layout
|
||||||
|
*/
|
||||||
|
CDockAreaLayout(QBoxLayout* ParentLayout)
|
||||||
|
: m_ParentLayout(ParentLayout)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of widgets in this layout
|
||||||
|
*/
|
||||||
|
int count() const
|
||||||
|
{
|
||||||
|
return m_Widgets.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts the widget at the given index position into the internal widget
|
||||||
|
* list
|
||||||
|
*/
|
||||||
|
void insertWidget(int index, QWidget* Widget)
|
||||||
|
{
|
||||||
|
Widget->setParent(nullptr);
|
||||||
|
if (index < 0)
|
||||||
|
{
|
||||||
|
index = m_Widgets.count();
|
||||||
|
}
|
||||||
|
m_Widgets.insert(index, Widget);
|
||||||
|
if (m_CurrentIndex < 0)
|
||||||
|
{
|
||||||
|
setCurrentIndex(index);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (index <= m_CurrentIndex )
|
||||||
|
{
|
||||||
|
++m_CurrentIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the given widget from the layout
|
||||||
|
*/
|
||||||
|
void removeWidget(QWidget* Widget)
|
||||||
|
{
|
||||||
|
if (currentWidget() == Widget)
|
||||||
|
{
|
||||||
|
auto LayoutItem = m_ParentLayout->takeAt(1);
|
||||||
|
if (LayoutItem)
|
||||||
|
{
|
||||||
|
LayoutItem->widget()->setParent(nullptr);
|
||||||
|
}
|
||||||
|
m_CurrentWidget = nullptr;
|
||||||
|
m_CurrentIndex = -1;
|
||||||
|
}
|
||||||
|
m_Widgets.removeOne(Widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current selected widget
|
||||||
|
*/
|
||||||
|
QWidget* currentWidget() const
|
||||||
|
{
|
||||||
|
return m_CurrentWidget;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activates the widget with the give index.
|
||||||
|
*/
|
||||||
|
void setCurrentIndex(int index)
|
||||||
|
{
|
||||||
|
QWidget *prev = currentWidget();
|
||||||
|
QWidget *next = widget(index);
|
||||||
|
if (!next || (next == prev && !m_CurrentWidget))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool reenableUpdates = false;
|
||||||
|
QWidget *parent = m_ParentLayout->parentWidget();
|
||||||
|
|
||||||
|
if (parent && parent->updatesEnabled())
|
||||||
|
{
|
||||||
|
reenableUpdates = true;
|
||||||
|
parent->setUpdatesEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto LayoutItem = m_ParentLayout->takeAt(1);
|
||||||
|
if (LayoutItem)
|
||||||
|
{
|
||||||
|
LayoutItem->widget()->setParent(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_ParentLayout->addWidget(next);
|
||||||
|
if (prev)
|
||||||
|
{
|
||||||
|
prev->hide();
|
||||||
|
}
|
||||||
|
m_CurrentIndex = index;
|
||||||
|
m_CurrentWidget = next;
|
||||||
|
|
||||||
|
|
||||||
|
if (reenableUpdates)
|
||||||
|
{
|
||||||
|
parent->setUpdatesEnabled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the index of the current active widget
|
||||||
|
*/
|
||||||
|
int currentIndex() const
|
||||||
|
{
|
||||||
|
return m_CurrentIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if there are no widgets in the layout
|
||||||
|
*/
|
||||||
|
bool isEmpty() const
|
||||||
|
{
|
||||||
|
return m_Widgets.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the index of the given widget
|
||||||
|
*/
|
||||||
|
int indexOf(QWidget* w) const
|
||||||
|
{
|
||||||
|
return m_Widgets.indexOf(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the widget for the given index
|
||||||
|
*/
|
||||||
|
QWidget* widget(int index) const
|
||||||
|
{
|
||||||
|
return (index < m_Widgets.size()) ? m_Widgets.at(index) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the geometry of the current active widget
|
||||||
|
*/
|
||||||
|
QRect geometry() const
|
||||||
|
{
|
||||||
|
return m_Widgets.empty() ? QRect() : currentWidget()->geometry();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
using DockAreaLayout = CDockAreaLayout;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private data class of CDockAreaWidget class (pimpl)
|
||||||
|
*/
|
||||||
|
struct DockAreaWidgetPrivate
|
||||||
|
{
|
||||||
|
CDockAreaWidget* _this = nullptr;
|
||||||
|
QBoxLayout* Layout = nullptr;
|
||||||
|
DockAreaLayout* ContentsLayout = nullptr;
|
||||||
|
CDockAreaTitleBar* TitleBar = nullptr;
|
||||||
|
CDockManager* DockManager = nullptr;
|
||||||
|
bool UpdateTitleBarButtons = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private data constructor
|
||||||
|
*/
|
||||||
|
DockAreaWidgetPrivate(CDockAreaWidget* _public);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the layout for top area with tabs and close button
|
||||||
|
*/
|
||||||
|
void createTitleBar();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the dock widget with the given index
|
||||||
|
*/
|
||||||
|
CDockWidget* dockWidgetAt(int index)
|
||||||
|
{
|
||||||
|
return dynamic_cast<CDockWidget*>(ContentsLayout->widget(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience function to ease title widget access by index
|
||||||
|
*/
|
||||||
|
CDockWidgetTab* tabWidgetAt(int index)
|
||||||
|
{
|
||||||
|
return dockWidgetAt(index)->tabWidget();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the tab action of the given dock widget
|
||||||
|
*/
|
||||||
|
QAction* dockWidgetTabAction(CDockWidget* DockWidget) const
|
||||||
|
{
|
||||||
|
return qvariant_cast<QAction*>(DockWidget->property(ACTION_PROPERTY));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the index of the given dock widget
|
||||||
|
*/
|
||||||
|
int dockWidgetIndex(CDockWidget* DockWidget) const
|
||||||
|
{
|
||||||
|
return DockWidget->property(INDEX_PROPERTY).toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience function for tabbar access
|
||||||
|
*/
|
||||||
|
CDockAreaTabBar* tabBar() const
|
||||||
|
{
|
||||||
|
return TitleBar->tabBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Udpates the enable state of the close and detach button
|
||||||
|
*/
|
||||||
|
void updateTitleBarButtonStates();
|
||||||
|
};
|
||||||
|
// struct DockAreaWidgetPrivate
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
DockAreaWidgetPrivate::DockAreaWidgetPrivate(CDockAreaWidget* _public) :
|
||||||
|
_this(_public)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void DockAreaWidgetPrivate::createTitleBar()
|
||||||
|
{
|
||||||
|
TitleBar = new CDockAreaTitleBar(_this);
|
||||||
|
Layout->addWidget(TitleBar);
|
||||||
|
QObject::connect(tabBar(), &CDockAreaTabBar::tabCloseRequested, _this, &CDockAreaWidget::onTabCloseRequested);
|
||||||
|
QObject::connect(TitleBar, &CDockAreaTitleBar::tabBarClicked, _this, &CDockAreaWidget::setCurrentIndex);
|
||||||
|
QObject::connect(tabBar(), &CDockAreaTabBar::tabMoved, _this, &CDockAreaWidget::reorderDockWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void DockAreaWidgetPrivate::updateTitleBarButtonStates()
|
||||||
|
{
|
||||||
|
if (_this->isHidden())
|
||||||
|
{
|
||||||
|
UpdateTitleBarButtons = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TitleBar->button(TitleBarButtonClose)->setEnabled(
|
||||||
|
_this->features().testFlag(CDockWidget::DockWidgetClosable));
|
||||||
|
TitleBar->button(TitleBarButtonUndock)->setEnabled(
|
||||||
|
_this->features().testFlag(CDockWidget::DockWidgetFloatable));
|
||||||
|
UpdateTitleBarButtons = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockAreaWidget::CDockAreaWidget(CDockManager* DockManager, CDockContainerWidget* parent) :
|
||||||
|
QFrame(parent),
|
||||||
|
d(new DockAreaWidgetPrivate(this))
|
||||||
|
{
|
||||||
|
d->DockManager = DockManager;
|
||||||
|
d->Layout = new QBoxLayout(QBoxLayout::TopToBottom);
|
||||||
|
d->Layout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
d->Layout->setSpacing(0);
|
||||||
|
setLayout(d->Layout);
|
||||||
|
|
||||||
|
d->createTitleBar();
|
||||||
|
d->ContentsLayout = new DockAreaLayout(d->Layout);
|
||||||
|
if (d->DockManager)
|
||||||
|
{
|
||||||
|
emit d->DockManager->dockAreaCreated(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockAreaWidget::~CDockAreaWidget()
|
||||||
|
{
|
||||||
|
ADS_PRINT("~CDockAreaWidget()");
|
||||||
|
delete d->ContentsLayout;
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockManager* CDockAreaWidget::dockManager() const
|
||||||
|
{
|
||||||
|
return d->DockManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockContainerWidget* CDockAreaWidget::dockContainer() const
|
||||||
|
{
|
||||||
|
return internal::findParent<CDockContainerWidget*>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaWidget::addDockWidget(CDockWidget* DockWidget)
|
||||||
|
{
|
||||||
|
insertDockWidget(d->ContentsLayout->count(), DockWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaWidget::insertDockWidget(int index, CDockWidget* DockWidget,
|
||||||
|
bool Activate)
|
||||||
|
{
|
||||||
|
d->ContentsLayout->insertWidget(index, DockWidget);
|
||||||
|
DockWidget->tabWidget()->setDockAreaWidget(this);
|
||||||
|
auto TabWidget = DockWidget->tabWidget();
|
||||||
|
// Inserting the tab will change the current index which in turn will
|
||||||
|
// make the tab widget visible in the slot
|
||||||
|
d->tabBar()->blockSignals(true);
|
||||||
|
d->tabBar()->insertTab(index, TabWidget);
|
||||||
|
d->tabBar()->blockSignals(false);
|
||||||
|
TabWidget->setVisible(!DockWidget->isClosed());
|
||||||
|
DockWidget->setProperty(INDEX_PROPERTY, index);
|
||||||
|
if (Activate)
|
||||||
|
{
|
||||||
|
setCurrentIndex(index);
|
||||||
|
}
|
||||||
|
DockWidget->setDockArea(this);
|
||||||
|
d->updateTitleBarButtonStates();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaWidget::removeDockWidget(CDockWidget* DockWidget)
|
||||||
|
{
|
||||||
|
ADS_PRINT("CDockAreaWidget::removeDockWidget");
|
||||||
|
auto NextOpenDockWidget = nextOpenDockWidget(DockWidget);
|
||||||
|
|
||||||
|
d->ContentsLayout->removeWidget(DockWidget);
|
||||||
|
auto TabWidget = DockWidget->tabWidget();
|
||||||
|
TabWidget->hide();
|
||||||
|
d->tabBar()->removeTab(TabWidget);
|
||||||
|
CDockContainerWidget* DockContainer = dockContainer();
|
||||||
|
if (NextOpenDockWidget)
|
||||||
|
{
|
||||||
|
setCurrentDockWidget(NextOpenDockWidget);
|
||||||
|
}
|
||||||
|
else if (d->ContentsLayout->isEmpty() && DockContainer->dockAreaCount() > 1)
|
||||||
|
{
|
||||||
|
ADS_PRINT("Dock Area empty");
|
||||||
|
DockContainer->removeDockArea(this);
|
||||||
|
this->deleteLater();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// if contents layout is not empty but there are no more open dock
|
||||||
|
// widgets, then we need to hide the dock area because it does not
|
||||||
|
// contain any visible content
|
||||||
|
hideAreaWithNoVisibleContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
d->updateTitleBarButtonStates();
|
||||||
|
updateTitleBarVisibility();
|
||||||
|
auto TopLevelDockWidget = DockContainer->topLevelDockWidget();
|
||||||
|
if (TopLevelDockWidget)
|
||||||
|
{
|
||||||
|
TopLevelDockWidget->emitTopLevelChanged(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (ADS_DEBUG_LEVEL > 0)
|
||||||
|
DockContainer->dumpLayout();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaWidget::hideAreaWithNoVisibleContent()
|
||||||
|
{
|
||||||
|
this->toggleView(false);
|
||||||
|
|
||||||
|
// Hide empty parent splitters
|
||||||
|
auto Splitter = internal::findParent<CDockSplitter*>(this);
|
||||||
|
internal::hideEmptyParentSplitters(Splitter);
|
||||||
|
|
||||||
|
//Hide empty floating widget
|
||||||
|
CDockContainerWidget* Container = this->dockContainer();
|
||||||
|
if (!Container->isFloating())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTitleBarVisibility();
|
||||||
|
auto TopLevelWidget = Container->topLevelDockWidget();
|
||||||
|
auto FloatingWidget = Container->floatingWidget();
|
||||||
|
if (TopLevelWidget)
|
||||||
|
{
|
||||||
|
FloatingWidget->updateWindowTitle();
|
||||||
|
CDockWidget::emitTopLevelEventForWidget(TopLevelWidget, true);
|
||||||
|
}
|
||||||
|
else if (Container->openedDockAreas().isEmpty())
|
||||||
|
{
|
||||||
|
FloatingWidget->hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaWidget::onTabCloseRequested(int Index)
|
||||||
|
{
|
||||||
|
ADS_PRINT("CDockAreaWidget::onTabCloseRequested " << Index);
|
||||||
|
auto* DockWidget = dockWidget(Index);
|
||||||
|
if (DockWidget->features().testFlag(CDockWidget::DockWidgetDeleteOnClose))
|
||||||
|
{
|
||||||
|
//DockWidget->deleteDockWidget();
|
||||||
|
DockWidget->closeDockWidgetInternal();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DockWidget->toggleView(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockWidget* CDockAreaWidget::currentDockWidget() const
|
||||||
|
{
|
||||||
|
int CurrentIndex = currentIndex();
|
||||||
|
if (CurrentIndex < 0)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dockWidget(CurrentIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaWidget::setCurrentDockWidget(CDockWidget* DockWidget)
|
||||||
|
{
|
||||||
|
if (dockManager()->isRestoringState())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
internalSetCurrentDockWidget(DockWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaWidget::internalSetCurrentDockWidget(CDockWidget* DockWidget)
|
||||||
|
{
|
||||||
|
int Index = index(DockWidget);
|
||||||
|
if (Index < 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setCurrentIndex(Index);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaWidget::setCurrentIndex(int index)
|
||||||
|
{
|
||||||
|
auto TabBar = d->tabBar();
|
||||||
|
if (index < 0 || index > (TabBar->count() - 1))
|
||||||
|
{
|
||||||
|
qWarning() << Q_FUNC_INFO << "Invalid index" << index;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cw = d->ContentsLayout->currentWidget();
|
||||||
|
auto nw = d->ContentsLayout->widget(index);
|
||||||
|
if (cw == nw && !nw->isHidden())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit currentChanging(index);
|
||||||
|
TabBar->setCurrentIndex(index);
|
||||||
|
d->ContentsLayout->setCurrentIndex(index);
|
||||||
|
d->ContentsLayout->currentWidget()->show();
|
||||||
|
emit currentChanged(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
int CDockAreaWidget::currentIndex() const
|
||||||
|
{
|
||||||
|
return d->ContentsLayout->currentIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QRect CDockAreaWidget::titleBarGeometry() const
|
||||||
|
{
|
||||||
|
return d->TitleBar->geometry();
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QRect CDockAreaWidget::contentAreaGeometry() const
|
||||||
|
{
|
||||||
|
return d->ContentsLayout->geometry();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
int CDockAreaWidget::index(CDockWidget* DockWidget)
|
||||||
|
{
|
||||||
|
return d->ContentsLayout->indexOf(DockWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QList<CDockWidget*> CDockAreaWidget::dockWidgets() const
|
||||||
|
{
|
||||||
|
QList<CDockWidget*> DockWidgetList;
|
||||||
|
for (int i = 0; i < d->ContentsLayout->count(); ++i)
|
||||||
|
{
|
||||||
|
DockWidgetList.append(dockWidget(i));
|
||||||
|
}
|
||||||
|
return DockWidgetList;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
int CDockAreaWidget::openDockWidgetsCount() const
|
||||||
|
{
|
||||||
|
int Count = 0;
|
||||||
|
for (int i = 0; i < d->ContentsLayout->count(); ++i)
|
||||||
|
{
|
||||||
|
if (!dockWidget(i)->isClosed())
|
||||||
|
{
|
||||||
|
++Count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QList<CDockWidget*> CDockAreaWidget::openedDockWidgets() const
|
||||||
|
{
|
||||||
|
QList<CDockWidget*> DockWidgetList;
|
||||||
|
for (int i = 0; i < d->ContentsLayout->count(); ++i)
|
||||||
|
{
|
||||||
|
CDockWidget* DockWidget = dockWidget(i);
|
||||||
|
if (!DockWidget->isClosed())
|
||||||
|
{
|
||||||
|
DockWidgetList.append(dockWidget(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return DockWidgetList;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
int CDockAreaWidget::indexOfFirstOpenDockWidget() const
|
||||||
|
{
|
||||||
|
for (int i = 0; i < d->ContentsLayout->count(); ++i)
|
||||||
|
{
|
||||||
|
if (!dockWidget(i)->isClosed())
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
int CDockAreaWidget::dockWidgetsCount() const
|
||||||
|
{
|
||||||
|
return d->ContentsLayout->count();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockWidget* CDockAreaWidget::dockWidget(int Index) const
|
||||||
|
{
|
||||||
|
return qobject_cast<CDockWidget*>(d->ContentsLayout->widget(Index));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaWidget::reorderDockWidget(int fromIndex, int toIndex)
|
||||||
|
{
|
||||||
|
ADS_PRINT("CDockAreaWidget::reorderDockWidget");
|
||||||
|
if (fromIndex >= d->ContentsLayout->count() || fromIndex < 0
|
||||||
|
|| toIndex >= d->ContentsLayout->count() || toIndex < 0 || fromIndex == toIndex)
|
||||||
|
{
|
||||||
|
ADS_PRINT("Invalid index for tab movement" << fromIndex << toIndex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Widget = d->ContentsLayout->widget(fromIndex);
|
||||||
|
d->ContentsLayout->removeWidget(Widget);
|
||||||
|
d->ContentsLayout->insertWidget(toIndex, Widget);
|
||||||
|
setCurrentIndex(toIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaWidget::toggleDockWidgetView(CDockWidget* DockWidget, bool Open)
|
||||||
|
{
|
||||||
|
Q_UNUSED(DockWidget);
|
||||||
|
Q_UNUSED(Open);
|
||||||
|
updateTitleBarVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaWidget::updateTitleBarVisibility()
|
||||||
|
{
|
||||||
|
CDockContainerWidget* Container = dockContainer();
|
||||||
|
if (!Container)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d->TitleBar)
|
||||||
|
{
|
||||||
|
d->TitleBar->setVisible(!Container->isFloating() || !Container->hasTopLevelDockWidget());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaWidget::markTitleBarMenuOutdated()
|
||||||
|
{
|
||||||
|
if (d->TitleBar)
|
||||||
|
{
|
||||||
|
d->TitleBar->markTabsMenuOutdated();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaWidget::saveState(QXmlStreamWriter& s) const
|
||||||
|
{
|
||||||
|
s.writeStartElement("Area");
|
||||||
|
s.writeAttribute("Tabs", QString::number(d->ContentsLayout->count()));
|
||||||
|
auto CurrentDockWidget = currentDockWidget();
|
||||||
|
QString Name = CurrentDockWidget ? CurrentDockWidget->objectName() : "";
|
||||||
|
s.writeAttribute("Current", Name);
|
||||||
|
ADS_PRINT("CDockAreaWidget::saveState TabCount: " << d->ContentsLayout->count()
|
||||||
|
<< " Current: " << Name);
|
||||||
|
for (int i = 0; i < d->ContentsLayout->count(); ++i)
|
||||||
|
{
|
||||||
|
dockWidget(i)->saveState(s);
|
||||||
|
}
|
||||||
|
s.writeEndElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockWidget* CDockAreaWidget::nextOpenDockWidget(CDockWidget* DockWidget) const
|
||||||
|
{
|
||||||
|
auto OpenDockWidgets = openedDockWidgets();
|
||||||
|
if (OpenDockWidgets.count() > 1 || (OpenDockWidgets.count() == 1 && OpenDockWidgets[0] != DockWidget))
|
||||||
|
{
|
||||||
|
CDockWidget* NextDockWidget;
|
||||||
|
if (OpenDockWidgets.last() == DockWidget)
|
||||||
|
{
|
||||||
|
NextDockWidget = OpenDockWidgets[OpenDockWidgets.count() - 2];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int NextIndex = OpenDockWidgets.indexOf(DockWidget) + 1;
|
||||||
|
NextDockWidget = OpenDockWidgets[NextIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
return NextDockWidget;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockWidget::DockWidgetFeatures CDockAreaWidget::features(eBitwiseOperator Mode) const
|
||||||
|
{
|
||||||
|
if (BitwiseAnd == Mode)
|
||||||
|
{
|
||||||
|
CDockWidget::DockWidgetFeatures Features(CDockWidget::AllDockWidgetFeatures);
|
||||||
|
for (const auto DockWidget : dockWidgets())
|
||||||
|
{
|
||||||
|
Features &= DockWidget->features();
|
||||||
|
}
|
||||||
|
return Features;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CDockWidget::DockWidgetFeatures Features(CDockWidget::NoDockWidgetFeatures);
|
||||||
|
for (const auto DockWidget : dockWidgets())
|
||||||
|
{
|
||||||
|
Features |= DockWidget->features();
|
||||||
|
}
|
||||||
|
return Features;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaWidget::toggleView(bool Open)
|
||||||
|
{
|
||||||
|
setVisible(Open);
|
||||||
|
|
||||||
|
emit viewToggled(Open);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaWidget::setVisible(bool Visible)
|
||||||
|
{
|
||||||
|
Super::setVisible(Visible);
|
||||||
|
if (d->UpdateTitleBarButtons)
|
||||||
|
{
|
||||||
|
d->updateTitleBarButtonStates();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QAbstractButton* CDockAreaWidget::titleBarButton(TitleBarButton which) const
|
||||||
|
{
|
||||||
|
return d->TitleBar->button(which);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaWidget::closeArea()
|
||||||
|
{
|
||||||
|
// If there is only one single dock widget and this widget has the
|
||||||
|
// DeleteOnClose feature, then we delete the dock widget now
|
||||||
|
auto OpenDockWidgets = openedDockWidgets();
|
||||||
|
if (OpenDockWidgets.count() == 1 && OpenDockWidgets[0]->features().testFlag(CDockWidget::DockWidgetDeleteOnClose))
|
||||||
|
{
|
||||||
|
OpenDockWidgets[0]->closeDockWidgetInternal();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (auto DockWidget : openedDockWidgets())
|
||||||
|
{
|
||||||
|
DockWidget->toggleView(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaWidget::closeOtherAreas()
|
||||||
|
{
|
||||||
|
dockContainer()->closeOtherAreas(this);
|
||||||
|
}
|
||||||
|
} // namespace ads
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// EOF DockAreaWidget.cpp
|
303
src/ui/AdvDock/DockAreaWidget.h
Normal file
303
src/ui/AdvDock/DockAreaWidget.h
Normal file
@ -0,0 +1,303 @@
|
|||||||
|
#ifndef DockAreaWidgetH
|
||||||
|
#define DockAreaWidgetH
|
||||||
|
/*******************************************************************************
|
||||||
|
** Qt Advanced Docking System
|
||||||
|
** Copyright (C) 2017 Uwe Kindler
|
||||||
|
**
|
||||||
|
** This library is free software; you can redistribute it and/or
|
||||||
|
** modify it under the terms of the GNU Lesser General Public
|
||||||
|
** License as published by the Free Software Foundation; either
|
||||||
|
** version 2.1 of the License, or (at your option) any later version.
|
||||||
|
**
|
||||||
|
** This library is distributed in the hope that it will be useful,
|
||||||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
** Lesser General Public License for more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU Lesser General Public
|
||||||
|
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
/// \file DockAreaWidget.h
|
||||||
|
/// \author Uwe Kindler
|
||||||
|
/// \date 24.02.2017
|
||||||
|
/// \brief Declaration of CDockAreaWidget class
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// INCLUDES
|
||||||
|
//============================================================================
|
||||||
|
#include <QFrame>
|
||||||
|
|
||||||
|
#include "DockWidget.h"
|
||||||
|
|
||||||
|
class QXmlStreamWriter;
|
||||||
|
class QAbstractButton;
|
||||||
|
|
||||||
|
namespace ads
|
||||||
|
{
|
||||||
|
struct DockAreaWidgetPrivate;
|
||||||
|
class CDockManager;
|
||||||
|
class CDockContainerWidget;
|
||||||
|
class DockContainerWidgetPrivate;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DockAreaWidget manages multiple instances of DockWidgets.
|
||||||
|
* It displays a title tab, which is clickable and will switch to
|
||||||
|
* the contents associated to the title when clicked.
|
||||||
|
*/
|
||||||
|
class CDockAreaWidget : public QFrame
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
DockAreaWidgetPrivate* d; ///< private data (pimpl)
|
||||||
|
friend struct DockAreaWidgetPrivate;
|
||||||
|
friend class CDockContainerWidget;
|
||||||
|
friend class DockContainerWidgetPrivate;
|
||||||
|
friend class CDockWidgetTab;
|
||||||
|
friend struct DockWidgetPrivate;
|
||||||
|
friend class CDockWidget;
|
||||||
|
friend struct DockManagerPrivate;
|
||||||
|
friend class CDockManager;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onTabCloseRequested(int Index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reorder the index position of DockWidget at fromIndx to toIndex
|
||||||
|
* if a tab in the tabbar is dragged from one index to another one
|
||||||
|
*/
|
||||||
|
void reorderDockWidget(int fromIndex, int toIndex);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* Inserts a dock widget into dock area.
|
||||||
|
* All dockwidgets in the dock area tabified in a stacked layout with tabs.
|
||||||
|
* The index indicates the index of the new dockwidget in the tabbar and
|
||||||
|
* in the stacked layout. If the Activate parameter is true, the new
|
||||||
|
* DockWidget will be the active one in the stacked layout
|
||||||
|
*/
|
||||||
|
void insertDockWidget(int index, CDockWidget* DockWidget, bool Activate = true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a new dock widget to dock area.
|
||||||
|
* All dockwidgets in the dock area tabified in a stacked layout with tabs
|
||||||
|
*/
|
||||||
|
void addDockWidget(CDockWidget* DockWidget);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the given dock widget from the dock area
|
||||||
|
*/
|
||||||
|
void removeDockWidget(CDockWidget* DockWidget);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called from dock widget if it is opened or closed
|
||||||
|
*/
|
||||||
|
void toggleDockWidgetView(CDockWidget* DockWidget, bool Open);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a helper function to get the next open dock widget to activate
|
||||||
|
* if the given DockWidget will be closed or removed.
|
||||||
|
* The function returns the next widget that should be activated or
|
||||||
|
* nullptr in case there are no more open widgets in this area.
|
||||||
|
*/
|
||||||
|
CDockWidget* nextOpenDockWidget(CDockWidget* DockWidget) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the index of the given DockWidget in the internal layout
|
||||||
|
*/
|
||||||
|
int index(CDockWidget* DockWidget);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call this function, if you already know, that the dock does not
|
||||||
|
* contain any visible content (any open dock widgets).
|
||||||
|
*/
|
||||||
|
void hideAreaWithNoVisibleContent();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the dock area layout and components visibility
|
||||||
|
*/
|
||||||
|
void updateTitleBarVisibility();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the internal private function for setting the current widget.
|
||||||
|
* This function is called by the public setCurrentDockWidget() function
|
||||||
|
* and by the dock manager when restoring the state
|
||||||
|
*/
|
||||||
|
void internalSetCurrentDockWidget(CDockWidget* DockWidget);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks tabs menu to update
|
||||||
|
*/
|
||||||
|
void markTitleBarMenuOutdated();
|
||||||
|
|
||||||
|
protected slots:
|
||||||
|
void toggleView(bool Open);
|
||||||
|
|
||||||
|
public:
|
||||||
|
using Super = QFrame;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default Constructor
|
||||||
|
*/
|
||||||
|
CDockAreaWidget(CDockManager* DockManager, CDockContainerWidget* parent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Virtual Destructor
|
||||||
|
*/
|
||||||
|
virtual ~CDockAreaWidget();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the dock manager object this dock area belongs to
|
||||||
|
*/
|
||||||
|
CDockManager* dockManager() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the dock container widget this dock area widget belongs to or 0
|
||||||
|
* if there is no
|
||||||
|
*/
|
||||||
|
CDockContainerWidget* dockContainer() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the rectangle of the title area
|
||||||
|
*/
|
||||||
|
QRect titleBarGeometry() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the rectangle of the content
|
||||||
|
*/
|
||||||
|
QRect contentAreaGeometry() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of dock widgets in this area
|
||||||
|
*/
|
||||||
|
int dockWidgetsCount() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of all dock widgets in this dock area.
|
||||||
|
* This list contains open and closed dock widgets.
|
||||||
|
*/
|
||||||
|
QList<CDockWidget*> dockWidgets() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of open dock widgets in this area
|
||||||
|
*/
|
||||||
|
int openDockWidgetsCount() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of dock widgets that are not closed.
|
||||||
|
*/
|
||||||
|
QList<CDockWidget*> openedDockWidgets() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a dock widget by its index
|
||||||
|
*/
|
||||||
|
CDockWidget* dockWidget(int Index) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the index of the current active dock widget or -1 if there
|
||||||
|
* are is no active dock widget (ie.e if all dock widgets are closed)
|
||||||
|
*/
|
||||||
|
int currentIndex() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the index of the first open dock widgets in the list of
|
||||||
|
* dock widgets.
|
||||||
|
* This function is here for performance reasons. Normally it would
|
||||||
|
* be possible to take the first dock widget from the list returned by
|
||||||
|
* openedDockWidgets() function. But that function enumerates all
|
||||||
|
* dock widgets while this functions stops after the first open dock widget.
|
||||||
|
* If there are no open dock widgets, the function returns -1.
|
||||||
|
*/
|
||||||
|
int indexOfFirstOpenDockWidget() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current active dock widget or a nullptr if there is no
|
||||||
|
* active dock widget (i.e. if all dock widgets are closed)
|
||||||
|
*/
|
||||||
|
CDockWidget* currentDockWidget() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows the tab with the given dock widget
|
||||||
|
*/
|
||||||
|
void setCurrentDockWidget(CDockWidget* DockWidget);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the state into the given stream
|
||||||
|
*/
|
||||||
|
void saveState(QXmlStreamWriter& Stream) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This functions returns the dock widget features of all dock widget in
|
||||||
|
* this area.
|
||||||
|
* A bitwise and is used to combine the flags of all dock widgets. That
|
||||||
|
* means, if only one single dock widget does not support a certain flag,
|
||||||
|
* the whole dock are does not support the flag. I.e. if one single
|
||||||
|
* dock widget in this area is not closable, the whole dock are is not
|
||||||
|
* closable.
|
||||||
|
*/
|
||||||
|
CDockWidget::DockWidgetFeatures features(eBitwiseOperator Mode = BitwiseAnd) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the title bar button corresponding to the given title bar
|
||||||
|
* button identifier
|
||||||
|
*/
|
||||||
|
QAbstractButton* titleBarButton(TitleBarButton which) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the close button if visibility changed
|
||||||
|
*/
|
||||||
|
virtual void setVisible(bool Visible) override;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
/**
|
||||||
|
* This activates the tab for the given tab index.
|
||||||
|
* If the dock widget for the given tab is not visible, the this function
|
||||||
|
* call will make it visible.
|
||||||
|
*/
|
||||||
|
void setCurrentIndex(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes the dock area and all dock widgets in this area
|
||||||
|
*/
|
||||||
|
void closeArea();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function closes all other areas except of this area
|
||||||
|
*/
|
||||||
|
void closeOtherAreas();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
/**
|
||||||
|
* This signal is emitted when user clicks on a tab at an index.
|
||||||
|
*/
|
||||||
|
void tabBarClicked(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted when the tab bar's current tab is about to be changed. The new
|
||||||
|
* current has the given index, or -1 if there isn't a new one.
|
||||||
|
* @param index
|
||||||
|
*/
|
||||||
|
void currentChanging(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted when the tab bar's current tab changes. The new
|
||||||
|
* current has the given index, or -1 if there isn't a new one
|
||||||
|
* @param index
|
||||||
|
*/
|
||||||
|
void currentChanged(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted if the visibility of this dock area is toggled
|
||||||
|
* via toggle view function
|
||||||
|
*/
|
||||||
|
void viewToggled(bool Open);
|
||||||
|
}; // class DockAreaWidget
|
||||||
|
}
|
||||||
|
// namespace ads
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
#endif // DockAreaWidgetH
|
1740
src/ui/AdvDock/DockContainerWidget.cpp
Normal file
1740
src/ui/AdvDock/DockContainerWidget.cpp
Normal file
File diff suppressed because it is too large
Load Diff
278
src/ui/AdvDock/DockContainerWidget.h
Normal file
278
src/ui/AdvDock/DockContainerWidget.h
Normal file
@ -0,0 +1,278 @@
|
|||||||
|
#ifndef DockContainerWidgetH
|
||||||
|
#define DockContainerWidgetH
|
||||||
|
/*******************************************************************************
|
||||||
|
** Qt Advanced Docking System
|
||||||
|
** Copyright (C) 2017 Uwe Kindler
|
||||||
|
**
|
||||||
|
** This library is free software; you can redistribute it and/or
|
||||||
|
** modify it under the terms of the GNU Lesser General Public
|
||||||
|
** License as published by the Free Software Foundation; either
|
||||||
|
** version 2.1 of the License, or (at your option) any later version.
|
||||||
|
**
|
||||||
|
** This library is distributed in the hope that it will be useful,
|
||||||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
** Lesser General Public License for more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU Lesser General Public
|
||||||
|
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
/// \file DockContainerWidget.h
|
||||||
|
/// \author Uwe Kindler
|
||||||
|
/// \date 24.02.2017
|
||||||
|
/// \brief Declaration of CDockContainerWidget class
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// INCLUDES
|
||||||
|
//============================================================================
|
||||||
|
#include <QFrame>
|
||||||
|
|
||||||
|
#include "DockWidget.h"
|
||||||
|
|
||||||
|
class QXmlStreamWriter;
|
||||||
|
|
||||||
|
|
||||||
|
namespace ads
|
||||||
|
{
|
||||||
|
class DockContainerWidgetPrivate;
|
||||||
|
class CDockAreaWidget;
|
||||||
|
class CDockWidget;
|
||||||
|
class CDockManager;
|
||||||
|
struct DockManagerPrivate;
|
||||||
|
class CFloatingDockContainer;
|
||||||
|
struct FloatingDockContainerPrivate;
|
||||||
|
class CFloatingDragPreview;
|
||||||
|
struct FloatingDragPreviewPrivate;
|
||||||
|
class CDockingStateReader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Container that manages a number of dock areas with single dock widgets
|
||||||
|
* or tabyfied dock widgets in each area.
|
||||||
|
* Each window that support docking has a DockContainerWidget. That means
|
||||||
|
* the main application window and all floating windows are ore contain
|
||||||
|
* an DockContainerWidget.
|
||||||
|
*/
|
||||||
|
class CDockContainerWidget : public QFrame
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
DockContainerWidgetPrivate* d; ///< private data (pimpl)
|
||||||
|
friend class DockContainerWidgetPrivate;
|
||||||
|
friend class CDockManager;
|
||||||
|
friend struct DockManagerPrivate;
|
||||||
|
friend class CDockAreaWidget;
|
||||||
|
friend struct DockAreaWidgetPrivate;
|
||||||
|
friend class CFloatingDockContainer;
|
||||||
|
friend struct FloatingDockContainerPrivate;
|
||||||
|
friend class CDockWidget;
|
||||||
|
friend class CFloatingDragPreview;
|
||||||
|
friend struct FloatingDragPreviewPrivate;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* Handles activation events to update zOrderIndex
|
||||||
|
*/
|
||||||
|
virtual bool event(QEvent *e) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Access function for the internal root splitter
|
||||||
|
*/
|
||||||
|
QSplitter* rootSplitter() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function for creation of the root splitter
|
||||||
|
*/
|
||||||
|
void createRootSplitter();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Drop floating widget into the container
|
||||||
|
*/
|
||||||
|
void dropFloatingWidget(CFloatingDockContainer* FloatingWidget, const QPoint& TargetPos);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Drop a dock area or a dock widget given in widget parameter
|
||||||
|
*/
|
||||||
|
void dropWidget(QWidget* Widget, const QPoint& TargetPos);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the given dock area to this container widget
|
||||||
|
*/
|
||||||
|
void addDockArea(CDockAreaWidget* DockAreaWidget, DockWidgetArea area = CenterDockWidgetArea);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the given dock area from this container
|
||||||
|
*/
|
||||||
|
void removeDockArea(CDockAreaWidget* area);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the state into the given stream
|
||||||
|
*/
|
||||||
|
void saveState(QXmlStreamWriter& Stream) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restores the state from given stream.
|
||||||
|
* If Testing is true, the function only parses the data from the given
|
||||||
|
* stream but does not restore anything. You can use this check for
|
||||||
|
* faulty files before you start restoring the state
|
||||||
|
*/
|
||||||
|
bool restoreState(CDockingStateReader& Stream, bool Testing);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function returns the last added dock area widget for the given
|
||||||
|
* area identifier or 0 if no dock area widget has been added for the given
|
||||||
|
* area
|
||||||
|
*/
|
||||||
|
CDockAreaWidget* lastAddedDockAreaWidget(DockWidgetArea area) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function returns true if this dock area has only one single
|
||||||
|
* visible dock widget.
|
||||||
|
* A top level widget is a real floating widget. Only the isFloating()
|
||||||
|
* function of top level widgets may returns true.
|
||||||
|
*/
|
||||||
|
bool hasTopLevelDockWidget() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If hasSingleVisibleDockWidget() returns true, this function returns the
|
||||||
|
* one and only visible dock widget. Otherwise it returns a nullptr.
|
||||||
|
*/
|
||||||
|
CDockWidget* topLevelDockWidget() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the top level dock area.
|
||||||
|
*/
|
||||||
|
CDockAreaWidget* topLevelDockArea() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function returns a list of all dock widgets in this floating widget.
|
||||||
|
* It may be possible, depending on the implementation, that dock widgets,
|
||||||
|
* that are not visible to the user have no parent widget. Therefore simply
|
||||||
|
* calling findChildren() would not work here. Therefore this function
|
||||||
|
* iterates over all dock areas and creates a list that contains all
|
||||||
|
* dock widgets returned from all dock areas.
|
||||||
|
*/
|
||||||
|
QList<CDockWidget*> dockWidgets() const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Default Constructor
|
||||||
|
*/
|
||||||
|
CDockContainerWidget(CDockManager* DockManager, QWidget* parent = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Virtual Destructor
|
||||||
|
*/
|
||||||
|
virtual ~CDockContainerWidget();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds dockwidget into the given area.
|
||||||
|
* If DockAreaWidget is not null, then the area parameter indicates the area
|
||||||
|
* into the DockAreaWidget. If DockAreaWidget is null, the Dockwidget will
|
||||||
|
* be dropped into the container.
|
||||||
|
* \return Returns the dock area widget that contains the new DockWidget
|
||||||
|
*/
|
||||||
|
CDockAreaWidget* addDockWidget(DockWidgetArea area, CDockWidget* Dockwidget,
|
||||||
|
CDockAreaWidget* DockAreaWidget = nullptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes dockwidget
|
||||||
|
*/
|
||||||
|
void removeDockWidget(CDockWidget* Dockwidget);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current zOrderIndex
|
||||||
|
*/
|
||||||
|
virtual unsigned int zOrderIndex() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function returns true if this container widgets z order index is
|
||||||
|
* higher than the index of the container widget given in Other parameter
|
||||||
|
*/
|
||||||
|
bool isInFrontOf(CDockContainerWidget* Other) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the dock area at teh given global position or 0 if there is no
|
||||||
|
* dock area at this position
|
||||||
|
*/
|
||||||
|
CDockAreaWidget* dockAreaAt(const QPoint& GlobalPos) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the dock area at the given Index or 0 if the index is out of
|
||||||
|
* range
|
||||||
|
*/
|
||||||
|
CDockAreaWidget* dockArea(int Index) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of dock areas that are not closed
|
||||||
|
* If all dock widgets in a dock area are closed, the dock area will be closed
|
||||||
|
*/
|
||||||
|
QList<CDockAreaWidget*> openedDockAreas() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of dock areas in this container
|
||||||
|
*/
|
||||||
|
int dockAreaCount() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of visible dock areas
|
||||||
|
*/
|
||||||
|
int visibleDockAreaCount() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function returns true, if this container is in a floating widget
|
||||||
|
*/
|
||||||
|
bool isFloating() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dumps the layout for debugging purposes
|
||||||
|
*/
|
||||||
|
void dumpLayout();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This functions returns the dock widget features of all dock widget in
|
||||||
|
* this container.
|
||||||
|
* A bitwise and is used to combine the flags of all dock widgets. That
|
||||||
|
* means, if only dock widget does not support a certain flag, the whole
|
||||||
|
* dock are does not support the flag.
|
||||||
|
*/
|
||||||
|
CDockWidget::DockWidgetFeatures features() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this dock container is in a floating widget, this function returns
|
||||||
|
* the floating widget.
|
||||||
|
* Else, it returns a nullptr.
|
||||||
|
*/
|
||||||
|
CFloatingDockContainer* floatingWidget() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call this function to close all dock areas except the KeepOpenArea
|
||||||
|
*/
|
||||||
|
void closeOtherAreas(CDockAreaWidget* KeepOpenArea);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
/**
|
||||||
|
* This signal is emitted if one or multiple dock areas has been added to
|
||||||
|
* the internal list of dock areas.
|
||||||
|
* If multiple dock areas are inserted, this signal is emitted only once
|
||||||
|
*/
|
||||||
|
void dockAreasAdded();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted if one or multiple dock areas has been removed
|
||||||
|
*/
|
||||||
|
void dockAreasRemoved();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted if a dock area is opened or closed via
|
||||||
|
* toggleView() function
|
||||||
|
*/
|
||||||
|
void dockAreaViewToggled(CDockAreaWidget* DockArea, bool Open);
|
||||||
|
}; // class DockContainerWidget
|
||||||
|
} // namespace ads
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
#endif // DockContainerWidgetH
|
852
src/ui/AdvDock/DockManager.cpp
Normal file
852
src/ui/AdvDock/DockManager.cpp
Normal file
@ -0,0 +1,852 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
** Qt Advanced Docking System
|
||||||
|
** Copyright (C) 2017 Uwe Kindler
|
||||||
|
**
|
||||||
|
** This library is free software; you can redistribute it and/or
|
||||||
|
** modify it under the terms of the GNU Lesser General Public
|
||||||
|
** License as published by the Free Software Foundation; either
|
||||||
|
** version 2.1 of the License, or (at your option) any later version.
|
||||||
|
**
|
||||||
|
** This library is distributed in the hope that it will be useful,
|
||||||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
** Lesser General Public License for more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU Lesser General Public
|
||||||
|
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
/// \file DockManager.cpp
|
||||||
|
/// \author Uwe Kindler
|
||||||
|
/// \date 26.02.2017
|
||||||
|
/// \brief Implementation of CDockManager class
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// INCLUDES
|
||||||
|
//============================================================================
|
||||||
|
#include "DockWidgetTab.h"
|
||||||
|
#include "DockManager.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <QMainWindow>
|
||||||
|
#include <QList>
|
||||||
|
#include <QMap>
|
||||||
|
#include <QVariant>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QAction>
|
||||||
|
#include <QXmlStreamWriter>
|
||||||
|
#include <QSettings>
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QApplication>
|
||||||
|
|
||||||
|
#include "FloatingDockContainer.h"
|
||||||
|
#include "DockOverlay.h"
|
||||||
|
#include "DockWidget.h"
|
||||||
|
#include "ads_globals.h"
|
||||||
|
#include "DockAreaWidget.h"
|
||||||
|
#include "IconProvider.h"
|
||||||
|
#include "DockingStateReader.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace ads
|
||||||
|
{
|
||||||
|
static CDockManager::ConfigFlags StaticConfigFlags = CDockManager::DefaultConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private data class of CDockManager class (pimpl)
|
||||||
|
*/
|
||||||
|
struct DockManagerPrivate
|
||||||
|
{
|
||||||
|
CDockManager* _this;
|
||||||
|
QList<CFloatingDockContainer*> FloatingWidgets;
|
||||||
|
QList<CDockContainerWidget*> Containers;
|
||||||
|
CDockOverlay* ContainerOverlay;
|
||||||
|
CDockOverlay* DockAreaOverlay;
|
||||||
|
QMap<QString, CDockWidget*> DockWidgetsMap;
|
||||||
|
QMap<QString, QByteArray> Perspectives;
|
||||||
|
QMap<QString, QMenu*> ViewMenuGroups;
|
||||||
|
QMenu* ViewMenu;
|
||||||
|
CDockManager::eViewMenuInsertionOrder MenuInsertionOrder = CDockManager::MenuAlphabeticallySorted;
|
||||||
|
bool RestoringState = false;
|
||||||
|
QVector<CFloatingDockContainer*> UninitializedFloatingWidgets;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private data constructor
|
||||||
|
*/
|
||||||
|
DockManagerPrivate(CDockManager* _public);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given data stream is a valid docking system state
|
||||||
|
* file.
|
||||||
|
*/
|
||||||
|
bool checkFormat(const QByteArray &state, int version);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restores the state
|
||||||
|
*/
|
||||||
|
bool restoreStateFromXml(const QByteArray &state, int version, bool Testing = internal::Restore);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restore state
|
||||||
|
*/
|
||||||
|
bool restoreState(const QByteArray &state, int version);
|
||||||
|
|
||||||
|
void restoreDockWidgetsOpenState();
|
||||||
|
void restoreDockAreasIndices();
|
||||||
|
void emitTopLevelEvents();
|
||||||
|
|
||||||
|
void hideFloatingWidgets()
|
||||||
|
{
|
||||||
|
// Hide updates of floating widgets from user
|
||||||
|
for (auto FloatingWidget : FloatingWidgets)
|
||||||
|
{
|
||||||
|
FloatingWidget->hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void markDockWidgetsDirty()
|
||||||
|
{
|
||||||
|
for (auto DockWidget : DockWidgetsMap)
|
||||||
|
{
|
||||||
|
DockWidget->setProperty("dirty", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restores the container with the given index
|
||||||
|
*/
|
||||||
|
bool restoreContainer(int Index, CDockingStateReader& stream, bool Testing);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the stylesheet
|
||||||
|
*/
|
||||||
|
void loadStylesheet();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds action to menu - optionally in sorted order
|
||||||
|
*/
|
||||||
|
void addActionToMenu(QAction* Action, QMenu* Menu, bool InsertSorted);
|
||||||
|
};
|
||||||
|
// struct DockManagerPrivate
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
DockManagerPrivate::DockManagerPrivate(CDockManager* _public) :
|
||||||
|
_this(_public)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void DockManagerPrivate::loadStylesheet()
|
||||||
|
{
|
||||||
|
QString Result;
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
QFile StyleSheetFile(":ads/stylesheets/default_linux.css");
|
||||||
|
#else
|
||||||
|
QFile StyleSheetFile(":ads/stylesheets/default.css");
|
||||||
|
#endif
|
||||||
|
StyleSheetFile.open(QIODevice::ReadOnly);
|
||||||
|
QTextStream StyleSheetStream(&StyleSheetFile);
|
||||||
|
Result = StyleSheetStream.readAll();
|
||||||
|
StyleSheetFile.close();
|
||||||
|
_this->setStyleSheet(Result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
bool DockManagerPrivate::restoreContainer(int Index, CDockingStateReader& stream, bool Testing)
|
||||||
|
{
|
||||||
|
if (Testing)
|
||||||
|
{
|
||||||
|
Index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Result = false;
|
||||||
|
if (Index >= Containers.count())
|
||||||
|
{
|
||||||
|
CFloatingDockContainer* FloatingWidget = new CFloatingDockContainer(_this);
|
||||||
|
Result = FloatingWidget->restoreState(stream, Testing);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ADS_PRINT("d->Containers[i]->restoreState ");
|
||||||
|
auto Container = Containers[Index];
|
||||||
|
if (Container->isFloating())
|
||||||
|
{
|
||||||
|
Result = Container->floatingWidget()->restoreState(stream, Testing);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Result = Container->restoreState(stream, Testing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
bool DockManagerPrivate::checkFormat(const QByteArray &state, int version)
|
||||||
|
{
|
||||||
|
return restoreStateFromXml(state, version, internal::RestoreTesting);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
bool DockManagerPrivate::restoreStateFromXml(const QByteArray &state, int version,
|
||||||
|
bool Testing)
|
||||||
|
{
|
||||||
|
Q_UNUSED(version);
|
||||||
|
|
||||||
|
if (state.isEmpty())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
CDockingStateReader s(state);
|
||||||
|
s.readNextStartElement();
|
||||||
|
if (s.name().toString() != "QtAdvancedDockingSystem")
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ADS_PRINT(s.attributes().value("Version"));
|
||||||
|
bool ok;
|
||||||
|
int v = s.attributes().value("Version").toInt(&ok);
|
||||||
|
if (!ok || v > CurrentVersion)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
s.setFileVersion(v);
|
||||||
|
bool Result = true;
|
||||||
|
#ifdef ADS_DEBUG_PRINT
|
||||||
|
int DockContainers = s.attributes().value("Containers").toInt();
|
||||||
|
#endif
|
||||||
|
ADS_PRINT(DockContainers);
|
||||||
|
int DockContainerCount = 0;
|
||||||
|
while (s.readNextStartElement())
|
||||||
|
{
|
||||||
|
if (s.name().toString() == "Container")
|
||||||
|
{
|
||||||
|
Result = restoreContainer(DockContainerCount, s, Testing);
|
||||||
|
if (!Result)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
DockContainerCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Testing)
|
||||||
|
{
|
||||||
|
// Delete remaining empty floating widgets
|
||||||
|
int FloatingWidgetIndex = DockContainerCount - 1;
|
||||||
|
int DeleteCount = FloatingWidgets.count() - FloatingWidgetIndex;
|
||||||
|
for (int i = 0; i < DeleteCount; ++i)
|
||||||
|
{
|
||||||
|
FloatingWidgets[FloatingWidgetIndex + i]->deleteLater();
|
||||||
|
_this->removeDockContainer(FloatingWidgets[FloatingWidgetIndex + i]->dockContainer());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void DockManagerPrivate::restoreDockWidgetsOpenState()
|
||||||
|
{
|
||||||
|
// All dock widgets, that have not been processed in the restore state
|
||||||
|
// function are invisible to the user now and have no assigned dock area
|
||||||
|
// They do not belong to any dock container, until the user toggles the
|
||||||
|
// toggle view action the next time
|
||||||
|
for (auto DockWidget : DockWidgetsMap)
|
||||||
|
{
|
||||||
|
if (DockWidget->property(internal::DirtyProperty).toBool())
|
||||||
|
{
|
||||||
|
DockWidget->flagAsUnassigned();
|
||||||
|
emit DockWidget->viewToggled(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DockWidget->toggleViewInternal(!DockWidget->property(internal::ClosedProperty).toBool());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void DockManagerPrivate::restoreDockAreasIndices()
|
||||||
|
{
|
||||||
|
// Now all dock areas are properly restored and we setup the index of
|
||||||
|
// The dock areas because the previous toggleView() action has changed
|
||||||
|
// the dock area index
|
||||||
|
int Count = 0;
|
||||||
|
for (auto DockContainer : Containers)
|
||||||
|
{
|
||||||
|
Count++;
|
||||||
|
for (int i = 0; i < DockContainer->dockAreaCount(); ++i)
|
||||||
|
{
|
||||||
|
CDockAreaWidget* DockArea = DockContainer->dockArea(i);
|
||||||
|
QString DockWidgetName = DockArea->property("currentDockWidget").toString();
|
||||||
|
CDockWidget* DockWidget = nullptr;
|
||||||
|
if (!DockWidgetName.isEmpty())
|
||||||
|
{
|
||||||
|
DockWidget = _this->findDockWidget(DockWidgetName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!DockWidget || DockWidget->isClosed())
|
||||||
|
{
|
||||||
|
int Index = DockArea->indexOfFirstOpenDockWidget();
|
||||||
|
if (Index < 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
DockArea->setCurrentIndex(Index);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DockArea->internalSetCurrentDockWidget(DockWidget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void DockManagerPrivate::emitTopLevelEvents()
|
||||||
|
{
|
||||||
|
// Finally we need to send the topLevelChanged() signals for all dock
|
||||||
|
// widgets if top level changed
|
||||||
|
for (auto DockContainer : Containers)
|
||||||
|
{
|
||||||
|
CDockWidget* TopLevelDockWidget = DockContainer->topLevelDockWidget();
|
||||||
|
if (TopLevelDockWidget)
|
||||||
|
{
|
||||||
|
TopLevelDockWidget->emitTopLevelChanged(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i = 0; i < DockContainer->dockAreaCount(); ++i)
|
||||||
|
{
|
||||||
|
auto DockArea = DockContainer->dockArea(i);
|
||||||
|
for (auto DockWidget : DockArea->dockWidgets())
|
||||||
|
{
|
||||||
|
DockWidget->emitTopLevelChanged(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
bool DockManagerPrivate::restoreState(const QByteArray& State, int version)
|
||||||
|
{
|
||||||
|
QByteArray state = State.startsWith("<?xml") ? State : qUncompress(State);
|
||||||
|
if (!checkFormat(state, version))
|
||||||
|
{
|
||||||
|
ADS_PRINT("checkFormat: Error checking format!!!!!!!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hide updates of floating widgets from use
|
||||||
|
hideFloatingWidgets();
|
||||||
|
markDockWidgetsDirty();
|
||||||
|
|
||||||
|
if (!restoreStateFromXml(state, version))
|
||||||
|
{
|
||||||
|
ADS_PRINT("restoreState: Error restoring state!!!!!!!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
restoreDockWidgetsOpenState();
|
||||||
|
restoreDockAreasIndices();
|
||||||
|
emitTopLevelEvents();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void DockManagerPrivate::addActionToMenu(QAction* Action, QMenu* Menu, bool InsertSorted)
|
||||||
|
{
|
||||||
|
if (InsertSorted)
|
||||||
|
{
|
||||||
|
auto Actions = Menu->actions();
|
||||||
|
auto it = std::find_if(Actions.begin(), Actions.end(),
|
||||||
|
[&Action](const QAction* a)
|
||||||
|
{
|
||||||
|
return a->text().compare(Action->text(), Qt::CaseInsensitive) > 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (it == Actions.end())
|
||||||
|
{
|
||||||
|
Menu->addAction(Action);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Menu->insertAction(*it, Action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Menu->addAction(Action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockManager::CDockManager(QWidget *parent) :
|
||||||
|
CDockContainerWidget(this, parent),
|
||||||
|
d(new DockManagerPrivate(this))
|
||||||
|
{
|
||||||
|
createRootSplitter();
|
||||||
|
QMainWindow* MainWindow = dynamic_cast<QMainWindow*>(parent);
|
||||||
|
if (MainWindow)
|
||||||
|
{
|
||||||
|
MainWindow->setCentralWidget(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
d->ViewMenu = new QMenu(tr("Show View"), this);
|
||||||
|
d->DockAreaOverlay = new CDockOverlay(this, CDockOverlay::ModeDockAreaOverlay);
|
||||||
|
d->ContainerOverlay = new CDockOverlay(this, CDockOverlay::ModeContainerOverlay);
|
||||||
|
d->Containers.append(this);
|
||||||
|
d->loadStylesheet();
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockManager::~CDockManager()
|
||||||
|
{
|
||||||
|
auto FloatingWidgets = d->FloatingWidgets;
|
||||||
|
for (auto FloatingWidget : FloatingWidgets)
|
||||||
|
{
|
||||||
|
delete FloatingWidget;
|
||||||
|
}
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockManager::registerFloatingWidget(CFloatingDockContainer* FloatingWidget)
|
||||||
|
{
|
||||||
|
d->FloatingWidgets.append(FloatingWidget);
|
||||||
|
ADS_PRINT("d->FloatingWidgets.count() " << d->FloatingWidgets.count());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockManager::removeFloatingWidget(CFloatingDockContainer* FloatingWidget)
|
||||||
|
{
|
||||||
|
d->FloatingWidgets.removeAll(FloatingWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockManager::registerDockContainer(CDockContainerWidget* DockContainer)
|
||||||
|
{
|
||||||
|
d->Containers.append(DockContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockManager::removeDockContainer(CDockContainerWidget* DockContainer)
|
||||||
|
{
|
||||||
|
if (this != DockContainer)
|
||||||
|
{
|
||||||
|
d->Containers.removeAll(DockContainer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockOverlay* CDockManager::containerOverlay() const
|
||||||
|
{
|
||||||
|
return d->ContainerOverlay;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockOverlay* CDockManager::dockAreaOverlay() const
|
||||||
|
{
|
||||||
|
return d->DockAreaOverlay;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
const QList<CDockContainerWidget*> CDockManager::dockContainers() const
|
||||||
|
{
|
||||||
|
return d->Containers;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
const QList<CFloatingDockContainer*> CDockManager::floatingWidgets() const
|
||||||
|
{
|
||||||
|
return d->FloatingWidgets;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
unsigned int CDockManager::zOrderIndex() const
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QByteArray CDockManager::saveState(int version) const
|
||||||
|
{
|
||||||
|
QByteArray xmldata;
|
||||||
|
QXmlStreamWriter s(&xmldata);
|
||||||
|
auto ConfigFlags = CDockManager::configFlags();
|
||||||
|
s.setAutoFormatting(ConfigFlags.testFlag(XmlAutoFormattingEnabled));
|
||||||
|
s.writeStartDocument();
|
||||||
|
s.writeStartElement("QtAdvancedDockingSystem");
|
||||||
|
s.writeAttribute("Version", QString::number(version));
|
||||||
|
s.writeAttribute("Containers", QString::number(d->Containers.count()));
|
||||||
|
for (auto Container : d->Containers)
|
||||||
|
{
|
||||||
|
Container->saveState(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
s.writeEndElement();
|
||||||
|
s.writeEndDocument();
|
||||||
|
|
||||||
|
return ConfigFlags.testFlag(XmlCompressionEnabled)
|
||||||
|
? qCompress(xmldata, 9) : xmldata;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
bool CDockManager::restoreState(const QByteArray &state, int version)
|
||||||
|
{
|
||||||
|
// Prevent multiple calls as long as state is not restore. This may
|
||||||
|
// happen, if QApplication::processEvents() is called somewhere
|
||||||
|
if (d->RestoringState)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We hide the complete dock manager here. Restoring the state means
|
||||||
|
// that DockWidgets are removed from the DockArea internal stack layout
|
||||||
|
// which in turn means, that each time a widget is removed the stack
|
||||||
|
// will show and raise the next available widget which in turn
|
||||||
|
// triggers show events for the dock widgets. To avoid this we hide the
|
||||||
|
// dock manager. Because there will be no processing of application
|
||||||
|
// events until this function is finished, the user will not see this
|
||||||
|
// hiding
|
||||||
|
bool IsHidden = this->isHidden();
|
||||||
|
if (!IsHidden)
|
||||||
|
{
|
||||||
|
hide();
|
||||||
|
}
|
||||||
|
d->RestoringState = true;
|
||||||
|
emit restoringState();
|
||||||
|
bool Result = d->restoreState(state, version);
|
||||||
|
d->RestoringState = false;
|
||||||
|
emit stateRestored();
|
||||||
|
if (!IsHidden)
|
||||||
|
{
|
||||||
|
show();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CFloatingDockContainer* CDockManager::addDockWidgetFloating(CDockWidget* Dockwidget)
|
||||||
|
{
|
||||||
|
d->DockWidgetsMap.insert(Dockwidget->objectName(), Dockwidget);
|
||||||
|
CDockAreaWidget* OldDockArea = Dockwidget->dockAreaWidget();
|
||||||
|
if (OldDockArea)
|
||||||
|
{
|
||||||
|
OldDockArea->removeDockWidget(Dockwidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
Dockwidget->setDockManager(this);
|
||||||
|
CFloatingDockContainer* FloatingWidget = new CFloatingDockContainer(Dockwidget);
|
||||||
|
FloatingWidget->resize(Dockwidget->size());
|
||||||
|
if (isVisible())
|
||||||
|
{
|
||||||
|
FloatingWidget->show();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
d->UninitializedFloatingWidgets.append(FloatingWidget);
|
||||||
|
}
|
||||||
|
return FloatingWidget;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockManager::showEvent(QShowEvent *event)
|
||||||
|
{
|
||||||
|
Super::showEvent(event);
|
||||||
|
if (d->UninitializedFloatingWidgets.empty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto FloatingWidget : d->UninitializedFloatingWidgets)
|
||||||
|
{
|
||||||
|
FloatingWidget->show();
|
||||||
|
}
|
||||||
|
d->UninitializedFloatingWidgets.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockAreaWidget* CDockManager::addDockWidget(DockWidgetArea area,
|
||||||
|
CDockWidget* Dockwidget, CDockAreaWidget* DockAreaWidget)
|
||||||
|
{
|
||||||
|
d->DockWidgetsMap.insert(Dockwidget->objectName(), Dockwidget);
|
||||||
|
return CDockContainerWidget::addDockWidget(area, Dockwidget, DockAreaWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockAreaWidget* CDockManager::addDockWidgetTab(DockWidgetArea area,
|
||||||
|
CDockWidget* Dockwidget)
|
||||||
|
{
|
||||||
|
CDockAreaWidget* AreaWidget = lastAddedDockAreaWidget(area);
|
||||||
|
if (AreaWidget)
|
||||||
|
{
|
||||||
|
return addDockWidget(ads::CenterDockWidgetArea, Dockwidget, AreaWidget);
|
||||||
|
}
|
||||||
|
else if (!openedDockAreas().isEmpty())
|
||||||
|
{
|
||||||
|
return addDockWidget(area, Dockwidget, openedDockAreas().last());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return addDockWidget(area, Dockwidget, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockAreaWidget* CDockManager::addDockWidgetTabToArea(CDockWidget* Dockwidget,
|
||||||
|
CDockAreaWidget* DockAreaWidget)
|
||||||
|
{
|
||||||
|
return addDockWidget(ads::CenterDockWidgetArea, Dockwidget, DockAreaWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockWidget* CDockManager::findDockWidget(const QString& ObjectName) const
|
||||||
|
{
|
||||||
|
return d->DockWidgetsMap.value(ObjectName, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockManager::removeDockWidget(CDockWidget* Dockwidget)
|
||||||
|
{
|
||||||
|
emit dockWidgetAboutToBeRemoved(Dockwidget);
|
||||||
|
d->DockWidgetsMap.remove(Dockwidget->objectName());
|
||||||
|
CDockContainerWidget::removeDockWidget(Dockwidget);
|
||||||
|
emit dockWidgetRemoved(Dockwidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QMap<QString, CDockWidget*> CDockManager::dockWidgetsMap() const
|
||||||
|
{
|
||||||
|
return d->DockWidgetsMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockManager::addPerspective(const QString& UniquePrespectiveName)
|
||||||
|
{
|
||||||
|
d->Perspectives.insert(UniquePrespectiveName, saveState());
|
||||||
|
emit perspectiveListChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockManager::removePerspective(const QString& Name)
|
||||||
|
{
|
||||||
|
removePerspectives({Name});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockManager::removePerspectives(const QStringList& Names)
|
||||||
|
{
|
||||||
|
int Count = 0;
|
||||||
|
for (auto Name : Names)
|
||||||
|
{
|
||||||
|
Count += d->Perspectives.remove(Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Count)
|
||||||
|
{
|
||||||
|
emit perspectivesRemoved();
|
||||||
|
emit perspectiveListChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QStringList CDockManager::perspectiveNames() const
|
||||||
|
{
|
||||||
|
return d->Perspectives.keys();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockManager::openPerspective(const QString& PerspectiveName)
|
||||||
|
{
|
||||||
|
const auto Iterator = d->Perspectives.find(PerspectiveName);
|
||||||
|
if (d->Perspectives.end() == Iterator)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit openingPerspective(PerspectiveName);
|
||||||
|
restoreState(Iterator.value());
|
||||||
|
emit perspectiveOpened(PerspectiveName);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockManager::savePerspectives(QSettings& Settings) const
|
||||||
|
{
|
||||||
|
Settings.beginWriteArray("Perspectives", d->Perspectives.size());
|
||||||
|
int i = 0;
|
||||||
|
for (auto it = d->Perspectives.constBegin(); it != d->Perspectives.constEnd(); ++it)
|
||||||
|
{
|
||||||
|
Settings.setArrayIndex(i);
|
||||||
|
Settings.setValue("Name", it.key());
|
||||||
|
Settings.setValue("State", it.value());
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
Settings.endArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockManager::loadPerspectives(QSettings& Settings)
|
||||||
|
{
|
||||||
|
d->Perspectives.clear();
|
||||||
|
int Size = Settings.beginReadArray("Perspectives");
|
||||||
|
if (!Size)
|
||||||
|
{
|
||||||
|
Settings.endArray();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < Size; ++i)
|
||||||
|
{
|
||||||
|
Settings.setArrayIndex(i);
|
||||||
|
QString Name = Settings.value("Name").toString();
|
||||||
|
QByteArray Data = Settings.value("State").toByteArray();
|
||||||
|
if (Name.isEmpty() || Data.isEmpty())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->Perspectives.insert(Name, Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
Settings.endArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QAction* CDockManager::addToggleViewActionToMenu(QAction* ToggleViewAction,
|
||||||
|
const QString& Group, const QIcon& GroupIcon)
|
||||||
|
{
|
||||||
|
bool AlphabeticallySorted = (MenuAlphabeticallySorted == d->MenuInsertionOrder);
|
||||||
|
if (!Group.isEmpty())
|
||||||
|
{
|
||||||
|
QMenu* GroupMenu = d->ViewMenuGroups.value(Group, 0);
|
||||||
|
if (!GroupMenu)
|
||||||
|
{
|
||||||
|
GroupMenu = new QMenu(Group, this);
|
||||||
|
GroupMenu->setIcon(GroupIcon);
|
||||||
|
d->addActionToMenu(GroupMenu->menuAction(), d->ViewMenu, AlphabeticallySorted);
|
||||||
|
d->ViewMenuGroups.insert(Group, GroupMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
d->addActionToMenu(ToggleViewAction, GroupMenu, AlphabeticallySorted);
|
||||||
|
return GroupMenu->menuAction();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
d->addActionToMenu(ToggleViewAction, d->ViewMenu, AlphabeticallySorted);
|
||||||
|
return ToggleViewAction;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QMenu* CDockManager::viewMenu() const
|
||||||
|
{
|
||||||
|
return d->ViewMenu;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockManager::setViewMenuInsertionOrder(eViewMenuInsertionOrder Order)
|
||||||
|
{
|
||||||
|
d->MenuInsertionOrder = Order;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
bool CDockManager::isRestoringState() const
|
||||||
|
{
|
||||||
|
return d->RestoringState;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
int CDockManager::startDragDistance()
|
||||||
|
{
|
||||||
|
return QApplication::startDragDistance() * 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
CDockManager::ConfigFlags CDockManager::configFlags()
|
||||||
|
{
|
||||||
|
return StaticConfigFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void CDockManager::setConfigFlags(const ConfigFlags Flags)
|
||||||
|
{
|
||||||
|
StaticConfigFlags = Flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void CDockManager::setConfigFlag(eConfigFlag Flag, bool On)
|
||||||
|
{
|
||||||
|
internal::setFlag(StaticConfigFlags, Flag, On);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
CIconProvider& CDockManager::iconProvider()
|
||||||
|
{
|
||||||
|
static CIconProvider Instance;
|
||||||
|
return Instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace ads
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// EOF DockManager.cpp
|
460
src/ui/AdvDock/DockManager.h
Normal file
460
src/ui/AdvDock/DockManager.h
Normal file
@ -0,0 +1,460 @@
|
|||||||
|
#ifndef DockManagerH
|
||||||
|
#define DockManagerH
|
||||||
|
/*******************************************************************************
|
||||||
|
** Qt Advanced Docking System
|
||||||
|
** Copyright (C) 2017 Uwe Kindler
|
||||||
|
**
|
||||||
|
** This library is free software; you can redistribute it and/or
|
||||||
|
** modify it under the terms of the GNU Lesser General Public
|
||||||
|
** License as published by the Free Software Foundation; either
|
||||||
|
** version 2.1 of the License, or (at your option) any later version.
|
||||||
|
**
|
||||||
|
** This library is distributed in the hope that it will be useful,
|
||||||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
** Lesser General Public License for more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU Lesser General Public
|
||||||
|
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
/// \file DockManager.h
|
||||||
|
/// \author Uwe Kindler
|
||||||
|
/// \date 26.02.2017
|
||||||
|
/// \brief Declaration of CDockManager class
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// INCLUDES
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
#include "DockContainerWidget.h"
|
||||||
|
#include "DockWidget.h"
|
||||||
|
#include "FloatingDockContainer.h"
|
||||||
|
#include <qbytearray.h>
|
||||||
|
#include <qflags.h>
|
||||||
|
#include <qlist.h>
|
||||||
|
#include <qmap.h>
|
||||||
|
#include <qobjectdefs.h>
|
||||||
|
#include <qstring.h>
|
||||||
|
#include <qstringlist.h>
|
||||||
|
#include <QtGui/qicon.h>
|
||||||
|
|
||||||
|
class QSettings;
|
||||||
|
class QMenu;
|
||||||
|
|
||||||
|
namespace ads
|
||||||
|
{
|
||||||
|
struct DockManagerPrivate;
|
||||||
|
class CFloatingDockContainer;
|
||||||
|
struct FloatingDockContainerPrivate;
|
||||||
|
class CDockContainerWidget;
|
||||||
|
class DockContainerWidgetPrivate;
|
||||||
|
class CDockOverlay;
|
||||||
|
class CDockAreaTabBar;
|
||||||
|
class CDockWidgetTab;
|
||||||
|
struct DockWidgetTabPrivate;
|
||||||
|
struct DockAreaWidgetPrivate;
|
||||||
|
class CIconProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The central dock manager that maintains the complete docking system.
|
||||||
|
* With the configuration flags you can globally control the functionality
|
||||||
|
* of the docking system. The dock manager uses an internal stylesheet to
|
||||||
|
* style its components like splitters, tabs and buttons. If you want to
|
||||||
|
* disable this stylesheet because your application uses its own,
|
||||||
|
* just call the function for settings the stylesheet with an empty
|
||||||
|
* string.
|
||||||
|
* \code
|
||||||
|
* DockManager->setStyleSheet("");
|
||||||
|
* \endcode
|
||||||
|
**/
|
||||||
|
class CDockManager : public CDockContainerWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
DockManagerPrivate* d; ///< private data (pimpl)
|
||||||
|
friend struct DockManagerPrivate;
|
||||||
|
friend class CFloatingDockContainer;
|
||||||
|
friend struct FloatingDockContainerPrivate;
|
||||||
|
friend class CDockContainerWidget;
|
||||||
|
friend class DockContainerWidgetPrivate;
|
||||||
|
friend class CDockAreaTabBar;
|
||||||
|
friend class CDockWidgetTab;
|
||||||
|
friend struct DockAreaWidgetPrivate;
|
||||||
|
friend struct DockWidgetTabPrivate;
|
||||||
|
friend class CFloatingDragPreview;
|
||||||
|
friend struct FloatingDragPreviewPrivate;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* Registers the given floating widget in the internal list of
|
||||||
|
* floating widgets
|
||||||
|
*/
|
||||||
|
void registerFloatingWidget(CFloatingDockContainer* FloatingWidget);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the given floating widget from the list of registered floating
|
||||||
|
* widgets
|
||||||
|
*/
|
||||||
|
void removeFloatingWidget(CFloatingDockContainer* FloatingWidget);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the given dock container widget
|
||||||
|
*/
|
||||||
|
void registerDockContainer(CDockContainerWidget* DockContainer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove dock container from the internal list of registered dock
|
||||||
|
* containers
|
||||||
|
*/
|
||||||
|
void removeDockContainer(CDockContainerWidget* DockContainer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overlay for containers
|
||||||
|
*/
|
||||||
|
CDockOverlay* containerOverlay() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overlay for dock areas
|
||||||
|
*/
|
||||||
|
CDockOverlay* dockAreaOverlay() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the floating widgets that has been created floating
|
||||||
|
*/
|
||||||
|
virtual void showEvent(QShowEvent *event) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using Super = CDockContainerWidget;
|
||||||
|
|
||||||
|
enum eViewMenuInsertionOrder
|
||||||
|
{
|
||||||
|
MenuSortedByInsertion,
|
||||||
|
MenuAlphabeticallySorted
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These global configuration flags configure some global dock manager
|
||||||
|
* settings.
|
||||||
|
*/
|
||||||
|
enum eConfigFlag
|
||||||
|
{
|
||||||
|
ActiveTabHasCloseButton = 0x0001, //!< If this flag is set, the active tab in a tab area has a close button
|
||||||
|
DockAreaHasCloseButton = 0x0002, //!< If the flag is set each dock area has a close button
|
||||||
|
DockAreaCloseButtonClosesTab = 0x0004,//!< If the flag is set, the dock area close button closes the active tab, if not set, it closes the complete cock area
|
||||||
|
OpaqueSplitterResize = 0x0008, //!< See QSplitter::setOpaqueResize() documentation
|
||||||
|
XmlAutoFormattingEnabled = 0x0010,//!< If enabled, the XML writer automatically adds line-breaks and indentation to empty sections between elements (ignorable whitespace).
|
||||||
|
XmlCompressionEnabled = 0x0020,//!< If enabled, the XML output will be compressed and is not human readable anymore
|
||||||
|
TabCloseButtonIsToolButton = 0x0040,//! If enabled the tab close buttons will be QToolButtons instead of QPushButtons - disabled by default
|
||||||
|
AllTabsHaveCloseButton = 0x0080, //!< if this flag is set, then all tabs that are closable show a close button
|
||||||
|
RetainTabSizeWhenCloseButtonHidden = 0x0100, //!< if this flag is set, the space for the close button is reserved even if the close button is not visible
|
||||||
|
OpaqueUndocking = 0x0200,///< If enabled, the widgets are immediately undocked into floating widgets, if disabled, only a draw preview is undocked and the real undocking is deferred until the mouse is released
|
||||||
|
DragPreviewIsDynamic = 0x0400,///< If opaque undocking is disabled, this flag defines the behavior of the drag preview window, if this flag is enabled, the preview will be adjusted dynamically to the drop area
|
||||||
|
DragPreviewShowsContentPixmap = 0x0800,///< If opaque undocking is disabled, the created drag preview window shows a copy of the content of the dock widget / dock are that is dragged
|
||||||
|
DragPreviewHasWindowFrame = 0x1000,///< If opaque undocking is disabled, then this flag configures if the drag preview is frameless or looks like a real window
|
||||||
|
DefaultConfig = ActiveTabHasCloseButton
|
||||||
|
| DockAreaHasCloseButton
|
||||||
|
| OpaqueSplitterResize
|
||||||
|
| XmlCompressionEnabled
|
||||||
|
| OpaqueUndocking, ///< the default configuration
|
||||||
|
DefaultNonOpaqueConfig = ActiveTabHasCloseButton
|
||||||
|
| DockAreaHasCloseButton
|
||||||
|
| XmlCompressionEnabled
|
||||||
|
| DragPreviewShowsContentPixmap, ///< the default configuration for non opaque operations
|
||||||
|
NonOpaqueWithWindowFrame = ActiveTabHasCloseButton
|
||||||
|
| DockAreaHasCloseButton
|
||||||
|
| XmlCompressionEnabled
|
||||||
|
| DragPreviewShowsContentPixmap
|
||||||
|
| DragPreviewHasWindowFrame ///< the default configuration for non opaque operations that show a real window with frame
|
||||||
|
};
|
||||||
|
Q_DECLARE_FLAGS(ConfigFlags, eConfigFlag)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default Constructor.
|
||||||
|
* If the given parent is a QMainWindow, the dock manager sets itself as the
|
||||||
|
* central widget.
|
||||||
|
* Before you create any dock widgets, you should properly setup the
|
||||||
|
* configuration flags via setConfigFlags().
|
||||||
|
*/
|
||||||
|
CDockManager(QWidget* parent = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Virtual Destructor
|
||||||
|
*/
|
||||||
|
virtual ~CDockManager();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function returns the global configuration flags
|
||||||
|
*/
|
||||||
|
static ConfigFlags configFlags();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the global configuration flags for the whole docking system.
|
||||||
|
* Call this function before you create your first dock widget.
|
||||||
|
*/
|
||||||
|
static void setConfigFlags(const ConfigFlags Flags);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a certain config flag
|
||||||
|
*/
|
||||||
|
static void setConfigFlag(eConfigFlag Flag, bool On = true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the global icon provider.
|
||||||
|
* The icon provider enables the use of custom icons in case using
|
||||||
|
* styleheets for icons is not an option.
|
||||||
|
*/
|
||||||
|
static CIconProvider& iconProvider();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds dockwidget into the given area.
|
||||||
|
* If DockAreaWidget is not null, then the area parameter indicates the area
|
||||||
|
* into the DockAreaWidget. If DockAreaWidget is null, the Dockwidget will
|
||||||
|
* be dropped into the container. If you would like to add a dock widget
|
||||||
|
* tabified, then you need to add it to an existing dock area object
|
||||||
|
* into the CenterDockWidgetArea. The following code shows this:
|
||||||
|
* \code
|
||||||
|
* DockManager->addDockWidget(ads::CenterDockWidgetArea, NewDockWidget,
|
||||||
|
* ExisitingDockArea);
|
||||||
|
* \endcode
|
||||||
|
* \return Returns the dock area widget that contains the new DockWidget
|
||||||
|
*/
|
||||||
|
CDockAreaWidget* addDockWidget(DockWidgetArea area, CDockWidget* Dockwidget,
|
||||||
|
CDockAreaWidget* DockAreaWidget = nullptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function will add the given Dockwidget to the given dock area as
|
||||||
|
* a new tab.
|
||||||
|
* If no dock area widget exists for the given area identifier, a new
|
||||||
|
* dock area widget is created.
|
||||||
|
*/
|
||||||
|
CDockAreaWidget* addDockWidgetTab(DockWidgetArea area,
|
||||||
|
CDockWidget* Dockwidget);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function will add the given Dockwidget to the given DockAreaWidget
|
||||||
|
* as a new tab.
|
||||||
|
*/
|
||||||
|
CDockAreaWidget* addDockWidgetTabToArea(CDockWidget* Dockwidget,
|
||||||
|
CDockAreaWidget* DockAreaWidget);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the given DockWidget floating and returns the created
|
||||||
|
* CFloatingDockContainer instance.
|
||||||
|
*/
|
||||||
|
CFloatingDockContainer* addDockWidgetFloating(CDockWidget* Dockwidget);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches for a registered doc widget with the given ObjectName
|
||||||
|
* \return Return the found dock widget or nullptr if a dock widget with the
|
||||||
|
* given name is not registered
|
||||||
|
*/
|
||||||
|
CDockWidget* findDockWidget(const QString& ObjectName) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the given Dock from the dock manager
|
||||||
|
*/
|
||||||
|
void removeDockWidget(CDockWidget* Dockwidget);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function returns a readable reference to the internal dock
|
||||||
|
* widgets map so that it is possible to iterate over all dock widgets
|
||||||
|
*/
|
||||||
|
QMap<QString, CDockWidget*> dockWidgetsMap() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of all active and visible dock containers
|
||||||
|
* Dock containers are the main dock manager and all floating widgets
|
||||||
|
*/
|
||||||
|
const QList<CDockContainerWidget*> dockContainers() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of all floating widgets
|
||||||
|
*/
|
||||||
|
const QList<CFloatingDockContainer*> floatingWidgets() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function always return 0 because the main window is always behind
|
||||||
|
* any floating widget
|
||||||
|
*/
|
||||||
|
virtual unsigned int zOrderIndex() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the current state of the dockmanger and all its dock widgets
|
||||||
|
* into the returned QByteArray.
|
||||||
|
* The XmlMode enables / disables the auto formatting for the XmlStreamWriter.
|
||||||
|
* If auto formatting is enabled, the output is intended and line wrapped.
|
||||||
|
* The XmlMode XmlAutoFormattingDisabled is better if you would like to have
|
||||||
|
* a more compact XML output - i.e. for storage in ini files.
|
||||||
|
*/
|
||||||
|
QByteArray saveState(int version = Version1) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restores the state of this dockmanagers dockwidgets.
|
||||||
|
* The version number is compared with that stored in state. If they do
|
||||||
|
* not match, the dockmanager's state is left unchanged, and this function
|
||||||
|
* returns false; otherwise, the state is restored, and this function
|
||||||
|
* returns true.
|
||||||
|
*/
|
||||||
|
bool restoreState(const QByteArray &state, int version = Version1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the current perspective to the internal list of perspectives.
|
||||||
|
* A perspective is the current state of the dock manager assigned
|
||||||
|
* with a certain name. This makes it possible for the user,
|
||||||
|
* to switch between different perspectives quickly.
|
||||||
|
* If a perspective with the given name already exists, then
|
||||||
|
* it will be overwritten with the new state.
|
||||||
|
*/
|
||||||
|
void addPerspective(const QString& UniquePrespectiveName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the perspective with the given name from the list of perspectives
|
||||||
|
*/
|
||||||
|
void removePerspective(const QString& Name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the given perspectives from the dock manager
|
||||||
|
*/
|
||||||
|
void removePerspectives(const QStringList& Names);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the names of all available perspectives
|
||||||
|
*/
|
||||||
|
QStringList perspectiveNames() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the perspectives to the given settings file.
|
||||||
|
*/
|
||||||
|
void savePerspectives(QSettings& Settings) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the perspectives from the given settings file
|
||||||
|
*/
|
||||||
|
void loadPerspectives(QSettings& Settings);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a toggle view action to the the internal view menu.
|
||||||
|
* You can either manage the insertion of the toggle view actions in your
|
||||||
|
* application or you can add the actions to the internal view menu and
|
||||||
|
* then simply insert the menu object into your.
|
||||||
|
* \param[in] ToggleViewAction The action to insert. If no group is provided
|
||||||
|
* the action is directly inserted into the menu. If a group
|
||||||
|
* is provided, the action is inserted into the group and the
|
||||||
|
* group is inserted into the menu if it is not existing yet.
|
||||||
|
* \param[in] Group This is the text used for the group menu item
|
||||||
|
* \param[in] GroupIcon The icon used for grouping the workbenches in the
|
||||||
|
* view menu. I.e. if there is a workbench for each device
|
||||||
|
* like for spectrometer devices, it is good to group all these
|
||||||
|
* workbenches under a menu item
|
||||||
|
* \return If Group is not empty, this function returns the GroupAction
|
||||||
|
* for this group. If the group is empty, the function returns
|
||||||
|
* the given ToggleViewAction.
|
||||||
|
*/
|
||||||
|
QAction* addToggleViewActionToMenu(QAction* ToggleViewAction,
|
||||||
|
const QString& Group = QString(), const QIcon& GroupIcon = QIcon());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function returns the internal view menu.
|
||||||
|
* To fill the view menu, you can use the addToggleViewActionToMenu()
|
||||||
|
* function.
|
||||||
|
*/
|
||||||
|
QMenu* viewMenu() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define the insertion order for toggle view menu items.
|
||||||
|
* The order defines how the actions are added to the view menu.
|
||||||
|
* The default insertion order is MenuAlphabeticallySorted to make it
|
||||||
|
* easier for users to find the menu entry for a certain dock widget.
|
||||||
|
* You need to call this function befor you insert the first menu item
|
||||||
|
* into the view menu.
|
||||||
|
*/
|
||||||
|
void setViewMenuInsertionOrder(eViewMenuInsertionOrder Order);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function returns true between the restoringState() and
|
||||||
|
* stateRestored() signals.
|
||||||
|
*/
|
||||||
|
bool isRestoringState() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The distance the user needs to move the mouse with the left button
|
||||||
|
* hold down before a dock widget start floating
|
||||||
|
*/
|
||||||
|
static int startDragDistance();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
/**
|
||||||
|
* Opens the perspective with the given name.
|
||||||
|
*/
|
||||||
|
void openPerspective(const QString& PerspectiveName);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
/**
|
||||||
|
* This signal is emitted if the list of perspectives changed
|
||||||
|
*/
|
||||||
|
void perspectiveListChanged();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted if perspectives have been removed
|
||||||
|
*/
|
||||||
|
void perspectivesRemoved();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted, if the restore function is called, just before
|
||||||
|
* the dock manager starts restoring the state.
|
||||||
|
* If this function is called, nothing has changed yet
|
||||||
|
*/
|
||||||
|
void restoringState();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted if the state changed in restoreState.
|
||||||
|
* The signal is emitted if the restoreState() function is called or
|
||||||
|
* if the openPerspective() function is called
|
||||||
|
*/
|
||||||
|
void stateRestored();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted, if the dock manager starts opening a
|
||||||
|
* perspective.
|
||||||
|
* Opening a perspective may take more than a second if there are
|
||||||
|
* many complex widgets. The application may use this signal
|
||||||
|
* to show some progress indicator or to change the mouse cursor
|
||||||
|
* into a busy cursor.
|
||||||
|
*/
|
||||||
|
void openingPerspective(const QString& PerspectiveName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted if the dock manager finished opening a
|
||||||
|
* perspective
|
||||||
|
*/
|
||||||
|
void perspectiveOpened(const QString& PerspectiveName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted, if a new DockArea has been created.
|
||||||
|
* An application can use this signal to set custom icons or custom
|
||||||
|
* tooltips for the DockArea buttons.
|
||||||
|
*/
|
||||||
|
void dockAreaCreated(CDockAreaWidget* DockArea);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted just before the given dock widget is removed
|
||||||
|
* from the
|
||||||
|
*/
|
||||||
|
void dockWidgetAboutToBeRemoved(CDockWidget* DockWidget);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted if a dock widget has been removed with the remove
|
||||||
|
* removeDockWidget() function.
|
||||||
|
* If this signal is emitted, the dock widget has been removed from the
|
||||||
|
* docking system but it is not deleted yet.
|
||||||
|
*/
|
||||||
|
void dockWidgetRemoved(CDockWidget* DockWidget);
|
||||||
|
}; // class DockManager
|
||||||
|
} // namespace ads
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
#endif // DockManagerH
|
817
src/ui/AdvDock/DockOverlay.cpp
Normal file
817
src/ui/AdvDock/DockOverlay.cpp
Normal file
@ -0,0 +1,817 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
** Qt Advanced Docking System
|
||||||
|
** Copyright (C) 2017 Uwe Kindler
|
||||||
|
**
|
||||||
|
** This library is free software; you can redistribute it and/or
|
||||||
|
** modify it under the terms of the GNU Lesser General Public
|
||||||
|
** License as published by the Free Software Foundation; either
|
||||||
|
** version 2.1 of the License, or (at your option) any later version.
|
||||||
|
**
|
||||||
|
** This library is distributed in the hope that it will be useful,
|
||||||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
** Lesser General Public License for more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU Lesser General Public
|
||||||
|
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// INCLUDES
|
||||||
|
//============================================================================
|
||||||
|
#include "DockOverlay.h"
|
||||||
|
|
||||||
|
#include <QPointer>
|
||||||
|
#include <QPaintEvent>
|
||||||
|
#include <QResizeEvent>
|
||||||
|
#include <QMoveEvent>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QGridLayout>
|
||||||
|
#include <QCursor>
|
||||||
|
#include <QIcon>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QtGlobal>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QMap>
|
||||||
|
#include <QWindow>
|
||||||
|
|
||||||
|
#include "DockAreaWidget.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace ads
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private data class of CDockOverlay
|
||||||
|
*/
|
||||||
|
struct DockOverlayPrivate
|
||||||
|
{
|
||||||
|
CDockOverlay* _this;
|
||||||
|
DockWidgetAreas AllowedAreas = InvalidDockWidgetArea;
|
||||||
|
CDockOverlayCross* Cross;
|
||||||
|
QPointer<QWidget> TargetWidget;
|
||||||
|
DockWidgetArea LastLocation = InvalidDockWidgetArea;
|
||||||
|
bool DropPreviewEnabled = true;
|
||||||
|
CDockOverlay::eMode Mode = CDockOverlay::ModeDockAreaOverlay;
|
||||||
|
QRect DropAreaRect;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private data constructor
|
||||||
|
*/
|
||||||
|
DockOverlayPrivate(CDockOverlay* _public) : _this(_public) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private data of CDockOverlayCross class
|
||||||
|
*/
|
||||||
|
struct DockOverlayCrossPrivate
|
||||||
|
{
|
||||||
|
CDockOverlayCross* _this;
|
||||||
|
CDockOverlay::eMode Mode = CDockOverlay::ModeDockAreaOverlay;
|
||||||
|
CDockOverlay* DockOverlay;
|
||||||
|
QHash<DockWidgetArea, QWidget*> DropIndicatorWidgets;
|
||||||
|
QGridLayout* GridLayout;
|
||||||
|
QColor IconColors[5];
|
||||||
|
bool UpdateRequired = false;
|
||||||
|
double LastDevicePixelRatio = 0.1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private data constructor
|
||||||
|
*/
|
||||||
|
DockOverlayCrossPrivate(CDockOverlayCross* _public) : _this(_public) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param area
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
QPoint areaGridPosition(const DockWidgetArea area);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Palette based default icon colors
|
||||||
|
*/
|
||||||
|
QColor defaultIconColor(CDockOverlayCross::eIconColor ColorIndex)
|
||||||
|
{
|
||||||
|
QPalette pal = _this->palette();
|
||||||
|
switch (ColorIndex)
|
||||||
|
{
|
||||||
|
case CDockOverlayCross::FrameColor: return pal.color(QPalette::Active, QPalette::Highlight);
|
||||||
|
case CDockOverlayCross::WindowBackgroundColor: return pal.color(QPalette::Active, QPalette::Base);
|
||||||
|
case CDockOverlayCross::OverlayColor:
|
||||||
|
{
|
||||||
|
QColor Color = pal.color(QPalette::Active, QPalette::Highlight);
|
||||||
|
Color.setAlpha(64);
|
||||||
|
return Color;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CDockOverlayCross::ArrowColor: return pal.color(QPalette::Active, QPalette::Base);
|
||||||
|
case CDockOverlayCross::ShadowColor: return QColor(0, 0, 0, 64);
|
||||||
|
default:
|
||||||
|
return QColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
return QColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stylehseet based icon colors
|
||||||
|
*/
|
||||||
|
QColor iconColor(CDockOverlayCross::eIconColor ColorIndex)
|
||||||
|
{
|
||||||
|
QColor Color = IconColors[ColorIndex];
|
||||||
|
if (!Color.isValid())
|
||||||
|
{
|
||||||
|
Color = defaultIconColor(ColorIndex);
|
||||||
|
IconColors[ColorIndex] = Color;
|
||||||
|
}
|
||||||
|
return Color;
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
/**
|
||||||
|
* Helper function that returns the drop indicator width depending on the
|
||||||
|
* operating system
|
||||||
|
*/
|
||||||
|
qreal dropIndicatiorWidth(QLabel* l) const
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
Q_UNUSED(l)
|
||||||
|
return 40;
|
||||||
|
#else
|
||||||
|
return static_cast<qreal>(l->fontMetrics().height()) * 3.f;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QWidget* createDropIndicatorWidget(DockWidgetArea DockWidgetArea,
|
||||||
|
CDockOverlay::eMode Mode)
|
||||||
|
{
|
||||||
|
QLabel* l = new QLabel();
|
||||||
|
l->setObjectName("DockWidgetAreaLabel");
|
||||||
|
|
||||||
|
const qreal metric = dropIndicatiorWidth(l);
|
||||||
|
const QSizeF size(metric, metric);
|
||||||
|
|
||||||
|
l->setPixmap(createHighDpiDropIndicatorPixmap(size, DockWidgetArea, Mode));
|
||||||
|
l->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
|
||||||
|
l->setAttribute(Qt::WA_TranslucentBackground);
|
||||||
|
l->setProperty("dockWidgetArea", DockWidgetArea);
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void updateDropIndicatorIcon(QWidget* DropIndicatorWidget)
|
||||||
|
{
|
||||||
|
QLabel* l = qobject_cast<QLabel*>(DropIndicatorWidget);
|
||||||
|
const qreal metric = dropIndicatiorWidth(l);
|
||||||
|
const QSizeF size(metric, metric);
|
||||||
|
|
||||||
|
int Area = l->property("dockWidgetArea").toInt();
|
||||||
|
l->setPixmap(createHighDpiDropIndicatorPixmap(size, (DockWidgetArea)Area, Mode));
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QPixmap createHighDpiDropIndicatorPixmap(const QSizeF& size, DockWidgetArea DockWidgetArea,
|
||||||
|
CDockOverlay::eMode Mode)
|
||||||
|
{
|
||||||
|
QColor borderColor = iconColor(CDockOverlayCross::FrameColor);
|
||||||
|
QColor backgroundColor = iconColor(CDockOverlayCross::WindowBackgroundColor);
|
||||||
|
|
||||||
|
#if QT_VERSION >= 0x050600
|
||||||
|
double DevicePixelRatio = _this->window()->devicePixelRatioF();
|
||||||
|
#else
|
||||||
|
double DevicePixelRatio = _this->window()->devicePixelRatio();
|
||||||
|
#endif
|
||||||
|
QSizeF PixmapSize = size * DevicePixelRatio;
|
||||||
|
QPixmap pm(PixmapSize.toSize());
|
||||||
|
pm.fill(QColor(0, 0, 0, 0));
|
||||||
|
|
||||||
|
QPainter p(&pm);
|
||||||
|
QPen pen = p.pen();
|
||||||
|
QRectF ShadowRect(pm.rect());
|
||||||
|
QRectF baseRect;
|
||||||
|
baseRect.setSize(ShadowRect.size() * 0.7);
|
||||||
|
baseRect.moveCenter(ShadowRect.center());
|
||||||
|
|
||||||
|
// Fill
|
||||||
|
QColor ShadowColor = iconColor(CDockOverlayCross::ShadowColor);
|
||||||
|
if (ShadowColor.alpha() == 255)
|
||||||
|
{
|
||||||
|
ShadowColor.setAlpha(64);
|
||||||
|
}
|
||||||
|
p.fillRect(ShadowRect, ShadowColor);
|
||||||
|
|
||||||
|
// Drop area rect.
|
||||||
|
p.save();
|
||||||
|
QRectF areaRect;
|
||||||
|
QLineF areaLine;
|
||||||
|
QRectF nonAreaRect;
|
||||||
|
switch (DockWidgetArea)
|
||||||
|
{
|
||||||
|
case TopDockWidgetArea:
|
||||||
|
areaRect = QRectF(baseRect.x(), baseRect.y(), baseRect.width(), baseRect.height() * .5f);
|
||||||
|
nonAreaRect = QRectF(baseRect.x(), ShadowRect.height() * .5f, baseRect.width(), baseRect.height() * .5f);
|
||||||
|
areaLine = QLineF(areaRect.bottomLeft(), areaRect.bottomRight());
|
||||||
|
break;
|
||||||
|
case RightDockWidgetArea:
|
||||||
|
areaRect = QRectF(ShadowRect.width() * .5f, baseRect.y(), baseRect.width() * .5f, baseRect.height());
|
||||||
|
nonAreaRect = QRectF(baseRect.x(), baseRect.y(), baseRect.width() * .5f, baseRect.height());
|
||||||
|
areaLine = QLineF(areaRect.topLeft(), areaRect.bottomLeft());
|
||||||
|
break;
|
||||||
|
case BottomDockWidgetArea:
|
||||||
|
areaRect = QRectF(baseRect.x(), ShadowRect.height() * .5f, baseRect.width(), baseRect.height() * .5f);
|
||||||
|
nonAreaRect = QRectF(baseRect.x(), baseRect.y(), baseRect.width(), baseRect.height() * .5f);
|
||||||
|
areaLine = QLineF(areaRect.topLeft(), areaRect.topRight());
|
||||||
|
break;
|
||||||
|
case LeftDockWidgetArea:
|
||||||
|
areaRect = QRectF(baseRect.x(), baseRect.y(), baseRect.width() * .5f, baseRect.height());
|
||||||
|
nonAreaRect = QRectF(ShadowRect.width() * .5f, baseRect.y(), baseRect.width() * .5f, baseRect.height());
|
||||||
|
areaLine = QLineF(areaRect.topRight(), areaRect.bottomRight());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSizeF baseSize = baseRect.size();
|
||||||
|
if (CDockOverlay::ModeContainerOverlay == Mode && DockWidgetArea != CenterDockWidgetArea)
|
||||||
|
{
|
||||||
|
baseRect = areaRect;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.fillRect(baseRect, backgroundColor);
|
||||||
|
if (areaRect.isValid())
|
||||||
|
{
|
||||||
|
pen = p.pen();
|
||||||
|
pen.setColor(borderColor);
|
||||||
|
QColor Color = iconColor(CDockOverlayCross::OverlayColor);
|
||||||
|
if (Color.alpha() == 255)
|
||||||
|
{
|
||||||
|
Color.setAlpha(64);
|
||||||
|
}
|
||||||
|
p.setBrush(Color);
|
||||||
|
p.setPen(Qt::NoPen);
|
||||||
|
p.drawRect(areaRect);
|
||||||
|
|
||||||
|
pen = p.pen();
|
||||||
|
pen.setWidth(1);
|
||||||
|
pen.setColor(borderColor);
|
||||||
|
pen.setStyle(Qt::DashLine);
|
||||||
|
p.setPen(pen);
|
||||||
|
p.drawLine(areaLine);
|
||||||
|
}
|
||||||
|
p.restore();
|
||||||
|
|
||||||
|
p.save();
|
||||||
|
// Draw outer border
|
||||||
|
pen = p.pen();
|
||||||
|
pen.setColor(borderColor);
|
||||||
|
pen.setWidth(1);
|
||||||
|
p.setBrush(Qt::NoBrush);
|
||||||
|
p.setPen(pen);
|
||||||
|
p.drawRect(baseRect);
|
||||||
|
|
||||||
|
// draw window title bar
|
||||||
|
p.setBrush(borderColor);
|
||||||
|
QRectF FrameRect(baseRect.topLeft(), QSizeF(baseRect.width(), baseSize.height() / 10));
|
||||||
|
p.drawRect(FrameRect);
|
||||||
|
p.restore();
|
||||||
|
|
||||||
|
// Draw arrow for outer container drop indicators
|
||||||
|
if (CDockOverlay::ModeContainerOverlay == Mode && DockWidgetArea != CenterDockWidgetArea)
|
||||||
|
{
|
||||||
|
QRectF ArrowRect;
|
||||||
|
ArrowRect.setSize(baseSize);
|
||||||
|
ArrowRect.setWidth(ArrowRect.width() / 4.6);
|
||||||
|
ArrowRect.setHeight(ArrowRect.height() / 2);
|
||||||
|
ArrowRect.moveCenter(QPointF(0, 0));
|
||||||
|
QPolygonF Arrow;
|
||||||
|
Arrow << ArrowRect.topLeft()
|
||||||
|
<< QPointF( ArrowRect.right(), ArrowRect.center().y())
|
||||||
|
<< ArrowRect.bottomLeft();
|
||||||
|
p.setPen(Qt::NoPen);
|
||||||
|
p.setBrush(iconColor(CDockOverlayCross::ArrowColor));
|
||||||
|
p.setRenderHint(QPainter::Antialiasing, true);
|
||||||
|
p.translate(nonAreaRect.center().x(), nonAreaRect.center().y());
|
||||||
|
|
||||||
|
switch (DockWidgetArea)
|
||||||
|
{
|
||||||
|
case TopDockWidgetArea:
|
||||||
|
p.rotate(-90);
|
||||||
|
break;
|
||||||
|
case RightDockWidgetArea:
|
||||||
|
break;
|
||||||
|
case BottomDockWidgetArea:
|
||||||
|
p.rotate(90);
|
||||||
|
break;
|
||||||
|
case LeftDockWidgetArea:
|
||||||
|
p.rotate(180);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.drawPolygon(Arrow);
|
||||||
|
}
|
||||||
|
|
||||||
|
pm.setDevicePixelRatio(DevicePixelRatio);
|
||||||
|
return pm;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockOverlay::CDockOverlay(QWidget* parent, eMode Mode) :
|
||||||
|
QFrame(parent),
|
||||||
|
d(new DockOverlayPrivate(this))
|
||||||
|
{
|
||||||
|
d->Mode = Mode;
|
||||||
|
d->Cross = new CDockOverlayCross(this);
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
setWindowFlags(Qt::Tool | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint);
|
||||||
|
#else
|
||||||
|
setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
|
||||||
|
#endif
|
||||||
|
setWindowOpacity(1);
|
||||||
|
setWindowTitle("DockOverlay");
|
||||||
|
setAttribute(Qt::WA_NoSystemBackground);
|
||||||
|
setAttribute(Qt::WA_TranslucentBackground);
|
||||||
|
|
||||||
|
d->Cross->setVisible(false);
|
||||||
|
setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockOverlay::~CDockOverlay()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockOverlay::setAllowedAreas(DockWidgetAreas areas)
|
||||||
|
{
|
||||||
|
if (areas == d->AllowedAreas)
|
||||||
|
return;
|
||||||
|
d->AllowedAreas = areas;
|
||||||
|
d->Cross->reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
DockWidgetAreas CDockOverlay::allowedAreas() const
|
||||||
|
{
|
||||||
|
return d->AllowedAreas;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
DockWidgetArea CDockOverlay::dropAreaUnderCursor() const
|
||||||
|
{
|
||||||
|
DockWidgetArea Result = d->Cross->cursorLocation();
|
||||||
|
if (Result != InvalidDockWidgetArea)
|
||||||
|
{
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
CDockAreaWidget* DockArea = dynamic_cast<CDockAreaWidget*>(d->TargetWidget.data());
|
||||||
|
if (!DockArea)
|
||||||
|
{
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DockArea->titleBarGeometry().contains(DockArea->mapFromGlobal(QCursor::pos())))
|
||||||
|
{
|
||||||
|
return CenterDockWidgetArea;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
DockWidgetArea CDockOverlay::showOverlay(QWidget* target)
|
||||||
|
{
|
||||||
|
if (d->TargetWidget == target)
|
||||||
|
{
|
||||||
|
// Hint: We could update geometry of overlay here.
|
||||||
|
DockWidgetArea da = dropAreaUnderCursor();
|
||||||
|
if (da != d->LastLocation)
|
||||||
|
{
|
||||||
|
repaint();
|
||||||
|
d->LastLocation = da;
|
||||||
|
}
|
||||||
|
return da;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->TargetWidget = target;
|
||||||
|
d->LastLocation = InvalidDockWidgetArea;
|
||||||
|
|
||||||
|
// Move it over the target.
|
||||||
|
resize(target->size());
|
||||||
|
QPoint TopLeft = target->mapToGlobal(target->rect().topLeft());
|
||||||
|
move(TopLeft);
|
||||||
|
show();
|
||||||
|
d->Cross->updatePosition();
|
||||||
|
d->Cross->updateOverlayIcons();
|
||||||
|
return dropAreaUnderCursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockOverlay::hideOverlay()
|
||||||
|
{
|
||||||
|
hide();
|
||||||
|
d->TargetWidget.clear();
|
||||||
|
d->LastLocation = InvalidDockWidgetArea;
|
||||||
|
d->DropAreaRect = QRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockOverlay::enableDropPreview(bool Enable)
|
||||||
|
{
|
||||||
|
d->DropPreviewEnabled = Enable;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
bool CDockOverlay::dropPreviewEnabled() const
|
||||||
|
{
|
||||||
|
return d->DropPreviewEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockOverlay::paintEvent(QPaintEvent* event)
|
||||||
|
{
|
||||||
|
Q_UNUSED(event);
|
||||||
|
// Draw rect based on location
|
||||||
|
if (!d->DropPreviewEnabled)
|
||||||
|
{
|
||||||
|
d->DropAreaRect = QRect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRect r = rect();
|
||||||
|
const DockWidgetArea da = dropAreaUnderCursor();
|
||||||
|
double Factor = (CDockOverlay::ModeContainerOverlay == d->Mode) ?
|
||||||
|
3 : 2;
|
||||||
|
|
||||||
|
switch (da)
|
||||||
|
{
|
||||||
|
case TopDockWidgetArea: r.setHeight(r.height() / Factor); break;
|
||||||
|
case RightDockWidgetArea: r.setX(r.width() * (1 - 1 / Factor)); break;
|
||||||
|
case BottomDockWidgetArea: r.setY(r.height() * (1 - 1 / Factor)); break;
|
||||||
|
case LeftDockWidgetArea: r.setWidth(r.width() / Factor); break;
|
||||||
|
case CenterDockWidgetArea: r = rect();break;
|
||||||
|
default: return;
|
||||||
|
}
|
||||||
|
QPainter painter(this);
|
||||||
|
QColor Color = palette().color(QPalette::Active, QPalette::Highlight);
|
||||||
|
QPen Pen = painter.pen();
|
||||||
|
Pen.setColor(Color.darker(120));
|
||||||
|
Pen.setStyle(Qt::SolidLine);
|
||||||
|
Pen.setWidth(1);
|
||||||
|
Pen.setCosmetic(true);
|
||||||
|
painter.setPen(Pen);
|
||||||
|
Color = Color.lighter(130);
|
||||||
|
Color.setAlpha(64);
|
||||||
|
painter.setBrush(Color);
|
||||||
|
painter.drawRect(r.adjusted(0, 0, -1, -1));
|
||||||
|
d->DropAreaRect = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QRect CDockOverlay::dropOverlayRect() const
|
||||||
|
{
|
||||||
|
return d->DropAreaRect;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockOverlay::showEvent(QShowEvent* e)
|
||||||
|
{
|
||||||
|
d->Cross->show();
|
||||||
|
QFrame::showEvent(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockOverlay::hideEvent(QHideEvent* e)
|
||||||
|
{
|
||||||
|
d->Cross->hide();
|
||||||
|
QFrame::hideEvent(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
bool CDockOverlay::event(QEvent *e)
|
||||||
|
{
|
||||||
|
bool Result = Super::event(e);
|
||||||
|
if (e->type() == QEvent::Polish)
|
||||||
|
{
|
||||||
|
d->Cross->setupOverlayCross(d->Mode);
|
||||||
|
}
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
static int areaAlignment(const DockWidgetArea area)
|
||||||
|
{
|
||||||
|
switch (area)
|
||||||
|
{
|
||||||
|
case TopDockWidgetArea: return (int) Qt::AlignHCenter | Qt::AlignBottom;
|
||||||
|
case RightDockWidgetArea: return (int) Qt::AlignLeft | Qt::AlignVCenter;
|
||||||
|
case BottomDockWidgetArea: return (int) Qt::AlignHCenter | Qt::AlignTop;
|
||||||
|
case LeftDockWidgetArea: return (int) Qt::AlignRight | Qt::AlignVCenter;
|
||||||
|
case CenterDockWidgetArea: return (int) Qt::AlignCenter;
|
||||||
|
default: return Qt::AlignCenter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// DockOverlayCrossPrivate
|
||||||
|
//============================================================================
|
||||||
|
QPoint DockOverlayCrossPrivate::areaGridPosition(const DockWidgetArea area)
|
||||||
|
{
|
||||||
|
if (CDockOverlay::ModeDockAreaOverlay == Mode)
|
||||||
|
{
|
||||||
|
switch (area)
|
||||||
|
{
|
||||||
|
case TopDockWidgetArea: return QPoint(1, 2);
|
||||||
|
case RightDockWidgetArea: return QPoint(2, 3);
|
||||||
|
case BottomDockWidgetArea: return QPoint(3, 2);
|
||||||
|
case LeftDockWidgetArea: return QPoint(2, 1);
|
||||||
|
case CenterDockWidgetArea: return QPoint(2, 2);
|
||||||
|
default: return QPoint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (area)
|
||||||
|
{
|
||||||
|
case TopDockWidgetArea: return QPoint(0, 2);
|
||||||
|
case RightDockWidgetArea: return QPoint(2, 4);
|
||||||
|
case BottomDockWidgetArea: return QPoint(4, 2);
|
||||||
|
case LeftDockWidgetArea: return QPoint(2, 0);
|
||||||
|
case CenterDockWidgetArea: return QPoint(2, 2);
|
||||||
|
default: return QPoint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockOverlayCross::CDockOverlayCross(CDockOverlay* overlay) :
|
||||||
|
QWidget(overlay->parentWidget()),
|
||||||
|
d(new DockOverlayCrossPrivate(this))
|
||||||
|
{
|
||||||
|
d->DockOverlay = overlay;
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
setWindowFlags(Qt::Tool | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint);
|
||||||
|
#else
|
||||||
|
setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
|
||||||
|
#endif
|
||||||
|
setWindowTitle("DockOverlayCross");
|
||||||
|
setAttribute(Qt::WA_TranslucentBackground);
|
||||||
|
|
||||||
|
d->GridLayout = new QGridLayout();
|
||||||
|
d->GridLayout->setSpacing(0);
|
||||||
|
setLayout(d->GridLayout);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockOverlayCross::~CDockOverlayCross()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockOverlayCross::setupOverlayCross(CDockOverlay::eMode Mode)
|
||||||
|
{
|
||||||
|
d->Mode = Mode;
|
||||||
|
|
||||||
|
QHash<DockWidgetArea, QWidget*> areaWidgets;
|
||||||
|
areaWidgets.insert(TopDockWidgetArea, d->createDropIndicatorWidget(TopDockWidgetArea, Mode));
|
||||||
|
areaWidgets.insert(RightDockWidgetArea, d->createDropIndicatorWidget(RightDockWidgetArea, Mode));
|
||||||
|
areaWidgets.insert(BottomDockWidgetArea, d->createDropIndicatorWidget(BottomDockWidgetArea, Mode));
|
||||||
|
areaWidgets.insert(LeftDockWidgetArea, d->createDropIndicatorWidget(LeftDockWidgetArea, Mode));
|
||||||
|
areaWidgets.insert(CenterDockWidgetArea, d->createDropIndicatorWidget(CenterDockWidgetArea, Mode));
|
||||||
|
#if QT_VERSION >= 0x050600
|
||||||
|
d->LastDevicePixelRatio = devicePixelRatioF();
|
||||||
|
#else
|
||||||
|
d->LastDevicePixelRatio = devicePixelRatio();
|
||||||
|
#endif
|
||||||
|
setAreaWidgets(areaWidgets);
|
||||||
|
d->UpdateRequired = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockOverlayCross::updateOverlayIcons()
|
||||||
|
{
|
||||||
|
if (windowHandle()->devicePixelRatio() == d->LastDevicePixelRatio)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto Widget : d->DropIndicatorWidgets)
|
||||||
|
{
|
||||||
|
d->updateDropIndicatorIcon(Widget);
|
||||||
|
}
|
||||||
|
#if QT_VESION >= 0x050600
|
||||||
|
d->LastDevicePixelRatio = devicePixelRatioF();
|
||||||
|
#else
|
||||||
|
d->LastDevicePixelRatio = devicePixelRatio();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockOverlayCross::setIconColor(eIconColor ColorIndex, const QColor& Color)
|
||||||
|
{
|
||||||
|
d->IconColors[ColorIndex] = Color;
|
||||||
|
d->UpdateRequired = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QColor CDockOverlayCross::iconColor(eIconColor ColorIndex) const
|
||||||
|
{
|
||||||
|
return d->IconColors[ColorIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockOverlayCross::setAreaWidgets(const QHash<DockWidgetArea, QWidget*>& widgets)
|
||||||
|
{
|
||||||
|
// Delete old widgets.
|
||||||
|
QMutableHashIterator<DockWidgetArea, QWidget*> i(d->DropIndicatorWidgets);
|
||||||
|
while (i.hasNext())
|
||||||
|
{
|
||||||
|
i.next();
|
||||||
|
QWidget* widget = i.value();
|
||||||
|
d->GridLayout->removeWidget(widget);
|
||||||
|
delete widget;
|
||||||
|
i.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert new widgets into grid.
|
||||||
|
d->DropIndicatorWidgets = widgets;
|
||||||
|
QHashIterator<DockWidgetArea, QWidget*> i2(d->DropIndicatorWidgets);
|
||||||
|
while (i2.hasNext())
|
||||||
|
{
|
||||||
|
i2.next();
|
||||||
|
const DockWidgetArea area = i2.key();
|
||||||
|
QWidget* widget = i2.value();
|
||||||
|
QPoint p = d->areaGridPosition(area);
|
||||||
|
d->GridLayout->addWidget(widget, p.x(), p.y(), (Qt::Alignment) areaAlignment(area));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CDockOverlay::ModeDockAreaOverlay == d->Mode)
|
||||||
|
{
|
||||||
|
d->GridLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
d->GridLayout->setRowStretch(0, 1);
|
||||||
|
d->GridLayout->setRowStretch(1, 0);
|
||||||
|
d->GridLayout->setRowStretch(2, 0);
|
||||||
|
d->GridLayout->setRowStretch(3, 0);
|
||||||
|
d->GridLayout->setRowStretch(4, 1);
|
||||||
|
|
||||||
|
d->GridLayout->setColumnStretch(0, 1);
|
||||||
|
d->GridLayout->setColumnStretch(1, 0);
|
||||||
|
d->GridLayout->setColumnStretch(2, 0);
|
||||||
|
d->GridLayout->setColumnStretch(3, 0);
|
||||||
|
d->GridLayout->setColumnStretch(4, 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
d->GridLayout->setContentsMargins(4, 4, 4, 4);
|
||||||
|
d->GridLayout->setRowStretch(0, 0);
|
||||||
|
d->GridLayout->setRowStretch(1, 1);
|
||||||
|
d->GridLayout->setRowStretch(2, 1);
|
||||||
|
d->GridLayout->setRowStretch(3, 1);
|
||||||
|
d->GridLayout->setRowStretch(4, 0);
|
||||||
|
|
||||||
|
d->GridLayout->setColumnStretch(0, 0);
|
||||||
|
d->GridLayout->setColumnStretch(1, 1);
|
||||||
|
d->GridLayout->setColumnStretch(2, 1);
|
||||||
|
d->GridLayout->setColumnStretch(3, 1);
|
||||||
|
d->GridLayout->setColumnStretch(4, 0);
|
||||||
|
}
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
DockWidgetArea CDockOverlayCross::cursorLocation() const
|
||||||
|
{
|
||||||
|
const QPoint pos = mapFromGlobal(QCursor::pos());
|
||||||
|
QHashIterator<DockWidgetArea, QWidget*> i(d->DropIndicatorWidgets);
|
||||||
|
while (i.hasNext())
|
||||||
|
{
|
||||||
|
i.next();
|
||||||
|
if (d->DockOverlay->allowedAreas().testFlag(i.key())
|
||||||
|
&& i.value()
|
||||||
|
&& i.value()->isVisible()
|
||||||
|
&& i.value()->geometry().contains(pos))
|
||||||
|
{
|
||||||
|
return i.key();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return InvalidDockWidgetArea;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockOverlayCross::showEvent(QShowEvent*)
|
||||||
|
{
|
||||||
|
if (d->UpdateRequired)
|
||||||
|
{
|
||||||
|
setupOverlayCross(d->Mode);
|
||||||
|
}
|
||||||
|
this->updatePosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockOverlayCross::updatePosition()
|
||||||
|
{
|
||||||
|
resize(d->DockOverlay->size());
|
||||||
|
QPoint TopLeft = d->DockOverlay->pos();
|
||||||
|
QPoint Offest((this->width() - d->DockOverlay->width()) / 2,
|
||||||
|
(this->height() - d->DockOverlay->height()) / 2);
|
||||||
|
QPoint CrossTopLeft = TopLeft - Offest;
|
||||||
|
move(CrossTopLeft);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockOverlayCross::reset()
|
||||||
|
{
|
||||||
|
QList<DockWidgetArea> allAreas;
|
||||||
|
allAreas << TopDockWidgetArea << RightDockWidgetArea
|
||||||
|
<< BottomDockWidgetArea << LeftDockWidgetArea << CenterDockWidgetArea;
|
||||||
|
const DockWidgetAreas allowedAreas = d->DockOverlay->allowedAreas();
|
||||||
|
|
||||||
|
// Update visibility of area widgets based on allowedAreas.
|
||||||
|
for (int i = 0; i < allAreas.count(); ++i)
|
||||||
|
{
|
||||||
|
QPoint p = d->areaGridPosition(allAreas.at(i));
|
||||||
|
QLayoutItem* item = d->GridLayout->itemAtPosition(p.x(), p.y());
|
||||||
|
QWidget* w = nullptr;
|
||||||
|
if (item && (w = item->widget()) != nullptr)
|
||||||
|
{
|
||||||
|
w->setVisible(allowedAreas.testFlag(allAreas.at(i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockOverlayCross::setIconColors(const QString& Colors)
|
||||||
|
{
|
||||||
|
static const QMap<QString, int> ColorCompenentStringMap{
|
||||||
|
{"Frame", CDockOverlayCross::FrameColor},
|
||||||
|
{"Background", CDockOverlayCross::WindowBackgroundColor},
|
||||||
|
{"Overlay", CDockOverlayCross::OverlayColor},
|
||||||
|
{"Arrow", CDockOverlayCross::ArrowColor},
|
||||||
|
{"Shadow", CDockOverlayCross::ShadowColor}};
|
||||||
|
|
||||||
|
auto ColorList = Colors.split(' ', Qt::SkipEmptyParts);
|
||||||
|
for (const auto& ColorListEntry : ColorList)
|
||||||
|
{
|
||||||
|
auto ComponentColor = ColorListEntry.split('=', Qt::SkipEmptyParts);
|
||||||
|
int Component = ColorCompenentStringMap.value(ComponentColor[0], -1);
|
||||||
|
if (Component < 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
d->IconColors[Component] = QColor(ComponentColor[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
d->UpdateRequired = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QString CDockOverlayCross::iconColors() const
|
||||||
|
{
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace ads
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
257
src/ui/AdvDock/DockOverlay.h
Normal file
257
src/ui/AdvDock/DockOverlay.h
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
#ifndef DockOverlayH
|
||||||
|
#define DockOverlayH
|
||||||
|
/*******************************************************************************
|
||||||
|
** Qt Advanced Docking System
|
||||||
|
** Copyright (C) 2017 Uwe Kindler
|
||||||
|
**
|
||||||
|
** This library is free software; you can redistribute it and/or
|
||||||
|
** modify it under the terms of the GNU Lesser General Public
|
||||||
|
** License as published by the Free Software Foundation; either
|
||||||
|
** version 2.1 of the License, or (at your option) any later version.
|
||||||
|
**
|
||||||
|
** This library is distributed in the hope that it will be useful,
|
||||||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
** Lesser General Public License for more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU Lesser General Public
|
||||||
|
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// INCLUDES
|
||||||
|
//============================================================================
|
||||||
|
#include <QPointer>
|
||||||
|
#include <QHash>
|
||||||
|
#include <QRect>
|
||||||
|
#include <QFrame>
|
||||||
|
|
||||||
|
#include "ads_globals.h"
|
||||||
|
|
||||||
|
class QGridLayout;
|
||||||
|
|
||||||
|
namespace ads
|
||||||
|
{
|
||||||
|
struct DockOverlayPrivate;
|
||||||
|
class CDockOverlayCross;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* DockOverlay paints a translucent rectangle over another widget. The geometry
|
||||||
|
* of the rectangle is based on the mouse location.
|
||||||
|
*/
|
||||||
|
class CDockOverlay : public QFrame
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
DockOverlayPrivate* d; //< private data class
|
||||||
|
friend struct DockOverlayPrivate;
|
||||||
|
friend class DockOverlayCross;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using Super = QFrame;
|
||||||
|
|
||||||
|
enum eMode
|
||||||
|
{
|
||||||
|
ModeDockAreaOverlay,
|
||||||
|
ModeContainerOverlay
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a dock overlay
|
||||||
|
*/
|
||||||
|
CDockOverlay(QWidget* parent, eMode Mode = ModeDockAreaOverlay);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Virtual destructor
|
||||||
|
*/
|
||||||
|
virtual ~CDockOverlay();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures the areas that are allowed for docking
|
||||||
|
*/
|
||||||
|
void setAllowedAreas(DockWidgetAreas areas);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns flags with all allowed drop areas
|
||||||
|
*/
|
||||||
|
DockWidgetAreas allowedAreas() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the drop area under the current cursor location
|
||||||
|
*/
|
||||||
|
DockWidgetArea dropAreaUnderCursor() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the drop overly for the given target widget
|
||||||
|
*/
|
||||||
|
DockWidgetArea showOverlay(QWidget* target);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hides the overlay
|
||||||
|
*/
|
||||||
|
void hideOverlay();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables / disables the semi transparent overlay rectangle that represents
|
||||||
|
* the future area of the dropped widget
|
||||||
|
*/
|
||||||
|
void enableDropPreview(bool Enable);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if drop preview is enabled
|
||||||
|
*/
|
||||||
|
bool dropPreviewEnabled() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The drop overlay rectangle for the target area
|
||||||
|
*/
|
||||||
|
QRect dropOverlayRect() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle polish events
|
||||||
|
*/
|
||||||
|
virtual bool event(QEvent *e) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void paintEvent(QPaintEvent *e) override;
|
||||||
|
virtual void showEvent(QShowEvent* e) override;
|
||||||
|
virtual void hideEvent(QHideEvent* e) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct DockOverlayCrossPrivate;
|
||||||
|
/*!
|
||||||
|
* DockOverlayCross shows a cross with 5 different drop area possibilities.
|
||||||
|
* I could have handled everything inside DockOverlay, but because of some
|
||||||
|
* styling issues it's better to have a separate class for the cross.
|
||||||
|
* You can style the cross icon using the property system.
|
||||||
|
* \code
|
||||||
|
* ads--CDockOverlayCross
|
||||||
|
{
|
||||||
|
qproperty-iconFrameColor: palette(highlight);
|
||||||
|
qproperty-iconBackgroundColor: palette(base);
|
||||||
|
qproperty-iconOverlayColor: palette(highlight);
|
||||||
|
qproperty-iconArrowColor: rgb(227, 227, 227);
|
||||||
|
qproperty-iconShadowColor: rgb(0, 0, 0);
|
||||||
|
}
|
||||||
|
* \endcode
|
||||||
|
* Or you can use the iconColors property to pass in AARRGGBB values as
|
||||||
|
* hex string like shown in the example below.
|
||||||
|
* \code
|
||||||
|
* ads--CDockOverlayCross
|
||||||
|
* {
|
||||||
|
* qproperty-iconColors: "Frame=#ff3d3d3d Background=#ff929292 Overlay=#1f3d3d3d Arrow=#ffb4b4b4 Shadow=#40474747";
|
||||||
|
* }
|
||||||
|
* \endcode
|
||||||
|
*/
|
||||||
|
class CDockOverlayCross : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(QString iconColors READ iconColors WRITE setIconColors)
|
||||||
|
Q_PROPERTY(QColor iconFrameColor READ iconColor WRITE setIconFrameColor)
|
||||||
|
Q_PROPERTY(QColor iconBackgroundColor READ iconColor WRITE setIconBackgroundColor)
|
||||||
|
Q_PROPERTY(QColor iconOverlayColor READ iconColor WRITE setIconOverlayColor)
|
||||||
|
Q_PROPERTY(QColor iconArrowColor READ iconColor WRITE setIconArrowColor)
|
||||||
|
Q_PROPERTY(QColor iconShadowColor READ iconColor WRITE setIconShadowColor)
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum eIconColor
|
||||||
|
{
|
||||||
|
FrameColor,///< the color of the frame of the small window icon
|
||||||
|
WindowBackgroundColor,///< the background color of the small window in the icon
|
||||||
|
OverlayColor,///< the color that shows the overlay (the dock side) in the icon
|
||||||
|
ArrowColor,///< the arrow that points into the direction
|
||||||
|
ShadowColor///< the color of the shadow rectangle that is painted below the icons
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
DockOverlayCrossPrivate* d;
|
||||||
|
friend struct DockOverlayCrossPrivate;
|
||||||
|
friend class CDockOverlay;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* This function returns an empty string and is only here to silence
|
||||||
|
* moc
|
||||||
|
*/
|
||||||
|
QString iconColors() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a dummy function for the property system
|
||||||
|
*/
|
||||||
|
QColor iconColor() const {return QColor();}
|
||||||
|
void setIconFrameColor(const QColor& Color) {setIconColor(FrameColor, Color);}
|
||||||
|
void setIconBackgroundColor(const QColor& Color) {setIconColor(WindowBackgroundColor, Color);}
|
||||||
|
void setIconOverlayColor(const QColor& Color) {setIconColor(OverlayColor, Color);}
|
||||||
|
void setIconArrowColor(const QColor& Color) {setIconColor(ArrowColor, Color);}
|
||||||
|
void setIconShadowColor(const QColor& Color) {setIconColor(ShadowColor, Color);}
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Creates an overlay cross for the given overlay
|
||||||
|
*/
|
||||||
|
CDockOverlayCross(CDockOverlay* overlay);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Virtual destructor
|
||||||
|
*/
|
||||||
|
virtual ~CDockOverlayCross();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a certain icon color
|
||||||
|
*/
|
||||||
|
void setIconColor(eIconColor ColorIndex, const QColor& Color);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the icon color given by ColorIndex
|
||||||
|
*/
|
||||||
|
QColor iconColor(eIconColor ColorIndex) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the dock widget area depending on the current cursor location.
|
||||||
|
* The function checks, if the mouse cursor is inside of any drop indicator
|
||||||
|
* widget and returns the corresponding DockWidgetArea.
|
||||||
|
*/
|
||||||
|
DockWidgetArea cursorLocation() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up the overlay cross for the given overlay mode
|
||||||
|
*/
|
||||||
|
void setupOverlayCross(CDockOverlay::eMode Mode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recreates the overlay icons.
|
||||||
|
*/
|
||||||
|
void updateOverlayIcons();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets and updates the
|
||||||
|
*/
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the current position
|
||||||
|
*/
|
||||||
|
void updatePosition();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A string with all icon colors to set.
|
||||||
|
* You can use this property to style the overly icon via CSS stylesheet
|
||||||
|
* file. The colors are set via a color identifier and a hex AARRGGBB value like
|
||||||
|
* in the example below.
|
||||||
|
* \code
|
||||||
|
* ads--CDockOverlayCross
|
||||||
|
* {
|
||||||
|
* qproperty-iconColors: "Frame=#ff3d3d3d Background=#ff929292 Overlay=#1f3d3d3d Arrow=#ffb4b4b4 Shadow=#40474747";
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
void setIconColors(const QString& Colors);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void showEvent(QShowEvent* e) override;
|
||||||
|
void setAreaWidgets(const QHash<DockWidgetArea, QWidget*>& widgets);
|
||||||
|
}; // CDockOverlayCross
|
||||||
|
|
||||||
|
} // namespace ads
|
||||||
|
#endif // DockOverlayH
|
95
src/ui/AdvDock/DockSplitter.cpp
Normal file
95
src/ui/AdvDock/DockSplitter.cpp
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
** Qt Advanced Docking System
|
||||||
|
** Copyright (C) 2017 Uwe Kindler
|
||||||
|
**
|
||||||
|
** This library is free software; you can redistribute it and/or
|
||||||
|
** modify it under the terms of the GNU Lesser General Public
|
||||||
|
** License as published by the Free Software Foundation; either
|
||||||
|
** version 2.1 of the License, or (at your option) any later version.
|
||||||
|
**
|
||||||
|
** This library is distributed in the hope that it will be useful,
|
||||||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
** Lesser General Public License for more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU Lesser General Public
|
||||||
|
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
/// \file DockSplitter.cpp
|
||||||
|
/// \author Uwe Kindler
|
||||||
|
/// \date 24.03.2017
|
||||||
|
/// \brief Implementation of CDockSplitter
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// INCLUDES
|
||||||
|
//============================================================================
|
||||||
|
#include "DockSplitter.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QChildEvent>
|
||||||
|
#include <QVariant>
|
||||||
|
|
||||||
|
#include "DockAreaWidget.h"
|
||||||
|
|
||||||
|
namespace ads
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Private dock splitter data
|
||||||
|
*/
|
||||||
|
struct DockSplitterPrivate
|
||||||
|
{
|
||||||
|
CDockSplitter* _this;
|
||||||
|
int VisibleContentCount = 0;
|
||||||
|
|
||||||
|
DockSplitterPrivate(CDockSplitter* _public) : _this(_public) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockSplitter::CDockSplitter(QWidget *parent)
|
||||||
|
: QSplitter(parent),
|
||||||
|
d(new DockSplitterPrivate(this))
|
||||||
|
{
|
||||||
|
setProperty("ads-splitter", true);
|
||||||
|
setChildrenCollapsible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockSplitter::CDockSplitter(Qt::Orientation orientation, QWidget *parent)
|
||||||
|
: QSplitter(orientation, parent),
|
||||||
|
d(new DockSplitterPrivate(this))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockSplitter::~CDockSplitter()
|
||||||
|
{
|
||||||
|
ADS_PRINT("~CDockSplitter");
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
bool CDockSplitter::hasVisibleContent() const
|
||||||
|
{
|
||||||
|
// TODO Cache or precalculate this to speed up
|
||||||
|
for (int i = 0; i < count(); ++i)
|
||||||
|
{
|
||||||
|
if (!widget(i)->isHidden())
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ads
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// EOF DockSplitter.cpp
|
69
src/ui/AdvDock/DockSplitter.h
Normal file
69
src/ui/AdvDock/DockSplitter.h
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
#ifndef DockSplitterH
|
||||||
|
#define DockSplitterH
|
||||||
|
/*******************************************************************************
|
||||||
|
** Qt Advanced Docking System
|
||||||
|
** Copyright (C) 2017 Uwe Kindler
|
||||||
|
**
|
||||||
|
** This library is free software; you can redistribute it and/or
|
||||||
|
** modify it under the terms of the GNU Lesser General Public
|
||||||
|
** License as published by the Free Software Foundation; either
|
||||||
|
** version 2.1 of the License, or (at your option) any later version.
|
||||||
|
**
|
||||||
|
** This library is distributed in the hope that it will be useful,
|
||||||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
** Lesser General Public License for more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU Lesser General Public
|
||||||
|
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
/// \file DockSplitter.h
|
||||||
|
/// \author Uwe Kindler
|
||||||
|
/// \date 24.03.2017
|
||||||
|
/// \brief Declaration of CDockSplitter
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// INCLUDES
|
||||||
|
//============================================================================
|
||||||
|
#include <QSplitter>
|
||||||
|
|
||||||
|
#include "ads_globals.h"
|
||||||
|
|
||||||
|
namespace ads
|
||||||
|
{
|
||||||
|
struct DockSplitterPrivate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Splitter used internally instead of QSplitter with some additional
|
||||||
|
* fuctionality.
|
||||||
|
*/
|
||||||
|
class CDockSplitter : public QSplitter
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
DockSplitterPrivate* d;
|
||||||
|
friend struct DockSplitterPrivate;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CDockSplitter(QWidget *parent = Q_NULLPTR);
|
||||||
|
CDockSplitter(Qt::Orientation orientation, QWidget *parent = Q_NULLPTR);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints debug info
|
||||||
|
*/
|
||||||
|
virtual ~CDockSplitter();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true, if any of the internal widgets is visible
|
||||||
|
*/
|
||||||
|
bool hasVisibleContent() const;
|
||||||
|
}; // class CDockSplitter
|
||||||
|
|
||||||
|
} // namespace ads
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
#endif // DockSplitterH
|
823
src/ui/AdvDock/DockWidget.cpp
Normal file
823
src/ui/AdvDock/DockWidget.cpp
Normal file
@ -0,0 +1,823 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
** Qt Advanced Docking System
|
||||||
|
** Copyright (C) 2017 Uwe Kindler
|
||||||
|
**
|
||||||
|
** This library is free software; you can redistribute it and/or
|
||||||
|
** modify it under the terms of the GNU Lesser General Public
|
||||||
|
** License as published by the Free Software Foundation; either
|
||||||
|
** version 2.1 of the License, or (at your option) any later version.
|
||||||
|
**
|
||||||
|
** This library is distributed in the hope that it will be useful,
|
||||||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
** Lesser General Public License for more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU Lesser General Public
|
||||||
|
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
/// \file DockWidget.cpp
|
||||||
|
/// \author Uwe Kindler
|
||||||
|
/// \date 26.02.2017
|
||||||
|
/// \brief Implementation of CDockWidget class
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// INCLUDES
|
||||||
|
//============================================================================
|
||||||
|
#include "DockWidgetTab.h"
|
||||||
|
#include "DockWidget.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <QBoxLayout>
|
||||||
|
#include <QAction>
|
||||||
|
#include <QSplitter>
|
||||||
|
#include <QStack>
|
||||||
|
#include <QScrollArea>
|
||||||
|
#include <QTextStream>
|
||||||
|
#include <QPointer>
|
||||||
|
#include <QEvent>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QToolBar>
|
||||||
|
#include <QXmlStreamWriter>
|
||||||
|
|
||||||
|
#include <QGuiApplication>
|
||||||
|
#include <QScreen>
|
||||||
|
#include <QWindow>
|
||||||
|
|
||||||
|
#include "DockContainerWidget.h"
|
||||||
|
#include "DockAreaWidget.h"
|
||||||
|
#include "DockManager.h"
|
||||||
|
#include "FloatingDockContainer.h"
|
||||||
|
#include "DockSplitter.h"
|
||||||
|
#include "ads_globals.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace ads
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Private data class of CDockWidget class (pimpl)
|
||||||
|
*/
|
||||||
|
struct DockWidgetPrivate
|
||||||
|
{
|
||||||
|
CDockWidget* _this = nullptr;
|
||||||
|
QBoxLayout* Layout = nullptr;
|
||||||
|
QWidget* Widget = nullptr;
|
||||||
|
CDockWidgetTab* TabWidget = nullptr;
|
||||||
|
CDockWidget::DockWidgetFeatures Features = CDockWidget::DefaultDockWidgetFeatures;
|
||||||
|
CDockManager* DockManager = nullptr;
|
||||||
|
CDockAreaWidget* DockArea = nullptr;
|
||||||
|
QAction* ToggleViewAction = nullptr;
|
||||||
|
bool Closed = false;
|
||||||
|
QScrollArea* ScrollArea = nullptr;
|
||||||
|
QToolBar* ToolBar = nullptr;
|
||||||
|
Qt::ToolButtonStyle ToolBarStyleDocked = Qt::ToolButtonIconOnly;
|
||||||
|
Qt::ToolButtonStyle ToolBarStyleFloating = Qt::ToolButtonTextUnderIcon;
|
||||||
|
QSize ToolBarIconSizeDocked = QSize(16, 16);
|
||||||
|
QSize ToolBarIconSizeFloating = QSize(24, 24);
|
||||||
|
bool IsFloatingTopLevel = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private data constructor
|
||||||
|
*/
|
||||||
|
DockWidgetPrivate(CDockWidget* _public);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show dock widget
|
||||||
|
*/
|
||||||
|
void showDockWidget();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hide dock widget.
|
||||||
|
*/
|
||||||
|
void hideDockWidget();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hides a dock area if all dock widgets in the area are closed.
|
||||||
|
* This function updates the current selected tab and hides the parent
|
||||||
|
* dock area if it is empty
|
||||||
|
*/
|
||||||
|
void updateParentDockArea();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup the top tool bar
|
||||||
|
*/
|
||||||
|
void setupToolBar();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup the main scroll area
|
||||||
|
*/
|
||||||
|
void setupScrollArea();
|
||||||
|
};
|
||||||
|
// struct DockWidgetPrivate
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
DockWidgetPrivate::DockWidgetPrivate(CDockWidget* _public) :
|
||||||
|
_this(_public)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void DockWidgetPrivate::showDockWidget()
|
||||||
|
{
|
||||||
|
if (!DockArea)
|
||||||
|
{
|
||||||
|
CFloatingDockContainer* FloatingWidget = new CFloatingDockContainer(_this);
|
||||||
|
FloatingWidget->resize(_this->size());
|
||||||
|
FloatingWidget->show();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DockArea->setCurrentDockWidget(_this);
|
||||||
|
DockArea->toggleView(true);
|
||||||
|
TabWidget->show();
|
||||||
|
QSplitter* Splitter = internal::findParent<QSplitter*>(DockArea);
|
||||||
|
while (Splitter && !Splitter->isVisible())
|
||||||
|
{
|
||||||
|
Splitter->show();
|
||||||
|
Splitter = internal::findParent<QSplitter*>(Splitter);
|
||||||
|
}
|
||||||
|
|
||||||
|
CDockContainerWidget* Container = DockArea->dockContainer();
|
||||||
|
if (Container->isFloating())
|
||||||
|
{
|
||||||
|
CFloatingDockContainer* FloatingWidget = internal::findParent<
|
||||||
|
CFloatingDockContainer*>(Container);
|
||||||
|
FloatingWidget->show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void DockWidgetPrivate::hideDockWidget()
|
||||||
|
{
|
||||||
|
TabWidget->hide();
|
||||||
|
updateParentDockArea();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void DockWidgetPrivate::updateParentDockArea()
|
||||||
|
{
|
||||||
|
if (!DockArea)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto NextDockWidget = DockArea->nextOpenDockWidget(_this);
|
||||||
|
if (NextDockWidget)
|
||||||
|
{
|
||||||
|
DockArea->setCurrentDockWidget(NextDockWidget);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DockArea->hideAreaWithNoVisibleContent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void DockWidgetPrivate::setupToolBar()
|
||||||
|
{
|
||||||
|
ToolBar = new QToolBar(_this);
|
||||||
|
ToolBar->setObjectName("dockWidgetToolBar");
|
||||||
|
Layout->insertWidget(0, ToolBar);
|
||||||
|
ToolBar->setIconSize(QSize(16, 16));
|
||||||
|
ToolBar->toggleViewAction()->setEnabled(false);
|
||||||
|
ToolBar->toggleViewAction()->setVisible(false);
|
||||||
|
_this->connect(_this, SIGNAL(topLevelChanged(bool)), SLOT(setToolbarFloatingStyle(bool)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void DockWidgetPrivate::setupScrollArea()
|
||||||
|
{
|
||||||
|
ScrollArea = new QScrollArea(_this);
|
||||||
|
ScrollArea->setObjectName("dockWidgetScrollArea");
|
||||||
|
ScrollArea->setWidgetResizable(true);
|
||||||
|
Layout->addWidget(ScrollArea);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockWidget::CDockWidget(const QString &title, QWidget *parent) :
|
||||||
|
QFrame(parent),
|
||||||
|
d(new DockWidgetPrivate(this))
|
||||||
|
{
|
||||||
|
d->Layout = new QBoxLayout(QBoxLayout::TopToBottom);
|
||||||
|
d->Layout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
d->Layout->setSpacing(0);
|
||||||
|
setLayout(d->Layout);
|
||||||
|
setWindowTitle(title);
|
||||||
|
setObjectName(title);
|
||||||
|
|
||||||
|
d->TabWidget = new CDockWidgetTab(this);
|
||||||
|
d->ToggleViewAction = new QAction(title, this);
|
||||||
|
d->ToggleViewAction->setCheckable(true);
|
||||||
|
connect(d->ToggleViewAction, SIGNAL(triggered(bool)), this,
|
||||||
|
SLOT(toggleView(bool)));
|
||||||
|
setToolbarFloatingStyle(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockWidget::~CDockWidget()
|
||||||
|
{
|
||||||
|
ADS_PRINT("~CDockWidget()");
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidget::setToggleViewActionChecked(bool Checked)
|
||||||
|
{
|
||||||
|
QAction* Action = d->ToggleViewAction;
|
||||||
|
Action->blockSignals(true);
|
||||||
|
Action->setChecked(Checked);
|
||||||
|
Action->blockSignals(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidget::setWidget(QWidget* widget, eInsertMode InsertMode)
|
||||||
|
{
|
||||||
|
QScrollArea* ScrollAreaWidget = qobject_cast<QScrollArea*>(widget);
|
||||||
|
if (ScrollAreaWidget || ForceNoScrollArea == InsertMode)
|
||||||
|
{
|
||||||
|
d->Layout->addWidget(widget);
|
||||||
|
if (ScrollAreaWidget && ScrollAreaWidget->viewport())
|
||||||
|
{
|
||||||
|
ScrollAreaWidget->viewport()->setProperty("dockWidgetContent", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
d->setupScrollArea();
|
||||||
|
d->ScrollArea->setWidget(widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
d->Widget = widget;
|
||||||
|
d->Widget->setProperty("dockWidgetContent", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QWidget* CDockWidget::takeWidget()
|
||||||
|
{
|
||||||
|
d->ScrollArea->takeWidget();
|
||||||
|
d->Layout->removeWidget(d->Widget);
|
||||||
|
d->Widget->setParent(nullptr);
|
||||||
|
return d->Widget;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QWidget* CDockWidget::widget() const
|
||||||
|
{
|
||||||
|
return d->Widget;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockWidgetTab* CDockWidget::tabWidget() const
|
||||||
|
{
|
||||||
|
return d->TabWidget;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidget::setFeatures(DockWidgetFeatures features)
|
||||||
|
{
|
||||||
|
if (d->Features == features)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
d->Features = features;
|
||||||
|
emit featuresChanged(d->Features);
|
||||||
|
d->TabWidget->onDockWidgetFeaturesChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidget::setFeature(DockWidgetFeature flag, bool on)
|
||||||
|
{
|
||||||
|
auto Features = features();
|
||||||
|
internal::setFlag(Features, flag, on);
|
||||||
|
setFeatures(Features);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockWidget::DockWidgetFeatures CDockWidget::features() const
|
||||||
|
{
|
||||||
|
return d->Features;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockManager* CDockWidget::dockManager() const
|
||||||
|
{
|
||||||
|
return d->DockManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidget::setDockManager(CDockManager* DockManager)
|
||||||
|
{
|
||||||
|
d->DockManager = DockManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockContainerWidget* CDockWidget::dockContainer() const
|
||||||
|
{
|
||||||
|
if (d->DockArea)
|
||||||
|
{
|
||||||
|
return d->DockArea->dockContainer();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockAreaWidget* CDockWidget::dockAreaWidget() const
|
||||||
|
{
|
||||||
|
return d->DockArea;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
bool CDockWidget::isFloating() const
|
||||||
|
{
|
||||||
|
if (!isInFloatingContainer())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dockContainer()->topLevelDockWidget() == this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
bool CDockWidget::isInFloatingContainer() const
|
||||||
|
{
|
||||||
|
auto Container = dockContainer();
|
||||||
|
if (!Container)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Container->isFloating())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
bool CDockWidget::isClosed() const
|
||||||
|
{
|
||||||
|
return d->Closed;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QAction* CDockWidget::toggleViewAction() const
|
||||||
|
{
|
||||||
|
return d->ToggleViewAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidget::setToggleViewActionMode(eToggleViewActionMode Mode)
|
||||||
|
{
|
||||||
|
if (ActionModeToggle == Mode)
|
||||||
|
{
|
||||||
|
d->ToggleViewAction->setCheckable(true);
|
||||||
|
d->ToggleViewAction->setIcon(QIcon());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
d->ToggleViewAction->setCheckable(false);
|
||||||
|
d->ToggleViewAction->setIcon(d->TabWidget->icon());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidget::toggleView(bool Open)
|
||||||
|
{
|
||||||
|
// If the toggle view action mode is ActionModeShow, then Open is always
|
||||||
|
// true if the sender is the toggle view action
|
||||||
|
QAction* Sender = qobject_cast<QAction*>(sender());
|
||||||
|
if (Sender == d->ToggleViewAction && !d->ToggleViewAction->isCheckable())
|
||||||
|
{
|
||||||
|
Open = true;
|
||||||
|
}
|
||||||
|
// If the dock widget state is different, then we really need to toggle
|
||||||
|
// the state. If we are in the right state, then we simply make this
|
||||||
|
// dock widget the current dock widget
|
||||||
|
if (d->Closed != !Open)
|
||||||
|
{
|
||||||
|
toggleViewInternal(Open);
|
||||||
|
}
|
||||||
|
else if (Open && d->DockArea)
|
||||||
|
{
|
||||||
|
d->DockArea->setCurrentDockWidget(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidget::toggleViewInternal(bool Open)
|
||||||
|
{
|
||||||
|
CDockContainerWidget* DockContainer = dockContainer();
|
||||||
|
CDockWidget* TopLevelDockWidgetBefore = DockContainer
|
||||||
|
? DockContainer->topLevelDockWidget() : nullptr;
|
||||||
|
|
||||||
|
if (Open)
|
||||||
|
{
|
||||||
|
d->showDockWidget();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
d->hideDockWidget();
|
||||||
|
}
|
||||||
|
d->Closed = !Open;
|
||||||
|
d->ToggleViewAction->blockSignals(true);
|
||||||
|
d->ToggleViewAction->setChecked(Open);
|
||||||
|
d->ToggleViewAction->blockSignals(false);
|
||||||
|
if (d->DockArea)
|
||||||
|
{
|
||||||
|
d->DockArea->toggleDockWidgetView(this, Open);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Open && TopLevelDockWidgetBefore)
|
||||||
|
{
|
||||||
|
CDockWidget::emitTopLevelEventForWidget(TopLevelDockWidgetBefore, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Here we need to call the dockContainer() function again, because if
|
||||||
|
// this dock widget was unassigned before the call to showDockWidget() then
|
||||||
|
// it has a dock container now
|
||||||
|
DockContainer = dockContainer();
|
||||||
|
CDockWidget* TopLevelDockWidgetAfter = DockContainer
|
||||||
|
? DockContainer->topLevelDockWidget() : nullptr;
|
||||||
|
CDockWidget::emitTopLevelEventForWidget(TopLevelDockWidgetAfter, true);
|
||||||
|
CFloatingDockContainer* FloatingContainer = DockContainer->floatingWidget();
|
||||||
|
if (FloatingContainer)
|
||||||
|
{
|
||||||
|
FloatingContainer->updateWindowTitle();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Open)
|
||||||
|
{
|
||||||
|
emit closed();
|
||||||
|
}
|
||||||
|
emit viewToggled(Open);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidget::setDockArea(CDockAreaWidget* DockArea)
|
||||||
|
{
|
||||||
|
d->DockArea = DockArea;
|
||||||
|
d->ToggleViewAction->setChecked(DockArea != nullptr && !this->isClosed());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidget::saveState(QXmlStreamWriter& s) const
|
||||||
|
{
|
||||||
|
s.writeStartElement("Widget");
|
||||||
|
s.writeAttribute("Name", objectName());
|
||||||
|
s.writeAttribute("Closed", QString::number(d->Closed ? 1 : 0));
|
||||||
|
s.writeEndElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidget::flagAsUnassigned()
|
||||||
|
{
|
||||||
|
d->Closed = true;
|
||||||
|
setParent(d->DockManager);
|
||||||
|
setVisible(false);
|
||||||
|
setDockArea(nullptr);
|
||||||
|
tabWidget()->setParent(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
bool CDockWidget::event(QEvent *e)
|
||||||
|
{
|
||||||
|
switch (e->type())
|
||||||
|
{
|
||||||
|
case QEvent::Hide:
|
||||||
|
emit visibilityChanged(false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QEvent::Show:
|
||||||
|
emit visibilityChanged(geometry().right() >= 0 && geometry().bottom() >= 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QEvent::WindowTitleChange :
|
||||||
|
{
|
||||||
|
const auto title = windowTitle();
|
||||||
|
if (d->TabWidget)
|
||||||
|
{
|
||||||
|
d->TabWidget->setText(title);
|
||||||
|
}
|
||||||
|
if (d->ToggleViewAction)
|
||||||
|
{
|
||||||
|
d->ToggleViewAction->setText(title);
|
||||||
|
}
|
||||||
|
if (d->DockArea)
|
||||||
|
{
|
||||||
|
d->DockArea->markTitleBarMenuOutdated();//update tabs menu
|
||||||
|
}
|
||||||
|
emit titleChanged(title);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Super::event(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef QT_NO_TOOLTIP
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidget::setTabToolTip(const QString &text)
|
||||||
|
{
|
||||||
|
if (d->TabWidget)
|
||||||
|
{
|
||||||
|
d->TabWidget->setToolTip(text);
|
||||||
|
}
|
||||||
|
if (d->ToggleViewAction)
|
||||||
|
{
|
||||||
|
d->ToggleViewAction->setToolTip(text);
|
||||||
|
}
|
||||||
|
if (d->DockArea)
|
||||||
|
{
|
||||||
|
d->DockArea->markTitleBarMenuOutdated();//update tabs menu
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidget::setIcon(const QIcon& Icon)
|
||||||
|
{
|
||||||
|
d->TabWidget->setIcon(Icon);
|
||||||
|
if (!d->ToggleViewAction->isCheckable())
|
||||||
|
{
|
||||||
|
d->ToggleViewAction->setIcon(Icon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QIcon CDockWidget::icon() const
|
||||||
|
{
|
||||||
|
return d->TabWidget->icon();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QToolBar* CDockWidget::toolBar() const
|
||||||
|
{
|
||||||
|
return d->ToolBar;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QToolBar* CDockWidget::createDefaultToolBar()
|
||||||
|
{
|
||||||
|
if (!d->ToolBar)
|
||||||
|
{
|
||||||
|
d->setupToolBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
return d->ToolBar;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidget::setToolBar(QToolBar* ToolBar)
|
||||||
|
{
|
||||||
|
if (d->ToolBar)
|
||||||
|
{
|
||||||
|
delete d->ToolBar;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->ToolBar = ToolBar;
|
||||||
|
d->Layout->insertWidget(0, d->ToolBar);
|
||||||
|
this->connect(this, SIGNAL(topLevelChanged(bool)), SLOT(setToolbarFloatingStyle(bool)));
|
||||||
|
setToolbarFloatingStyle(isFloating());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidget::setToolBarStyle(Qt::ToolButtonStyle Style, eState State)
|
||||||
|
{
|
||||||
|
if (StateFloating == State)
|
||||||
|
{
|
||||||
|
d->ToolBarStyleFloating = Style;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
d->ToolBarStyleDocked = Style;
|
||||||
|
}
|
||||||
|
|
||||||
|
setToolbarFloatingStyle(isFloating());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
Qt::ToolButtonStyle CDockWidget::toolBarStyle(eState State) const
|
||||||
|
{
|
||||||
|
if (StateFloating == State)
|
||||||
|
{
|
||||||
|
return d->ToolBarStyleFloating;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return d->ToolBarStyleDocked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidget::setToolBarIconSize(const QSize& IconSize, eState State)
|
||||||
|
{
|
||||||
|
if (StateFloating == State)
|
||||||
|
{
|
||||||
|
d->ToolBarIconSizeFloating = IconSize;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
d->ToolBarIconSizeDocked = IconSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
setToolbarFloatingStyle(isFloating());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QSize CDockWidget::toolBarIconSize(eState State) const
|
||||||
|
{
|
||||||
|
if (StateFloating == State)
|
||||||
|
{
|
||||||
|
return d->ToolBarIconSizeFloating;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return d->ToolBarIconSizeDocked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidget::setToolbarFloatingStyle(bool Floating)
|
||||||
|
{
|
||||||
|
if (!d->ToolBar)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto IconSize = Floating ? d->ToolBarIconSizeFloating : d->ToolBarIconSizeDocked;
|
||||||
|
if (IconSize != d->ToolBar->iconSize())
|
||||||
|
{
|
||||||
|
d->ToolBar->setIconSize(IconSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ButtonStyle = Floating ? d->ToolBarStyleFloating : d->ToolBarStyleDocked;
|
||||||
|
if (ButtonStyle != d->ToolBar->toolButtonStyle())
|
||||||
|
{
|
||||||
|
d->ToolBar->setToolButtonStyle(ButtonStyle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidget::emitTopLevelEventForWidget(CDockWidget* TopLevelDockWidget, bool Floating)
|
||||||
|
{
|
||||||
|
if (TopLevelDockWidget)
|
||||||
|
{
|
||||||
|
TopLevelDockWidget->dockAreaWidget()->updateTitleBarVisibility();
|
||||||
|
TopLevelDockWidget->emitTopLevelChanged(Floating);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidget::emitTopLevelChanged(bool Floating)
|
||||||
|
{
|
||||||
|
if (Floating != d->IsFloatingTopLevel)
|
||||||
|
{
|
||||||
|
d->IsFloatingTopLevel = Floating;
|
||||||
|
emit topLevelChanged(d->IsFloatingTopLevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidget::setClosedState(bool Closed)
|
||||||
|
{
|
||||||
|
d->Closed = Closed;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QSize CDockWidget::minimumSizeHint() const
|
||||||
|
{
|
||||||
|
return QSize(60, 40);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidget::setFloating()
|
||||||
|
{
|
||||||
|
if (isClosed())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
d->TabWidget->detachDockWidget();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidget::deleteDockWidget()
|
||||||
|
{
|
||||||
|
dockManager()->removeDockWidget(this);
|
||||||
|
deleteLater();
|
||||||
|
d->Closed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidget::closeDockWidget()
|
||||||
|
{
|
||||||
|
closeDockWidgetInternal(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
bool CDockWidget::closeDockWidgetInternal(bool ForceClose)
|
||||||
|
{
|
||||||
|
if (!ForceClose)
|
||||||
|
{
|
||||||
|
emit closeRequested();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ForceClose && features().testFlag(CDockWidget::CustomCloseHandling))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (features().testFlag(CDockWidget::DockWidgetDeleteOnClose))
|
||||||
|
{
|
||||||
|
// If the dock widget is floating, then we check if we also need to
|
||||||
|
// delete the floating widget
|
||||||
|
if (isFloating())
|
||||||
|
{
|
||||||
|
CFloatingDockContainer* FloatingWidget = internal::findParent<
|
||||||
|
CFloatingDockContainer*>(this);
|
||||||
|
if (FloatingWidget->dockWidgets().count() == 1)
|
||||||
|
{
|
||||||
|
FloatingWidget->deleteLater();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FloatingWidget->hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deleteDockWidget();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
toggleView(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace ads
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// EOF DockWidget.cpp
|
488
src/ui/AdvDock/DockWidget.h
Normal file
488
src/ui/AdvDock/DockWidget.h
Normal file
@ -0,0 +1,488 @@
|
|||||||
|
#ifndef DockWidgetH
|
||||||
|
#define DockWidgetH
|
||||||
|
/*******************************************************************************
|
||||||
|
** Qt Advanced Docking System
|
||||||
|
** Copyright (C) 2017 Uwe Kindler
|
||||||
|
**
|
||||||
|
** This library is free software; you can redistribute it and/or
|
||||||
|
** modify it under the terms of the GNU Lesser General Public
|
||||||
|
** License as published by the Free Software Foundation; either
|
||||||
|
** version 2.1 of the License, or (at your option) any later version.
|
||||||
|
**
|
||||||
|
** This library is distributed in the hope that it will be useful,
|
||||||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
** Lesser General Public License for more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU Lesser General Public
|
||||||
|
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
/// \file DockWidget.h
|
||||||
|
/// \author Uwe Kindler
|
||||||
|
/// \date 26.02.2017
|
||||||
|
/// \brief Declaration of CDockWidget class
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// INCLUDES
|
||||||
|
//============================================================================
|
||||||
|
#include <QFrame>
|
||||||
|
|
||||||
|
#include "ads_globals.h"
|
||||||
|
|
||||||
|
class QToolBar;
|
||||||
|
class QXmlStreamWriter;
|
||||||
|
|
||||||
|
namespace ads
|
||||||
|
{
|
||||||
|
struct DockWidgetPrivate;
|
||||||
|
class CDockWidgetTab;
|
||||||
|
class CDockManager;
|
||||||
|
class CDockContainerWidget;
|
||||||
|
class CDockAreaWidget;
|
||||||
|
class DockContainerWidgetPrivate;
|
||||||
|
class CFloatingDockContainer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The QDockWidget class provides a widget that can be docked inside a
|
||||||
|
* CDockManager or floated as a top-level window on the desktop.
|
||||||
|
*/
|
||||||
|
class CDockWidget : public QFrame
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
DockWidgetPrivate* d; ///< private data (pimpl)
|
||||||
|
friend struct DockWidgetPrivate;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
/**
|
||||||
|
* Adjusts the toolbar icon sizes according to the floating state
|
||||||
|
*/
|
||||||
|
void setToolbarFloatingStyle(bool topLevel);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
friend class CDockContainerWidget;
|
||||||
|
friend class CDockAreaWidget;
|
||||||
|
friend class CFloatingDockContainer;
|
||||||
|
friend class CDockManager;
|
||||||
|
friend struct DockManagerPrivate;
|
||||||
|
friend class DockContainerWidgetPrivate;
|
||||||
|
friend class CDockAreaTabBar;
|
||||||
|
friend class CDockWidgetTab;
|
||||||
|
friend struct DockWidgetTabPrivate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assigns the dock manager that manages this dock widget
|
||||||
|
*/
|
||||||
|
void setDockManager(CDockManager* DockManager);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this dock widget is inserted into a dock area, the dock area will
|
||||||
|
* be registered on this widget via this function. If a dock widget is
|
||||||
|
* removed from a dock area, this function will be called with nullptr
|
||||||
|
* value.
|
||||||
|
*/
|
||||||
|
void setDockArea(CDockAreaWidget* DockArea);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function changes the toggle view action without emitting any
|
||||||
|
* signal
|
||||||
|
*/
|
||||||
|
void setToggleViewActionChecked(bool Checked);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the state into the given stream
|
||||||
|
*/
|
||||||
|
void saveState(QXmlStreamWriter& Stream) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a helper function for the dock manager to flag this widget
|
||||||
|
* as unassigned.
|
||||||
|
* When calling the restore function, it may happen, that the saved state
|
||||||
|
* contains less dock widgets then currently available. All widgets whose
|
||||||
|
* data is not contained in the saved state, are flagged as unassigned
|
||||||
|
* after the restore process. If the user shows an unassigned dock widget,
|
||||||
|
* a floating widget will be created to take up the dock widget.
|
||||||
|
*/
|
||||||
|
void flagAsUnassigned();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call this function to emit a topLevelChanged() signal and to update
|
||||||
|
* the dock area tool bar visibility
|
||||||
|
*/
|
||||||
|
static void emitTopLevelEventForWidget(CDockWidget* TopLevelDockWidget, bool Floating);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this function to emit a top level changed event.
|
||||||
|
* Do never use emit topLevelChanged(). Always use this function because
|
||||||
|
* it only emits a signal if the floating state has really changed
|
||||||
|
*/
|
||||||
|
void emitTopLevelChanged(bool Floating);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal function for modifying the closed state when restoring
|
||||||
|
* a saved docking state
|
||||||
|
*/
|
||||||
|
void setClosedState(bool Closed);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal toggle view function that does not check if the widget
|
||||||
|
* already is in the given state
|
||||||
|
*/
|
||||||
|
void toggleViewInternal(bool Open);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal close dock widget implementation.
|
||||||
|
* The function returns true if the dock widget has been closed or hidden
|
||||||
|
*/
|
||||||
|
bool closeDockWidgetInternal(bool ForceClose = false);
|
||||||
|
|
||||||
|
public:
|
||||||
|
using Super = QFrame;
|
||||||
|
|
||||||
|
enum DockWidgetFeature
|
||||||
|
{
|
||||||
|
DockWidgetClosable = 0x01,
|
||||||
|
DockWidgetMovable = 0x02,///< this feature is not properly implemented yet and is ignored
|
||||||
|
DockWidgetFloatable = 0x04,
|
||||||
|
DockWidgetDeleteOnClose = 0x08, ///< deletes the dock widget when it is closed
|
||||||
|
CustomCloseHandling = 0x10,
|
||||||
|
DefaultDockWidgetFeatures = DockWidgetClosable | DockWidgetMovable | DockWidgetFloatable,
|
||||||
|
AllDockWidgetFeatures = DefaultDockWidgetFeatures | DockWidgetDeleteOnClose | CustomCloseHandling,
|
||||||
|
NoDockWidgetFeatures = 0x00
|
||||||
|
};
|
||||||
|
Q_DECLARE_FLAGS(DockWidgetFeatures, DockWidgetFeature)
|
||||||
|
|
||||||
|
enum eState
|
||||||
|
{
|
||||||
|
StateHidden,
|
||||||
|
StateDocked,
|
||||||
|
StateFloating
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the widget for the dock widget to widget.
|
||||||
|
* The InsertMode defines how the widget is inserted into the dock widget.
|
||||||
|
* The content of a dock widget should be resizable do a very small size to
|
||||||
|
* prevent the dock widget from blocking the resizing. To ensure, that a
|
||||||
|
* dock widget can be resized very well, it is better to insert the content+
|
||||||
|
* widget into a scroll area or to provide a widget that is already a scroll
|
||||||
|
* area or that contains a scroll area.
|
||||||
|
* If the InsertMode is AutoScrollArea, the DockWidget tries to automatically
|
||||||
|
* detect how to insert the given widget. If the widget is derived from
|
||||||
|
* QScrollArea (i.e. an QAbstractItemView), then the widget is inserted
|
||||||
|
* directly. If the given widget is not a scroll area, the widget will be
|
||||||
|
* inserted into a scroll area.
|
||||||
|
* To force insertion into a scroll area, you can also provide the InsertMode
|
||||||
|
* ForceScrollArea. To prevent insertion into a scroll area, you can
|
||||||
|
* provide the InsertMode ForceNoScrollArea
|
||||||
|
*/
|
||||||
|
enum eInsertMode
|
||||||
|
{
|
||||||
|
AutoScrollArea,
|
||||||
|
ForceScrollArea,
|
||||||
|
ForceNoScrollArea
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This mode configures the behavior of the toggle view action.
|
||||||
|
* If the mode if ActionModeToggle, then the toggle view action is
|
||||||
|
* a checkable action to show / hide the dock widget. If the mode
|
||||||
|
* is ActionModeShow, then the action is not checkable an it will
|
||||||
|
* always show the dock widget if clicked. If the mode is ActionModeShow,
|
||||||
|
* the user can only close the DockWidget with the close button.
|
||||||
|
*/
|
||||||
|
enum eToggleViewActionMode
|
||||||
|
{
|
||||||
|
ActionModeToggle,//!< ActionModeToggle
|
||||||
|
ActionModeShow //!< ActionModeShow
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constructor creates a dock widget with the given title.
|
||||||
|
* The title is the text that is shown in the window title when the dock
|
||||||
|
* widget is floating and it is the title that is shown in the titlebar
|
||||||
|
* or the tab of this dock widget if it is tabified.
|
||||||
|
* The object name of the dock widget is also set to the title. The
|
||||||
|
* object name is required by the dock manager to properly save and restore
|
||||||
|
* the state of the dock widget. That means, the title needs to be unique.
|
||||||
|
* If your title is not unique or if you would like to change the title
|
||||||
|
* during runtime, you need to set a unique object name explicitely
|
||||||
|
* by calling setObjectName() after construction.
|
||||||
|
* Use the layoutFlags to configure the layout of the dock widget.
|
||||||
|
*/
|
||||||
|
CDockWidget(const QString &title, QWidget* parent = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Virtual Destructor
|
||||||
|
*/
|
||||||
|
virtual ~CDockWidget();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We return a fixed minimum size hint for all dock widgets
|
||||||
|
*/
|
||||||
|
virtual QSize minimumSizeHint() const override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the widget for the dock widget to widget.
|
||||||
|
* The InsertMode defines how the widget is inserted into the dock widget.
|
||||||
|
* The content of a dock widget should be resizable do a very small size to
|
||||||
|
* prevent the dock widget from blocking the resizing. To ensure, that a
|
||||||
|
* dock widget can be resized very well, it is better to insert the content+
|
||||||
|
* widget into a scroll area or to provide a widget that is already a scroll
|
||||||
|
* area or that contains a scroll area.
|
||||||
|
* If the InsertMode is AutoScrollArea, the DockWidget tries to automatically
|
||||||
|
* detect how to insert the given widget. If the widget is derived from
|
||||||
|
* QScrollArea (i.e. an QAbstractItemView), then the widget is inserted
|
||||||
|
* directly. If the given widget is not a scroll area, the widget will be
|
||||||
|
* inserted into a scroll area.
|
||||||
|
* To force insertion into a scroll area, you can also provide the InsertMode
|
||||||
|
* ForceScrollArea. To prevent insertion into a scroll area, you can
|
||||||
|
* provide the InsertMode ForceNoScrollArea
|
||||||
|
*/
|
||||||
|
void setWidget(QWidget* widget, eInsertMode InsertMode = AutoScrollArea);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the widget from the dock and give ownership back to the caller
|
||||||
|
*/
|
||||||
|
QWidget* takeWidget();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the widget for the dock widget. This function returns zero if
|
||||||
|
* the widget has not been set.
|
||||||
|
*/
|
||||||
|
QWidget* widget() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the tab widget of this dock widget that is shown in the dock
|
||||||
|
* area title bar
|
||||||
|
*/
|
||||||
|
CDockWidgetTab* tabWidget() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets, whether the dock widget is movable, closable, and floatable.
|
||||||
|
*/
|
||||||
|
void setFeatures(DockWidgetFeatures features);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the feature flag for this dock widget if on is true; otherwise
|
||||||
|
* clears the flag.
|
||||||
|
*/
|
||||||
|
void setFeature(DockWidgetFeature flag, bool on);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This property holds whether the dock widget is movable, closable, and
|
||||||
|
* floatable.
|
||||||
|
* By default, this property is set to a combination of DockWidgetClosable,
|
||||||
|
* DockWidgetMovable and DockWidgetFloatable.
|
||||||
|
*/
|
||||||
|
DockWidgetFeatures features() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the dock manager that manages the dock widget or 0 if the widget
|
||||||
|
* has not been assigned to any dock manager yet
|
||||||
|
*/
|
||||||
|
CDockManager* dockManager() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the dock container widget this dock area widget belongs to or 0
|
||||||
|
* if this dock widget has not been docked yet
|
||||||
|
*/
|
||||||
|
CDockContainerWidget* dockContainer() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the dock area widget this dock widget belongs to or 0
|
||||||
|
* if this dock widget has not been docked yet
|
||||||
|
*/
|
||||||
|
CDockAreaWidget* dockAreaWidget() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This property holds whether the dock widget is floating.
|
||||||
|
* A dock widget is only floating, if it is the one and only widget inside
|
||||||
|
* of a floating container. If there are more than one dock widget in a
|
||||||
|
* floating container, the all dock widgets are docked and not floating.
|
||||||
|
*/
|
||||||
|
bool isFloating() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function returns true, if this dock widget is in a floating.
|
||||||
|
* The function returns true, if the dock widget is floating and it also
|
||||||
|
* returns true if it is docked inside of a floating container.
|
||||||
|
*/
|
||||||
|
bool isInFloatingContainer() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true, if this dock widget is closed.
|
||||||
|
*/
|
||||||
|
bool isClosed() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a checkable action that can be used to show or close this dock widget.
|
||||||
|
* The action's text is set to the dock widget's window title.
|
||||||
|
*/
|
||||||
|
QAction* toggleViewAction() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures the behavior of the toggle view action.
|
||||||
|
* \see eToggleViewActionMode for a detailed description
|
||||||
|
*/
|
||||||
|
void setToggleViewActionMode(eToggleViewActionMode Mode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the dock widget icon that is shown in tabs and in toggle view
|
||||||
|
* actions
|
||||||
|
*/
|
||||||
|
void setIcon(const QIcon& Icon);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the icon that has been assigned to the dock widget
|
||||||
|
*/
|
||||||
|
QIcon icon() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the WithToolBar layout flag is enabled, then this function returns
|
||||||
|
* the dock widget toolbar. If the flag is disabled, the function returns
|
||||||
|
* a nullptr.
|
||||||
|
* This function returns the dock widget top tool bar.
|
||||||
|
* If no toolbar is assigned, this function returns nullptr. To get a vaild
|
||||||
|
* toolbar you either need to create a default empty toolbar via
|
||||||
|
* createDefaultToolBar() function or you need to assign you custom
|
||||||
|
* toolbar via setToolBar().
|
||||||
|
*/
|
||||||
|
QToolBar* toolBar() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If you would like to use the default top tool bar, then call this
|
||||||
|
* function to create the default tool bar.
|
||||||
|
* After this function the toolBar() function will return a valid toolBar()
|
||||||
|
* object.
|
||||||
|
*/
|
||||||
|
QToolBar* createDefaultToolBar();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assign a new tool bar that is shown above the content widget.
|
||||||
|
* The dock widget will become the owner of the tool bar and deletes it
|
||||||
|
* on destruction
|
||||||
|
*/
|
||||||
|
void setToolBar(QToolBar* ToolBar);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function sets the tool button style for the given dock widget state.
|
||||||
|
* It is possible to switch the tool button style depending on the state.
|
||||||
|
* If a dock widget is floating, then here are more space and it is
|
||||||
|
* possible to select a style that requires more space like
|
||||||
|
* Qt::ToolButtonTextUnderIcon. For the docked state Qt::ToolButtonIconOnly
|
||||||
|
* might be better.
|
||||||
|
*/
|
||||||
|
void setToolBarStyle(Qt::ToolButtonStyle Style, eState State);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the tool button style for the given docking state.
|
||||||
|
* \see setToolBarStyle()
|
||||||
|
*/
|
||||||
|
Qt::ToolButtonStyle toolBarStyle(eState State) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function sets the tool button icon size for the given state.
|
||||||
|
* If a dock widget is floating, there is more space an increasing the
|
||||||
|
* icon size is possible. For docked widgets, small icon sizes, eg. 16 x 16
|
||||||
|
* might be better.
|
||||||
|
*/
|
||||||
|
void setToolBarIconSize(const QSize& IconSize, eState State);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the icon size for a given docking state.
|
||||||
|
* \see setToolBarIconSize()
|
||||||
|
*/
|
||||||
|
QSize toolBarIconSize(eState State) const;
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef QT_NO_TOOLTIP
|
||||||
|
/**
|
||||||
|
* This is function sets text tooltip for title bar widget
|
||||||
|
* and tooltip for toggle view action
|
||||||
|
*/
|
||||||
|
void setTabToolTip(const QString &text);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public: // reimplements QFrame -----------------------------------------------
|
||||||
|
/**
|
||||||
|
* Emits titleChanged signal if title change event occurs
|
||||||
|
*/
|
||||||
|
virtual bool event(QEvent *e) override;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
/**
|
||||||
|
* This property controls whether the dock widget is open or closed.
|
||||||
|
* The toogleViewAction triggers this slot
|
||||||
|
*/
|
||||||
|
void toggleView(bool Open = true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function will make a docked widget floating
|
||||||
|
*/
|
||||||
|
void setFloating();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function will delete the dock widget and its content from the
|
||||||
|
* docking system
|
||||||
|
*/
|
||||||
|
void deleteDockWidget();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes the dock widget
|
||||||
|
*/
|
||||||
|
void closeDockWidget();
|
||||||
|
|
||||||
|
|
||||||
|
signals:
|
||||||
|
/**
|
||||||
|
* This signal is emitted if the dock widget is opened or closed
|
||||||
|
*/
|
||||||
|
void viewToggled(bool Open);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted if the dock widget is closed
|
||||||
|
*/
|
||||||
|
void closed();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted if the window title of this dock widget
|
||||||
|
* changed
|
||||||
|
*/
|
||||||
|
void titleChanged(const QString& Title);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted when the floating property changes.
|
||||||
|
* The topLevel parameter is true if the dock widget is now floating;
|
||||||
|
* otherwise it is false.
|
||||||
|
*/
|
||||||
|
void topLevelChanged(bool topLevel);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted, if close is requested
|
||||||
|
*/
|
||||||
|
void closeRequested();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted when the dock widget becomes visible (or invisible).
|
||||||
|
* This happens when the widget is hidden or shown, as well as when it is
|
||||||
|
* docked in a tabbed dock area and its tab becomes selected or unselected.
|
||||||
|
*/
|
||||||
|
void visibilityChanged(bool visible);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted when the features property changes.
|
||||||
|
* The features parameter gives the new value of the property.
|
||||||
|
*/
|
||||||
|
void featuresChanged(DockWidgetFeatures features);
|
||||||
|
}; // class DockWidget
|
||||||
|
}
|
||||||
|
// namespace ads
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
#endif // DockWidgetH
|
623
src/ui/AdvDock/DockWidgetTab.cpp
Normal file
623
src/ui/AdvDock/DockWidgetTab.cpp
Normal file
@ -0,0 +1,623 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
** Qt Advanced Docking System
|
||||||
|
** Copyright (C) 2017 Uwe Kindler
|
||||||
|
**
|
||||||
|
** This library is free software; you can redistribute it and/or
|
||||||
|
** modify it under the terms of the GNU Lesser General Public
|
||||||
|
** License as published by the Free Software Foundation; either
|
||||||
|
** version 2.1 of the License, or (at your option) any later version.
|
||||||
|
**
|
||||||
|
** This library is distributed in the hope that it will be useful,
|
||||||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
** Lesser General Public License for more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU Lesser General Public
|
||||||
|
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
/// \file DockWidgetTab.cpp
|
||||||
|
/// \author Uwe Kindler
|
||||||
|
/// \date 27.02.2017
|
||||||
|
/// \brief Implementation of CDockWidgetTab class
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// INCLUDES
|
||||||
|
//============================================================================
|
||||||
|
#include "FloatingDragPreview.h"
|
||||||
|
#include "ElidingLabel.h"
|
||||||
|
#include "DockWidgetTab.h"
|
||||||
|
|
||||||
|
#include <QBoxLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QStyle>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QSplitter>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QToolButton>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QMenu>
|
||||||
|
|
||||||
|
#include "DockWidget.h"
|
||||||
|
#include "DockAreaWidget.h"
|
||||||
|
#include "FloatingDockContainer.h"
|
||||||
|
#include "DockOverlay.h"
|
||||||
|
#include "DockManager.h"
|
||||||
|
#include "IconProvider.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace ads
|
||||||
|
{
|
||||||
|
|
||||||
|
using tTabLabel = CElidingLabel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private data class of CDockWidgetTab class (pimpl)
|
||||||
|
*/
|
||||||
|
struct DockWidgetTabPrivate
|
||||||
|
{
|
||||||
|
CDockWidgetTab* _this;
|
||||||
|
CDockWidget* DockWidget;
|
||||||
|
QLabel* IconLabel = nullptr;
|
||||||
|
tTabLabel* TitleLabel;
|
||||||
|
QPoint GlobalDragStartMousePosition;
|
||||||
|
bool IsActiveTab = false;
|
||||||
|
CDockAreaWidget* DockArea = nullptr;
|
||||||
|
eDragState DragState = DraggingInactive;
|
||||||
|
IFloatingWidget* FloatingWidget = nullptr;
|
||||||
|
QIcon Icon;
|
||||||
|
QAbstractButton* CloseButton = nullptr;
|
||||||
|
QSpacerItem* IconTextSpacer;
|
||||||
|
QPoint TabDragStartPosition;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private data constructor
|
||||||
|
*/
|
||||||
|
DockWidgetTabPrivate(CDockWidgetTab* _public);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the complete layout including all controls
|
||||||
|
*/
|
||||||
|
void createLayout();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves the tab depending on the position in the given mouse event
|
||||||
|
*/
|
||||||
|
void moveTab(QMouseEvent* ev);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test function for current drag state
|
||||||
|
*/
|
||||||
|
bool isDraggingState(eDragState dragState) const
|
||||||
|
{
|
||||||
|
return this->DragState == dragState;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the given global point is inside the title area geometry
|
||||||
|
* rectangle.
|
||||||
|
* The position is given as global position.
|
||||||
|
*/
|
||||||
|
bool titleAreaGeometryContains(const QPoint& GlobalPos) const
|
||||||
|
{
|
||||||
|
return DockArea->titleBarGeometry().contains(DockArea->mapFromGlobal(GlobalPos));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts floating of the dock widget that belongs to this title bar
|
||||||
|
* Returns true, if floating has been started and false if floating
|
||||||
|
* is not possible for any reason
|
||||||
|
*/
|
||||||
|
bool startFloating(eDragState DraggingState = DraggingFloatingWidget);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the given config flag is set
|
||||||
|
*/
|
||||||
|
bool testConfigFlag(CDockManager::eConfigFlag Flag) const
|
||||||
|
{
|
||||||
|
return CDockManager::configFlags().testFlag(Flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the close button as QPushButton or as QToolButton
|
||||||
|
*/
|
||||||
|
QAbstractButton* createCloseButton() const
|
||||||
|
{
|
||||||
|
if (testConfigFlag(CDockManager::TabCloseButtonIsToolButton))
|
||||||
|
{
|
||||||
|
auto Button = new QToolButton();
|
||||||
|
Button->setAutoRaise(true);
|
||||||
|
return Button;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new QPushButton();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
IFloatingWidget* createFloatingWidget(T* Widget, bool OpaqueUndocking)
|
||||||
|
{
|
||||||
|
if (OpaqueUndocking)
|
||||||
|
{
|
||||||
|
return new CFloatingDockContainer(Widget);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto w = new CFloatingDragPreview(Widget);
|
||||||
|
_this->connect(w, &CFloatingDragPreview::draggingCanceled, [=]()
|
||||||
|
{
|
||||||
|
DragState = DraggingInactive;
|
||||||
|
});
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// struct DockWidgetTabPrivate
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
DockWidgetTabPrivate::DockWidgetTabPrivate(CDockWidgetTab* _public) :
|
||||||
|
_this(_public)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void DockWidgetTabPrivate::createLayout()
|
||||||
|
{
|
||||||
|
TitleLabel = new tTabLabel();
|
||||||
|
TitleLabel->setElideMode(Qt::ElideRight);
|
||||||
|
TitleLabel->setText(DockWidget->windowTitle());
|
||||||
|
TitleLabel->setObjectName("dockWidgetTabLabel");
|
||||||
|
TitleLabel->setAlignment(Qt::AlignCenter);
|
||||||
|
|
||||||
|
CloseButton = createCloseButton();
|
||||||
|
CloseButton->setObjectName("tabCloseButton");
|
||||||
|
QIcon CloseIcon = CDockManager::iconProvider().customIcon(TabCloseIcon);
|
||||||
|
if (CloseIcon.isNull())
|
||||||
|
{
|
||||||
|
// The standard icons do does not look good on high DPI screens
|
||||||
|
QPixmap normalPixmap = _this->style()->standardPixmap(QStyle::SP_TitleBarCloseButton, 0, CloseButton);
|
||||||
|
CloseIcon.addPixmap(normalPixmap, QIcon::Normal);
|
||||||
|
CloseIcon.addPixmap(internal::createTransparentPixmap(normalPixmap, 0.25), QIcon::Disabled);
|
||||||
|
}
|
||||||
|
CloseButton->setIcon(CloseIcon);
|
||||||
|
CloseButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||||
|
_this->onDockWidgetFeaturesChanged();
|
||||||
|
#ifndef QT_NO_TOOLTIP
|
||||||
|
CloseButton->setToolTip(QObject::tr("Close Tab"));
|
||||||
|
#endif
|
||||||
|
_this->connect(CloseButton, SIGNAL(clicked()), SIGNAL(closeRequested()));
|
||||||
|
|
||||||
|
QFontMetrics fm(TitleLabel->font());
|
||||||
|
int Spacing = qRound(fm.height() / 4.0);
|
||||||
|
|
||||||
|
// Fill the layout
|
||||||
|
QBoxLayout* Layout = new QBoxLayout(QBoxLayout::LeftToRight);
|
||||||
|
Layout->setContentsMargins(2 * Spacing,0,0,0);
|
||||||
|
Layout->setSpacing(0);
|
||||||
|
_this->setLayout(Layout);
|
||||||
|
Layout->addWidget(TitleLabel, 1);
|
||||||
|
Layout->addSpacing(Spacing);
|
||||||
|
Layout->addWidget(CloseButton);
|
||||||
|
Layout->addSpacing(qRound(Spacing * 4.0 / 3.0));
|
||||||
|
Layout->setAlignment(Qt::AlignCenter);
|
||||||
|
|
||||||
|
TitleLabel->setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void DockWidgetTabPrivate::moveTab(QMouseEvent* ev)
|
||||||
|
{
|
||||||
|
ev->accept();
|
||||||
|
QPoint Distance = ev->globalPos() - GlobalDragStartMousePosition;
|
||||||
|
Distance.setY(0);
|
||||||
|
auto TargetPos = Distance + TabDragStartPosition;
|
||||||
|
_this->move(TargetPos);
|
||||||
|
_this->raise();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
bool DockWidgetTabPrivate::startFloating(eDragState DraggingState)
|
||||||
|
{
|
||||||
|
auto dockContainer = DockWidget->dockContainer();
|
||||||
|
ADS_PRINT("isFloating " << dockContainer->isFloating());
|
||||||
|
ADS_PRINT("areaCount " << dockContainer->dockAreaCount());
|
||||||
|
ADS_PRINT("widgetCount " << DockWidget->dockAreaWidget()->dockWidgetsCount());
|
||||||
|
// if this is the last dock widget inside of this floating widget,
|
||||||
|
// then it does not make any sense, to make it floating because
|
||||||
|
// it is already floating
|
||||||
|
if (dockContainer->isFloating()
|
||||||
|
&& (dockContainer->visibleDockAreaCount() == 1)
|
||||||
|
&& (DockWidget->dockAreaWidget()->dockWidgetsCount() == 1))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ADS_PRINT("startFloating");
|
||||||
|
DragState = DraggingState;
|
||||||
|
auto DragStartMousePosition = _this->mapFromGlobal(GlobalDragStartMousePosition);
|
||||||
|
QSize Size = DockArea->size();
|
||||||
|
IFloatingWidget* FloatingWidget = nullptr;
|
||||||
|
bool OpaqueUndocking = CDockManager::configFlags().testFlag(CDockManager::OpaqueUndocking) ||
|
||||||
|
(DraggingFloatingWidget != DraggingState);
|
||||||
|
|
||||||
|
// If section widget has multiple tabs, we take only one tab
|
||||||
|
// If it has only one single tab, we can move the complete
|
||||||
|
// dock area into floating widget
|
||||||
|
if (DockArea->dockWidgetsCount() > 1)
|
||||||
|
{
|
||||||
|
FloatingWidget = createFloatingWidget(DockWidget, OpaqueUndocking);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FloatingWidget = createFloatingWidget(DockArea, OpaqueUndocking);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DraggingFloatingWidget == DraggingState)
|
||||||
|
{
|
||||||
|
FloatingWidget->startFloating(DragStartMousePosition, Size, DraggingFloatingWidget, _this);
|
||||||
|
auto Overlay = DockWidget->dockManager()->containerOverlay();
|
||||||
|
Overlay->setAllowedAreas(OuterDockAreas);
|
||||||
|
this->FloatingWidget = FloatingWidget;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FloatingWidget->startFloating(DragStartMousePosition, Size, DraggingInactive, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockWidgetTab::CDockWidgetTab(CDockWidget* DockWidget, QWidget *parent) :
|
||||||
|
QFrame(parent),
|
||||||
|
d(new DockWidgetTabPrivate(this))
|
||||||
|
{
|
||||||
|
setAttribute(Qt::WA_NoMousePropagation, true);
|
||||||
|
d->DockWidget = DockWidget;
|
||||||
|
d->createLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockWidgetTab::~CDockWidgetTab()
|
||||||
|
{
|
||||||
|
ADS_PRINT("~CDockWidgetTab()");
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidgetTab::mousePressEvent(QMouseEvent* ev)
|
||||||
|
{
|
||||||
|
if (ev->button() == Qt::LeftButton)
|
||||||
|
{
|
||||||
|
ev->accept();
|
||||||
|
d->GlobalDragStartMousePosition = ev->globalPos();
|
||||||
|
d->DragState = DraggingMousePressed;
|
||||||
|
emit clicked();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Super::mousePressEvent(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidgetTab::mouseReleaseEvent(QMouseEvent* ev)
|
||||||
|
{
|
||||||
|
if (ev->button() == Qt::LeftButton)
|
||||||
|
{
|
||||||
|
auto CurrentDragState = d->DragState;
|
||||||
|
d->GlobalDragStartMousePosition = QPoint();
|
||||||
|
d->DragState = DraggingInactive;
|
||||||
|
|
||||||
|
switch (CurrentDragState)
|
||||||
|
{
|
||||||
|
case DraggingTab:
|
||||||
|
// End of tab moving, emit signal
|
||||||
|
if (d->DockArea)
|
||||||
|
{
|
||||||
|
emit moved(ev->globalPos());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DraggingFloatingWidget:
|
||||||
|
d->FloatingWidget->finishDragging();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:; // do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Super::mouseReleaseEvent(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidgetTab::mouseMoveEvent(QMouseEvent* ev)
|
||||||
|
{
|
||||||
|
if (!(ev->buttons() & Qt::LeftButton) || d->isDraggingState(DraggingInactive))
|
||||||
|
{
|
||||||
|
d->DragState = DraggingInactive;
|
||||||
|
Super::mouseMoveEvent(ev);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// move floating window
|
||||||
|
if (d->isDraggingState(DraggingFloatingWidget))
|
||||||
|
{
|
||||||
|
d->FloatingWidget->moveFloating();
|
||||||
|
Super::mouseMoveEvent(ev);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// move tab
|
||||||
|
if (d->isDraggingState(DraggingTab))
|
||||||
|
{
|
||||||
|
// Moving the tab is always allowed because it does not mean moving the
|
||||||
|
// dock widget around
|
||||||
|
d->moveTab(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Maybe a fixed drag distance is better here ?
|
||||||
|
int DragDistanceY = qAbs(d->GlobalDragStartMousePosition.y() - ev->globalPos().y());
|
||||||
|
if (DragDistanceY >= CDockManager::startDragDistance())
|
||||||
|
{
|
||||||
|
// If this is the last dock area in a dock container with only
|
||||||
|
// one single dock widget it does not make sense to move it to a new
|
||||||
|
// floating widget and leave this one empty
|
||||||
|
if (d->DockArea->dockContainer()->isFloating()
|
||||||
|
&& d->DockArea->openDockWidgetsCount() == 1
|
||||||
|
&& d->DockArea->dockContainer()->visibleDockAreaCount() == 1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Floating is only allowed for widgets that are movable
|
||||||
|
if (d->DockWidget->features().testFlag(CDockWidget::DockWidgetFloatable))
|
||||||
|
{
|
||||||
|
// If we undock, we need to restore the initial position of this
|
||||||
|
// tab because it looks strange if it remains on its dragged position
|
||||||
|
if (d->isDraggingState(DraggingTab) && !CDockManager::configFlags().testFlag(CDockManager::OpaqueUndocking))
|
||||||
|
{
|
||||||
|
this->move(d->TabDragStartPosition);
|
||||||
|
}
|
||||||
|
d->startFloating();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (d->DockArea->openDockWidgetsCount() > 1
|
||||||
|
&& (ev->globalPos() - d->GlobalDragStartMousePosition).manhattanLength() >= QApplication::startDragDistance()) // Wait a few pixels before start moving
|
||||||
|
{
|
||||||
|
// If we start dragging the tab, we save its inital position to
|
||||||
|
// restore it later
|
||||||
|
if (DraggingTab != d->DragState)
|
||||||
|
{
|
||||||
|
d->TabDragStartPosition = this->pos();
|
||||||
|
}
|
||||||
|
d->DragState = DraggingTab;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Super::mouseMoveEvent(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidgetTab::contextMenuEvent(QContextMenuEvent* ev)
|
||||||
|
{
|
||||||
|
ev->accept();
|
||||||
|
if (d->isDraggingState(DraggingFloatingWidget))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->GlobalDragStartMousePosition = ev->globalPos();
|
||||||
|
QMenu Menu(this);
|
||||||
|
auto Action = Menu.addAction(tr("Detach"), this, SLOT(detachDockWidget()));
|
||||||
|
Action->setEnabled(d->DockWidget->features().testFlag(CDockWidget::DockWidgetFloatable));
|
||||||
|
Menu.addSeparator();
|
||||||
|
Action = Menu.addAction(tr("Close"), this, SIGNAL(closeRequested()));
|
||||||
|
Action->setEnabled(isClosable());
|
||||||
|
Menu.addAction(tr("Close Others"), this, SIGNAL(closeOtherTabsRequested()));
|
||||||
|
Menu.exec(ev->globalPos());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
bool CDockWidgetTab::isActiveTab() const
|
||||||
|
{
|
||||||
|
return d->IsActiveTab;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidgetTab::setActiveTab(bool active)
|
||||||
|
{
|
||||||
|
bool DockWidgetClosable = d->DockWidget->features().testFlag(CDockWidget::DockWidgetClosable);
|
||||||
|
bool ActiveTabHasCloseButton = d->testConfigFlag(CDockManager::ActiveTabHasCloseButton);
|
||||||
|
bool AllTabsHaveCloseButton = d->testConfigFlag(CDockManager::AllTabsHaveCloseButton);
|
||||||
|
bool TabHasCloseButton = (ActiveTabHasCloseButton && active) | AllTabsHaveCloseButton;
|
||||||
|
d->CloseButton->setVisible(DockWidgetClosable && TabHasCloseButton);
|
||||||
|
if (d->IsActiveTab == active)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->IsActiveTab = active;
|
||||||
|
style()->unpolish(this);
|
||||||
|
style()->polish(this);
|
||||||
|
d->TitleLabel->style()->unpolish(d->TitleLabel);
|
||||||
|
d->TitleLabel->style()->polish(d->TitleLabel);
|
||||||
|
update();
|
||||||
|
|
||||||
|
emit activeTabChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockWidget* CDockWidgetTab::dockWidget() const
|
||||||
|
{
|
||||||
|
return d->DockWidget;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidgetTab::setDockAreaWidget(CDockAreaWidget* DockArea)
|
||||||
|
{
|
||||||
|
d->DockArea = DockArea;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockAreaWidget* CDockWidgetTab::dockAreaWidget() const
|
||||||
|
{
|
||||||
|
return d->DockArea;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidgetTab::setIcon(const QIcon& Icon)
|
||||||
|
{
|
||||||
|
QBoxLayout* Layout = qobject_cast<QBoxLayout*>(layout());
|
||||||
|
if (!d->IconLabel && Icon.isNull())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!d->IconLabel)
|
||||||
|
{
|
||||||
|
d->IconLabel = new QLabel();
|
||||||
|
d->IconLabel->setAlignment(Qt::AlignVCenter);
|
||||||
|
d->IconLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
|
||||||
|
#ifndef QT_NO_TOOLTIP
|
||||||
|
d->IconLabel->setToolTip(d->TitleLabel->toolTip());
|
||||||
|
#endif
|
||||||
|
Layout->insertWidget(0, d->IconLabel, Qt::AlignVCenter);
|
||||||
|
Layout->insertSpacing(1, qRound(1.5 * Layout->contentsMargins().left() / 2.0));
|
||||||
|
}
|
||||||
|
else if (Icon.isNull())
|
||||||
|
{
|
||||||
|
// Remove icon label and spacer item
|
||||||
|
Layout->removeWidget(d->IconLabel);
|
||||||
|
Layout->removeItem(Layout->itemAt(0));
|
||||||
|
delete d->IconLabel;
|
||||||
|
d->IconLabel = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->Icon = Icon;
|
||||||
|
if (d->IconLabel)
|
||||||
|
{
|
||||||
|
d->IconLabel->setPixmap(Icon.pixmap(style()->pixelMetric(QStyle::PM_SmallIconSize, nullptr, this)));
|
||||||
|
d->IconLabel->setVisible(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
const QIcon& CDockWidgetTab::icon() const
|
||||||
|
{
|
||||||
|
return d->Icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QString CDockWidgetTab::text() const
|
||||||
|
{
|
||||||
|
return d->TitleLabel->text();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidgetTab::mouseDoubleClickEvent(QMouseEvent *event)
|
||||||
|
{
|
||||||
|
// If this is the last dock area in a dock container it does not make
|
||||||
|
// sense to move it to a new floating widget and leave this one
|
||||||
|
// empty
|
||||||
|
if ((!d->DockArea->dockContainer()->isFloating() || d->DockArea->dockWidgetsCount() > 1)
|
||||||
|
&& d->DockWidget->features().testFlag(CDockWidget::DockWidgetFloatable))
|
||||||
|
{
|
||||||
|
d->GlobalDragStartMousePosition = event->globalPos();
|
||||||
|
d->startFloating(DraggingInactive);
|
||||||
|
}
|
||||||
|
|
||||||
|
Super::mouseDoubleClickEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidgetTab::setVisible(bool visible)
|
||||||
|
{
|
||||||
|
// Just here for debugging to insert debug output
|
||||||
|
Super::setVisible(visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidgetTab::setText(const QString& title)
|
||||||
|
{
|
||||||
|
d->TitleLabel->setText(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
bool CDockWidgetTab::isClosable() const
|
||||||
|
{
|
||||||
|
return d->DockWidget && d->DockWidget->features().testFlag(CDockWidget::DockWidgetClosable);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void CDockWidgetTab::detachDockWidget()
|
||||||
|
{
|
||||||
|
if (!d->DockWidget->features().testFlag(CDockWidget::DockWidgetFloatable))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
d->GlobalDragStartMousePosition = QCursor::pos();
|
||||||
|
d->startFloating(DraggingInactive);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
bool CDockWidgetTab::event(QEvent *e)
|
||||||
|
{
|
||||||
|
#ifndef QT_NO_TOOLTIP
|
||||||
|
if (e->type() == QEvent::ToolTipChange)
|
||||||
|
{
|
||||||
|
const auto text = toolTip();
|
||||||
|
d->TitleLabel->setToolTip(text);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return Super::event(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidgetTab::onDockWidgetFeaturesChanged()
|
||||||
|
{
|
||||||
|
auto Features = d->DockWidget->features();
|
||||||
|
auto SizePolicy = d->CloseButton->sizePolicy();
|
||||||
|
SizePolicy.setRetainSizeWhenHidden(Features.testFlag(CDockWidget::DockWidgetClosable)
|
||||||
|
&& d->testConfigFlag(CDockManager::RetainTabSizeWhenCloseButtonHidden));
|
||||||
|
d->CloseButton->setSizePolicy(SizePolicy);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace ads
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// EOF DockWidgetTab.cpp
|
159
src/ui/AdvDock/DockWidgetTab.h
Normal file
159
src/ui/AdvDock/DockWidgetTab.h
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
#ifndef DockWidgetTabH
|
||||||
|
#define DockWidgetTabH
|
||||||
|
/*******************************************************************************
|
||||||
|
** Qt Advanced Docking System
|
||||||
|
** Copyright (C) 2017 Uwe Kindler
|
||||||
|
**
|
||||||
|
** This library is free software; you can redistribute it and/or
|
||||||
|
** modify it under the terms of the GNU Lesser General Public
|
||||||
|
** License as published by the Free Software Foundation; either
|
||||||
|
** version 2.1 of the License, or (at your option) any later version.
|
||||||
|
**
|
||||||
|
** This library is distributed in the hope that it will be useful,
|
||||||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
** Lesser General Public License for more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU Lesser General Public
|
||||||
|
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
/// \file DockWidgetTab.h
|
||||||
|
/// \author Uwe Kindler
|
||||||
|
/// \date 27.02.2017
|
||||||
|
/// \brief Declaration of CDockWidgetTab class
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// INCLUDES
|
||||||
|
//============================================================================
|
||||||
|
#include <QFrame>
|
||||||
|
|
||||||
|
#include "ads_globals.h"
|
||||||
|
|
||||||
|
namespace ads
|
||||||
|
{
|
||||||
|
class CDockWidget;
|
||||||
|
class CDockAreaWidget;
|
||||||
|
struct DockWidgetTabPrivate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A dock widget tab that shows a title and an icon.
|
||||||
|
* The dock widget tab is shown in the dock area title bar to switch between
|
||||||
|
* tabbed dock widgets
|
||||||
|
*/
|
||||||
|
class CDockWidgetTab : public QFrame
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(bool activeTab READ isActiveTab WRITE setActiveTab NOTIFY activeTabChanged)
|
||||||
|
|
||||||
|
private:
|
||||||
|
DockWidgetTabPrivate* d; ///< private data (pimpl)
|
||||||
|
friend struct DockWidgetTabPrivate;
|
||||||
|
friend class CDockWidget;
|
||||||
|
void onDockWidgetFeaturesChanged();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void detachDockWidget();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void mousePressEvent(QMouseEvent* ev) override;
|
||||||
|
virtual void mouseReleaseEvent(QMouseEvent* ev) override;
|
||||||
|
virtual void mouseMoveEvent(QMouseEvent* ev) override;
|
||||||
|
virtual void contextMenuEvent(QContextMenuEvent* ev) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Double clicking the tab widget makes the assigned dock widget floating
|
||||||
|
*/
|
||||||
|
virtual void mouseDoubleClickEvent(QMouseEvent *event) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using Super = QFrame;
|
||||||
|
/**
|
||||||
|
* Default Constructor
|
||||||
|
* param[in] DockWidget The dock widget this title bar belongs to
|
||||||
|
* param[in] parent The parent widget of this title bar
|
||||||
|
*/
|
||||||
|
CDockWidgetTab(CDockWidget* DockWidget, QWidget* parent = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Virtual Destructor
|
||||||
|
*/
|
||||||
|
virtual ~CDockWidgetTab();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true, if this is the active tab
|
||||||
|
*/
|
||||||
|
bool isActiveTab() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set this true to make this tab the active tab
|
||||||
|
*/
|
||||||
|
void setActiveTab(bool active);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the dock widget this title widget belongs to
|
||||||
|
*/
|
||||||
|
CDockWidget* dockWidget() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the dock area widget the dockWidget returned by dockWidget()
|
||||||
|
* function belongs to.
|
||||||
|
*/
|
||||||
|
void setDockAreaWidget(CDockAreaWidget* DockArea);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the dock area widget this title bar belongs to.
|
||||||
|
* \return This function returns 0 if the dock widget that owns this title
|
||||||
|
* bar widget has not been added to any dock area yet.
|
||||||
|
*/
|
||||||
|
CDockAreaWidget* dockAreaWidget() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the icon to show in title bar
|
||||||
|
*/
|
||||||
|
void setIcon(const QIcon& Icon);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the icon
|
||||||
|
*/
|
||||||
|
const QIcon& icon() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the tab text
|
||||||
|
*/
|
||||||
|
QString text() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the tab text
|
||||||
|
*/
|
||||||
|
void setText(const QString& title);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function returns true if the assigned dock widget is closable
|
||||||
|
*/
|
||||||
|
bool isClosable() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Track event ToolTipChange and set child ToolTip
|
||||||
|
*/
|
||||||
|
virtual bool event(QEvent *e) override;
|
||||||
|
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
virtual void setVisible(bool visible) override;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void activeTabChanged();
|
||||||
|
void clicked();
|
||||||
|
void closeRequested();
|
||||||
|
void closeOtherTabsRequested();
|
||||||
|
void moved(const QPoint& GlobalPos);
|
||||||
|
}; // class DockWidgetTab
|
||||||
|
}
|
||||||
|
// namespace ads
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
#endif // DockWidgetTabH
|
30
src/ui/AdvDock/DockingStateReader.cpp
Normal file
30
src/ui/AdvDock/DockingStateReader.cpp
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
//============================================================================
|
||||||
|
/// \file DockingStateReader.cpp
|
||||||
|
/// \author Uwe Kindler
|
||||||
|
/// \date 29.11.2019
|
||||||
|
/// \brief Implementation of CDockingStateReader
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// INCLUDES
|
||||||
|
//============================================================================
|
||||||
|
#include "DockingStateReader.h"
|
||||||
|
|
||||||
|
namespace ads
|
||||||
|
{
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockingStateReader::setFileVersion(int FileVersion)
|
||||||
|
{
|
||||||
|
m_FileVersion = FileVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
int CDockingStateReader::fileVersion() const
|
||||||
|
{
|
||||||
|
return m_FileVersion;
|
||||||
|
}
|
||||||
|
} // namespace ads
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// EOF DockingStateReader.cpp
|
43
src/ui/AdvDock/DockingStateReader.h
Normal file
43
src/ui/AdvDock/DockingStateReader.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#ifndef DockingStateReaderH
|
||||||
|
#define DockingStateReaderH
|
||||||
|
//============================================================================
|
||||||
|
/// \file DockingStateReader.h
|
||||||
|
/// \author Uwe Kindler
|
||||||
|
/// \date 29.11.2019
|
||||||
|
/// \brief Declaration of CDockingStateReader
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// INCLUDES
|
||||||
|
//============================================================================
|
||||||
|
#include <QXmlStreamReader>
|
||||||
|
|
||||||
|
namespace ads
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extends QXmlStreamReader with file version information
|
||||||
|
*/
|
||||||
|
class CDockingStateReader : public QXmlStreamReader
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
int m_FileVersion;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using QXmlStreamReader::QXmlStreamReader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the file version for this state reader
|
||||||
|
*/
|
||||||
|
void setFileVersion(int FileVersion);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the file version set via setFileVersion
|
||||||
|
*/
|
||||||
|
int fileVersion() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ads
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
#endif // DockingStateReaderH
|
220
src/ui/AdvDock/ElidingLabel.cpp
Normal file
220
src/ui/AdvDock/ElidingLabel.cpp
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
** Qt Advanced Docking System
|
||||||
|
** Copyright (C) 2017 Uwe Kindler
|
||||||
|
**
|
||||||
|
** This library is free software; you can redistribute it and/or
|
||||||
|
** modify it under the terms of the GNU Lesser General Public
|
||||||
|
** License as published by the Free Software Foundation; either
|
||||||
|
** version 2.1 of the License, or (at your option) any later version.
|
||||||
|
**
|
||||||
|
** This library is distributed in the hope that it will be useful,
|
||||||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
** Lesser General Public License for more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU Lesser General Public
|
||||||
|
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
/// \file ElidingLabel.cpp
|
||||||
|
/// \author Uwe Kindler
|
||||||
|
/// \date 05.11.2018
|
||||||
|
/// \brief Implementation of CElidingLabel
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// INCLUDES
|
||||||
|
//============================================================================
|
||||||
|
#include "ElidingLabel.h"
|
||||||
|
#include <QMouseEvent>
|
||||||
|
|
||||||
|
|
||||||
|
namespace ads
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Private data of public CClickableLabel
|
||||||
|
*/
|
||||||
|
struct ElidingLabelPrivate
|
||||||
|
{
|
||||||
|
CElidingLabel* _this;
|
||||||
|
Qt::TextElideMode ElideMode = Qt::ElideNone;
|
||||||
|
QString Text;
|
||||||
|
|
||||||
|
ElidingLabelPrivate(CElidingLabel* _public) : _this(_public) {}
|
||||||
|
|
||||||
|
void elideText(int Width);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience function to check if the
|
||||||
|
*/
|
||||||
|
bool isModeElideNone() const
|
||||||
|
{
|
||||||
|
return Qt::ElideNone == ElideMode;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void ElidingLabelPrivate::elideText(int Width)
|
||||||
|
{
|
||||||
|
if (isModeElideNone())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QFontMetrics fm = _this->fontMetrics();
|
||||||
|
QString str = fm.elidedText(Text, ElideMode, Width - _this->margin() * 2 - _this->indent());
|
||||||
|
if (str == "...")
|
||||||
|
{
|
||||||
|
str = Text.at(0);
|
||||||
|
}
|
||||||
|
_this->QLabel::setText(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CElidingLabel::CElidingLabel(QWidget* parent, Qt::WindowFlags f)
|
||||||
|
: QLabel(parent, f),
|
||||||
|
d(new ElidingLabelPrivate(this))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CElidingLabel::CElidingLabel(const QString& text, QWidget* parent, Qt::WindowFlags f)
|
||||||
|
: QLabel(text, parent,f),
|
||||||
|
d(new ElidingLabelPrivate(this))
|
||||||
|
{
|
||||||
|
d->Text = text;
|
||||||
|
#ifndef QT_NO_TOOLTIP
|
||||||
|
setToolTip(text);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CElidingLabel::~CElidingLabel()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
Qt::TextElideMode CElidingLabel::elideMode() const
|
||||||
|
{
|
||||||
|
return d->ElideMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CElidingLabel::setElideMode(Qt::TextElideMode mode)
|
||||||
|
{
|
||||||
|
d->ElideMode = mode;
|
||||||
|
d->elideText(size().width());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CElidingLabel::mouseReleaseEvent(QMouseEvent* event)
|
||||||
|
{
|
||||||
|
Super::mouseReleaseEvent(event);
|
||||||
|
if (event->button() != Qt::LeftButton)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit clicked();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CElidingLabel::mouseDoubleClickEvent( QMouseEvent *ev )
|
||||||
|
{
|
||||||
|
Q_UNUSED(ev)
|
||||||
|
emit doubleClicked();
|
||||||
|
Super::mouseDoubleClickEvent(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CElidingLabel::resizeEvent(QResizeEvent *event)
|
||||||
|
{
|
||||||
|
if (!d->isModeElideNone())
|
||||||
|
{
|
||||||
|
d->elideText(event->size().width());
|
||||||
|
}
|
||||||
|
Super::resizeEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QSize CElidingLabel::minimumSizeHint() const
|
||||||
|
{
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
|
if (!pixmap().isNull() || d->isModeElideNone())
|
||||||
|
#else
|
||||||
|
if (pixmap() || d->isModeElideNone())
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
return QLabel::minimumSizeHint();
|
||||||
|
}
|
||||||
|
const QFontMetrics &fm = fontMetrics();
|
||||||
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0))
|
||||||
|
QSize size(fm.horizontalAdvance(d->Text.left(2) + "..."), fm.height());
|
||||||
|
#else
|
||||||
|
QSize size(fm.width(d->Text.left(2) + "…"), fm.height());
|
||||||
|
#endif
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QSize CElidingLabel::sizeHint() const
|
||||||
|
{
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
|
if (!pixmap().isNull() || d->isModeElideNone())
|
||||||
|
#else
|
||||||
|
if (pixmap() || d->isModeElideNone())
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
return QLabel::sizeHint();
|
||||||
|
}
|
||||||
|
const QFontMetrics& fm = fontMetrics();
|
||||||
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0))
|
||||||
|
QSize size(fm.horizontalAdvance(d->Text), QLabel::sizeHint().height());
|
||||||
|
#else
|
||||||
|
QSize size(fm.width(d->Text), QLabel::sizeHint().height());
|
||||||
|
#endif
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CElidingLabel::setText(const QString &text)
|
||||||
|
{
|
||||||
|
if (d->isModeElideNone())
|
||||||
|
{
|
||||||
|
Super::setText(text);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
d->Text = text;
|
||||||
|
#ifndef QT_NO_TOOLTIP
|
||||||
|
setToolTip( text );
|
||||||
|
#endif
|
||||||
|
d->elideText(this->size().width());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QString CElidingLabel::text() const
|
||||||
|
{
|
||||||
|
return d->Text;
|
||||||
|
}
|
||||||
|
} // namespace QtLabb
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// EOF ClickableLabel.cpp
|
99
src/ui/AdvDock/ElidingLabel.h
Normal file
99
src/ui/AdvDock/ElidingLabel.h
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
#ifndef ElidingLabelH
|
||||||
|
#define ElidingLabelH
|
||||||
|
/*******************************************************************************
|
||||||
|
** Qt Advanced Docking System
|
||||||
|
** Copyright (C) 2017 Uwe Kindler
|
||||||
|
**
|
||||||
|
** This library is free software; you can redistribute it and/or
|
||||||
|
** modify it under the terms of the GNU Lesser General Public
|
||||||
|
** License as published by the Free Software Foundation; either
|
||||||
|
** version 2.1 of the License, or (at your option) any later version.
|
||||||
|
**
|
||||||
|
** This library is distributed in the hope that it will be useful,
|
||||||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
** Lesser General Public License for more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU Lesser General Public
|
||||||
|
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
/// \file ElidingLabel.h
|
||||||
|
/// \author Uwe Kindler
|
||||||
|
/// \date 05.11.2018
|
||||||
|
/// \brief Declaration of CElidingLabel
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// INCLUDES
|
||||||
|
//============================================================================
|
||||||
|
#include <QLabel>
|
||||||
|
|
||||||
|
#include "ads_globals.h"
|
||||||
|
|
||||||
|
namespace ads
|
||||||
|
{
|
||||||
|
struct ElidingLabelPrivate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A QLabel that supports eliding text.
|
||||||
|
* Because the functions setText() and text() are no virtual functions setting
|
||||||
|
* and reading the text via a pointer to the base class QLabel does not work
|
||||||
|
* properly
|
||||||
|
*/
|
||||||
|
class CElidingLabel : public QLabel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
ElidingLabelPrivate* d;
|
||||||
|
friend struct ElidingLabelPrivate;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void mouseReleaseEvent(QMouseEvent* event) override;
|
||||||
|
virtual void resizeEvent( QResizeEvent *event ) override;
|
||||||
|
virtual void mouseDoubleClickEvent( QMouseEvent *ev ) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using Super = QLabel;
|
||||||
|
|
||||||
|
CElidingLabel(QWidget* parent = 0, Qt::WindowFlags f = Qt::Widget);
|
||||||
|
CElidingLabel(const QString& text, QWidget* parent = 0, Qt::WindowFlags f = Qt::Widget);
|
||||||
|
virtual ~CElidingLabel();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the text elide mode.
|
||||||
|
* The default mode is ElideNone
|
||||||
|
*/
|
||||||
|
Qt::TextElideMode elideMode() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the text elide mode
|
||||||
|
*/
|
||||||
|
void setElideMode(Qt::TextElideMode mode);
|
||||||
|
|
||||||
|
|
||||||
|
public: // reimplements QLabel ----------------------------------------------
|
||||||
|
virtual QSize minimumSizeHint() const override;
|
||||||
|
virtual QSize sizeHint() const override;
|
||||||
|
void setText(const QString &text);
|
||||||
|
QString text() const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
/**
|
||||||
|
* This signal is emitted if the user clicks on the label (i.e. pressed
|
||||||
|
* down then released while the mouse cursor is inside the label)
|
||||||
|
*/
|
||||||
|
void clicked();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted if the user does a double click on the label
|
||||||
|
*/
|
||||||
|
void doubleClicked();
|
||||||
|
}; //class CElidingLabel
|
||||||
|
|
||||||
|
} // namespace QtLabb
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
#endif // ElidingLabelH
|
629
src/ui/AdvDock/FloatingDockContainer.cpp
Normal file
629
src/ui/AdvDock/FloatingDockContainer.cpp
Normal file
@ -0,0 +1,629 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
** Qt Advanced Docking System
|
||||||
|
** Copyright (C) 2017 Uwe Kindler
|
||||||
|
**
|
||||||
|
** This library is free software; you can redistribute it and/or
|
||||||
|
** modify it under the terms of the GNU Lesser General Public
|
||||||
|
** License as published by the Free Software Foundation; either
|
||||||
|
** version 2.1 of the License, or (at your option) any later version.
|
||||||
|
**
|
||||||
|
** This library is distributed in the hope that it will be useful,
|
||||||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
** Lesser General Public License for more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU Lesser General Public
|
||||||
|
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
/// \file FloatingDockContainer.cpp
|
||||||
|
/// \author Uwe Kindler
|
||||||
|
/// \date 01.03.2017
|
||||||
|
/// \brief Implementation of CFloatingDockContainer class
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// INCLUDES
|
||||||
|
//============================================================================
|
||||||
|
#include "FloatingDockContainer.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <QBoxLayout>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QPointer>
|
||||||
|
#include <QAction>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QAbstractButton>
|
||||||
|
#include <QElapsedTimer>
|
||||||
|
|
||||||
|
#include "DockContainerWidget.h"
|
||||||
|
#include "DockAreaWidget.h"
|
||||||
|
#include "DockManager.h"
|
||||||
|
#include "DockWidget.h"
|
||||||
|
#include "DockOverlay.h"
|
||||||
|
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
#include "linux/FloatingWidgetTitleBar.h"
|
||||||
|
#include <xcb/xcb.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace ads
|
||||||
|
{
|
||||||
|
static unsigned int zOrderCounter = 0;
|
||||||
|
/**
|
||||||
|
* Private data class of CFloatingDockContainer class (pimpl)
|
||||||
|
*/
|
||||||
|
struct FloatingDockContainerPrivate
|
||||||
|
{
|
||||||
|
CFloatingDockContainer *_this;
|
||||||
|
CDockContainerWidget *DockContainer;
|
||||||
|
unsigned int zOrderIndex = ++zOrderCounter;
|
||||||
|
QPointer<CDockManager> DockManager;
|
||||||
|
eDragState DraggingState = DraggingInactive;
|
||||||
|
QPoint DragStartMousePosition;
|
||||||
|
CDockContainerWidget *DropContainer = nullptr;
|
||||||
|
CDockAreaWidget *SingleDockArea = nullptr;
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
QWidget* MouseEventHandler = nullptr;
|
||||||
|
CFloatingWidgetTitleBar* TitleBar = nullptr;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private data constructor
|
||||||
|
*/
|
||||||
|
FloatingDockContainerPrivate(CFloatingDockContainer *_public);
|
||||||
|
|
||||||
|
void titleMouseReleaseEvent();
|
||||||
|
void updateDropOverlays(const QPoint &GlobalPos);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests is a certain state is active
|
||||||
|
*/
|
||||||
|
bool isState(eDragState StateId) const
|
||||||
|
{
|
||||||
|
return StateId == DraggingState;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setState(eDragState StateId)
|
||||||
|
{
|
||||||
|
DraggingState = StateId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setWindowTitle(const QString &Text)
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
TitleBar->setTitle(Text);
|
||||||
|
#else
|
||||||
|
_this->setWindowTitle(Text);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// struct FloatingDockContainerPrivate
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
FloatingDockContainerPrivate::FloatingDockContainerPrivate(
|
||||||
|
CFloatingDockContainer *_public) :
|
||||||
|
_this(_public)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void FloatingDockContainerPrivate::titleMouseReleaseEvent()
|
||||||
|
{
|
||||||
|
setState(DraggingInactive);
|
||||||
|
if (!DropContainer)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DockManager->dockAreaOverlay()->dropAreaUnderCursor()
|
||||||
|
!= InvalidDockWidgetArea
|
||||||
|
|| DockManager->containerOverlay()->dropAreaUnderCursor()
|
||||||
|
!= InvalidDockWidgetArea)
|
||||||
|
{
|
||||||
|
// Resize the floating widget to the size of the highlighted drop area
|
||||||
|
// rectangle
|
||||||
|
CDockOverlay *Overlay = DockManager->containerOverlay();
|
||||||
|
if (!Overlay->dropOverlayRect().isValid())
|
||||||
|
{
|
||||||
|
Overlay = DockManager->dockAreaOverlay();
|
||||||
|
}
|
||||||
|
|
||||||
|
QRect Rect = Overlay->dropOverlayRect();
|
||||||
|
int FrameWidth = (_this->frameSize().width() - _this->rect().width())
|
||||||
|
/ 2;
|
||||||
|
int TitleBarHeight = _this->frameSize().height()
|
||||||
|
- _this->rect().height() - FrameWidth;
|
||||||
|
if (Rect.isValid())
|
||||||
|
{
|
||||||
|
QPoint TopLeft = Overlay->mapToGlobal(Rect.topLeft());
|
||||||
|
TopLeft.ry() += TitleBarHeight;
|
||||||
|
_this->setGeometry(
|
||||||
|
QRect(TopLeft,
|
||||||
|
QSize(Rect.width(), Rect.height() - TitleBarHeight)));
|
||||||
|
QApplication::processEvents();
|
||||||
|
}
|
||||||
|
DropContainer->dropFloatingWidget(_this, QCursor::pos());
|
||||||
|
}
|
||||||
|
|
||||||
|
DockManager->containerOverlay()->hideOverlay();
|
||||||
|
DockManager->dockAreaOverlay()->hideOverlay();
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void FloatingDockContainerPrivate::updateDropOverlays(const QPoint &GlobalPos)
|
||||||
|
{
|
||||||
|
if (!_this->isVisible() || !DockManager)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Containers = DockManager->dockContainers();
|
||||||
|
CDockContainerWidget *TopContainer = nullptr;
|
||||||
|
for (auto ContainerWidget : Containers)
|
||||||
|
{
|
||||||
|
if (!ContainerWidget->isVisible())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DockContainer == ContainerWidget)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPoint MappedPos = ContainerWidget->mapFromGlobal(GlobalPos);
|
||||||
|
if (ContainerWidget->rect().contains(MappedPos))
|
||||||
|
{
|
||||||
|
if (!TopContainer || ContainerWidget->isInFrontOf(TopContainer))
|
||||||
|
{
|
||||||
|
TopContainer = ContainerWidget;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DropContainer = TopContainer;
|
||||||
|
auto ContainerOverlay = DockManager->containerOverlay();
|
||||||
|
auto DockAreaOverlay = DockManager->dockAreaOverlay();
|
||||||
|
|
||||||
|
if (!TopContainer)
|
||||||
|
{
|
||||||
|
ContainerOverlay->hideOverlay();
|
||||||
|
DockAreaOverlay->hideOverlay();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int VisibleDockAreas = TopContainer->visibleDockAreaCount();
|
||||||
|
ContainerOverlay->setAllowedAreas(
|
||||||
|
VisibleDockAreas > 1 ? OuterDockAreas : AllDockAreas);
|
||||||
|
DockWidgetArea ContainerArea = ContainerOverlay->showOverlay(TopContainer);
|
||||||
|
ContainerOverlay->enableDropPreview(ContainerArea != InvalidDockWidgetArea);
|
||||||
|
auto DockArea = TopContainer->dockAreaAt(GlobalPos);
|
||||||
|
if (DockArea && DockArea->isVisible() && VisibleDockAreas > 0)
|
||||||
|
{
|
||||||
|
DockAreaOverlay->enableDropPreview(true);
|
||||||
|
DockAreaOverlay->setAllowedAreas(
|
||||||
|
(VisibleDockAreas == 1) ? NoDockWidgetArea : AllDockAreas);
|
||||||
|
DockWidgetArea Area = DockAreaOverlay->showOverlay(DockArea);
|
||||||
|
|
||||||
|
// A CenterDockWidgetArea for the dockAreaOverlay() indicates that
|
||||||
|
// the mouse is in the title bar. If the ContainerArea is valid
|
||||||
|
// then we ignore the dock area of the dockAreaOverlay() and disable
|
||||||
|
// the drop preview
|
||||||
|
if ((Area == CenterDockWidgetArea)
|
||||||
|
&& (ContainerArea != InvalidDockWidgetArea))
|
||||||
|
{
|
||||||
|
DockAreaOverlay->enableDropPreview(false);
|
||||||
|
ContainerOverlay->enableDropPreview(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ContainerOverlay->enableDropPreview(InvalidDockWidgetArea == Area);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DockAreaOverlay->hideOverlay();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CFloatingDockContainer::CFloatingDockContainer(CDockManager *DockManager) :
|
||||||
|
tFloatingWidgetBase(DockManager),
|
||||||
|
d(new FloatingDockContainerPrivate(this))
|
||||||
|
{
|
||||||
|
d->DockManager = DockManager;
|
||||||
|
d->DockContainer = new CDockContainerWidget(DockManager, this);
|
||||||
|
connect(d->DockContainer, SIGNAL(dockAreasAdded()), this,
|
||||||
|
SLOT(onDockAreasAddedOrRemoved()));
|
||||||
|
connect(d->DockContainer, SIGNAL(dockAreasRemoved()), this,
|
||||||
|
SLOT(onDockAreasAddedOrRemoved()));
|
||||||
|
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
d->TitleBar = new CFloatingWidgetTitleBar(this);
|
||||||
|
setWindowFlags(windowFlags() | Qt::Tool);
|
||||||
|
QDockWidget::setWidget(d->DockContainer);
|
||||||
|
QDockWidget::setFloating(true);
|
||||||
|
QDockWidget::setFeatures(QDockWidget::AllDockWidgetFeatures);
|
||||||
|
setTitleBarWidget(d->TitleBar);
|
||||||
|
connect(d->TitleBar, SIGNAL(closeRequested()), SLOT(close()));
|
||||||
|
#else
|
||||||
|
setWindowFlags(
|
||||||
|
Qt::Window | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint);
|
||||||
|
QBoxLayout *l = new QBoxLayout(QBoxLayout::TopToBottom);
|
||||||
|
l->setContentsMargins(0, 0, 0, 0);
|
||||||
|
l->setSpacing(0);
|
||||||
|
setLayout(l);
|
||||||
|
l->addWidget(d->DockContainer);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DockManager->registerFloatingWidget(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CFloatingDockContainer::CFloatingDockContainer(CDockAreaWidget *DockArea) :
|
||||||
|
CFloatingDockContainer(DockArea->dockManager())
|
||||||
|
{
|
||||||
|
d->DockContainer->addDockArea(DockArea);
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
d->TitleBar->enableCloseButton(isClosable());
|
||||||
|
#endif
|
||||||
|
auto TopLevelDockWidget = topLevelDockWidget();
|
||||||
|
if (TopLevelDockWidget)
|
||||||
|
{
|
||||||
|
TopLevelDockWidget->emitTopLevelChanged(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CFloatingDockContainer::CFloatingDockContainer(CDockWidget *DockWidget) :
|
||||||
|
CFloatingDockContainer(DockWidget->dockManager())
|
||||||
|
{
|
||||||
|
d->DockContainer->addDockWidget(CenterDockWidgetArea, DockWidget);
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
d->TitleBar->enableCloseButton(isClosable());
|
||||||
|
#endif
|
||||||
|
auto TopLevelDockWidget = topLevelDockWidget();
|
||||||
|
if (TopLevelDockWidget)
|
||||||
|
{
|
||||||
|
TopLevelDockWidget->emitTopLevelChanged(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CFloatingDockContainer::~CFloatingDockContainer()
|
||||||
|
{
|
||||||
|
ADS_PRINT("~CFloatingDockContainer");
|
||||||
|
if (d->DockManager)
|
||||||
|
{
|
||||||
|
d->DockManager->removeFloatingWidget(this);
|
||||||
|
}
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockContainerWidget* CFloatingDockContainer::dockContainer() const
|
||||||
|
{
|
||||||
|
return d->DockContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CFloatingDockContainer::changeEvent(QEvent *event)
|
||||||
|
{
|
||||||
|
QWidget::changeEvent(event);
|
||||||
|
if ((event->type() == QEvent::ActivationChange) && isActiveWindow())
|
||||||
|
{
|
||||||
|
ADS_PRINT("FloatingWidget::changeEvent QEvent::ActivationChange ");
|
||||||
|
d->zOrderIndex = ++zOrderCounter;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CFloatingDockContainer::moveEvent(QMoveEvent *event)
|
||||||
|
{
|
||||||
|
QWidget::moveEvent(event);
|
||||||
|
switch (d->DraggingState)
|
||||||
|
{
|
||||||
|
case DraggingMousePressed:
|
||||||
|
d->setState(DraggingFloatingWidget);
|
||||||
|
d->updateDropOverlays(QCursor::pos());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DraggingFloatingWidget:
|
||||||
|
d->updateDropOverlays(QCursor::pos());
|
||||||
|
#ifdef Q_OS_MACOS
|
||||||
|
// In OSX when hiding the DockAreaOverlay the application would set
|
||||||
|
// the main window as the active window for some reason. This fixes
|
||||||
|
// that by resetting the active window to the floating widget after
|
||||||
|
// updating the overlays.
|
||||||
|
QApplication::setActiveWindow(this);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CFloatingDockContainer::closeEvent(QCloseEvent *event)
|
||||||
|
{
|
||||||
|
ADS_PRINT("CFloatingDockContainer closeEvent");
|
||||||
|
d->setState(DraggingInactive);
|
||||||
|
event->ignore();
|
||||||
|
|
||||||
|
if (isClosable())
|
||||||
|
{
|
||||||
|
auto TopLevelDockWidget = topLevelDockWidget();
|
||||||
|
if (TopLevelDockWidget && TopLevelDockWidget->features().testFlag(CDockWidget::DockWidgetDeleteOnClose))
|
||||||
|
{
|
||||||
|
if (!TopLevelDockWidget->closeDockWidgetInternal())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// In Qt version after 5.9.2 there seems to be a bug that causes the
|
||||||
|
// QWidget::event() function to not receive any NonClientArea mouse
|
||||||
|
// events anymore after a close/show cycle. The bug is reported here:
|
||||||
|
// https://bugreports.qt.io/browse/QTBUG-73295
|
||||||
|
// The following code is a workaround for Qt versions > 5.9.2 that seems
|
||||||
|
// to work
|
||||||
|
// Starting from Qt version 5.12.2 this seems to work again. But
|
||||||
|
// now the QEvent::NonClientAreaMouseButtonPress function returns always
|
||||||
|
// Qt::RightButton even if the left button was pressed
|
||||||
|
this->hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CFloatingDockContainer::hideEvent(QHideEvent *event)
|
||||||
|
{
|
||||||
|
Super::hideEvent(event);
|
||||||
|
if (event->spontaneous())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevent toogleView() events during restore state
|
||||||
|
if (d->DockManager->isRestoringState())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto DockArea : d->DockContainer->openedDockAreas())
|
||||||
|
{
|
||||||
|
for (auto DockWidget : DockArea->openedDockWidgets())
|
||||||
|
{
|
||||||
|
DockWidget->toggleView(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CFloatingDockContainer::showEvent(QShowEvent *event)
|
||||||
|
{
|
||||||
|
Super::showEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
bool CFloatingDockContainer::event(QEvent *e)
|
||||||
|
{
|
||||||
|
switch (d->DraggingState)
|
||||||
|
{
|
||||||
|
case DraggingInactive:
|
||||||
|
{
|
||||||
|
// Normally we would check here, if the left mouse button is pressed.
|
||||||
|
// But from QT version 5.12.2 on the mouse events from
|
||||||
|
// QEvent::NonClientAreaMouseButtonPress return the wrong mouse button
|
||||||
|
// The event always returns Qt::RightButton even if the left button
|
||||||
|
// is clicked.
|
||||||
|
// It is really great to work around the whole NonClientMouseArea
|
||||||
|
// bugs
|
||||||
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 2))
|
||||||
|
if (e->type()
|
||||||
|
== QEvent::NonClientAreaMouseButtonPress /*&& QGuiApplication::mouseButtons().testFlag(Qt::LeftButton)*/)
|
||||||
|
{
|
||||||
|
ADS_PRINT("FloatingWidget::event Event::NonClientAreaMouseButtonPress" << e->type());
|
||||||
|
d->setState(DraggingMousePressed);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (e->type() == QEvent::NonClientAreaMouseButtonPress && QGuiApplication::mouseButtons().testFlag(Qt::LeftButton))
|
||||||
|
{
|
||||||
|
ADS_PRINT("FloatingWidget::event Event::NonClientAreaMouseButtonPress" << e->type());
|
||||||
|
d->setState(DraggingMousePressed);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DraggingMousePressed:
|
||||||
|
switch (e->type())
|
||||||
|
{
|
||||||
|
case QEvent::NonClientAreaMouseButtonDblClick:
|
||||||
|
ADS_PRINT("FloatingWidget::event QEvent::NonClientAreaMouseButtonDblClick");
|
||||||
|
d->setState(DraggingInactive);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QEvent::Resize:
|
||||||
|
// If the first event after the mouse press is a resize event, then
|
||||||
|
// the user resizes the window instead of dragging it around.
|
||||||
|
// But there is one exception. If the window is maximized,
|
||||||
|
// then dragging the window via title bar will cause the widget to
|
||||||
|
// leave the maximized state. This in turn will trigger a resize event.
|
||||||
|
// To know, if the resize event was triggered by user via moving a
|
||||||
|
// corner of the window frame or if it was caused by a windows state
|
||||||
|
// change, we check, if we are not in maximized state.
|
||||||
|
if (!isMaximized())
|
||||||
|
{
|
||||||
|
d->setState(DraggingInactive);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DraggingFloatingWidget:
|
||||||
|
if (e->type() == QEvent::NonClientAreaMouseButtonRelease)
|
||||||
|
{
|
||||||
|
ADS_PRINT("FloatingWidget::event QEvent::NonClientAreaMouseButtonRelease");
|
||||||
|
d->titleMouseReleaseEvent();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (ADS_DEBUG_LEVEL > 0)
|
||||||
|
qDebug() << "CFloatingDockContainer::event " << e->type();
|
||||||
|
#endif
|
||||||
|
return QWidget::event(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CFloatingDockContainer::startFloating(const QPoint &DragStartMousePos,
|
||||||
|
const QSize &Size, eDragState DragState, QWidget *MouseEventHandler)
|
||||||
|
{
|
||||||
|
#ifndef Q_OS_LINUX
|
||||||
|
Q_UNUSED(MouseEventHandler)
|
||||||
|
#endif
|
||||||
|
resize(Size);
|
||||||
|
d->setState(DragState);
|
||||||
|
d->DragStartMousePosition = DragStartMousePos;
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
if (DraggingFloatingWidget == DragState)
|
||||||
|
{
|
||||||
|
setAttribute(Qt::WA_X11NetWmWindowTypeDock, true);
|
||||||
|
d->MouseEventHandler = MouseEventHandler;
|
||||||
|
if (d->MouseEventHandler)
|
||||||
|
{
|
||||||
|
d->MouseEventHandler->grabMouse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
moveFloating();
|
||||||
|
show();
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CFloatingDockContainer::moveFloating()
|
||||||
|
{
|
||||||
|
int BorderSize = (frameSize().width() - size().width()) / 2;
|
||||||
|
const QPoint moveToPos = QCursor::pos() - d->DragStartMousePosition
|
||||||
|
- QPoint(BorderSize, 0);
|
||||||
|
move(moveToPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
bool CFloatingDockContainer::isClosable() const
|
||||||
|
{
|
||||||
|
return d->DockContainer->features().testFlag(
|
||||||
|
CDockWidget::DockWidgetClosable);
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CFloatingDockContainer::onDockAreasAddedOrRemoved()
|
||||||
|
{
|
||||||
|
ADS_PRINT("CFloatingDockContainer::onDockAreasAddedOrRemoved()");
|
||||||
|
auto TopLevelDockArea = d->DockContainer->topLevelDockArea();
|
||||||
|
if (TopLevelDockArea)
|
||||||
|
{
|
||||||
|
d->SingleDockArea = TopLevelDockArea;
|
||||||
|
d->setWindowTitle(
|
||||||
|
d->SingleDockArea->currentDockWidget()->windowTitle());
|
||||||
|
connect(d->SingleDockArea, SIGNAL(currentChanged(int)), this,
|
||||||
|
SLOT(onDockAreaCurrentChanged(int)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (d->SingleDockArea)
|
||||||
|
{
|
||||||
|
disconnect(d->SingleDockArea, SIGNAL(currentChanged(int)), this,
|
||||||
|
SLOT(onDockAreaCurrentChanged(int)));
|
||||||
|
d->SingleDockArea = nullptr;
|
||||||
|
}
|
||||||
|
d->setWindowTitle(qApp->applicationDisplayName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CFloatingDockContainer::updateWindowTitle()
|
||||||
|
{
|
||||||
|
auto TopLevelDockArea = d->DockContainer->topLevelDockArea();
|
||||||
|
if (TopLevelDockArea)
|
||||||
|
{
|
||||||
|
d->setWindowTitle(TopLevelDockArea->currentDockWidget()->windowTitle());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
d->setWindowTitle(qApp->applicationDisplayName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CFloatingDockContainer::onDockAreaCurrentChanged(int Index)
|
||||||
|
{
|
||||||
|
Q_UNUSED(Index);
|
||||||
|
d->setWindowTitle(d->SingleDockArea->currentDockWidget()->windowTitle());
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
bool CFloatingDockContainer::restoreState(CDockingStateReader &Stream,
|
||||||
|
bool Testing)
|
||||||
|
{
|
||||||
|
if (!d->DockContainer->restoreState(Stream, Testing))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
onDockAreasAddedOrRemoved();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
bool CFloatingDockContainer::hasTopLevelDockWidget() const
|
||||||
|
{
|
||||||
|
return d->DockContainer->hasTopLevelDockWidget();
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockWidget* CFloatingDockContainer::topLevelDockWidget() const
|
||||||
|
{
|
||||||
|
return d->DockContainer->topLevelDockWidget();
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QList<CDockWidget*> CFloatingDockContainer::dockWidgets() const
|
||||||
|
{
|
||||||
|
return d->DockContainer->dockWidgets();
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CFloatingDockContainer::finishDragging()
|
||||||
|
{
|
||||||
|
ADS_PRINT("CFloatingDockContainer::finishDragging");
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
setAttribute(Qt::WA_X11NetWmWindowTypeDock, false);
|
||||||
|
setWindowOpacity(1);
|
||||||
|
activateWindow();
|
||||||
|
if (d->MouseEventHandler)
|
||||||
|
{
|
||||||
|
d->MouseEventHandler->releaseMouse();
|
||||||
|
d->MouseEventHandler = nullptr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
d->titleMouseReleaseEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ads
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// EOF FloatingDockContainer.cpp
|
244
src/ui/AdvDock/FloatingDockContainer.h
Normal file
244
src/ui/AdvDock/FloatingDockContainer.h
Normal file
@ -0,0 +1,244 @@
|
|||||||
|
#ifndef FloatingDockContainerH
|
||||||
|
#define FloatingDockContainerH
|
||||||
|
/*******************************************************************************
|
||||||
|
** Qt Advanced Docking System
|
||||||
|
** Copyright (C) 2017 Uwe Kindler
|
||||||
|
**
|
||||||
|
** This library is free software; you can redistribute it and/or
|
||||||
|
** modify it under the terms of the GNU Lesser General Public
|
||||||
|
** License as published by the Free Software Foundation; either
|
||||||
|
** version 2.1 of the License, or (at your option) any later version.
|
||||||
|
**
|
||||||
|
** This library is distributed in the hope that it will be useful,
|
||||||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
** Lesser General Public License for more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU Lesser General Public
|
||||||
|
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
/// \file FloatingDockContainer.h
|
||||||
|
/// \author Uwe Kindler
|
||||||
|
/// \date 01.03.2017
|
||||||
|
/// \brief Declaration of CFloatingDockContainer class
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// INCLUDES
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
#include <QRubberBand>
|
||||||
|
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
#include <QDockWidget>
|
||||||
|
#define tFloatingWidgetBase QDockWidget
|
||||||
|
#else
|
||||||
|
#include <QWidget>
|
||||||
|
#define tFloatingWidgetBase QWidget
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "ads_globals.h"
|
||||||
|
|
||||||
|
class CDockingStateReader;
|
||||||
|
|
||||||
|
namespace ads
|
||||||
|
{
|
||||||
|
struct FloatingDockContainerPrivate;
|
||||||
|
class CDockManager;
|
||||||
|
struct DockManagerPrivate;
|
||||||
|
class CDockAreaWidget;
|
||||||
|
class CDockContainerWidget;
|
||||||
|
class CDockWidget;
|
||||||
|
class CDockManager;
|
||||||
|
class CDockAreaTabBar;
|
||||||
|
class CDockWidgetTab;
|
||||||
|
struct DockWidgetTabPrivate;
|
||||||
|
class CDockAreaTitleBar;
|
||||||
|
struct DockAreaTitleBarPrivate;
|
||||||
|
class CFloatingWidgetTitleBar;
|
||||||
|
class CDockingStateReader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pure virtual interface for floating widgets.
|
||||||
|
* This interface is used for opaque and non-opaque undocking. If opaque
|
||||||
|
* undocking is used, the a real CFloatingDockContainer widget will be created
|
||||||
|
*/
|
||||||
|
class IFloatingWidget
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Starts floating.
|
||||||
|
* This function should get called typically from a mouse press event
|
||||||
|
* handler
|
||||||
|
*/
|
||||||
|
virtual void startFloating(const QPoint& DragStartMousePos, const QSize& Size,
|
||||||
|
eDragState DragState, QWidget* MouseEventHandler) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves the widget to a new position relative to the position given when
|
||||||
|
* startFloating() was called.
|
||||||
|
* This function should be called from a mouse mouve event handler to
|
||||||
|
* move the floating widget on mouse move events.
|
||||||
|
*/
|
||||||
|
virtual void moveFloating() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells the widget that to finish dragging if the mouse is released.
|
||||||
|
* This function should be called from a mouse release event handler
|
||||||
|
* to finish the dragging
|
||||||
|
*/
|
||||||
|
virtual void finishDragging() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This implements a floating widget that is a dock container that accepts
|
||||||
|
* docking of dock widgets like the main window and that can be docked into
|
||||||
|
* another dock container.
|
||||||
|
* Every floating window of the docking system is a FloatingDockContainer.
|
||||||
|
*/
|
||||||
|
class CFloatingDockContainer : public tFloatingWidgetBase, public IFloatingWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
FloatingDockContainerPrivate* d; ///< private data (pimpl)
|
||||||
|
friend struct FloatingDockContainerPrivate;
|
||||||
|
friend class CDockManager;
|
||||||
|
friend struct DockManagerPrivate;
|
||||||
|
friend class CDockAreaTabBar;
|
||||||
|
friend struct DockWidgetTabPrivate;
|
||||||
|
friend class CDockWidgetTab;
|
||||||
|
friend class CDockAreaTitleBar;
|
||||||
|
friend struct DockAreaTitleBarPrivate;
|
||||||
|
friend class CDockWidget;
|
||||||
|
friend class CDockAreaWidget;
|
||||||
|
friend class CFloatingWidgetTitleBar;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onDockAreasAddedOrRemoved();
|
||||||
|
void onDockAreaCurrentChanged(int Index);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* Starts floating at the given global position.
|
||||||
|
* Use moveToGlobalPos() to move the widget to a new position
|
||||||
|
* depending on the start position given in Pos parameter
|
||||||
|
*/
|
||||||
|
virtual void startFloating(const QPoint& DragStartMousePos, const QSize& Size,
|
||||||
|
eDragState DragState, QWidget* MouseEventHandler) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call this function to start dragging the floating widget
|
||||||
|
*/
|
||||||
|
void startDragging(const QPoint& DragStartMousePos, const QSize& Size,
|
||||||
|
QWidget* MouseEventHandler)
|
||||||
|
{
|
||||||
|
startFloating(DragStartMousePos, Size, DraggingFloatingWidget, MouseEventHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call this function if you explicitly want to signal that dragging has
|
||||||
|
* finished
|
||||||
|
*/
|
||||||
|
virtual void finishDragging() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call this function if you just want to initialize the position
|
||||||
|
* and size of the floating widget
|
||||||
|
*/
|
||||||
|
void initFloatingGeometry(const QPoint& DragStartMousePos, const QSize& Size)
|
||||||
|
{
|
||||||
|
startFloating(DragStartMousePos, Size, DraggingInactive, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves the widget to a new position relative to the position given when
|
||||||
|
* startFloating() was called
|
||||||
|
*/
|
||||||
|
void moveFloating();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restores the state from given stream.
|
||||||
|
* If Testing is true, the function only parses the data from the given
|
||||||
|
* stream but does not restore anything. You can use this check for
|
||||||
|
* faulty files before you start restoring the state
|
||||||
|
*/
|
||||||
|
bool restoreState(CDockingStateReader& Stream, bool Testing);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call this function to update the window title
|
||||||
|
*/
|
||||||
|
void updateWindowTitle();
|
||||||
|
|
||||||
|
|
||||||
|
protected: // reimplements QWidget
|
||||||
|
virtual void changeEvent(QEvent *event) override;
|
||||||
|
virtual void moveEvent(QMoveEvent *event) override;
|
||||||
|
virtual bool event(QEvent *e) override;
|
||||||
|
virtual void closeEvent(QCloseEvent *event) override;
|
||||||
|
virtual void hideEvent(QHideEvent *event) override;
|
||||||
|
virtual void showEvent(QShowEvent *event) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using Super = QWidget;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create empty floating widget - required for restore state
|
||||||
|
*/
|
||||||
|
CFloatingDockContainer(CDockManager* DockManager);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create floating widget with the given dock area
|
||||||
|
*/
|
||||||
|
CFloatingDockContainer(CDockAreaWidget* DockArea);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create floating widget with the given dock widget
|
||||||
|
*/
|
||||||
|
CFloatingDockContainer(CDockWidget* DockWidget);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Virtual Destructor
|
||||||
|
*/
|
||||||
|
virtual ~CFloatingDockContainer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Access function for the internal dock container
|
||||||
|
*/
|
||||||
|
CDockContainerWidget* dockContainer() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function returns true, if it can be closed.
|
||||||
|
* It can be closed, if all dock widgets in all dock areas can be closed
|
||||||
|
*/
|
||||||
|
bool isClosable() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function returns true, if this floating widget has only one single
|
||||||
|
* visible dock widget in a single visible dock area.
|
||||||
|
* The single dock widget is a real top level floating widget because no
|
||||||
|
* other widgets are docked.
|
||||||
|
*/
|
||||||
|
bool hasTopLevelDockWidget() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function returns the first dock widget in the first dock area.
|
||||||
|
* If the function hasSingleDockWidget() returns true, then this function
|
||||||
|
* returns this single dock widget.
|
||||||
|
*/
|
||||||
|
CDockWidget* topLevelDockWidget() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function returns a list of all dock widget in this floating widget.
|
||||||
|
* This is a simple convenience function that simply calls the dockWidgets()
|
||||||
|
* function of the internal container widget.
|
||||||
|
*/
|
||||||
|
QList<CDockWidget*> dockWidgets() const;
|
||||||
|
}; // class FloatingDockContainer
|
||||||
|
}
|
||||||
|
// namespace ads
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
#endif // FloatingDockContainerH
|
405
src/ui/AdvDock/FloatingDragPreview.cpp
Normal file
405
src/ui/AdvDock/FloatingDragPreview.cpp
Normal file
@ -0,0 +1,405 @@
|
|||||||
|
//============================================================================
|
||||||
|
/// \file FloatingDragPreview.cpp
|
||||||
|
/// \author Uwe Kindler
|
||||||
|
/// \date 26.11.2019
|
||||||
|
/// \brief Implementation of CFloatingDragPreview
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// INCLUDES
|
||||||
|
//============================================================================
|
||||||
|
#include "FloatingDragPreview.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <QEvent>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QKeyEvent>
|
||||||
|
|
||||||
|
#include "DockWidget.h"
|
||||||
|
#include "DockAreaWidget.h"
|
||||||
|
#include "DockManager.h"
|
||||||
|
#include "DockContainerWidget.h"
|
||||||
|
#include "DockOverlay.h"
|
||||||
|
|
||||||
|
namespace ads
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private data class (pimpl)
|
||||||
|
*/
|
||||||
|
struct FloatingDragPreviewPrivate
|
||||||
|
{
|
||||||
|
CFloatingDragPreview *_this;
|
||||||
|
QWidget* Content;
|
||||||
|
CDockAreaWidget* ContentSourceArea = nullptr;
|
||||||
|
CDockContainerWidget* ContenSourceContainer = nullptr;
|
||||||
|
QPoint DragStartMousePosition;
|
||||||
|
CDockManager* DockManager;
|
||||||
|
CDockContainerWidget *DropContainer = nullptr;
|
||||||
|
qreal WindowOpacity;
|
||||||
|
bool Hidden = false;
|
||||||
|
QPixmap ContentPreviewPixmap;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private data constructor
|
||||||
|
*/
|
||||||
|
FloatingDragPreviewPrivate(CFloatingDragPreview *_public);
|
||||||
|
void updateDropOverlays(const QPoint &GlobalPos);
|
||||||
|
|
||||||
|
void setHidden(bool Value)
|
||||||
|
{
|
||||||
|
Hidden = Value;
|
||||||
|
_this->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel dragging and emit the draggingCanceled event
|
||||||
|
*/
|
||||||
|
void cancelDragging()
|
||||||
|
{
|
||||||
|
emit _this->draggingCanceled();
|
||||||
|
DockManager->containerOverlay()->hideOverlay();
|
||||||
|
DockManager->dockAreaOverlay()->hideOverlay();
|
||||||
|
_this->close();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// struct LedArrayPanelPrivate
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void FloatingDragPreviewPrivate::updateDropOverlays(const QPoint &GlobalPos)
|
||||||
|
{
|
||||||
|
if (!_this->isVisible() || !DockManager)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Containers = DockManager->dockContainers();
|
||||||
|
CDockContainerWidget *TopContainer = nullptr;
|
||||||
|
for (auto ContainerWidget : Containers)
|
||||||
|
{
|
||||||
|
if (!ContainerWidget->isVisible())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*if (DockContainer == ContainerWidget)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
QPoint MappedPos = ContainerWidget->mapFromGlobal(GlobalPos);
|
||||||
|
if (ContainerWidget->rect().contains(MappedPos))
|
||||||
|
{
|
||||||
|
if (!TopContainer || ContainerWidget->isInFrontOf(TopContainer))
|
||||||
|
{
|
||||||
|
TopContainer = ContainerWidget;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DropContainer = TopContainer;
|
||||||
|
auto ContainerOverlay = DockManager->containerOverlay();
|
||||||
|
auto DockAreaOverlay = DockManager->dockAreaOverlay();
|
||||||
|
auto DockDropArea = DockAreaOverlay->dropAreaUnderCursor();
|
||||||
|
auto ContainerDropArea = ContainerOverlay->dropAreaUnderCursor();
|
||||||
|
|
||||||
|
if (!TopContainer)
|
||||||
|
{
|
||||||
|
ContainerOverlay->hideOverlay();
|
||||||
|
DockAreaOverlay->hideOverlay();
|
||||||
|
if (CDockManager::configFlags().testFlag(CDockManager::DragPreviewIsDynamic))
|
||||||
|
{
|
||||||
|
setHidden(false);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int VisibleDockAreas = TopContainer->visibleDockAreaCount();
|
||||||
|
ContainerOverlay->setAllowedAreas(
|
||||||
|
VisibleDockAreas > 1 ? OuterDockAreas : AllDockAreas);
|
||||||
|
DockWidgetArea ContainerArea = ContainerOverlay->showOverlay(TopContainer);
|
||||||
|
ContainerOverlay->enableDropPreview(ContainerArea != InvalidDockWidgetArea);
|
||||||
|
auto DockArea = TopContainer->dockAreaAt(GlobalPos);
|
||||||
|
if (DockArea && DockArea->isVisible() && VisibleDockAreas > 0 && DockArea != ContentSourceArea)
|
||||||
|
{
|
||||||
|
DockAreaOverlay->enableDropPreview(true);
|
||||||
|
DockAreaOverlay->setAllowedAreas(
|
||||||
|
(VisibleDockAreas == 1) ? NoDockWidgetArea : AllDockAreas);
|
||||||
|
DockWidgetArea Area = DockAreaOverlay->showOverlay(DockArea);
|
||||||
|
|
||||||
|
// A CenterDockWidgetArea for the dockAreaOverlay() indicates that
|
||||||
|
// the mouse is in the title bar. If the ContainerArea is valid
|
||||||
|
// then we ignore the dock area of the dockAreaOverlay() and disable
|
||||||
|
// the drop preview
|
||||||
|
if ((Area == CenterDockWidgetArea)
|
||||||
|
&& (ContainerArea != InvalidDockWidgetArea))
|
||||||
|
{
|
||||||
|
DockAreaOverlay->enableDropPreview(false);
|
||||||
|
ContainerOverlay->enableDropPreview(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ContainerOverlay->enableDropPreview(InvalidDockWidgetArea == Area);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DockAreaOverlay->hideOverlay();
|
||||||
|
if (DockArea == ContentSourceArea && InvalidDockWidgetArea == ContainerDropArea)
|
||||||
|
{
|
||||||
|
DropContainer = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CDockManager::configFlags().testFlag(CDockManager::DragPreviewIsDynamic))
|
||||||
|
{
|
||||||
|
setHidden(DockDropArea != InvalidDockWidgetArea || ContainerDropArea != InvalidDockWidgetArea);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
FloatingDragPreviewPrivate::FloatingDragPreviewPrivate(CFloatingDragPreview *_public) :
|
||||||
|
_this(_public)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CFloatingDragPreview::CFloatingDragPreview(QWidget* Content, QWidget* parent) :
|
||||||
|
QWidget(parent),
|
||||||
|
d(new FloatingDragPreviewPrivate(this))
|
||||||
|
{
|
||||||
|
d->Content = Content;
|
||||||
|
setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
if (CDockManager::configFlags().testFlag(CDockManager::DragPreviewHasWindowFrame))
|
||||||
|
{
|
||||||
|
setWindowFlags(
|
||||||
|
Qt::Window | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
|
||||||
|
setAttribute(Qt::WA_NoSystemBackground);
|
||||||
|
setAttribute(Qt::WA_TranslucentBackground);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
auto Flags = windowFlags();
|
||||||
|
Flags |= Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint;
|
||||||
|
setWindowFlags(Flags);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
setWindowOpacity(0.6);
|
||||||
|
|
||||||
|
// Create a static image of the widget that should get undocked
|
||||||
|
// This is like some kind preview image like it is uses in drag and drop
|
||||||
|
// operations
|
||||||
|
if (CDockManager::configFlags().testFlag(CDockManager::DragPreviewShowsContentPixmap))
|
||||||
|
{
|
||||||
|
d->ContentPreviewPixmap = QPixmap(Content->size());
|
||||||
|
Content->render(&d->ContentPreviewPixmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(qApp, SIGNAL(applicationStateChanged(Qt::ApplicationState)),
|
||||||
|
SLOT(onApplicationStateChanged(Qt::ApplicationState)));
|
||||||
|
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
// In Windows this widget directly receives the escape key press events
|
||||||
|
// in Linux we need to install an event filter for the given Content
|
||||||
|
// widget to receive the escape key press
|
||||||
|
Content->installEventFilter(this);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CFloatingDragPreview::CFloatingDragPreview(CDockWidget* Content)
|
||||||
|
: CFloatingDragPreview((QWidget*)Content, Content->dockManager())
|
||||||
|
{
|
||||||
|
d->DockManager = Content->dockManager();
|
||||||
|
if (Content->dockAreaWidget()->openDockWidgetsCount() == 1)
|
||||||
|
{
|
||||||
|
d->ContentSourceArea = Content->dockAreaWidget();
|
||||||
|
d->ContenSourceContainer = Content->dockContainer();
|
||||||
|
}
|
||||||
|
setWindowTitle(Content->windowTitle());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CFloatingDragPreview::CFloatingDragPreview(CDockAreaWidget* Content)
|
||||||
|
: CFloatingDragPreview((QWidget*)Content, Content->dockManager())
|
||||||
|
{
|
||||||
|
d->DockManager = Content->dockManager();
|
||||||
|
d->ContentSourceArea = Content;
|
||||||
|
d->ContenSourceContainer = Content->dockContainer();
|
||||||
|
setWindowTitle(Content->currentDockWidget()->windowTitle());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CFloatingDragPreview::~CFloatingDragPreview()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CFloatingDragPreview::moveFloating()
|
||||||
|
{
|
||||||
|
int BorderSize = (frameSize().width() - size().width()) / 2;
|
||||||
|
const QPoint moveToPos = QCursor::pos() - d->DragStartMousePosition
|
||||||
|
- QPoint(BorderSize, 0);
|
||||||
|
move(moveToPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CFloatingDragPreview::startFloating(const QPoint &DragStartMousePos,
|
||||||
|
const QSize &Size, eDragState DragState, QWidget *MouseEventHandler)
|
||||||
|
{
|
||||||
|
Q_UNUSED(MouseEventHandler)
|
||||||
|
Q_UNUSED(DragState)
|
||||||
|
resize(Size);
|
||||||
|
d->DragStartMousePosition = DragStartMousePos;
|
||||||
|
moveFloating();
|
||||||
|
show();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CFloatingDragPreview::moveEvent(QMoveEvent *event)
|
||||||
|
{
|
||||||
|
QWidget::moveEvent(event);
|
||||||
|
d->updateDropOverlays(QCursor::pos());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CFloatingDragPreview::finishDragging()
|
||||||
|
{
|
||||||
|
ADS_PRINT("CFloatingDragPreview::finishDragging");
|
||||||
|
auto DockDropArea = d->DockManager->dockAreaOverlay()->dropAreaUnderCursor();
|
||||||
|
auto ContainerDropArea = d->DockManager->containerOverlay()->dropAreaUnderCursor();
|
||||||
|
bool DropPossible = (DockDropArea != InvalidDockWidgetArea) || (ContainerDropArea != InvalidDockWidgetArea);
|
||||||
|
if (d->DropContainer && DropPossible)
|
||||||
|
{
|
||||||
|
d->DropContainer->dropWidget(d->Content, QCursor::pos());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CDockWidget* DockWidget = qobject_cast<CDockWidget*>(d->Content);
|
||||||
|
CFloatingDockContainer* FloatingWidget;
|
||||||
|
if (DockWidget)
|
||||||
|
{
|
||||||
|
FloatingWidget = new CFloatingDockContainer(DockWidget);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CDockAreaWidget* DockArea = qobject_cast<CDockAreaWidget*>(d->Content);
|
||||||
|
FloatingWidget = new CFloatingDockContainer(DockArea);
|
||||||
|
}
|
||||||
|
FloatingWidget->setGeometry(this->geometry());
|
||||||
|
FloatingWidget->show();
|
||||||
|
if (!CDockManager::configFlags().testFlag(CDockManager::DragPreviewHasWindowFrame))
|
||||||
|
{
|
||||||
|
QApplication::processEvents();
|
||||||
|
int FrameHeight = FloatingWidget->frameGeometry().height() - FloatingWidget->geometry().height();
|
||||||
|
QRect FixedGeometry = this->geometry();
|
||||||
|
FixedGeometry.adjust(0, FrameHeight, 0, 0);
|
||||||
|
FloatingWidget->setGeometry(FixedGeometry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this->close();
|
||||||
|
d->DockManager->containerOverlay()->hideOverlay();
|
||||||
|
d->DockManager->dockAreaOverlay()->hideOverlay();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CFloatingDragPreview::paintEvent(QPaintEvent* event)
|
||||||
|
{
|
||||||
|
Q_UNUSED(event);
|
||||||
|
if (d->Hidden)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPainter painter(this);
|
||||||
|
if (CDockManager::configFlags().testFlag(CDockManager::DragPreviewShowsContentPixmap))
|
||||||
|
{
|
||||||
|
painter.drawPixmap(QPoint(0, 0), d->ContentPreviewPixmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we do not have a window frame then we paint a QRubberBand like
|
||||||
|
// frameless window
|
||||||
|
if (!CDockManager::configFlags().testFlag(CDockManager::DragPreviewHasWindowFrame))
|
||||||
|
{
|
||||||
|
QColor Color = palette().color(QPalette::Active, QPalette::Highlight);
|
||||||
|
QPen Pen = painter.pen();
|
||||||
|
Pen.setColor(Color.darker(120));
|
||||||
|
Pen.setStyle(Qt::SolidLine);
|
||||||
|
Pen.setWidth(1);
|
||||||
|
Pen.setCosmetic(true);
|
||||||
|
painter.setPen(Pen);
|
||||||
|
Color = Color.lighter(130);
|
||||||
|
Color.setAlpha(64);
|
||||||
|
painter.setBrush(Color);
|
||||||
|
painter.drawRect(rect().adjusted(0, 0, -1, -1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CFloatingDragPreview::keyPressEvent(QKeyEvent *event)
|
||||||
|
{
|
||||||
|
Super::keyPressEvent(event);
|
||||||
|
if (event->key() == Qt::Key_Escape)
|
||||||
|
{
|
||||||
|
d->cancelDragging();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CFloatingDragPreview::onApplicationStateChanged(Qt::ApplicationState state)
|
||||||
|
{
|
||||||
|
if (state != Qt::ApplicationActive)
|
||||||
|
{
|
||||||
|
disconnect(qApp, SIGNAL(applicationStateChanged(Qt::ApplicationState)),
|
||||||
|
this, SLOT(onApplicationStateChanged(Qt::ApplicationState)));
|
||||||
|
d->cancelDragging();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
bool CFloatingDragPreview::eventFilter(QObject *watched, QEvent *event)
|
||||||
|
{
|
||||||
|
Q_UNUSED(watched);
|
||||||
|
if (event->type() == QEvent::KeyPress)
|
||||||
|
{
|
||||||
|
QKeyEvent* e = static_cast<QKeyEvent*>(event);
|
||||||
|
if (e->key() == Qt::Key_Escape)
|
||||||
|
{
|
||||||
|
d->Content->removeEventFilter(this);
|
||||||
|
d->cancelDragging();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace ads
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// EOF FloatingDragPreview.cpp
|
118
src/ui/AdvDock/FloatingDragPreview.h
Normal file
118
src/ui/AdvDock/FloatingDragPreview.h
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
#ifndef FloatingDragPreviewH
|
||||||
|
#define FloatingDragPreviewH
|
||||||
|
//============================================================================
|
||||||
|
/// \file FloatingDragPreview.h
|
||||||
|
/// \author Uwe Kindler
|
||||||
|
/// \date 26.11.2019
|
||||||
|
/// \brief Declaration of CFloatingDragPreview
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// INCLUDES
|
||||||
|
//============================================================================
|
||||||
|
#include <QWidget>
|
||||||
|
#include "FloatingDockContainer.h"
|
||||||
|
|
||||||
|
namespace ads
|
||||||
|
{
|
||||||
|
class CDockWidget;
|
||||||
|
class CDockAreaWidget;
|
||||||
|
struct FloatingDragPreviewPrivate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A floating overlay is a temporary floating widget that is just used to
|
||||||
|
* indicate the floating widget movement.
|
||||||
|
* This widget is used as a placeholder for drag operations for non-opaque
|
||||||
|
* docking
|
||||||
|
*/
|
||||||
|
class CFloatingDragPreview : public QWidget, public IFloatingWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
FloatingDragPreviewPrivate* d;
|
||||||
|
friend struct FloatingDragPreviewPrivate;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
/**
|
||||||
|
* Cancel non opaque undocking if application becomes inactive
|
||||||
|
*/
|
||||||
|
void onApplicationStateChanged(Qt::ApplicationState state);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* Updates the drop overlays
|
||||||
|
*/
|
||||||
|
virtual void moveEvent(QMoveEvent *event) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cares about painting the
|
||||||
|
*/
|
||||||
|
virtual void paintEvent(QPaintEvent *e) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel non opaque undocking with escape key
|
||||||
|
*/
|
||||||
|
virtual void keyPressEvent(QKeyEvent *event) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The content is a DockArea or a DockWidget
|
||||||
|
*/
|
||||||
|
CFloatingDragPreview(QWidget* Content, QWidget* parent);
|
||||||
|
|
||||||
|
public:
|
||||||
|
using Super = QWidget;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance for undocking the DockWidget in Content parameter
|
||||||
|
*/
|
||||||
|
CFloatingDragPreview(CDockWidget* Content);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance for undocking the DockArea given in Content
|
||||||
|
* parameters
|
||||||
|
*/
|
||||||
|
CFloatingDragPreview(CDockAreaWidget* Content);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete private data
|
||||||
|
*/
|
||||||
|
~CFloatingDragPreview();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We filter the events of the assigned content widget to receive
|
||||||
|
* escape key presses for canceling the drag operation
|
||||||
|
*/
|
||||||
|
virtual bool eventFilter(QObject *watched, QEvent *event) override;
|
||||||
|
|
||||||
|
|
||||||
|
public: // implements IFloatingWidget -----------------------------------------
|
||||||
|
virtual void startFloating(const QPoint& DragStartMousePos, const QSize& Size,
|
||||||
|
eDragState DragState, QWidget* MouseEventHandler) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves the widget to a new position relative to the position given when
|
||||||
|
* startFloating() was called
|
||||||
|
*/
|
||||||
|
virtual void moveFloating() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finishes dragging.
|
||||||
|
* Hides the dock overlays and executes the real undocking and docking
|
||||||
|
* of the assigned Content widget
|
||||||
|
*/
|
||||||
|
virtual void finishDragging() override;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
/**
|
||||||
|
* This signal is emitted, if dragging has been canceled by escape key
|
||||||
|
* or by active application switching via task manager
|
||||||
|
*/
|
||||||
|
void draggingCanceled();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace ads
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
#endif // FloatingDragPreviewH
|
||||||
|
|
73
src/ui/AdvDock/IconProvider.cpp
Normal file
73
src/ui/AdvDock/IconProvider.cpp
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
//============================================================================
|
||||||
|
/// \file IconProvider.cpp
|
||||||
|
/// \author Uwe Kindler
|
||||||
|
/// \date 18.10.2019
|
||||||
|
/// \brief Implementation of CIconProvider
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// INCLUDES
|
||||||
|
//============================================================================
|
||||||
|
#include "IconProvider.h"
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
|
namespace ads
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Private data class (pimpl)
|
||||||
|
*/
|
||||||
|
struct IconProviderPrivate
|
||||||
|
{
|
||||||
|
CIconProvider *_this;
|
||||||
|
QVector<QIcon> UserIcons{IconCount, QIcon()};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private data constructor
|
||||||
|
*/
|
||||||
|
IconProviderPrivate(CIconProvider *_public);
|
||||||
|
};
|
||||||
|
// struct LedArrayPanelPrivate
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
IconProviderPrivate::IconProviderPrivate(CIconProvider *_public) :
|
||||||
|
_this(_public)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CIconProvider::CIconProvider() :
|
||||||
|
d(new IconProviderPrivate(this))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CIconProvider::~CIconProvider()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QIcon CIconProvider::customIcon(eIcon IconId) const
|
||||||
|
{
|
||||||
|
Q_ASSERT(IconId < d->UserIcons.size());
|
||||||
|
return d->UserIcons[IconId];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CIconProvider::registerCustomIcon(eIcon IconId, const QIcon &icon)
|
||||||
|
{
|
||||||
|
Q_ASSERT(IconId < d->UserIcons.size());
|
||||||
|
d->UserIcons[IconId] = icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ads
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// EOF IconProvider.cpp
|
61
src/ui/AdvDock/IconProvider.h
Normal file
61
src/ui/AdvDock/IconProvider.h
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#ifndef IconProviderH
|
||||||
|
#define IconProviderH
|
||||||
|
//============================================================================
|
||||||
|
/// \file IconProvider.h
|
||||||
|
/// \author Uwe Kindler
|
||||||
|
/// \date 18.10.2019
|
||||||
|
/// \brief Declaration of CIconProvider
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// INCLUDES
|
||||||
|
//============================================================================
|
||||||
|
#include <QIcon>
|
||||||
|
|
||||||
|
#include "ads_globals.h"
|
||||||
|
|
||||||
|
namespace ads
|
||||||
|
{
|
||||||
|
|
||||||
|
struct IconProviderPrivate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This object provides all icons that are required by the advanced docking
|
||||||
|
* system.
|
||||||
|
* The IconProvider enables the user to register custom icons in case using
|
||||||
|
* stylesheets is not an option.
|
||||||
|
*/
|
||||||
|
class CIconProvider
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
IconProviderPrivate* d; ///< private data (pimpl)
|
||||||
|
friend struct IconProviderPrivate;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Default Constructor
|
||||||
|
*/
|
||||||
|
CIconProvider();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Virtual Destructor
|
||||||
|
*/
|
||||||
|
virtual ~CIconProvider();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function returns a custom icon if one is registered and a null Icon
|
||||||
|
* if no custom icon is registered
|
||||||
|
*/
|
||||||
|
QIcon customIcon(eIcon IconId) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a custom icon for the given IconId
|
||||||
|
*/
|
||||||
|
void registerCustomIcon(eIcon IconId, const QIcon &icon);
|
||||||
|
}; // class IconProvider
|
||||||
|
|
||||||
|
} // namespace ads
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
#endif // IconProviderH
|
99
src/ui/AdvDock/ads_globals.cpp
Normal file
99
src/ui/AdvDock/ads_globals.cpp
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
** Qt Advanced Docking System
|
||||||
|
** Copyright (C) 2017 Uwe Kindler
|
||||||
|
**
|
||||||
|
** This library is free software; you can redistribute it and/or
|
||||||
|
** modify it under the terms of the GNU Lesser General Public
|
||||||
|
** License as published by the Free Software Foundation; either
|
||||||
|
** version 2.1 of the License, or (at your option) any later version.
|
||||||
|
**
|
||||||
|
** This library is distributed in the hope that it will be useful,
|
||||||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
** Lesser General Public License for more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU Lesser General Public
|
||||||
|
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
/// \file ads_globals.cpp
|
||||||
|
/// \author Uwe Kindler
|
||||||
|
/// \date 24.02.2017
|
||||||
|
/// \brief Implementation of
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// INCLUDES
|
||||||
|
//============================================================================
|
||||||
|
#include <QVariant>
|
||||||
|
#include <QPainter>
|
||||||
|
|
||||||
|
#include "DockSplitter.h"
|
||||||
|
#include "ads_globals.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace ads
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace internal
|
||||||
|
{
|
||||||
|
//============================================================================
|
||||||
|
void replaceSplitterWidget(QSplitter* Splitter, QWidget* From, QWidget* To)
|
||||||
|
{
|
||||||
|
int index = Splitter->indexOf(From);
|
||||||
|
From->setParent(nullptr);
|
||||||
|
Splitter->insertWidget(index, To);
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockInsertParam dockAreaInsertParameters(DockWidgetArea Area)
|
||||||
|
{
|
||||||
|
switch (Area)
|
||||||
|
{
|
||||||
|
case TopDockWidgetArea: return CDockInsertParam(Qt::Vertical, false);
|
||||||
|
case RightDockWidgetArea: return CDockInsertParam(Qt::Horizontal, true);
|
||||||
|
case CenterDockWidgetArea:
|
||||||
|
case BottomDockWidgetArea: return CDockInsertParam(Qt::Vertical, true);
|
||||||
|
case LeftDockWidgetArea: return CDockInsertParam(Qt::Horizontal, false);
|
||||||
|
default: CDockInsertParam(Qt::Vertical, false);
|
||||||
|
} // switch (Area)
|
||||||
|
|
||||||
|
return CDockInsertParam(Qt::Vertical, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QPixmap createTransparentPixmap(const QPixmap& Source, qreal Opacity)
|
||||||
|
{
|
||||||
|
QPixmap TransparentPixmap(Source.size());
|
||||||
|
TransparentPixmap.fill(Qt::transparent);
|
||||||
|
QPainter p(&TransparentPixmap);
|
||||||
|
p.setOpacity(Opacity);
|
||||||
|
p.drawPixmap(0, 0, Source);
|
||||||
|
return TransparentPixmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void hideEmptyParentSplitters(CDockSplitter* Splitter)
|
||||||
|
{
|
||||||
|
while (Splitter && Splitter->isVisible())
|
||||||
|
{
|
||||||
|
if (!Splitter->hasVisibleContent())
|
||||||
|
{
|
||||||
|
Splitter->hide();
|
||||||
|
}
|
||||||
|
Splitter = internal::findParent<CDockSplitter*>(Splitter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace ads
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// EOF ads_globals.cpp
|
223
src/ui/AdvDock/ads_globals.h
Normal file
223
src/ui/AdvDock/ads_globals.h
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
#ifndef ads_globalsH
|
||||||
|
#define ads_globalsH
|
||||||
|
/*******************************************************************************
|
||||||
|
** Qt Advanced Docking System
|
||||||
|
** Copyright (C) 2017 Uwe Kindler
|
||||||
|
**
|
||||||
|
** This library is free software; you can redistribute it and/or
|
||||||
|
** modify it under the terms of the GNU Lesser General Public
|
||||||
|
** License as published by the Free Software Foundation; either
|
||||||
|
** version 2.1 of the License, or (at your option) any later version.
|
||||||
|
**
|
||||||
|
** This library is distributed in the hope that it will be useful,
|
||||||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
** Lesser General Public License for more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU Lesser General Public
|
||||||
|
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
/// \file ads_globals.h
|
||||||
|
/// \author Uwe Kindler
|
||||||
|
/// \date 24.02.2017
|
||||||
|
/// \brief Declaration of
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// INCLUDES
|
||||||
|
//============================================================================
|
||||||
|
#include <QPair>
|
||||||
|
#include <QtCore/QtGlobal>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
#ifndef ADS_STATIC
|
||||||
|
#ifdef ADS_SHARED_EXPORT
|
||||||
|
#define ADS_EXPORT Q_DECL_EXPORT
|
||||||
|
#else
|
||||||
|
#define ADS_EXPORT Q_DECL_IMPORT
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define ADS_EXPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Define ADS_DEBUG_PRINT to enable a lot of debug output
|
||||||
|
#ifdef ADS_DEBUG_PRINT
|
||||||
|
#define ADS_PRINT(s) qDebug() << s
|
||||||
|
#else
|
||||||
|
#define ADS_PRINT(s)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Set ADS_DEBUG_LEVEL to enable additional debug output and to enable layout
|
||||||
|
// dumps to qDebug and std::cout after layout changes
|
||||||
|
#define ADS_DEBUG_LEVEL 0
|
||||||
|
|
||||||
|
class QSplitter;
|
||||||
|
|
||||||
|
namespace ads
|
||||||
|
{
|
||||||
|
enum eStateFileVersion
|
||||||
|
{
|
||||||
|
InitialVerison = 0,
|
||||||
|
Version1 = 1,
|
||||||
|
CurrentVersion = Version1
|
||||||
|
};
|
||||||
|
|
||||||
|
class CDockSplitter;
|
||||||
|
|
||||||
|
enum DockWidgetArea
|
||||||
|
{
|
||||||
|
NoDockWidgetArea = 0x00,
|
||||||
|
LeftDockWidgetArea = 0x01,
|
||||||
|
RightDockWidgetArea = 0x02,
|
||||||
|
TopDockWidgetArea = 0x04,
|
||||||
|
BottomDockWidgetArea = 0x08,
|
||||||
|
CenterDockWidgetArea = 0x10,
|
||||||
|
|
||||||
|
InvalidDockWidgetArea = NoDockWidgetArea,
|
||||||
|
OuterDockAreas = TopDockWidgetArea | LeftDockWidgetArea | RightDockWidgetArea | BottomDockWidgetArea,
|
||||||
|
AllDockAreas = OuterDockAreas | CenterDockWidgetArea
|
||||||
|
};
|
||||||
|
Q_DECLARE_FLAGS(DockWidgetAreas, DockWidgetArea)
|
||||||
|
|
||||||
|
|
||||||
|
enum TitleBarButton
|
||||||
|
{
|
||||||
|
TitleBarButtonTabsMenu,
|
||||||
|
TitleBarButtonUndock,
|
||||||
|
TitleBarButtonClose
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The different dragging states
|
||||||
|
*/
|
||||||
|
enum eDragState
|
||||||
|
{
|
||||||
|
DraggingInactive, //!< DraggingInactive
|
||||||
|
DraggingMousePressed, //!< DraggingMousePressed
|
||||||
|
DraggingTab, //!< DraggingTab
|
||||||
|
DraggingFloatingWidget//!< DraggingFloatingWidget
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The different icons used in the UI
|
||||||
|
*/
|
||||||
|
enum eIcon
|
||||||
|
{
|
||||||
|
TabCloseIcon, //!< TabCloseIcon
|
||||||
|
DockAreaMenuIcon, //!< DockAreaMenuIcon
|
||||||
|
DockAreaUndockIcon,//!< DockAreaUndockIcon
|
||||||
|
DockAreaCloseIcon, //!< DockAreaCloseIcon
|
||||||
|
|
||||||
|
IconCount, //!< just a delimiter for range checks
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For bitwise combination of dock wdget features
|
||||||
|
*/
|
||||||
|
enum eBitwiseOperator
|
||||||
|
{
|
||||||
|
BitwiseAnd,
|
||||||
|
BitwiseOr
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace internal
|
||||||
|
{
|
||||||
|
static const bool RestoreTesting = true;
|
||||||
|
static const bool Restore = false;
|
||||||
|
static const char* const ClosedProperty = "close";
|
||||||
|
static const char* const DirtyProperty = "dirty";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace the from widget in the given splitter with the To widget
|
||||||
|
*/
|
||||||
|
void replaceSplitterWidget(QSplitter* Splitter, QWidget* From, QWidget* To);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function walks the splitter tree upwards to hides all splitters
|
||||||
|
* that do not have visible content
|
||||||
|
*/
|
||||||
|
void hideEmptyParentSplitters(CDockSplitter* FirstParentSplitter);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience class for QPair to provide better naming than first and
|
||||||
|
* second
|
||||||
|
*/
|
||||||
|
class CDockInsertParam : public QPair<Qt::Orientation, bool>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//using QPair::QPair;
|
||||||
|
CDockInsertParam(Qt::Orientation o, bool b) : QPair<Qt::Orientation, bool>(o, b) {}
|
||||||
|
Qt::Orientation orientation() const {return this->first;}
|
||||||
|
bool append() const {return this->second;}
|
||||||
|
int insertOffset() const {return append() ? 1 : 0;}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the insertion parameters for the given dock area
|
||||||
|
*/
|
||||||
|
CDockInsertParam dockAreaInsertParameters(DockWidgetArea Area);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches for the parent widget of the given type.
|
||||||
|
* Returns the parent widget of the given widget or 0 if the widget is not
|
||||||
|
* child of any widget of type T
|
||||||
|
*
|
||||||
|
* It is not safe to use this function in in CDockWidget because only
|
||||||
|
* the current dock widget has a parent. All dock widgets that are not the
|
||||||
|
* current dock widget in a dock area have no parent.
|
||||||
|
*/
|
||||||
|
template <class T>
|
||||||
|
T findParent(const QWidget* w)
|
||||||
|
{
|
||||||
|
QWidget* parentWidget = w->parentWidget();
|
||||||
|
while (parentWidget)
|
||||||
|
{
|
||||||
|
T ParentImpl = qobject_cast<T>(parentWidget);
|
||||||
|
if (ParentImpl)
|
||||||
|
{
|
||||||
|
return ParentImpl;
|
||||||
|
}
|
||||||
|
parentWidget = parentWidget->parentWidget();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a semi transparent pixmap from the given pixmap Source.
|
||||||
|
* The Opacity parameter defines the opacity from completely transparent (0.0)
|
||||||
|
* to completely opaque (1.0)
|
||||||
|
*/
|
||||||
|
QPixmap createTransparentPixmap(const QPixmap& Source, qreal Opacity);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function for settings flags in a QFlags instance.
|
||||||
|
*/
|
||||||
|
template <class T>
|
||||||
|
void setFlag(T& Flags, typename T::enum_type flag, bool on = true)
|
||||||
|
{
|
||||||
|
#if QT_VERSION >= 0x050700
|
||||||
|
Flags.setFlag(flag, on);
|
||||||
|
#else
|
||||||
|
if(on)
|
||||||
|
{
|
||||||
|
Flags |= flag;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Flags &= ~flag;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace ads
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
#endif // ads_globalsH
|
@ -13,17 +13,17 @@ DockTitleBar::DockTitleBar(QWidget* parent)
|
|||||||
: DockWidgetTitleBar(parent)
|
: DockWidgetTitleBar(parent)
|
||||||
, ui(new Ui::DockTitleBar) {
|
, ui(new Ui::DockTitleBar) {
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
connect(ui->sys_close, &QPushButton::clicked, this, &DockTitleBar::signalClose);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DockTitleBar::~DockTitleBar() {
|
DockTitleBar::~DockTitleBar() {
|
||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
//QSize DockTitleBar::minimumSizeHint() const {
|
QSize DockTitleBar::minimumSizeHint() const {
|
||||||
// QSize s = size();
|
QSize s = size();
|
||||||
// return s;
|
return s;
|
||||||
//}
|
}
|
||||||
|
|
||||||
void DockTitleBar::SetTitle(const QString& title) {
|
void DockTitleBar::SetTitle(const QString& title) {
|
||||||
ui->sys_title->setText(title);
|
ui->sys_title->setText(title);
|
||||||
|
@ -13,7 +13,7 @@ public:
|
|||||||
DockTitleBar(QWidget* parent = 0);
|
DockTitleBar(QWidget* parent = 0);
|
||||||
~DockTitleBar() override;
|
~DockTitleBar() override;
|
||||||
|
|
||||||
//QSize minimumSizeHint() const override;
|
QSize minimumSizeHint() const override;
|
||||||
|
|
||||||
void SetTitle(const QString& title) override;
|
void SetTitle(const QString& title) override;
|
||||||
|
|
||||||
|
@ -1,38 +1,36 @@
|
|||||||
#include "DockWidget.h"
|
#include "DockWidget.h"
|
||||||
|
|
||||||
|
#include <QAbstractButton>
|
||||||
#include <QStyleOptionDockWidget>
|
#include <QStyleOptionDockWidget>
|
||||||
|
#include <QHBoxLayout>
|
||||||
#include "ui/Menu/SystemManagerMenu.h"
|
#include <QPaintEvent>
|
||||||
#include "common/SpdLogger.h"
|
#include <QPainter>
|
||||||
#include "ui/MainFrame.h"
|
#include <QPainterPath>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QApplication>
|
||||||
|
|
||||||
|
|
||||||
DockWidgetTitleBar::DockWidgetTitleBar(QWidget* parent)
|
DockWidgetTitleBar::DockWidgetTitleBar(QWidget* parent)
|
||||||
: QWidget(parent) {
|
: QWidget(parent) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DockWidgetTitleBar::~DockWidgetTitleBar() {
|
DockWidgetTitleBar::~DockWidgetTitleBar() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//QSize DockWidgetTitleBar::minimumSizeHint() const {
|
QSize DockWidgetTitleBar::minimumSizeHint() const {
|
||||||
// QDockWidget* dw = qobject_cast<QDockWidget*>(parentWidget());
|
QDockWidget* dw = qobject_cast<QDockWidget*>(parentWidget());
|
||||||
// Q_ASSERT(dw);
|
Q_ASSERT(dw);
|
||||||
// QSize result(0, 90);
|
QSize result(0, 90);
|
||||||
// if (dw->features() & QDockWidget::DockWidgetVerticalTitleBar)
|
if (dw->features() & QDockWidget::DockWidgetVerticalTitleBar)
|
||||||
// result.transpose();
|
result.transpose();
|
||||||
// return result;
|
return result;
|
||||||
//}
|
}
|
||||||
|
|
||||||
|
|
||||||
DockWidget::DockWidget(const QString& title, QWidget* parent)
|
DockWidget::DockWidget(const QString& title, QWidget* parent)
|
||||||
: QDockWidget(title, parent) {
|
: QDockWidget(title, parent) {
|
||||||
setFeatures(DockWidgetClosable | DockWidgetMovable | DockWidgetFloatable);
|
setFeatures(DockWidgetClosable | DockWidgetMovable | DockWidgetFloatable);
|
||||||
SystemManagerMenu* windowManagerMenu = MainFrame::Get().GetMenuManager<SystemManagerMenu>("system_manager");
|
|
||||||
if (nullptr != windowManagerMenu) {
|
|
||||||
windowManagerMenu->AddDockWidget(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DockWidget::DockWidget(QWidget* parent)
|
DockWidget::DockWidget(QWidget* parent)
|
||||||
@ -52,17 +50,7 @@ void DockWidget::setWindowTitle(const QString& text) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DockWidget::SetDockWidgetTitleBar(DockWidgetTitleBar* titleBar) {
|
void DockWidget::SetDockWidgetTitleBar(DockWidgetTitleBar* titleBar) {
|
||||||
if (nullptr != titleBar_) {
|
|
||||||
disconnect(titleBar_, &DockWidgetTitleBar::signalClose, this, &DockWidget::close);
|
|
||||||
}
|
|
||||||
titleBar_ = titleBar;
|
titleBar_ = titleBar;
|
||||||
if (nullptr == titleBar_) {
|
|
||||||
LOG_ERROR("DockWidget::SetDockWidgetTitleBar titleBar is nullptr");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
titleBar_->SetTitle(windowTitle());
|
|
||||||
connect(titleBar_, &DockWidgetTitleBar::signalClose, this, &DockWidget::OnClose);
|
|
||||||
QDockWidget::setTitleBarWidget(titleBar_);
|
QDockWidget::setTitleBarWidget(titleBar_);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,17 +60,7 @@ void DockWidget::showEvent(QShowEvent* e) {
|
|||||||
|
|
||||||
void DockWidget::resizeEvent(QResizeEvent* e) {
|
void DockWidget::resizeEvent(QResizeEvent* e) {
|
||||||
QDockWidget::resizeEvent(e);
|
QDockWidget::resizeEvent(e);
|
||||||
}
|
|
||||||
|
|
||||||
void DockWidget::paintEvent(QPaintEvent* e) {
|
|
||||||
QDockWidget::paintEvent(e);
|
|
||||||
QStyleOptionDockWidget opt;
|
QStyleOptionDockWidget opt;
|
||||||
initStyleOption(&opt);
|
initStyleOption(&opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DockWidget::OnClose() {
|
|
||||||
LOG_INFO("DockWidget::OnClose");
|
|
||||||
close();
|
|
||||||
emit signalClose();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -5,16 +5,6 @@
|
|||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
#include <QApplication>
|
|
||||||
#include <QMainWindow>
|
|
||||||
#include <QMouseEvent>
|
|
||||||
#include <QDrag>
|
|
||||||
#include <QMimeData>
|
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QTextStream>
|
|
||||||
#include <QFile>
|
|
||||||
#include <QJsonDocument>
|
|
||||||
|
|
||||||
class DockWidgetTitleBar : public QWidget {
|
class DockWidgetTitleBar : public QWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -24,13 +14,10 @@ public:
|
|||||||
|
|
||||||
virtual void SetTitle(const QString& title) {}
|
virtual void SetTitle(const QString& title) {}
|
||||||
|
|
||||||
//QSize sizeHint() const override {
|
QSize sizeHint() const override {
|
||||||
// return QSize(270, 900);
|
return minimumSizeHint();
|
||||||
//}
|
}
|
||||||
//QSize minimumSizeHint() const override;
|
QSize minimumSizeHint() const override;
|
||||||
|
|
||||||
Q_SIGNALS:
|
|
||||||
void signalClose();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DockWidget : public QDockWidget {
|
class DockWidget : public QDockWidget {
|
||||||
@ -45,136 +32,10 @@ public:
|
|||||||
|
|
||||||
void SetDockWidgetTitleBar(DockWidgetTitleBar* titleBar);
|
void SetDockWidgetTitleBar(DockWidgetTitleBar* titleBar);
|
||||||
|
|
||||||
Q_SIGNALS:
|
|
||||||
void signalClose();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void showEvent(QShowEvent* e) override;
|
void showEvent(QShowEvent* e) override;
|
||||||
void resizeEvent(QResizeEvent* e) override;
|
void resizeEvent(QResizeEvent* e) override;
|
||||||
void paintEvent(QPaintEvent* e) override;
|
|
||||||
|
|
||||||
void mousePressEvent(QMouseEvent* event) override {
|
|
||||||
if (event->button() == Qt::LeftButton)
|
|
||||||
m_dragStartPosition = event->pos();
|
|
||||||
QDockWidget::mousePressEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void mouseMoveEvent(QMouseEvent* event) override {
|
|
||||||
if (!(event->buttons() & Qt::LeftButton))
|
|
||||||
return;
|
|
||||||
if ((event->pos() - m_dragStartPosition).manhattanLength() < QApplication::startDragDistance())
|
|
||||||
return;
|
|
||||||
|
|
||||||
QDrag* drag = new QDrag(this);
|
|
||||||
QMimeData* mimeData = new QMimeData;
|
|
||||||
mimeData->setData("application/x-dockwidget", QByteArray());
|
|
||||||
drag->setMimeData(mimeData);
|
|
||||||
drag->exec(Qt::MoveAction);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void OnClose();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DockWidgetTitleBar* titleBar_{ nullptr };
|
DockWidgetTitleBar* titleBar_{ nullptr };
|
||||||
|
|
||||||
QPoint m_dragStartPosition;
|
|
||||||
};
|
|
||||||
|
|
||||||
class CustomMainWindow : public QMainWindow {
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
CustomMainWindow(QWidget* parent = nullptr) : QMainWindow(parent) {
|
|
||||||
setAcceptDrops(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void saveStateToFile(const QString& filename) {
|
|
||||||
QByteArray state = saveState(); // 获取窗口状态
|
|
||||||
QByteArray base64 = state.toBase64(); // 转换为 Base64 字符串
|
|
||||||
|
|
||||||
QFile file(filename);
|
|
||||||
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
|
||||||
QTextStream out(&file);
|
|
||||||
out << base64; // 写入文本文件
|
|
||||||
file.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void saveDocksToJson(const QString& filename) {
|
|
||||||
QJsonObject mainData;
|
|
||||||
|
|
||||||
// 保存每个 DockWidget 的属性
|
|
||||||
for (QDockWidget* dock : findChildren<QDockWidget*>()) {
|
|
||||||
QJsonObject dockData;
|
|
||||||
dockData["visible"] = dock->isVisible();
|
|
||||||
dockData["floating"] = dock->isFloating();
|
|
||||||
dockData["geometry"] = QString("%1,%2,%3,%4")
|
|
||||||
.arg(dock->geometry().x())
|
|
||||||
.arg(dock->geometry().y())
|
|
||||||
.arg(dock->geometry().width())
|
|
||||||
.arg(dock->geometry().height());
|
|
||||||
dockData["area"] = dockWidgetArea(dock); // 停靠区域
|
|
||||||
|
|
||||||
mainData[dock->objectName()] = dockData;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 写入文件
|
|
||||||
QFile file(filename);
|
|
||||||
if (file.open(QIODevice::WriteOnly)) {
|
|
||||||
QJsonDocument doc(mainData);
|
|
||||||
file.write(doc.toJson());
|
|
||||||
file.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void restoreDocksFromJson(const QString& filename) {
|
|
||||||
QFile file(filename);
|
|
||||||
if (!file.open(QIODevice::ReadOnly)) return;
|
|
||||||
|
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
|
|
||||||
QJsonObject mainData = doc.object();
|
|
||||||
|
|
||||||
foreach(const QString & key, mainData.keys()) {
|
|
||||||
QDockWidget* dock = findChild<QDockWidget*>(key);
|
|
||||||
if (!dock) continue;
|
|
||||||
|
|
||||||
QJsonObject dockData = mainData[key].toObject();
|
|
||||||
dock->setVisible(dockData["visible"].toBool());
|
|
||||||
dock->setFloating(dockData["floating"].toBool());
|
|
||||||
|
|
||||||
// 解析几何位置
|
|
||||||
QStringList geom = dockData["geometry"].toString().split(",");
|
|
||||||
if (geom.size() == 4) {
|
|
||||||
dock->setGeometry(geom[0].toInt(), geom[1].toInt(),
|
|
||||||
geom[2].toInt(), geom[3].toInt());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 恢复停靠区域
|
|
||||||
Qt::DockWidgetArea area = static_cast<Qt::DockWidgetArea>(
|
|
||||||
dockData["area"].toInt());
|
|
||||||
|
|
||||||
addDockWidget(area, dock);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void dragEnterEvent(QDragEnterEvent* event) override {
|
|
||||||
if (event->mimeData()->hasFormat("application/x-dockwidget"))
|
|
||||||
event->acceptProposedAction();
|
|
||||||
}
|
|
||||||
|
|
||||||
void dropEvent(QDropEvent* event) override {
|
|
||||||
DockWidget* dock = qobject_cast<DockWidget*>(event->source());
|
|
||||||
if (dock && dock->parent() != this) {
|
|
||||||
// 从原窗口移除
|
|
||||||
QMainWindow* oldParent = qobject_cast<QMainWindow*>(dock->parent());
|
|
||||||
if (oldParent) oldParent->removeDockWidget(dock);
|
|
||||||
|
|
||||||
// 添加到当前窗口
|
|
||||||
dock->setParent(this);
|
|
||||||
addDockWidget(Qt::RightDockWidgetArea, dock);
|
|
||||||
dock->show();
|
|
||||||
event->acceptProposedAction();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
@ -22,7 +22,7 @@ AddParamSetting::AddParamSetting(const QString& strDir, QWidget* parent)
|
|||||||
{
|
{
|
||||||
ui.setupUi(this);
|
ui.setupUi(this);
|
||||||
|
|
||||||
//setWindowFlags(/*Qt::FramelessWindowHint | */Qt::Window);
|
setWindowFlags(/*Qt::FramelessWindowHint | */Qt::Window);
|
||||||
|
|
||||||
listType << "String" << "Int" << "Double" << "Int[]" << "Double[]" << "String[]" << "a+bi";
|
listType << "String" << "Int" << "Double" << "Int[]" << "Double[]" << "String[]" << "a+bi";
|
||||||
|
|
||||||
|
@ -16,12 +16,6 @@
|
|||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QTableWidget" name="tableWidget">
|
<widget class="QTableWidget" name="tableWidget">
|
||||||
<property name="editTriggers">
|
|
||||||
<set>QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed</set>
|
|
||||||
</property>
|
|
||||||
<property name="selectionMode">
|
|
||||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
|
||||||
</property>
|
|
||||||
<column>
|
<column>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>参数名称</string>
|
<string>参数名称</string>
|
||||||
|
@ -9,10 +9,7 @@
|
|||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
#include <QFont>
|
#include <QFont>
|
||||||
#include <qdebug.h>
|
#include <qdebug.h>
|
||||||
#include <QDir>
|
|
||||||
#include <QProcess>
|
|
||||||
|
|
||||||
#include "../../common/RecourceHelper.h"
|
|
||||||
#include "../../workspace/WorkSpaceManager.h"
|
#include "../../workspace/WorkSpaceManager.h"
|
||||||
|
|
||||||
#include "SyntaxHighlighter.h"
|
#include "SyntaxHighlighter.h"
|
||||||
@ -35,28 +32,25 @@ CodeEdtUI::CodeEdtUI(QWidget *parent)
|
|||||||
|
|
||||||
setCentralWidget(editor);
|
setCentralWidget(editor);
|
||||||
|
|
||||||
|
// ´´½¨²Ëµ¥
|
||||||
|
QMenu* fileMenu = menuBar()->addMenu(tr("&file"));
|
||||||
|
QAction* openMainAction = new QAction(tr("&Import the template"), this);
|
||||||
|
/* QAction* openLDAction = new QAction(tr("&Import the LD template"), this);
|
||||||
|
QAction* openSeekerSimAction = new QAction(tr("&Import the SeekerSim template"), this);*/
|
||||||
|
QAction* saveAction = new QAction(tr("&save"), this);
|
||||||
|
fileMenu->addAction(openMainAction);
|
||||||
|
//fileMenu->addAction(openLDAction);
|
||||||
|
//fileMenu->addAction(openSeekerSimAction);
|
||||||
|
fileMenu->addAction(saveAction);
|
||||||
|
|
||||||
InitBat();
|
connect(openMainAction, &QAction::triggered, this, &CodeEdtUI::openMainFile);
|
||||||
|
/* connect(openLDAction, &QAction::triggered, this, &CodeEdtUI::openLDFile);
|
||||||
|
connect(openSeekerSimAction, &QAction::triggered, this, &CodeEdtUI::openSeekerSimFile);*/
|
||||||
|
|
||||||
// // 创建菜单
|
connect(saveAction, &QAction::triggered, this, &CodeEdtUI::saveFile);
|
||||||
// QMenu* fileMenu = menuBar()->addMenu(tr("&file"));
|
|
||||||
// QAction* openMainAction = new QAction(tr("&Import the template"), this);
|
|
||||||
///* QAction* openLDAction = new QAction(tr("&Import the LD template"), this);
|
|
||||||
// QAction* openSeekerSimAction = new QAction(tr("&Import the SeekerSim template"), this);*/
|
|
||||||
// QAction* saveAction = new QAction(tr("&save"), this);
|
|
||||||
// fileMenu->addAction(openMainAction);
|
|
||||||
// //fileMenu->addAction(openLDAction);
|
|
||||||
// //fileMenu->addAction(openSeekerSimAction);
|
|
||||||
// fileMenu->addAction(saveAction);
|
|
||||||
|
|
||||||
// connect(openMainAction, &QAction::triggered, this, &CodeEdtUI::openMainFile);
|
// ״̬À¸
|
||||||
///* connect(openLDAction, &QAction::triggered, this, &CodeEdtUI::openLDFile);
|
statusBar();
|
||||||
// connect(openSeekerSimAction, &QAction::triggered, this, &CodeEdtUI::openSeekerSimFile);*/
|
|
||||||
|
|
||||||
// connect(saveAction, &QAction::triggered, this, &CodeEdtUI::saveFile);
|
|
||||||
|
|
||||||
// // 状态栏
|
|
||||||
// statusBar();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeEdtUI::AttachDock(DockWidget* dockWidget)
|
void CodeEdtUI::AttachDock(DockWidget* dockWidget)
|
||||||
@ -71,51 +65,17 @@ void CodeEdtUI::AttachDock(DockWidget* dockWidget)
|
|||||||
|
|
||||||
DockTitleBar* dockTitleBar = new DockTitleBar;
|
DockTitleBar* dockTitleBar = new DockTitleBar;
|
||||||
|
|
||||||
dockTitleBar->SetTitle(u8"bat文件");
|
dockTitleBar->SetTitle(tr("matlab editor"));
|
||||||
|
|
||||||
dockWidget->SetDockWidgetTitleBar(dockTitleBar);
|
dockWidget->SetDockWidgetTitleBar(dockTitleBar);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeEdtUI::InitBat()
|
|
||||||
{
|
|
||||||
{
|
|
||||||
QMenu* fileMenu = menuBar()->addMenu(u8"文件");
|
|
||||||
|
|
||||||
QDir dir(RecourceHelper::Get().GetBasePath() + "/bat");
|
|
||||||
QFileInfoList fileInfoList = dir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks);
|
|
||||||
for (int i = 0; i < fileInfoList.size(); i++)
|
|
||||||
{
|
|
||||||
QFileInfo fileInfo = fileInfoList[i];
|
|
||||||
QString strSuff = fileInfo.suffix();
|
|
||||||
strSuff = strSuff.toLower();
|
|
||||||
if (strSuff == "bat")
|
|
||||||
{
|
|
||||||
QAction* fileAction = new QAction(fileInfo.fileName(), this);
|
|
||||||
fileMenu->addAction(fileAction);
|
|
||||||
|
|
||||||
connect(fileAction, &QAction::triggered, this, &CodeEdtUI::openMainFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
QMenu* ctrlMenu = menuBar()->addMenu(u8"控制");
|
|
||||||
|
|
||||||
QAction* runAction = new QAction(tr(u8"执行"), this);
|
|
||||||
ctrlMenu->addAction(runAction);
|
|
||||||
|
|
||||||
QAction* saveAction = new QAction(u8"保存", this);
|
|
||||||
ctrlMenu->addAction(saveAction);
|
|
||||||
|
|
||||||
connect(runAction, &QAction::triggered, this, &CodeEdtUI::runFile);
|
|
||||||
connect(saveAction, &QAction::triggered, this, &CodeEdtUI::saveFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CodeEdtUI::openMainFile() {
|
void CodeEdtUI::openMainFile() {
|
||||||
|
QString fileName = ""; //QFileDialog::getOpenFileName(this, "Open File", "", "Matlab Files (*.m)");
|
||||||
QAction* fileAction = (QAction*)(sender());
|
if (fileName.isEmpty())
|
||||||
QString fileName = RecourceHelper::Get().GetBasePath() + "/bat/" + fileAction->text(); //QFileDialog::getOpenFileName(this, "Open File", "", "Matlab Files (*.bat)");
|
{
|
||||||
|
fileName = QFileDialog::getOpenFileName(this, "Open File", "", "Matlab Files (*.m)");
|
||||||
|
}
|
||||||
|
|
||||||
if (!fileName.isEmpty()) {
|
if (!fileName.isEmpty()) {
|
||||||
QFile file(fileName);
|
QFile file(fileName);
|
||||||
@ -123,13 +83,10 @@ void CodeEdtUI::openMainFile() {
|
|||||||
editor->clear();
|
editor->clear();
|
||||||
|
|
||||||
QTextStream in(&file);
|
QTextStream in(&file);
|
||||||
in.setCodec("utf-8");
|
|
||||||
editor->setPlainText(in.readAll());
|
editor->setPlainText(in.readAll());
|
||||||
file.close();
|
file.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_strCurOpenFile = fileName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeEdtUI::openLDFile()
|
void CodeEdtUI::openLDFile()
|
||||||
@ -176,37 +133,12 @@ void CodeEdtUI::openSeekerSimFile()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeEdtUI::runFile()
|
|
||||||
{
|
|
||||||
if (!m_strCurOpenFile.isEmpty())
|
|
||||||
{
|
|
||||||
saveFile();
|
|
||||||
|
|
||||||
// 创建QProcess对象
|
|
||||||
QProcess process;
|
|
||||||
|
|
||||||
// 启动批处理文件
|
|
||||||
process.start(m_strCurOpenFile);
|
|
||||||
|
|
||||||
// 等待过程完成
|
|
||||||
process.waitForFinished();
|
|
||||||
|
|
||||||
// 获取输出
|
|
||||||
QString output = process.readAllStandardOutput();
|
|
||||||
QString errorOutput = process.readAllStandardError();
|
|
||||||
|
|
||||||
// 打印输出
|
|
||||||
qDebug() << "Output:" << output;
|
|
||||||
qDebug() << "Error Output:" << errorOutput;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CodeEdtUI::saveFile() {
|
void CodeEdtUI::saveFile() {
|
||||||
if (!m_strCurOpenFile.isEmpty()) {
|
QString fileName = QFileDialog::getSaveFileName(this, "Save File", "", "Matlab Files (*.m)");
|
||||||
QFile file(m_strCurOpenFile);
|
if (!fileName.isEmpty()) {
|
||||||
|
QFile file(fileName);
|
||||||
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||||
QTextStream out(&file);
|
QTextStream out(&file);
|
||||||
out.setCodec("utf-8");
|
|
||||||
out << editor->toPlainText();
|
out << editor->toPlainText();
|
||||||
file.close();
|
file.close();
|
||||||
}
|
}
|
||||||
|
@ -11,13 +11,10 @@ public:
|
|||||||
CodeEdtUI(QWidget *parent = Q_NULLPTR);
|
CodeEdtUI(QWidget *parent = Q_NULLPTR);
|
||||||
void AttachDock(class DockWidget* dockWidget);
|
void AttachDock(class DockWidget* dockWidget);
|
||||||
|
|
||||||
void InitBat();
|
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void openMainFile();
|
void openMainFile();
|
||||||
void openLDFile();
|
void openLDFile();
|
||||||
void openSeekerSimFile();
|
void openSeekerSimFile();
|
||||||
void runFile();
|
|
||||||
|
|
||||||
void saveFile();
|
void saveFile();
|
||||||
|
|
||||||
|
@ -16,14 +16,12 @@
|
|||||||
#include "ui/Menu/DynamicDisplayMenu.h"
|
#include "ui/Menu/DynamicDisplayMenu.h"
|
||||||
#include "ui/Menu/SystemManagerMenu.h"
|
#include "ui/Menu/SystemManagerMenu.h"
|
||||||
#include "ui/Menu/PlayManagerMenu.h"
|
#include "ui/Menu/PlayManagerMenu.h"
|
||||||
#include "ui/Menu/WindowManagerMenu.h"
|
|
||||||
#include "viewer/QtOsgViewWidget.h"
|
#include "viewer/QtOsgViewWidget.h"
|
||||||
|
|
||||||
#include "chartPlot/FitCurveDialog.h"
|
#include "chartPlot/FitCurveDialog.h"
|
||||||
#include "chartPlot/SurfaceDialog.h"
|
#include "chartPlot/SurfaceDialog.h"
|
||||||
|
|
||||||
#include "ui/Menu/ChartPlotMenu.h" // lz 20140914
|
#include "ui/Menu/ChartPlotMenu.h" // lz 20140914
|
||||||
#include "common/SpdLogger.h"
|
|
||||||
|
|
||||||
#include "ui_MainFrame.h"
|
#include "ui_MainFrame.h"
|
||||||
|
|
||||||
@ -115,9 +113,9 @@ void MainFrame::InitUI() {
|
|||||||
MainWindow* mainWindow = new MainWindow(this);
|
MainWindow* mainWindow = new MainWindow(this);
|
||||||
layout->addWidget(mainWindow);
|
layout->addWidget(mainWindow);
|
||||||
|
|
||||||
QtOsgViewWidget* viewWidget = mainWindow->GetViewWidget();
|
/* QtOsgViewWidget* viewWidget = mainWindow->GetViewWidget();
|
||||||
connect(fileMenu, &FileManagerMenu::LoadDyt, viewWidget, &QtOsgViewWidget::OnLoadDyt);
|
connect(fileMenu, &FileManagerMenu::LoadDyt, viewWidget, &QtOsgViewWidget::OnLoadDyt);
|
||||||
connect(viewWidget, &QtOsgViewWidget::signalResetWorkSpace, mainWindow, &MainWindow::slotResetWorkSpace);
|
connect(viewWidget, &QtOsgViewWidget::signalResetWorkSpace, mainWindow, &MainWindow::slotResetWorkSpace);*/
|
||||||
|
|
||||||
connect(system_, &SystemManagerMenu::signalShowUISetting, mainWindow, &MainWindow::slotShowUISetting);
|
connect(system_, &SystemManagerMenu::signalShowUISetting, mainWindow, &MainWindow::slotShowUISetting);
|
||||||
|
|
||||||
@ -142,20 +140,3 @@ void MainFrame::AddMenuWidget(const QString& name, const QString& text, QWidget*
|
|||||||
int index = ui->menuWidget->addWidget(widget);
|
int index = ui->menuWidget->addWidget(widget);
|
||||||
menuWidget_.insert(btn, index);
|
menuWidget_.insert(btn, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
QWidget* MainFrame::GetMenuWidget(const QString& name) {
|
|
||||||
int index = -1;
|
|
||||||
for (auto it = menuWidget_.begin(); it != menuWidget_.end(); ++it) {
|
|
||||||
if (it.key()->objectName() == name) {
|
|
||||||
index = it.value();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (index < 0) {
|
|
||||||
LOG_INFO("not find menu widget : {}", name.toLocal8Bit().constData());
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ui->menuWidget->widget(index);
|
|
||||||
}
|
|
||||||
|
@ -20,18 +20,6 @@ public:
|
|||||||
|
|
||||||
static MainFrame& Get();
|
static MainFrame& Get();
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
T* GetMenuManager(const QString& name) {
|
|
||||||
QWidget* widget = GetMenuWidget(name);
|
|
||||||
if (widget) {
|
|
||||||
T* t = qobject_cast<T*>(widget);
|
|
||||||
if (t) {
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void paintEvent(QPaintEvent* event) override;
|
void paintEvent(QPaintEvent* event) override;
|
||||||
|
|
||||||
@ -43,7 +31,6 @@ protected:
|
|||||||
private:
|
private:
|
||||||
void InitUI();
|
void InitUI();
|
||||||
void AddMenuWidget(const QString& name, const QString& text, QWidget* widget);
|
void AddMenuWidget(const QString& name, const QString& text, QWidget* widget);
|
||||||
QWidget* GetMenuWidget(const QString& name);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::MainFrame* ui;
|
Ui::MainFrame* ui;
|
||||||
|
@ -13,7 +13,8 @@
|
|||||||
#include "ModelBrowser.h"
|
#include "ModelBrowser.h"
|
||||||
#include "DockWidget.h"
|
#include "DockWidget.h"
|
||||||
|
|
||||||
#include "viewer/QtOsgViewWidget.h"
|
#include "viewer/ViewWidget.h"
|
||||||
|
#include "viewer/OsgOpenGLWindow.h"
|
||||||
#include "viewer/OsgViewer.h"
|
#include "viewer/OsgViewer.h"
|
||||||
|
|
||||||
#include "chartPlot/FitCurveDialog.h"
|
#include "chartPlot/FitCurveDialog.h"
|
||||||
@ -44,7 +45,6 @@ MainWindow::MainWindow(QWidget* parent)
|
|||||||
}
|
}
|
||||||
|
|
||||||
MainWindow::~MainWindow() {
|
MainWindow::~MainWindow() {
|
||||||
OsgViewer::Get().Uninitialize();
|
|
||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,8 +83,9 @@ void MainWindow::InitUI() {
|
|||||||
connect(modelBrowser_, &ModelBrowser::WorkSpaceChange, propertyBrowser_, &PropertyBrowser::OnWorkSpaceChange);
|
connect(modelBrowser_, &ModelBrowser::WorkSpaceChange, propertyBrowser_, &PropertyBrowser::OnWorkSpaceChange);
|
||||||
connect(modelBrowser_, &ModelBrowser::EntityChange, propertyBrowser_, &PropertyBrowser::OnEntityChange);
|
connect(modelBrowser_, &ModelBrowser::EntityChange, propertyBrowser_, &PropertyBrowser::OnEntityChange);
|
||||||
|
|
||||||
qtOsgViewWidget_ = new QtOsgViewWidget;
|
qtOsgViewWidget_ = new ViewWidget;
|
||||||
qtOsgViewWidget_->Initialize();
|
//qtOsgViewWidget_ = new OsgOpenGLWindow;
|
||||||
|
//qtOsgViewWidget_->Initialize();
|
||||||
m_mapDockWidget.insert("PropertyBrowser", attribte);
|
m_mapDockWidget.insert("PropertyBrowser", attribte);
|
||||||
|
|
||||||
QString wavePath ="", speedPath = "", rdPath = "", matlabParam="";
|
QString wavePath ="", speedPath = "", rdPath = "", matlabParam="";
|
||||||
@ -112,11 +113,13 @@ void MainWindow::InitUI() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DockWidget* fitCurveDock = new DockWidget(tr("Wave Curve"), 0);
|
DockWidget* fitCurveDock = new DockWidget(tr("Wave Curve"), 0);
|
||||||
|
|
||||||
fitCurveDlg_ = new FitCurveDialog(1);
|
fitCurveDlg_ = new FitCurveDialog(1);
|
||||||
fitCurveDlg_->AttachDock(fitCurveDock);
|
fitCurveDlg_->AttachDock(fitCurveDock);
|
||||||
m_mapDockWidget.insert("WaveCurveDialog", fitCurveDock);
|
m_mapDockWidget.insert("WaveCurveDialog", fitCurveDock);
|
||||||
|
|
||||||
fitCurveDlg_->InitWaveFile(wavePath);
|
fitCurveDlg_->InitWaveFile(wavePath);
|
||||||
|
|
||||||
DockWidget* fitLgCurveDock = new DockWidget(tr("Speed Curve"), 0);
|
DockWidget* fitLgCurveDock = new DockWidget(tr("Speed Curve"), 0);
|
||||||
|
|
||||||
fitYLgCurveDlg_ = new FitCurveDialog(1);
|
fitYLgCurveDlg_ = new FitCurveDialog(1);
|
||||||
@ -158,6 +161,31 @@ void MainWindow::InitUI() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
targetUI_ = new TargetListWgt;
|
||||||
|
//WorkSpaceManager::Get().SetTargetListWgt(targetUITable_);
|
||||||
|
|
||||||
|
QStringList headerLabels;
|
||||||
|
headerLabels << tr("Target number") << tr("Signal-to-noise ratio") //QString::fromLocal8Bit("目标编号") << QString::fromLocal8Bit("信噪比")
|
||||||
|
<< tr("Azimuth line of sight") << tr("Pitch gaze angle") // QString::fromLocal8Bit("方位视线角") << QString::fromLocal8Bit("俯仰视线角")
|
||||||
|
<< tr("azimuth") << tr("Pitch angle") // QString::fromLocal8Bit("方位角") << QString::fromLocal8Bit("俯仰角")
|
||||||
|
<< tr("attribute") << tr("Doppler") // QString::fromLocal8Bit("属性") << QString::fromLocal8Bit("多普勒")
|
||||||
|
<< tr("course") << tr("Speed") // QString::fromLocal8Bit("航向") << QString::fromLocal8Bit("航速")
|
||||||
|
<< tr("longitude") << tr("latitude") // QString::fromLocal8Bit("经度") << QString::fromLocal8Bit("纬度")
|
||||||
|
<< tr("distance") << tr("velocity") // QString::fromLocal8Bit("距离") << QString::fromLocal8Bit("速度")
|
||||||
|
<< tr("Radial dimensions") << tr("Target RCS"); // QString::fromLocal8Bit("径向尺寸") << QString::fromLocal8Bit("目标RCS");
|
||||||
|
|
||||||
|
targetUI_->SetHeader(headerLabels);
|
||||||
|
const QString reportPath = RecourceHelper::Get().GetBasePath() + "/workspace/Report.txt";
|
||||||
|
targetUI_->InitFile(reportPath, 50);
|
||||||
|
|
||||||
|
DockWidget* dataTableDock = new DockWidget(tr("Report"), 0);
|
||||||
|
// addDockWidget(pSettingUI->GetArea("TargetListWgt"), dataTableDock);
|
||||||
|
targetUI_->AttachDock(dataTableDock);
|
||||||
|
m_mapDockWidget.insert("TargetListWgt", dataTableDock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const QString lampPath = RecourceHelper::Get().GetBasePath() + "/workspace/Lamp.txt";
|
const QString lampPath = RecourceHelper::Get().GetBasePath() + "/workspace/Lamp.txt";
|
||||||
|
|
||||||
DockWidget* signalIndicatorLampDock = new DockWidget(tr("Signal Indicator Lamp"), 0);
|
DockWidget* signalIndicatorLampDock = new DockWidget(tr("Signal Indicator Lamp"), 0);
|
||||||
@ -172,7 +200,7 @@ void MainWindow::InitUI() {
|
|||||||
addParamDlg_->AttachDock(addParamSettingDock);
|
addParamDlg_->AttachDock(addParamSettingDock);
|
||||||
m_mapDockWidget.insert("ParamSetting", addParamSettingDock);
|
m_mapDockWidget.insert("ParamSetting", addParamSettingDock);
|
||||||
|
|
||||||
DockWidget* matlabDock = new DockWidget(tr("bat File"), 0);
|
DockWidget* matlabDock = new DockWidget(tr("Matlab File"), 0);
|
||||||
matlabFileDlg_ = new CodeEdtUI;
|
matlabFileDlg_ = new CodeEdtUI;
|
||||||
matlabFileDlg_->AttachDock(matlabDock);
|
matlabFileDlg_->AttachDock(matlabDock);
|
||||||
m_mapDockWidget.insert("Matlab", matlabDock);
|
m_mapDockWidget.insert("Matlab", matlabDock);
|
||||||
@ -183,13 +211,12 @@ void MainWindow::InitUI() {
|
|||||||
InitDockLayout();
|
InitDockLayout();
|
||||||
|
|
||||||
//ui->viewWidget->layout()->addWidget(qtOsgViewWidget_);
|
//ui->viewWidget->layout()->addWidget(qtOsgViewWidget_);
|
||||||
qtOsgViewWidget_->LoadDefaultScene();
|
//qtOsgViewWidget_->LoadDefaultScene();
|
||||||
OsgViewer::Get().Initialize();
|
|
||||||
OsgViewer::Get().OnFrame();
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// MatlabObject* mtlb = new MatlabObject;
|
MatlabObject* mtlb = new MatlabObject;
|
||||||
MatlabObject::GetInstance()->RunMatlabFile("");
|
mtlb->RunMatlabFile("D:\\DYT\\TestGUI\\TestGUI\\LDPlatformTest.m");
|
||||||
#endif // 1
|
#endif // 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,32 +225,26 @@ void MainWindow::InitDockLayout() {
|
|||||||
tabWidget_->removeTab(0);
|
tabWidget_->removeTab(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
tabWidget_->tabBar()->setExpanding(true);
|
|
||||||
|
|
||||||
QVariantList listTab = pSettingUI->GetAreaLayout().toList();
|
QVariantList listTab = pSettingUI->GetAreaLayout().toList();
|
||||||
for (int i = 0; i < listTab.size(); i++) {
|
for (int i = 0; i < listTab.size(); i++) {
|
||||||
QVariantMap mapTab = listTab[i].toMap();
|
QVariantMap mapTab = listTab[i].toMap();
|
||||||
QString strTabName = mapTab.value("Name").toString();
|
QString strTabName = mapTab.value("Name").toString();
|
||||||
|
|
||||||
CustomMainWindow* mainWindow_ = new CustomMainWindow;
|
QMainWindow* mainWindow_ = new QMainWindow;
|
||||||
mainWindow_->setDockOptions(QMainWindow::AllowNestedDocks |
|
|
||||||
QMainWindow::AllowTabbedDocks | QMainWindow::AnimatedDocks |
|
|
||||||
QMainWindow::ForceTabbedDocks | QMainWindow::VerticalTabs);
|
|
||||||
|
|
||||||
connect(mainWindow_, &QMainWindow::tabifiedDockWidgetActivated, this, &MainWindow::OnTabifiedDockWidgetActivated);
|
|
||||||
|
|
||||||
QVariantList listDocArea = mapTab.value("Widget").toList();
|
QVariantList listDocArea = mapTab.value("Widget").toList();
|
||||||
|
|
||||||
tabWidget_->insertTab(i, mainWindow_, strTabName);
|
tabWidget_->insertTab(i, mainWindow_, strTabName);
|
||||||
if (listDocArea[0].toList().size() > 0) {
|
if (listDocArea[0].toList().size() > 0) {
|
||||||
mainWindow_->setCentralWidget(qtOsgViewWidget_);
|
mainWindow_->setCentralWidget(qtOsgViewWidget_);
|
||||||
OsgViewer::Get().Initialize();
|
//mainWindow_->setCentralWidget(qtOsgViewWidget_->AsWidget());
|
||||||
OsgViewer::Get().OnFrame();
|
//OsgViewer::Get().Initialize();
|
||||||
}
|
//OsgViewer::Get().OnFrame();
|
||||||
else {
|
} else {
|
||||||
mainWindow_->takeCentralWidget();
|
mainWindow_->takeCentralWidget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (listDocArea.size() > 0) {
|
if (listDocArea.size() > 0) {
|
||||||
QDockWidget* lastDock = nullptr;
|
QDockWidget* lastDock = nullptr;
|
||||||
|
|
||||||
@ -231,14 +252,11 @@ void MainWindow::InitDockLayout() {
|
|||||||
Qt::DockWidgetArea dockArea;
|
Qt::DockWidgetArea dockArea;
|
||||||
if (j == 1) {
|
if (j == 1) {
|
||||||
dockArea = Qt::LeftDockWidgetArea;
|
dockArea = Qt::LeftDockWidgetArea;
|
||||||
}
|
} else if (j == 2) {
|
||||||
else if (j == 2) {
|
|
||||||
dockArea = Qt::TopDockWidgetArea;
|
dockArea = Qt::TopDockWidgetArea;
|
||||||
}
|
} else if (j == 3) {
|
||||||
else if (j == 3) {
|
|
||||||
dockArea = Qt::RightDockWidgetArea;
|
dockArea = Qt::RightDockWidgetArea;
|
||||||
}
|
} else if (j == 4) {
|
||||||
else if (j == 4) {
|
|
||||||
dockArea = Qt::BottomDockWidgetArea;
|
dockArea = Qt::BottomDockWidgetArea;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,8 +271,7 @@ void MainWindow::InitDockLayout() {
|
|||||||
}
|
}
|
||||||
mainWindow_->addDockWidget(dockArea, pDock);
|
mainWindow_->addDockWidget(dockArea, pDock);
|
||||||
lastDock = pDock;
|
lastDock = pDock;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
QVariantList listWidget = varWidget.toList();
|
QVariantList listWidget = varWidget.toList();
|
||||||
for (int k = 0; k < listWidget.size(); k++) {
|
for (int k = 0; k < listWidget.size(); k++) {
|
||||||
QDockWidget* pDock = m_mapDockWidget.value(listWidget[k].toString());
|
QDockWidget* pDock = m_mapDockWidget.value(listWidget[k].toString());
|
||||||
@ -264,8 +281,7 @@ void MainWindow::InitDockLayout() {
|
|||||||
if (lastDock) {
|
if (lastDock) {
|
||||||
mainWindow_->splitDockWidget(lastDock, pDock, Qt::Vertical);
|
mainWindow_->splitDockWidget(lastDock, pDock, Qt::Vertical);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
mainWindow_->splitDockWidget(lastDock, pDock, Qt::Horizontal);
|
mainWindow_->splitDockWidget(lastDock, pDock, Qt::Horizontal);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -277,8 +293,6 @@ void MainWindow::InitDockLayout() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tabWidget_->tabBar()->setMinimumWidth(500);
|
|
||||||
|
|
||||||
/* AddDockArea("DockLeftArea");
|
/* AddDockArea("DockLeftArea");
|
||||||
AddDockArea("DockTopArea");
|
AddDockArea("DockTopArea");
|
||||||
AddDockArea("DockRightArea");
|
AddDockArea("DockRightArea");
|
||||||
@ -292,20 +306,16 @@ void MainWindow::AddDockArea(const QString& strArea) {
|
|||||||
if (strArea == "DockLeftArea") {
|
if (strArea == "DockLeftArea") {
|
||||||
dockArea = Qt::LeftDockWidgetArea;
|
dockArea = Qt::LeftDockWidgetArea;
|
||||||
orient = Qt::Vertical;
|
orient = Qt::Vertical;
|
||||||
}
|
} else if (strArea == "DockTopArea") {
|
||||||
else if (strArea == "DockTopArea") {
|
|
||||||
dockArea = Qt::TopDockWidgetArea;
|
dockArea = Qt::TopDockWidgetArea;
|
||||||
orient = Qt::Horizontal;
|
orient = Qt::Horizontal;
|
||||||
}
|
} else if (strArea == "DockRightArea") {
|
||||||
else if (strArea == "DockRightArea") {
|
|
||||||
dockArea = Qt::RightDockWidgetArea;
|
dockArea = Qt::RightDockWidgetArea;
|
||||||
orient = Qt::Vertical;
|
orient = Qt::Vertical;
|
||||||
}
|
} else if (strArea == "DockBottomArea") {
|
||||||
else if (strArea == "DockBottomArea") {
|
|
||||||
dockArea = Qt::BottomDockWidgetArea;
|
dockArea = Qt::BottomDockWidgetArea;
|
||||||
orient = Qt::Horizontal;
|
orient = Qt::Horizontal;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,8 +330,7 @@ void MainWindow::AddDockArea(const QString& strArea) {
|
|||||||
addDockWidget(dockArea, pDock);
|
addDockWidget(dockArea, pDock);
|
||||||
|
|
||||||
listAdd.push_back(pDock);
|
listAdd.push_back(pDock);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
QDockWidget* pLastDock = nullptr;
|
QDockWidget* pLastDock = nullptr;
|
||||||
QVariantList listTab = varWidget.toList();
|
QVariantList listTab = varWidget.toList();
|
||||||
for each(QVariant tabChild in listTab) {
|
for each(QVariant tabChild in listTab) {
|
||||||
@ -348,22 +357,6 @@ void MainWindow::AddDockArea(const QString& strArea) {
|
|||||||
resizeDocks(listAdd, listSpliter, orient);
|
resizeDocks(listAdd, listSpliter, orient);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::SaveDockStatus()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::OnTabifiedDockWidgetActivated(QDockWidget* dockWidget) {
|
|
||||||
//if (dockWidget) {
|
|
||||||
// QMainWindow* mainWindow = qobject_cast<QMainWindow*>(dockWidget->parentWidget());
|
|
||||||
// if (mainWindow) {
|
|
||||||
// mainWindow->removeDockWidget(dockWidget);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // tabWidget_->setCurrentWidget(dockWidget->parentWidget());
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::slotShowUISetting() {
|
void MainWindow::slotShowUISetting() {
|
||||||
pSettingUI->show();
|
pSettingUI->show();
|
||||||
}
|
}
|
||||||
@ -375,20 +368,17 @@ void MainWindow::slotResetWorkSpace()
|
|||||||
{
|
{
|
||||||
if (!WorkSpaceManager::Get().GetCurrent()->GetWavePath().isEmpty())
|
if (!WorkSpaceManager::Get().GetCurrent()->GetWavePath().isEmpty())
|
||||||
{
|
{
|
||||||
wavePath = WorkSpaceManager::Get().GetCurrent()->GetWavePath();
|
wavePath = RecourceHelper::Get().GetBasePath() + "/" + WorkSpaceManager::Get().GetCurrent()->GetWavePath();
|
||||||
//wavePath = RecourceHelper::Get().GetBasePath() + "/" + WorkSpaceManager::Get().GetCurrent()->GetWavePath();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!WorkSpaceManager::Get().GetCurrent()->GetReportPath().isEmpty())
|
if (!WorkSpaceManager::Get().GetCurrent()->GetReportPath().isEmpty())
|
||||||
{
|
{
|
||||||
speedPath = WorkSpaceManager::Get().GetCurrent()->GetReportPath();
|
speedPath = RecourceHelper::Get().GetBasePath() + "/" + WorkSpaceManager::Get().GetCurrent()->GetReportPath();
|
||||||
//speedPath = RecourceHelper::Get().GetBasePath() + "/" + WorkSpaceManager::Get().GetCurrent()->GetReportPath();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!WorkSpaceManager::Get().GetCurrent()->GetRDPath().isEmpty())
|
if (!WorkSpaceManager::Get().GetCurrent()->GetRDPath().isEmpty())
|
||||||
{
|
{
|
||||||
rdPath = WorkSpaceManager::Get().GetCurrent()->GetRDPath();
|
rdPath = RecourceHelper::Get().GetBasePath() + "/" + WorkSpaceManager::Get().GetCurrent()->GetRDPath();
|
||||||
//rdPath = RecourceHelper::Get().GetBasePath() + "/" + WorkSpaceManager::Get().GetCurrent()->GetRDPath();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,9 +21,9 @@ public:
|
|||||||
class ModelBrowser* GetModelBrowser() const {
|
class ModelBrowser* GetModelBrowser() const {
|
||||||
return modelBrowser_;
|
return modelBrowser_;
|
||||||
}
|
}
|
||||||
class QtOsgViewWidget* GetViewWidget() const {
|
/*class ViewWidget* GetViewWidget() const {
|
||||||
return qtOsgViewWidget_;
|
return qtOsgViewWidget_;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
class FitCurveDialog* GetFitCurveDlg() const {
|
class FitCurveDialog* GetFitCurveDlg() const {
|
||||||
return fitCurveDlg_;
|
return fitCurveDlg_;
|
||||||
@ -46,10 +46,8 @@ private:
|
|||||||
void InitDockLayout();
|
void InitDockLayout();
|
||||||
void AddDockArea(const QString& strArea);
|
void AddDockArea(const QString& strArea);
|
||||||
|
|
||||||
void SaveDockStatus();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void OnTabifiedDockWidgetActivated(QDockWidget* dockWidget);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::MainWindow* ui;
|
Ui::MainWindow* ui;
|
||||||
@ -57,12 +55,14 @@ private:
|
|||||||
class ModelBrowser* modelBrowser_{ nullptr };
|
class ModelBrowser* modelBrowser_{ nullptr };
|
||||||
class PropertyBrowser* propertyBrowser_{ nullptr };
|
class PropertyBrowser* propertyBrowser_{ nullptr };
|
||||||
class QWebEngineView* webEngineView_{ nullptr };
|
class QWebEngineView* webEngineView_{ nullptr };
|
||||||
class QtOsgViewWidget* qtOsgViewWidget_{ nullptr };
|
class ViewWidget* qtOsgViewWidget_{ nullptr };
|
||||||
|
//class OsgOpenGLWindow* qtOsgViewWidget_{ nullptr };
|
||||||
|
|
||||||
class FitCurveDialog* fitCurveDlg_{ nullptr };
|
class FitCurveDialog* fitCurveDlg_{ nullptr };
|
||||||
class FitCurveDialog* fitYLgCurveDlg_{ nullptr };
|
class FitCurveDialog* fitYLgCurveDlg_{ nullptr };
|
||||||
class SurfaceDialog* surfaceDlg_{ nullptr };
|
class SurfaceDialog* surfaceDlg_{ nullptr };
|
||||||
class LayoutSettingUI* pSettingUI{ nullptr };
|
class LayoutSettingUI* pSettingUI{ nullptr };
|
||||||
|
class TargetListWgt* targetUI_{ nullptr };
|
||||||
class TargetListWgt* targetUITable_{ nullptr };
|
class TargetListWgt* targetUITable_{ nullptr };
|
||||||
class QTabWidget* tabWidget_{ nullptr };
|
class QTabWidget* tabWidget_{ nullptr };
|
||||||
class SignalIndicatorLampUI* signalIndicatorLampUI_{ nullptr };
|
class SignalIndicatorLampUI* signalIndicatorLampUI_{ nullptr };
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
#include "MatlabObject.h"
|
#include "MatlabObject.h"
|
||||||
|
|
||||||
#include <QTextCodec>
|
#include <QTextCodec>
|
||||||
#include <QFile>
|
|
||||||
#include <QTextStream>
|
|
||||||
#include <qDebug>
|
|
||||||
#include "engine.h"
|
#include "engine.h"
|
||||||
|
|
||||||
MatlabObject::MatlabObject(QObject *parent)
|
MatlabObject::MatlabObject(QObject *parent)
|
||||||
@ -17,16 +15,6 @@ MatlabObject::~MatlabObject()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MatlabObject* MatlabObject::m_pInstance = nullptr;
|
|
||||||
MatlabObject* MatlabObject::GetInstance()
|
|
||||||
{
|
|
||||||
if (!m_pInstance)
|
|
||||||
{
|
|
||||||
m_pInstance = new MatlabObject;
|
|
||||||
}
|
|
||||||
return m_pInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MatlabObject::RunMatlabFile(const QString& strFile)
|
void MatlabObject::RunMatlabFile(const QString& strFile)
|
||||||
{
|
{
|
||||||
QString strMatlabRun = QString("run('%1')").arg(strFile);
|
QString strMatlabRun = QString("run('%1')").arg(strFile);
|
||||||
@ -35,27 +23,11 @@ void MatlabObject::RunMatlabFile(const QString& strFile)
|
|||||||
std::string strRun = code->fromUnicode(strMatlabRun.toUtf8().data()).data();
|
std::string strRun = code->fromUnicode(strMatlabRun.toUtf8().data()).data();
|
||||||
|
|
||||||
Engine* ep;
|
Engine* ep;
|
||||||
if (!(ep = engOpen(nullptr))) {
|
if (!(ep = engOpen("\0"))) {
|
||||||
fprintf(stderr, "\nCan't start MATLAB engine\n");
|
fprintf(stderr, "\nCan't start MATLAB engine\n");
|
||||||
return; // EXIT_FAILURE;
|
return; // EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strFile.isEmpty())
|
|
||||||
{
|
|
||||||
engEvalString(ep, strRun.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*engEvalString(ep, "shu=666666;");
|
|
||||||
engEvalString(ep, "fileItgt1 = fopen('tgt1.txt', 'w');");
|
|
||||||
engEvalString(ep, "if fileItgt1 == -1");
|
|
||||||
engEvalString(ep, " error('ÎÞ·¨´ò¿ªÎļþ');");
|
|
||||||
engEvalString(ep, "end");
|
|
||||||
|
|
||||||
engEvalString(ep, "fprintf(fileItgt1, '%f ', shu);");
|
|
||||||
engEvalString(ep, "fprintf(fileItgt1, '\n');");
|
|
||||||
engEvalString(ep, "fclose(fileItgt1);");*/
|
|
||||||
|
|
||||||
engClose(ep);
|
engClose(ep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,13 +10,9 @@ public:
|
|||||||
MatlabObject(QObject *parent=nullptr);
|
MatlabObject(QObject *parent=nullptr);
|
||||||
~MatlabObject();
|
~MatlabObject();
|
||||||
|
|
||||||
static MatlabObject* MatlabObject::GetInstance();
|
|
||||||
|
|
||||||
void RunMatlabFile(const QString& strFile);
|
void RunMatlabFile(const QString& strFile);
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//std::u16string string2u16string(std::string& str);
|
//std::u16string string2u16string(std::string& str);
|
||||||
|
|
||||||
static MatlabObject* MatlabObject::m_pInstance;
|
|
||||||
};
|
};
|
||||||
|
@ -6,8 +6,6 @@
|
|||||||
#include "workspace/WorkSpaceManager.h"
|
#include "workspace/WorkSpaceManager.h"
|
||||||
#include <qmessagebox.h>
|
#include <qmessagebox.h>
|
||||||
|
|
||||||
#include <qfiledialog.h>
|
|
||||||
|
|
||||||
ChartPlotMenu::ChartPlotMenu(QWidget *parent)
|
ChartPlotMenu::ChartPlotMenu(QWidget *parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
{
|
{
|
||||||
@ -26,10 +24,13 @@ void ChartPlotMenu::InitMenu()
|
|||||||
connect(ui.toolButton, &QToolButton::clicked, this, [=] {
|
connect(ui.toolButton, &QToolButton::clicked, this, [=] {
|
||||||
if (WorkSpaceManager::Get().GetCurrent())
|
if (WorkSpaceManager::Get().GetCurrent())
|
||||||
{
|
{
|
||||||
|
MatlabObject mtlb;
|
||||||
QString strFile = WorkSpaceManager::Get().GetCurrent()->GetSimMatlab();
|
QString strFile = WorkSpaceManager::Get().GetCurrent()->GetSimMatlab();
|
||||||
if (!strFile.isEmpty())
|
if (!strFile.isEmpty())
|
||||||
{
|
{
|
||||||
MatlabObject::GetInstance()->RunMatlabFile(strFile);
|
strFile = RecourceHelper::Get().GetBasePath() + "/" + WorkSpaceManager::Get().GetCurrent()->GetSimMatlab();
|
||||||
|
|
||||||
|
mtlb.RunMatlabFile(strFile);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -37,147 +38,4 @@ void ChartPlotMenu::InitMenu()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(ui.toolButton_2, &QToolButton::clicked, this, [=] {
|
|
||||||
auto current = WorkSpaceManager::Get().GetCurrent();
|
|
||||||
if (nullptr == current) {
|
|
||||||
QMessageBox::information(nullptr, QString::fromLocal8Bit("提示"), QString::fromLocal8Bit("请先创建空间!"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
QString strSel = QFileDialog::getOpenFileName(this, u8"选择仿真运行文件", RecourceHelper::Get().GetBasePath() + "/workspace/", "*.m");
|
|
||||||
if (strSel.isEmpty()) {
|
|
||||||
LOG_WARN("选择文件为空");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString old = current->GetSimMatlab();
|
|
||||||
if (old == strSel) {
|
|
||||||
LOG_INFO("选择文件与当前文件相同");
|
|
||||||
return;
|
|
||||||
} else if (!old.isEmpty()) {
|
|
||||||
if (QMessageBox::Yes == QMessageBox::question(nullptr,
|
|
||||||
QString::fromLocal8Bit("询问"),
|
|
||||||
QString::fromLocal8Bit("替换当前仿真文件!"),
|
|
||||||
QMessageBox::Yes | QMessageBox::No)
|
|
||||||
) {
|
|
||||||
if (!QFile::remove(old)) {
|
|
||||||
LOG_WARN("删除文件失败");
|
|
||||||
QMessageBox::information(nullptr,
|
|
||||||
QString::fromLocal8Bit("提示"),
|
|
||||||
QString::fromLocal8Bit("删除文件失败!"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
current->SetSimMatlab(strSel);
|
|
||||||
});
|
|
||||||
|
|
||||||
connect(ui.toolButton_5, &QToolButton::clicked, this, [=] {
|
|
||||||
auto current = WorkSpaceManager::Get().GetCurrent();
|
|
||||||
if (nullptr == current) {
|
|
||||||
QMessageBox::information(nullptr, QString::fromLocal8Bit("提示"), QString::fromLocal8Bit("请先创建空间!"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
QString strSel = QFileDialog::getOpenFileName(this, u8"选择Wave文件", RecourceHelper::Get().GetBasePath() + "/workspace/", "*.txt");
|
|
||||||
if (strSel.isEmpty()) {
|
|
||||||
LOG_WARN("选择文件为空");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString old = current->GetWavePath();
|
|
||||||
if (old == strSel) {
|
|
||||||
LOG_INFO("选择文件与当前文件相同");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (!old.isEmpty()) {
|
|
||||||
if (QMessageBox::Yes == QMessageBox::question(nullptr,
|
|
||||||
QString::fromLocal8Bit("询问"),
|
|
||||||
QString::fromLocal8Bit("替换当前Wave文件!"),
|
|
||||||
QMessageBox::Yes | QMessageBox::No)
|
|
||||||
) {
|
|
||||||
if (!QFile::remove(old)) {
|
|
||||||
LOG_WARN("删除文件失败");
|
|
||||||
QMessageBox::information(nullptr,
|
|
||||||
QString::fromLocal8Bit("提示"),
|
|
||||||
QString::fromLocal8Bit("删除文件失败!"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
current->SetWavePath(strSel);
|
|
||||||
});
|
|
||||||
|
|
||||||
connect(ui.toolButton_3, &QToolButton::clicked, this, [=] {
|
|
||||||
auto current = WorkSpaceManager::Get().GetCurrent();
|
|
||||||
if (nullptr == current) {
|
|
||||||
QMessageBox::information(nullptr, QString::fromLocal8Bit("提示"), QString::fromLocal8Bit("请先创建空间!"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
QString strSel = QFileDialog::getOpenFileName(this, u8"选择RD文件", RecourceHelper::Get().GetBasePath() + "/workspace/", "*.txt");
|
|
||||||
if (strSel.isEmpty()) {
|
|
||||||
LOG_WARN("选择文件为空");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString old = current->GetRDPath();
|
|
||||||
if (old == strSel) {
|
|
||||||
LOG_INFO("选择文件与当前文件相同");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (!old.isEmpty()) {
|
|
||||||
if (QMessageBox::Yes == QMessageBox::question(nullptr,
|
|
||||||
QString::fromLocal8Bit("询问"),
|
|
||||||
QString::fromLocal8Bit("替换当前RD文件!"),
|
|
||||||
QMessageBox::Yes | QMessageBox::No)
|
|
||||||
) {
|
|
||||||
if (!QFile::remove(old)) {
|
|
||||||
LOG_WARN("删除文件失败");
|
|
||||||
QMessageBox::information(nullptr,
|
|
||||||
QString::fromLocal8Bit("提示"),
|
|
||||||
QString::fromLocal8Bit("删除文件失败!"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
current->SetRDPath(strSel);
|
|
||||||
});
|
|
||||||
|
|
||||||
connect(ui.toolButton_4, &QToolButton::clicked, this, [=] {
|
|
||||||
auto current = WorkSpaceManager::Get().GetCurrent();
|
|
||||||
if (nullptr == current) {
|
|
||||||
QMessageBox::information(nullptr, QString::fromLocal8Bit("提示"), QString::fromLocal8Bit("请先创建空间!"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
QString strSel = QFileDialog::getOpenFileName(this, u8"选择Report文件", RecourceHelper::Get().GetBasePath() + "/workspace/", "*.txt");
|
|
||||||
if (strSel.isEmpty()) {
|
|
||||||
LOG_WARN("选择文件为空");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString old = current->GetReportPath();
|
|
||||||
if (old == strSel) {
|
|
||||||
LOG_INFO("选择文件与当前文件相同");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (!old.isEmpty()) {
|
|
||||||
if (QMessageBox::Yes == QMessageBox::question(nullptr,
|
|
||||||
QString::fromLocal8Bit("询问"),
|
|
||||||
QString::fromLocal8Bit("替换当前Report文件!"),
|
|
||||||
QMessageBox::Yes | QMessageBox::No)
|
|
||||||
) {
|
|
||||||
if (!QFile::remove(old)) {
|
|
||||||
LOG_WARN("删除文件失败");
|
|
||||||
QMessageBox::information(nullptr,
|
|
||||||
QString::fromLocal8Bit("提示"),
|
|
||||||
QString::fromLocal8Bit("删除文件失败!"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
current->SetReportPath(strSel);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
@ -21,4 +21,5 @@ signals:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::ChartPlotMenuClass ui;
|
Ui::ChartPlotMenuClass ui;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -16,58 +16,6 @@
|
|||||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
<item>
|
|
||||||
<widget class="QToolButton" name="toolButton_5">
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>60</width>
|
|
||||||
<height>30</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Wave文件</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QToolButton" name="toolButton_4">
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>60</width>
|
|
||||||
<height>30</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Report文件</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QToolButton" name="toolButton_3">
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>60</width>
|
|
||||||
<height>30</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>RD文件</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QToolButton" name="toolButton_2">
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>60</width>
|
|
||||||
<height>30</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Matlab文件</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<widget class="QToolButton" name="toolButton">
|
<widget class="QToolButton" name="toolButton">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
#include "common/SpdLogger.h"
|
#include "common/SpdLogger.h"
|
||||||
#include "workspace/WorkSpace.h"
|
#include "workspace/WorkSpace.h"
|
||||||
#include "workspace/WorkSpaceManager.h"
|
#include "workspace/WorkSpaceManager.h"
|
||||||
#include "utils/FileUtils.h"
|
|
||||||
|
|
||||||
#include "ui_FileManagerMenu.h"
|
#include "ui_FileManagerMenu.h"
|
||||||
|
|
||||||
@ -58,30 +57,22 @@ void FileManagerMenu::OpenWorkSpace() {
|
|||||||
|
|
||||||
void FileManagerMenu::SaveWorkSpace() {
|
void FileManagerMenu::SaveWorkSpace() {
|
||||||
LOG_INFO("click SaveWorkSpace");
|
LOG_INFO("click SaveWorkSpace");
|
||||||
|
|
||||||
WorkSpace* workspace = WorkSpaceManager::Get().GetCurrent();
|
|
||||||
if (nullptr == workspace) {
|
|
||||||
LOG_WARN("workspace is nullptr");
|
|
||||||
QMessageBox::warning(&MainFrame::Get(), tr("warning"), tr("workspace is nullptr"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString name = workspace->GetName();
|
|
||||||
QString dytFile = workspace->GetPath();
|
|
||||||
LOG_INFO("save {} dyt file: {}", name.toLocal8Bit().constData(),
|
|
||||||
dytFile.toLocal8Bit().constData());
|
|
||||||
/* if (!FileUtils::IsExist(dytFile)) {
|
|
||||||
QString selfilter = tr("Dyt (*.dyt)");
|
QString selfilter = tr("Dyt (*.dyt)");
|
||||||
|
|
||||||
const QString workspacePath = Application::GetWorkSpacePath();
|
const QString workspacePath = Application::GetWorkSpacePath();
|
||||||
dytFile = QFileDialog::getSaveFileName(&MainFrame::Get(), tr("save dyt file"), workspacePath,
|
QString dytFile = QFileDialog::getSaveFileName(&MainFrame::Get(), tr("save dyt file"), workspacePath,
|
||||||
tr("Dyt (*.dyt);;All files (*.*)"),
|
tr("Dyt (*.dyt);;All files (*.*)"),
|
||||||
&selfilter);
|
&selfilter);
|
||||||
LOG_INFO("user select file: {}", dytFile.toLocal8Bit().constData());
|
LOG_INFO("user select file: {}", dytFile.toStdString());
|
||||||
if (dytFile.isEmpty()) {
|
if (dytFile.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
}*/
|
WorkSpace* workspace = WorkSpaceManager::Get().GetCurrent();
|
||||||
|
if (nullptr == workspace) {
|
||||||
|
LOG_WARN("workspace is nullptr");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
bool success = workspace->Save(dytFile);
|
bool success = workspace->Save(dytFile);
|
||||||
LOG_INFO("save dyt: {}", success);
|
LOG_INFO("save dyt: {}", success);
|
||||||
|
@ -31,14 +31,14 @@ PlayManagerMenu::~PlayManagerMenu() {
|
|||||||
void PlayManagerMenu::OnPlay() {
|
void PlayManagerMenu::OnPlay() {
|
||||||
workSpace_ = WorkSpaceManager::Get().GetCurrent();
|
workSpace_ = WorkSpaceManager::Get().GetCurrent();
|
||||||
if (nullptr == workSpace_) {
|
if (nullptr == workSpace_) {
|
||||||
QMessageBox::warning(&MainFrame::Get(), tr("warning"), tr("has not workspace"),
|
QMessageBox::warning(&MainFrame::Get(), tr("question"), tr("has not workspace"),
|
||||||
QMessageBox::Ok);
|
QMessageBox::Ok);
|
||||||
LOG_INFO("current is nullptr");
|
LOG_INFO("current is nullptr");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Timestep* timestep = workSpace_->GetTimestep();
|
Timestep* timestep = workSpace_->GetTimestep();
|
||||||
if (nullptr == timestep) {
|
if (nullptr == timestep) {
|
||||||
QMessageBox::warning(&MainFrame::Get(), tr("warning"), tr("has not workspace"),
|
QMessageBox::warning(&MainFrame::Get(), tr("question"), tr("has not workspace"),
|
||||||
QMessageBox::Ok);
|
QMessageBox::Ok);
|
||||||
LOG_INFO("current is nullptr");
|
LOG_INFO("current is nullptr");
|
||||||
return;
|
return;
|
||||||
@ -60,14 +60,14 @@ void PlayManagerMenu::OnPlay() {
|
|||||||
void PlayManagerMenu::OnStop() {
|
void PlayManagerMenu::OnStop() {
|
||||||
workSpace_ = WorkSpaceManager::Get().GetCurrent();
|
workSpace_ = WorkSpaceManager::Get().GetCurrent();
|
||||||
if (nullptr == workSpace_) {
|
if (nullptr == workSpace_) {
|
||||||
QMessageBox::warning(&MainFrame::Get(), tr("warning"), tr("has not workspace"),
|
QMessageBox::warning(&MainFrame::Get(), tr("question"), tr("has not workspace"),
|
||||||
QMessageBox::Ok);
|
QMessageBox::Ok);
|
||||||
LOG_INFO("current is nullptr");
|
LOG_INFO("current is nullptr");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Timestep* timestep = workSpace_->GetTimestep();
|
Timestep* timestep = workSpace_->GetTimestep();
|
||||||
if (nullptr == timestep) {
|
if (nullptr == timestep) {
|
||||||
QMessageBox::warning(&MainFrame::Get(), tr("warning"), tr("has not workspace"),
|
QMessageBox::warning(&MainFrame::Get(), tr("question"), tr("has not workspace"),
|
||||||
QMessageBox::Ok);
|
QMessageBox::Ok);
|
||||||
LOG_INFO("current is nullptr");
|
LOG_INFO("current is nullptr");
|
||||||
return;
|
return;
|
||||||
@ -78,14 +78,14 @@ void PlayManagerMenu::OnStop() {
|
|||||||
void PlayManagerMenu::OnUp() {
|
void PlayManagerMenu::OnUp() {
|
||||||
workSpace_ = WorkSpaceManager::Get().GetCurrent();
|
workSpace_ = WorkSpaceManager::Get().GetCurrent();
|
||||||
if (nullptr == workSpace_) {
|
if (nullptr == workSpace_) {
|
||||||
QMessageBox::warning(&MainFrame::Get(), tr("warning"), tr("has not workspace"),
|
QMessageBox::warning(&MainFrame::Get(), tr("question"), tr("has not workspace"),
|
||||||
QMessageBox::Ok);
|
QMessageBox::Ok);
|
||||||
LOG_INFO("current is nullptr");
|
LOG_INFO("current is nullptr");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Timestep* timestep = workSpace_->GetTimestep();
|
Timestep* timestep = workSpace_->GetTimestep();
|
||||||
if (nullptr == timestep) {
|
if (nullptr == timestep) {
|
||||||
QMessageBox::warning(&MainFrame::Get(), tr("warning"), tr("has not workspace"),
|
QMessageBox::warning(&MainFrame::Get(), tr("question"), tr("has not workspace"),
|
||||||
QMessageBox::Ok);
|
QMessageBox::Ok);
|
||||||
LOG_INFO("current is nullptr");
|
LOG_INFO("current is nullptr");
|
||||||
return;
|
return;
|
||||||
@ -96,14 +96,14 @@ void PlayManagerMenu::OnUp() {
|
|||||||
void PlayManagerMenu::OnDown() {
|
void PlayManagerMenu::OnDown() {
|
||||||
workSpace_ = WorkSpaceManager::Get().GetCurrent();
|
workSpace_ = WorkSpaceManager::Get().GetCurrent();
|
||||||
if (nullptr == workSpace_) {
|
if (nullptr == workSpace_) {
|
||||||
QMessageBox::warning(&MainFrame::Get(), tr("warning"), tr("has not workspace"),
|
QMessageBox::warning(&MainFrame::Get(), tr("question"), tr("has not workspace"),
|
||||||
QMessageBox::Ok);
|
QMessageBox::Ok);
|
||||||
LOG_INFO("current is nullptr");
|
LOG_INFO("current is nullptr");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Timestep* timestep = workSpace_->GetTimestep();
|
Timestep* timestep = workSpace_->GetTimestep();
|
||||||
if (nullptr == timestep) {
|
if (nullptr == timestep) {
|
||||||
QMessageBox::warning(&MainFrame::Get(), tr("warning"), tr("has not workspace"),
|
QMessageBox::warning(&MainFrame::Get(), tr("question"), tr("has not workspace"),
|
||||||
QMessageBox::Ok);
|
QMessageBox::Ok);
|
||||||
LOG_INFO("current is nullptr");
|
LOG_INFO("current is nullptr");
|
||||||
return;
|
return;
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
#include "common/SpdLogger.h"
|
#include "common/SpdLogger.h"
|
||||||
#include "ui/MainFrame.h"
|
#include "ui/MainFrame.h"
|
||||||
#include "ui/DockWidget.h"
|
|
||||||
|
|
||||||
#include "ui_SystemManagerMenu.h"
|
#include "ui_SystemManagerMenu.h"
|
||||||
|
|
||||||
@ -14,42 +13,14 @@ SystemManagerMenu::SystemManagerMenu(QWidget* parent)
|
|||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
InitConnect();
|
InitConnect();
|
||||||
LOG_INFO("SystemManagerMenu init");
|
|
||||||
windowManagerMenu_ = new QMenu(this);
|
|
||||||
windowManagerMenu_->setWindowFlags(windowManagerMenu_->windowFlags() | Qt::FramelessWindowHint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SystemManagerMenu::~SystemManagerMenu() {
|
SystemManagerMenu::~SystemManagerMenu() {
|
||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemManagerMenu::AddDockWidget(class DockWidget* dockWidget) {
|
|
||||||
QAction* action = new QAction(dockWidget->windowTitle(), this);
|
|
||||||
connect(dockWidget, &DockWidget::windowTitleChanged, [action](const QString& title) {
|
|
||||||
action->setText(title);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
action->setCheckable(true);
|
|
||||||
action->setChecked(!dockWidget->isVisible());
|
|
||||||
connect(action, &QAction::triggered, [dockWidget, action]() {
|
|
||||||
dockWidget->setVisible(action->isChecked());
|
|
||||||
}
|
|
||||||
);
|
|
||||||
connect(dockWidget, &DockWidget::signalClose, [action]() {
|
|
||||||
action->setChecked(false);
|
|
||||||
});
|
|
||||||
windowManagerMenu_->addAction(action);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SystemManagerMenu::RemoveDockWidget(class DockWidget* dockWidget) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void SystemManagerMenu::InitConnect() {
|
void SystemManagerMenu::InitConnect() {
|
||||||
connect(ui->menu_exit, &QToolButton::clicked, this, &SystemManagerMenu::OnExit);
|
connect(ui->menu_exit, &QToolButton::clicked, this, &SystemManagerMenu::OnExit);
|
||||||
//ui->menu_window_manager->setContextMenuPolicy(Qt::CustomContextMenu);
|
|
||||||
connect(ui->menu_window_manager, &QToolButton::clicked,
|
|
||||||
this, &SystemManagerMenu::OnWindowManagerMenu);
|
|
||||||
connect(ui->menu_uisetting, &QToolButton::clicked, this, &SystemManagerMenu::signalShowUISetting);
|
connect(ui->menu_uisetting, &QToolButton::clicked, this, &SystemManagerMenu::signalShowUISetting);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,9 +32,3 @@ void SystemManagerMenu::OnExit() {
|
|||||||
qApp->quit();
|
qApp->quit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemManagerMenu::OnWindowManagerMenu() {
|
|
||||||
// Ìí¼Ó´°¿Ú¹ÜÀí²Ëµ¥
|
|
||||||
LOG_INFO("add window manager menu");
|
|
||||||
windowManagerMenu_->exec(QCursor::pos());
|
|
||||||
}
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QMenu>
|
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class SystemManagerMenu;
|
class SystemManagerMenu;
|
||||||
@ -14,9 +13,6 @@ public:
|
|||||||
SystemManagerMenu(QWidget* parent = 0);
|
SystemManagerMenu(QWidget* parent = 0);
|
||||||
~SystemManagerMenu() override;
|
~SystemManagerMenu() override;
|
||||||
|
|
||||||
void AddDockWidget(class DockWidget* dockWidget);
|
|
||||||
void RemoveDockWidget(class DockWidget* dockWidget);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void InitConnect();
|
void InitConnect();
|
||||||
|
|
||||||
@ -25,9 +21,7 @@ signals:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void OnExit();
|
void OnExit();
|
||||||
void OnWindowManagerMenu();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::SystemManagerMenu* ui;
|
Ui::SystemManagerMenu* ui;
|
||||||
QMenu* windowManagerMenu_{ nullptr };
|
|
||||||
};
|
};
|
@ -34,16 +34,6 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<widget class="QToolButton" name="menu_window_manager">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>ui setting</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<widget class="QToolButton" name="menu_uisetting">
|
<widget class="QToolButton" name="menu_uisetting">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#include "ViewManagerMenu.h"
|
#include "ViewManagerMenu.h"
|
||||||
|
|
||||||
#include "ui/DockWidget.h"
|
|
||||||
#include "ui_ViewManagerMenu.h"
|
#include "ui_ViewManagerMenu.h"
|
||||||
|
|
||||||
ViewManagerMenu::ViewManagerMenu(QWidget* parent)
|
ViewManagerMenu::ViewManagerMenu(QWidget* parent)
|
||||||
|
@ -1,52 +0,0 @@
|
|||||||
#include "ui/Menu/WindowManagerMenu.h"
|
|
||||||
|
|
||||||
#include <QMessageBox>
|
|
||||||
|
|
||||||
#include "ui/MainFrame.h"
|
|
||||||
#include "ui/DockWidget.h"
|
|
||||||
#include "common/SpdLogger.h"
|
|
||||||
|
|
||||||
#include "ui_WindowManagerMenu.h"
|
|
||||||
|
|
||||||
const int DockWidgetRole = Qt::UserRole + 1;
|
|
||||||
|
|
||||||
WindowManagerMenu::WindowManagerMenu(QWidget* parent)
|
|
||||||
: QWidget(parent)
|
|
||||||
, ui(new Ui::WindowManagerMenu) {
|
|
||||||
ui->setupUi(this);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
WindowManagerMenu::~WindowManagerMenu() {
|
|
||||||
delete ui;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WindowManagerMenu::AddDockWidget(DockWidget* dockWidget) {
|
|
||||||
if (nullptr == dockWidget) {
|
|
||||||
LOG_ERROR("dockWidget is nullptr");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QListWidgetItem* item = new QListWidgetItem(dockWidget->windowTitle());
|
|
||||||
connect(dockWidget, &DockWidget::windowTitleChanged, [item](const QString& title) {
|
|
||||||
item->setText(title);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
item->setCheckState(Qt::Checked);
|
|
||||||
connect(ui->listWidget, &QListWidget::itemClicked, [](QListWidgetItem* item) {
|
|
||||||
bool checked = !(item->checkState() == Qt::Checked);
|
|
||||||
item->setCheckState(checked ? Qt::Checked : Qt::Unchecked);
|
|
||||||
item->data(DockWidgetRole).value<DockWidget*>()->setVisible(checked);
|
|
||||||
});
|
|
||||||
item->setData(DockWidgetRole, QVariant::fromValue(dockWidget));
|
|
||||||
connect(dockWidget, &DockWidget::signalClose, [this, item]() {
|
|
||||||
item->setCheckState(Qt::Unchecked);
|
|
||||||
});
|
|
||||||
ui->listWidget->addItem(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WindowManagerMenu::RemoveDockWidget(class DockWidget* dockWidget) {
|
|
||||||
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QWidget>
|
|
||||||
|
|
||||||
#include "workspace/WorkSpace.h"
|
|
||||||
|
|
||||||
namespace Ui {
|
|
||||||
class WindowManagerMenu;
|
|
||||||
}
|
|
||||||
|
|
||||||
class WindowManagerMenu : public QWidget {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
WindowManagerMenu(QWidget* parent = 0);
|
|
||||||
~WindowManagerMenu() override;
|
|
||||||
|
|
||||||
void AddDockWidget(class DockWidget* dockWidget);
|
|
||||||
void RemoveDockWidget(class DockWidget* dockWidget);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
Ui::WindowManagerMenu* ui;
|
|
||||||
};
|
|
@ -1,47 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ui version="4.0">
|
|
||||||
<class>WindowManagerMenu</class>
|
|
||||||
<widget class="QWidget" name="WindowManagerMenu">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>847</width>
|
|
||||||
<height>91</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>WindowManagerMenu</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
|
||||||
<item>
|
|
||||||
<widget class="QListWidget" name="listWidget">
|
|
||||||
<property name="verticalScrollBarPolicy">
|
|
||||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
|
||||||
</property>
|
|
||||||
<property name="horizontalScrollBarPolicy">
|
|
||||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
|
||||||
</property>
|
|
||||||
<property name="flow">
|
|
||||||
<enum>QListView::LeftToRight</enum>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>408</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<resources/>
|
|
||||||
<connections/>
|
|
||||||
</ui>
|
|
@ -28,6 +28,7 @@ void ModelBrowser::AttachDock(DockWidget* dockWidget) {
|
|||||||
dockWidget->setWidget(this);
|
dockWidget->setWidget(this);
|
||||||
|
|
||||||
DockTitleBar* dockTitleBar = new DockTitleBar;
|
DockTitleBar* dockTitleBar = new DockTitleBar;
|
||||||
|
dockTitleBar->SetTitle(tr("model elements"));
|
||||||
dockWidget->SetDockWidgetTitleBar(dockTitleBar);
|
dockWidget->SetDockWidgetTitleBar(dockTitleBar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
|
|
||||||
#include <osgEarth/EarthManipulator>
|
#include <osgEarthUtil/EarthManipulator>
|
||||||
|
|
||||||
#include "common/RecourceHelper.h"
|
#include "common/RecourceHelper.h"
|
||||||
#include "common/SpdLogger.h"
|
#include "common/SpdLogger.h"
|
||||||
|
@ -107,8 +107,7 @@ void PropertyBrowser::InitUI() {
|
|||||||
browser_ = new QtTreePropertyBrowser;
|
browser_ = new QtTreePropertyBrowser;
|
||||||
layout->addWidget(browser_);
|
layout->addWidget(browser_);
|
||||||
|
|
||||||
browser_->setHeaderVisible(true);
|
browser_->setHeaderVisible(false);
|
||||||
//browser_->setResizeMode(QtTreePropertyBrowser::Stretch);
|
|
||||||
|
|
||||||
InitPropertyManager();
|
InitPropertyManager();
|
||||||
InitComponentPropertyManager();
|
InitComponentPropertyManager();
|
||||||
|
@ -696,9 +696,8 @@ QFilePathEdit::QFilePathEdit(QWidget* parent) :
|
|||||||
QWidget(parent),
|
QWidget(parent),
|
||||||
m_stringEdit(new QLineEdit(this)),
|
m_stringEdit(new QLineEdit(this)),
|
||||||
m_button(new QPushButton(this)) {
|
m_button(new QPushButton(this)) {
|
||||||
m_button->setIcon(QIcon(QLatin1String(":/res/select_file.ico")));
|
m_button->setIcon(QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/button-reset.ico")));
|
||||||
m_button->setMaximumWidth(64);
|
m_button->setMaximumWidth(15);
|
||||||
m_button->setMinimumWidth(32);
|
|
||||||
|
|
||||||
m_stringEdit->setReadOnly(true);
|
m_stringEdit->setReadOnly(true);
|
||||||
|
|
||||||
@ -752,12 +751,12 @@ void QFilePathEdit::onFileSelect() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!FileUtils::CopyFileToPath(filePath, savePath, true)) {
|
if (!FileUtils::CopyFileToPath(filePath, filePath, true)) {
|
||||||
LOG_ERROR("Failed to copy file to workspace");
|
LOG_ERROR("Failed to copy file to workspace");
|
||||||
QMessageBox::critical(nullptr, "Error", "Failed to copy file to workspace");
|
QMessageBox::critical(nullptr, "Error", "Failed to copy file to workspace");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LOG_INFO("SetPath: {}", savePath.toLocal8Bit().constData());
|
LOG_INFO("PathComponent::SetPath: {}", workPath.toStdString().c_str());
|
||||||
m_initialvalue = m_fileName;
|
m_initialvalue = m_fileName;
|
||||||
m_stringEdit->setText(m_fileName);
|
m_stringEdit->setText(m_fileName);
|
||||||
}
|
}
|
||||||
@ -772,9 +771,8 @@ QModelFilePathEdit::QModelFilePathEdit(QWidget* parent) :
|
|||||||
QWidget(parent),
|
QWidget(parent),
|
||||||
m_stringEdit(new QLineEdit(this)),
|
m_stringEdit(new QLineEdit(this)),
|
||||||
m_button(new QPushButton(this)) {
|
m_button(new QPushButton(this)) {
|
||||||
m_button->setIcon(QIcon(QLatin1String(":/res/select_file.ico")));
|
m_button->setIcon(QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/button-reset.ico")));
|
||||||
m_button->setMaximumWidth(64);
|
m_button->setMaximumWidth(15);
|
||||||
m_button->setMinimumWidth(32);
|
|
||||||
|
|
||||||
m_stringEdit->setReadOnly(true);
|
m_stringEdit->setReadOnly(true);
|
||||||
|
|
||||||
|
@ -7875,10 +7875,22 @@ public:
|
|||||||
QMap<const QtProperty*, QtProperty*> m_properyToName;
|
QMap<const QtProperty*, QtProperty*> m_properyToName;
|
||||||
QMap<const QtProperty*, QtProperty*> m_properyToDescription;
|
QMap<const QtProperty*, QtProperty*> m_properyToDescription;
|
||||||
QMap<const QtProperty*, QtProperty*> m_properyToTimestep;
|
QMap<const QtProperty*, QtProperty*> m_properyToTimestep;
|
||||||
|
QMap<const QtProperty*, QtProperty*> m_properyToSimMatlab;
|
||||||
|
QMap<const QtProperty*, QtProperty*> m_properyToMatlabParam;
|
||||||
|
|
||||||
|
QMap<const QtProperty*, QtProperty*> m_properyToWave;
|
||||||
|
QMap<const QtProperty*, QtProperty*> m_properyToReport;
|
||||||
|
QMap<const QtProperty*, QtProperty*> m_properyToRD;
|
||||||
|
|
||||||
QMap<const QtProperty*, QtProperty*> m_nameToPropery;
|
QMap<const QtProperty*, QtProperty*> m_nameToPropery;
|
||||||
QMap<const QtProperty*, QtProperty*> m_descriptionToPropery;
|
QMap<const QtProperty*, QtProperty*> m_descriptionToPropery;
|
||||||
QMap<const QtProperty*, QtProperty*> m_timestepToPropery;
|
QMap<const QtProperty*, QtProperty*> m_timestepToPropery;
|
||||||
|
QMap<const QtProperty*, QtProperty*> m_simMatlabToPropery;
|
||||||
|
QMap<const QtProperty*, QtProperty*> m_matlabParamToPropery;
|
||||||
|
|
||||||
|
QMap<const QtProperty*, QtProperty*> m_waveToPropery;
|
||||||
|
QMap<const QtProperty*, QtProperty*> m_reportToPropery;
|
||||||
|
QMap<const QtProperty*, QtProperty*> m_rdToPropery;
|
||||||
};
|
};
|
||||||
|
|
||||||
void QtWorkspacePropertyManagerPrivate::slotStringChanged(QtProperty* property, QString value) {
|
void QtWorkspacePropertyManagerPrivate::slotStringChanged(QtProperty* property, QString value) {
|
||||||
@ -7894,6 +7906,10 @@ void QtWorkspacePropertyManagerPrivate::slotStringChanged(QtProperty* property,
|
|||||||
QWorkspaceAttribute c = m_values[prop];
|
QWorkspaceAttribute c = m_values[prop];
|
||||||
c.SetTimeStep(value);
|
c.SetTimeStep(value);
|
||||||
q_ptr->setValue(prop, c);
|
q_ptr->setValue(prop, c);
|
||||||
|
} else if (QtProperty* prop = m_simMatlabToPropery.value(property, 0)) {
|
||||||
|
QWorkspaceAttribute c = m_values[prop];
|
||||||
|
c.SetSimMatlab(value);
|
||||||
|
q_ptr->setValue(prop, c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7912,6 +7928,11 @@ void QtWorkspacePropertyManagerPrivate::slotPropertyDestroyed(QtProperty* proper
|
|||||||
m_timestepToPropery[subProp] = 0;
|
m_timestepToPropery[subProp] = 0;
|
||||||
m_timestepToPropery.remove(property);
|
m_timestepToPropery.remove(property);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (QtProperty* subProp = m_simMatlabToPropery.value(property, nullptr)) {
|
||||||
|
m_simMatlabToPropery[subProp] = 0;
|
||||||
|
m_simMatlabToPropery.remove(property);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QtWorkspacePropertyManager::QtWorkspacePropertyManager(QObject* parent)
|
QtWorkspacePropertyManager::QtWorkspacePropertyManager(QObject* parent)
|
||||||
@ -7996,6 +8017,12 @@ void QtWorkspacePropertyManager::setValue(QtProperty* property, const QWorkspace
|
|||||||
d_ptr->m_stringProperyManager->setValue(d_ptr->m_properyToName[property], value.GetName());
|
d_ptr->m_stringProperyManager->setValue(d_ptr->m_properyToName[property], value.GetName());
|
||||||
d_ptr->m_stringProperyManager->setValue(d_ptr->m_properyToDescription[property], value.GetDescription());
|
d_ptr->m_stringProperyManager->setValue(d_ptr->m_properyToDescription[property], value.GetDescription());
|
||||||
d_ptr->m_filesProperyManager->setValue(d_ptr->m_properyToTimestep[property], value.GetTimeStep());
|
d_ptr->m_filesProperyManager->setValue(d_ptr->m_properyToTimestep[property], value.GetTimeStep());
|
||||||
|
d_ptr->m_filesProperyManager->setValue(d_ptr->m_properyToSimMatlab[property], value.GetSimMatlab());
|
||||||
|
d_ptr->m_filesProperyManager->setValue(d_ptr->m_properyToMatlabParam[property], value.GetMatlabParam());
|
||||||
|
|
||||||
|
d_ptr->m_filesProperyManager->setValue(d_ptr->m_properyToWave[property], value.GetWavePath());
|
||||||
|
d_ptr->m_filesProperyManager->setValue(d_ptr->m_properyToReport[property], value.GetReportPath());
|
||||||
|
d_ptr->m_filesProperyManager->setValue(d_ptr->m_properyToRD[property], value.GetRDPath());
|
||||||
|
|
||||||
emit propertyChanged(property);
|
emit propertyChanged(property);
|
||||||
emit valueChanged(property, value);
|
emit valueChanged(property, value);
|
||||||
@ -8028,6 +8055,41 @@ void QtWorkspacePropertyManager::initializeProperty(QtProperty* property) {
|
|||||||
d_ptr->m_properyToTimestep[property] = prop;
|
d_ptr->m_properyToTimestep[property] = prop;
|
||||||
d_ptr->m_timestepToPropery[prop] = property;
|
d_ptr->m_timestepToPropery[prop] = property;
|
||||||
property->addSubProperty(prop);
|
property->addSubProperty(prop);
|
||||||
|
|
||||||
|
prop = d_ptr->m_filesProperyManager->addProperty();
|
||||||
|
prop->setPropertyName(tr("SimMatlab"));
|
||||||
|
d_ptr->m_filesProperyManager->setValueOnly(prop, val.GetSimMatlab());
|
||||||
|
d_ptr->m_properyToSimMatlab[property] = prop;
|
||||||
|
d_ptr->m_simMatlabToPropery[prop] = property;
|
||||||
|
property->addSubProperty(prop);
|
||||||
|
|
||||||
|
prop = d_ptr->m_filesProperyManager->addProperty();
|
||||||
|
prop->setPropertyName(tr("MatlabParam"));
|
||||||
|
d_ptr->m_filesProperyManager->setValueOnly(prop, val.GetMatlabParam());
|
||||||
|
d_ptr->m_properyToMatlabParam[property] = prop;
|
||||||
|
d_ptr->m_simMatlabToPropery[prop] = property;
|
||||||
|
property->addSubProperty(prop);
|
||||||
|
|
||||||
|
prop = d_ptr->m_filesProperyManager->addProperty();
|
||||||
|
prop->setPropertyName(tr("Wave"));
|
||||||
|
d_ptr->m_filesProperyManager->setValueOnly(prop, val.GetWavePath());
|
||||||
|
d_ptr->m_properyToWave[property] = prop;
|
||||||
|
d_ptr->m_waveToPropery[prop] = property;
|
||||||
|
property->addSubProperty(prop);
|
||||||
|
|
||||||
|
prop = d_ptr->m_filesProperyManager->addProperty();
|
||||||
|
prop->setPropertyName(tr("RD"));
|
||||||
|
d_ptr->m_filesProperyManager->setValueOnly(prop, val.GetRDPath());
|
||||||
|
d_ptr->m_properyToRD[property] = prop;
|
||||||
|
d_ptr->m_rdToPropery[prop] = property;
|
||||||
|
property->addSubProperty(prop);
|
||||||
|
|
||||||
|
prop = d_ptr->m_filesProperyManager->addProperty();
|
||||||
|
prop->setPropertyName(tr("Report"));
|
||||||
|
d_ptr->m_filesProperyManager->setValueOnly(prop, val.GetReportPath());
|
||||||
|
d_ptr->m_properyToReport[property] = prop;
|
||||||
|
d_ptr->m_reportToPropery[prop] = property;
|
||||||
|
property->addSubProperty(prop);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -8054,6 +8116,41 @@ void QtWorkspacePropertyManager::uninitializeProperty(QtProperty* property) {
|
|||||||
delete prop;
|
delete prop;
|
||||||
}
|
}
|
||||||
d_ptr->m_properyToTimestep.remove(property);
|
d_ptr->m_properyToTimestep.remove(property);
|
||||||
|
|
||||||
|
prop = d_ptr->m_simMatlabToPropery[property];
|
||||||
|
if (prop) {
|
||||||
|
d_ptr->m_simMatlabToPropery.remove(prop);
|
||||||
|
delete prop;
|
||||||
|
}
|
||||||
|
d_ptr->m_properyToSimMatlab.remove(property);
|
||||||
|
|
||||||
|
prop = d_ptr->m_matlabParamToPropery[property];
|
||||||
|
if (prop) {
|
||||||
|
d_ptr->m_matlabParamToPropery.remove(prop);
|
||||||
|
delete prop;
|
||||||
|
}
|
||||||
|
d_ptr->m_properyToMatlabParam.remove(property);
|
||||||
|
|
||||||
|
prop = d_ptr->m_waveToPropery[property];
|
||||||
|
if (prop) {
|
||||||
|
d_ptr->m_waveToPropery.remove(prop);
|
||||||
|
delete prop;
|
||||||
|
}
|
||||||
|
d_ptr->m_properyToWave.remove(property);
|
||||||
|
|
||||||
|
prop = d_ptr->m_reportToPropery[property];
|
||||||
|
if (prop) {
|
||||||
|
d_ptr->m_reportToPropery.remove(prop);
|
||||||
|
delete prop;
|
||||||
|
}
|
||||||
|
d_ptr->m_properyToReport.remove(property);
|
||||||
|
|
||||||
|
prop = d_ptr->m_rdToPropery[property];
|
||||||
|
if (prop) {
|
||||||
|
d_ptr->m_rdToPropery.remove(prop);
|
||||||
|
delete prop;
|
||||||
|
}
|
||||||
|
d_ptr->m_properyToRD.remove(property);
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
@ -460,11 +460,8 @@ void QtTreePropertyBrowserPrivate::init(QWidget *parent)
|
|||||||
m_delegate = new QtPropertyEditorDelegate(parent);
|
m_delegate = new QtPropertyEditorDelegate(parent);
|
||||||
m_delegate->setEditorPrivate(this);
|
m_delegate->setEditorPrivate(this);
|
||||||
m_treeWidget->setItemDelegate(m_delegate);
|
m_treeWidget->setItemDelegate(m_delegate);
|
||||||
QHeaderView* header = m_treeWidget->header();
|
m_treeWidget->header()->setSectionsMovable(false);
|
||||||
header->setSectionResizeMode(QHeaderView::Interactive);
|
m_treeWidget->header()->setSectionResizeMode(QHeaderView::Stretch);
|
||||||
header->setStretchLastSection(true);
|
|
||||||
|
|
||||||
//header->setSectionResizeMode(QHeaderView::Stretch);
|
|
||||||
|
|
||||||
m_expandIcon = drawIndicatorIcon(q_ptr->palette(), q_ptr->style());
|
m_expandIcon = drawIndicatorIcon(q_ptr->palette(), q_ptr->style());
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user