"Professional CMake" book suggest the following: "Targets should build successfully with or without compiler support for precompiled headers. It should be considered an optimization, not a requirement. In particular, do not explicitly include a precompile header (e.g. stdafx.h) in the source code, let CMake force-include an automatically generated precompile header on the compiler command line instead. This is more portable across the major compilers and is likely to be easier to maintain. It will also avoid warnings being generated from certain code checking tools like iwyu (include what you use)." Therefore, removed the "#include <PreCompiled.h>" from sources, also there is no need for the "#ifdef _PreComp_" anymore
368 lines
11 KiB
C++
368 lines
11 KiB
C++
/***************************************************************************
|
|
* Copyright (c) 2005 Werner Mayer <wmayer[at]users.sourceforge.net> *
|
|
* *
|
|
* This file is part of the FreeCAD CAx development system. *
|
|
* *
|
|
* This library is free software; you can redistribute it and/or *
|
|
* modify it under the terms of the GNU Library General Public *
|
|
* License as published by the Free Software Foundation; either *
|
|
* version 2 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 Library General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU Library General Public *
|
|
* License along with this library; see the file COPYING.LIB. If not, *
|
|
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
|
* Suite 330, Boston, MA 02111-1307, USA *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
# include <boost/core/ignore_unused.hpp>
|
|
# include <Inventor/actions/SoGetBoundingBoxAction.h>
|
|
# include <Inventor/actions/SoGLRenderAction.h>
|
|
# include <Inventor/events/SoMouseButtonEvent.h>
|
|
# include <Inventor/nodes/SoEventCallback.h>
|
|
# include <Inventor/nodes/SoOrthographicCamera.h>
|
|
# include <Inventor/nodes/SoSwitch.h>
|
|
# include <QApplication>
|
|
# include <QMenu>
|
|
|
|
|
|
#include "SoFCColorBar.h"
|
|
#include "SoFCColorGradient.h"
|
|
#include "SoFCColorLegend.h"
|
|
|
|
|
|
using namespace Gui;
|
|
|
|
SO_NODE_ABSTRACT_SOURCE(SoFCColorBarBase)
|
|
|
|
/*!
|
|
Constructor.
|
|
*/
|
|
SoFCColorBarBase::SoFCColorBarBase() : _windowSize(0,0)
|
|
{
|
|
SO_NODE_CONSTRUCTOR(SoFCColorBarBase);
|
|
}
|
|
|
|
/*!
|
|
Destructor.
|
|
*/
|
|
SoFCColorBarBase::~SoFCColorBarBase() = default;
|
|
|
|
// doc from parent
|
|
void SoFCColorBarBase::initClass()
|
|
{
|
|
SO_NODE_INIT_ABSTRACT_CLASS(SoFCColorBarBase,SoSeparator,"Separator");
|
|
}
|
|
|
|
void SoFCColorBarBase::finish()
|
|
{
|
|
atexit_cleanup();
|
|
}
|
|
|
|
void SoFCColorBarBase::GLRenderBelowPath(SoGLRenderAction * action)
|
|
{
|
|
const SbViewportRegion& vp = action->getViewportRegion();
|
|
const SbVec2s& size = vp.getWindowSize();
|
|
if (_windowSize != size) {
|
|
_windowSize = size;
|
|
setViewportSize(size);
|
|
}
|
|
SoSeparator::GLRenderBelowPath(action);
|
|
}
|
|
|
|
void SoFCColorBarBase::setModified()
|
|
{
|
|
_boxWidth = -1.0f;
|
|
}
|
|
|
|
void SoFCColorBarBase::setFormat(const SoLabelTextFormat& fmt)
|
|
{
|
|
format = fmt;
|
|
applyFormat(fmt);
|
|
}
|
|
|
|
SoLabelTextFormat SoFCColorBarBase::getFormat() const
|
|
{
|
|
return format;
|
|
}
|
|
|
|
void SoFCColorBarBase::applyFormat(const SoLabelTextFormat& fmt)
|
|
{
|
|
boost::ignore_unused(fmt);
|
|
}
|
|
|
|
float SoFCColorBarBase::getBoundingWidth(const SbVec2s& size)
|
|
{
|
|
float fRatio = static_cast<float>(size[0]) / static_cast<float>(size[1]);
|
|
if (fRatio >= 1.0f && _boxWidth >= 0.0f) {
|
|
return _boxWidth;
|
|
}
|
|
|
|
// These are the same camera settings for front nodes as defined in the 3d view
|
|
auto cam = new SoOrthographicCamera;
|
|
cam->position = SbVec3f(0, 0, 5); // the 5 is just a value > 0
|
|
cam->height = 10; // sets the coordinate range of the screen to [-5, +5]
|
|
cam->nearDistance = 0;
|
|
cam->farDistance = 10;
|
|
|
|
auto group = new SoGroup();
|
|
group->ref();
|
|
group->addChild(cam);
|
|
group->addChild(this);
|
|
|
|
SbViewportRegion vpr(size);
|
|
SoGetBoundingBoxAction bbact(vpr);
|
|
bbact.apply(group);
|
|
SbBox3f box = bbact.getBoundingBox();
|
|
SbVec3f minPt, maxPt;
|
|
box.getBounds(minPt, maxPt);
|
|
group->unref();
|
|
|
|
float boxWidth = maxPt[0] - minPt[0];
|
|
_boxWidth = boxWidth;
|
|
return boxWidth;
|
|
}
|
|
|
|
float SoFCColorBarBase::getBounds(const SbVec2s& size, float& fMinX, float&fMinY, float& fMaxX, float& fMaxY)
|
|
{
|
|
// ratio of window width / height
|
|
float fRatio = static_cast<float>(size[0]) / static_cast<float>(size[1]);
|
|
|
|
// The cam height is set in SoFCColorBarBase::getBoundingWidth to 10.
|
|
// Therefore the normalized coordinates are in the range [-5, +5] x [-5ratio, +5ratio] if ratio > 1
|
|
// and [-5ratio, +5ratio] x [-5, +5] if ratio < 1.
|
|
// We don't want the whole height covered by the color bar (to have e.g space to the axis cross
|
|
// and the Navigation Cube) thus we take as base 3 or if the height reduces significantly it is 2.5.
|
|
|
|
float baseYValue;
|
|
if (fRatio > 3.0f) {
|
|
baseYValue = 2.5f;
|
|
}
|
|
else {
|
|
baseYValue = 3.0f;
|
|
}
|
|
float barWidth = 0.5f;
|
|
|
|
// we want the color bar at the rightmost position, therefore we take 4.95 as base
|
|
fMinX = 4.95f * fRatio; // must be scaled with the ratio to assure it stays at the right
|
|
|
|
fMaxX = fMinX + barWidth;
|
|
fMinY = -baseYValue - 0.6f; // Extend shortened bar towards axis cross
|
|
fMaxY = baseYValue; // bar has the height of almost whole window height
|
|
|
|
if (fRatio < 1.0f) {
|
|
// must be adjusted to assure that the size of the bar doesn't shrink
|
|
fMinX /= fRatio;
|
|
fMaxX /= fRatio;
|
|
fMinY = -baseYValue / fRatio;
|
|
fMaxY = baseYValue / fRatio;
|
|
}
|
|
|
|
// get the bounding box width of the color bar and labels
|
|
float boxWidth = getBoundingWidth(size);
|
|
return boxWidth;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
namespace Gui {
|
|
// Proxy class that receives an asynchronous custom event
|
|
class SoFCColorBarProxyObject : public QObject
|
|
{
|
|
public:
|
|
explicit SoFCColorBarProxyObject(SoFCColorBar* b)
|
|
: QObject(nullptr), bar(b) {}
|
|
~SoFCColorBarProxyObject() override = default;
|
|
void customEvent(QEvent *) override
|
|
{
|
|
bar->customize(bar->getActiveBar());
|
|
this->deleteLater();
|
|
}
|
|
|
|
private:
|
|
SoFCColorBar* bar;
|
|
};
|
|
}
|
|
|
|
SO_NODE_SOURCE(SoFCColorBar)
|
|
|
|
/*!
|
|
Constructor.
|
|
*/
|
|
SoFCColorBar::SoFCColorBar()
|
|
{
|
|
SO_NODE_CONSTRUCTOR(SoFCColorBar);
|
|
|
|
// SoEventCallback * cb = new SoEventCallback;
|
|
// cb->addEventCallback(SoMouseButtonEvent::getClassTypeId(), eventCallback, this);
|
|
// insertChild(cb, 0);
|
|
|
|
pColorMode = new SoSwitch;
|
|
addChild(pColorMode);
|
|
|
|
_colorBars.push_back( new SoFCColorGradient );
|
|
_colorBars.push_back( new SoFCColorLegend );
|
|
|
|
for (auto it : _colorBars)
|
|
pColorMode->addChild(it);
|
|
pColorMode->whichChild = 0;
|
|
}
|
|
|
|
/*!
|
|
Destructor.
|
|
*/
|
|
SoFCColorBar::~SoFCColorBar() = default;
|
|
|
|
// doc from parent
|
|
void SoFCColorBar::initClass()
|
|
{
|
|
SO_NODE_INIT_CLASS(SoFCColorBar,SoFCColorBarBase,"Separator");
|
|
}
|
|
|
|
void SoFCColorBar::finish()
|
|
{
|
|
atexit_cleanup();
|
|
}
|
|
|
|
SoFCColorBarBase* SoFCColorBar::getActiveBar() const
|
|
{
|
|
int child = pColorMode->whichChild.getValue();
|
|
return _colorBars[child];
|
|
}
|
|
|
|
void SoFCColorBar::setFormat(const SoLabelTextFormat& fmt)
|
|
{
|
|
for (auto it : _colorBars)
|
|
it->setFormat(fmt);
|
|
}
|
|
|
|
void SoFCColorBar::setViewportSize( const SbVec2s& size )
|
|
{
|
|
boost::ignore_unused(size);
|
|
}
|
|
|
|
void SoFCColorBar::setRange( float fMin, float fMax, int prec )
|
|
{
|
|
for (auto it : _colorBars)
|
|
it->setRange(fMin, fMax, prec);
|
|
}
|
|
|
|
void SoFCColorBar::setOutsideGrayed (bool bVal)
|
|
{
|
|
for (auto it : _colorBars)
|
|
it->setOutsideGrayed(bVal);
|
|
}
|
|
|
|
bool SoFCColorBar::isVisible (float fVal) const
|
|
{
|
|
return this->getActiveBar()->isVisible(fVal);
|
|
}
|
|
|
|
float SoFCColorBar::getMinValue () const
|
|
{
|
|
return this->getActiveBar()->getMinValue();
|
|
}
|
|
|
|
float SoFCColorBar::getMaxValue () const
|
|
{
|
|
return this->getActiveBar()->getMaxValue();
|
|
}
|
|
|
|
void SoFCColorBar::triggerChange(SoFCColorBarBase*)
|
|
{
|
|
Notify(0);
|
|
}
|
|
|
|
void SoFCColorBar::customize(SoFCColorBarBase* child)
|
|
{
|
|
try {
|
|
return child->customize(this);
|
|
}
|
|
catch (const Base::ValueError& e) {
|
|
e.reportException();
|
|
}
|
|
}
|
|
|
|
Base::Color SoFCColorBar::getColor( float fVal ) const
|
|
{
|
|
return this->getActiveBar()->getColor( fVal );
|
|
}
|
|
|
|
void SoFCColorBar::eventCallback(void * /*userdata*/, SoEventCallback * node)
|
|
{
|
|
const SoEvent * event = node->getEvent();
|
|
if (event->getTypeId().isDerivedFrom(SoMouseButtonEvent::getClassTypeId())) {
|
|
const auto e = static_cast<const SoMouseButtonEvent*>(event);
|
|
if ((e->getButton() == SoMouseButtonEvent::BUTTON2)) {
|
|
if (e->getState() == SoButtonEvent::UP) {
|
|
// do nothing here
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SoFCColorBar::handleEvent (SoHandleEventAction *action)
|
|
{
|
|
const SoEvent * event = action->getEvent();
|
|
|
|
// check for mouse button events
|
|
if (event->getTypeId().isDerivedFrom(SoMouseButtonEvent::getClassTypeId())) {
|
|
const auto e = static_cast<const SoMouseButtonEvent*>(event);
|
|
|
|
// check if the cursor is near to the color bar
|
|
if (!action->getPickedPoint())
|
|
return; // not inside the rectangle
|
|
|
|
// left mouse pressed
|
|
action->setHandled();
|
|
if ((e->getButton() == SoMouseButtonEvent::BUTTON1)) {
|
|
if (e->getState() == SoButtonEvent::DOWN) {
|
|
// double click event
|
|
if (!_timer.isValid()) {
|
|
_timer.start();
|
|
}
|
|
else if (_timer.restart() < QApplication::doubleClickInterval()) {
|
|
QApplication::postEvent(
|
|
new SoFCColorBarProxyObject(this),
|
|
new QEvent(QEvent::User));
|
|
}
|
|
}
|
|
}
|
|
// right mouse pressed
|
|
else if ((e->getButton() == SoMouseButtonEvent::BUTTON2)) {
|
|
if (e->getState() == SoButtonEvent::UP) {
|
|
SoFCColorBarBase* current = getActiveBar();
|
|
QMenu menu;
|
|
int i=0;
|
|
for (auto it : _colorBars) {
|
|
QAction* item = menu.addAction(QObject::tr(it->getColorBarName()));
|
|
item->setCheckable(true);
|
|
item->setChecked(it == current);
|
|
item->setData(QVariant(i++));
|
|
}
|
|
|
|
menu.addSeparator();
|
|
QAction* option = menu.addAction(QObject::tr("Options"));
|
|
QAction* select = menu.exec(QCursor::pos());
|
|
|
|
if (select == option) {
|
|
QApplication::postEvent(
|
|
new SoFCColorBarProxyObject(this),
|
|
new QEvent(QEvent::User));
|
|
}
|
|
else if (select) {
|
|
int id = select->data().toInt();
|
|
pColorMode->whichChild = id;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|