diff --git a/Modules/Core/include/mitkIPreferences.h b/Modules/Core/include/mitkIPreferences.h index bdf31f2c17..ae881b24a6 100644 --- a/Modules/Core/include/mitkIPreferences.h +++ b/Modules/Core/include/mitkIPreferences.h @@ -1,297 +1,297 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkIPreferences_h #define mitkIPreferences_h #include #include #include #include #include namespace mitk { /** * \brief Interface to application preferences. * * %Preferences are implemented as nodes in a tree structure. Each preference node may consist of * properties, i.e. key-value pairs, and child preferences nodes. The lifetime of nodes is managed * by their respective parent node. * * Use CoreServices::GetPreferencesService() and IPreferencesService::GetSystemPreferences() to * access the application preferences, i.e. the preferences root node. * * Use the Node() method to traverse through the tree. * * Getters and setters for various data types, e.g. GetInt() and PutInt(), are provided to conveniently * access properties as their intended data types. All preferences are ultimately stored as strings. * * Call Flush() to enforce the persistence of the whole (!) preferences tree. Preferences are flushed * automatically at least on a regular application shutdown. * - * Structural changes of a preference node can be observed via IPreferences::OnChanged. - * Property changes of a preference node can be observed via IPreferences::OnPropertyChanged. + * Changes of a preference node can be observed via IPreferences::OnChanged. + * Property changes of a preference node can be observed additionally via IPreferences::OnPropertyChanged. * * \sa CoreServices::GetPreferencesService() * \sa IPreferencesService */ class MITKCORE_EXPORT IPreferences { public: /** * \brief Event object sent on IPreferences::OnPropertyChanged events. */ class MITKCORE_EXPORT ChangeEvent { public: ChangeEvent(IPreferences* source, const std::string& property, const std::string& oldValue, const std::string& newValue); IPreferences* GetSource() const; std::string GetProperty() const; std::string GetOldValue() const; std::string GetNewValue() const; private: IPreferences* m_Source; std::string m_Property; std::string m_OldValue; std::string m_NewValue; }; virtual ~IPreferences(); /** * \brief Get a property value as string. * * If the property cannot be found, return the provided default value instead. * * \param key Name of the property * \param def Default value * * \return Property value or default value */ virtual std::string Get(const std::string& key, const std::string& def) const = 0; /** * \brief Set a property value. * * Create the property if not yet existent. Otherwise change its value. * * Trigger an IPreferences::OnPropertyChanged event if the new value is different * or if a new property has been created, except the string value is empty in * the latter case. */ virtual void Put(const std::string& key, const std::string& value) = 0; /** * \brief Get a property value as \c int. * * Convenience wrapper of Get() undertaking string to integer conversion. * * \throw Exception The property value is not a valid string representation of an \c int value. */ virtual int GetInt(const std::string& key, int def) const = 0; /** * \brief Set an \c int property value. * * Convenience wrapper of Put() undertaking integer to string conversion. */ virtual void PutInt(const std::string& key, int value) = 0; /** * \brief Get a property value as \c bool. * * Convenience wrapper of Get() checking if the string value literally equals \c "true". * Returns false otherwise. The comparison is case-insensitive. */ virtual bool GetBool(const std::string& key, bool def) const = 0; /** * \brief Set a \c bool property value. * * Convenience wrapper of Put() using the literal strings \c "true" and \c "false" to * encode the \c bool value. */ virtual void PutBool(const std::string& key, bool value) = 0; /** * \brief Get a property value as \c float. * * Convenience wrapper of Get() undertaking string to \c float conversion. * * \throw Exception The property value is not a valid string representation of a \c float value. */ virtual float GetFloat(const std::string& key, float def) const = 0; /** * \brief Set a \c float property value. * * Convenience wrapper of Put() undertaking \c float to string conversion. */ virtual void PutFloat(const std::string& key, float value) = 0; /** * \brief Get a property value as \c double. * * Convenience wrapper of Get() undertaking string to \c double conversion. * * \throw Exception The property value is not a valid string representation of a \c double value. */ virtual double GetDouble(const std::string& key, double def) const = 0; /** * \brief Set a \c double property value. * * Convenience wrapper of Put() undertaking \c double to string conversion. */ virtual void PutDouble(const std::string& key, double value) = 0; /** * \brief Get a property value as typeless binary representation. * * Decode a Base64-encoded property value into a typeless binary representation. * Use \c reinterpret_cast to restore the original type: * * \code{.cpp} * // Restore position and size of a widget from preferences * std::vector geometry = preferences->GetByteArray("widget geometry", nullptr, 0); * widget->restoreGeometry(QByteArray(reinterpret_cast(geometry.data())), geometry.size()); * \endcode * * \param key Name of the property * \param def Raw pointer to the default binary data or \c nullptr * \param size Size of the default binary data in bytes or \c 0 in case of \c nullptr * * \return Decoded binary data encapsulated in a vector of bytes. Use \c std::vector::data() to get a raw pointer to the data. */ virtual std::vector GetByteArray(const std::string& key, const std::byte* def, size_t size) const = 0; /** * \brief Put binary data into a property value. * * The Base64 algorithm is used to encode binary data into a valid text representation. * Use \c reinterpret_cast to pass a raw pointer to binary data and specify its total * number of bytes: * * \code{.cpp} * // Store position and size of a widget in preferences * QByteArray geometry = widget->saveGeometry(); * preferences->PutByteArray("widget geometry", reinterpret_cast(geometry.data()), geometry.size()); * \endcode * * \param key Name of the property * \param array Raw pointer to binary data * \param size Size of the binary data in bytes */ virtual void PutByteArray(const std::string& key, const std::byte* array, size_t size) = 0; /** * \brief Write all (!) preferences to disk. * * Enforce the persistence of the whole preferences tree. * * \note Preferences are flushed automatically at least on a regular application shutdown. * * \sa IPreferencesStorage::Flush() */ virtual void Flush() = 0; /** * \brief Remove a property from this preferences node. * * \param key Name of the property */ virtual void Remove(const std::string& key) = 0; /** * \brief Remove all properties from this preferences node. */ virtual void Clear() = 0; /** * \brief Get the names of all properties of this preferences node. */ virtual std::vector Keys() const = 0; /** * \brief Get the name of this preferences node. * * The name can be used in an absolute or relative path separated by forward slashes to address a specific properties node. * * \sa AbsolutePath() const * \sa Node() */ virtual std::string Name() const = 0; /** * \brief Get the absolute path (relative to the root node) of this preferences node. * * \sa Name() const * \sa Node() */ virtual std::string AbsolutePath() const = 0; /** * \brief Get the names of all direct child preference nodes. */ virtual std::vector ChildrenNames() const = 0; /** * \brief Get the parent preferences node or \c nullptr in case of the root node. */ virtual IPreferences* Parent() = 0; /** * \sa Parent() */ virtual const IPreferences* Parent() const = 0; /** * \brief Get the root preferences node. */ virtual IPreferences* Root() = 0; /** * \sa Root() */ virtual const IPreferences* Root() const = 0; /** * \brief Get (and possibly create) the preferences node specified by the given path. * * The path is considered to be absolute if it starts with a forward slash. It is relative to * this preferences node otherwise. If any preferences node does not yet exist during traversal, * it is created on the fly. * * \sa Name() const * \sa AbsolutePath() const */ virtual IPreferences* Node(const std::string& path) = 0; /** * \brief Remove this preferences node from its parent node. * * \note Since preferences nodes are owned by their parents, this preferences node * is immediately deleted after removal. */ virtual void RemoveNode() = 0; - Message1 OnChanged; /**< \brief Notify on structural node changes. */ + Message1 OnChanged; /**< \brief Notify on node changes. */ Message1 OnPropertyChanged; /**< \brief Notify on property changes. */ }; } #endif diff --git a/Modules/Core/src/IO/mitkPreferences.h b/Modules/Core/src/IO/mitkPreferences.h index 1d6e43d5f8..d03678e77e 100644 --- a/Modules/Core/src/IO/mitkPreferences.h +++ b/Modules/Core/src/IO/mitkPreferences.h @@ -1,103 +1,106 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkPreferences_h #define mitkPreferences_h #include #include #include namespace mitk { class IPreferencesStorage; /** * \brief Implementation of the IPreferences interface. * * Only used through the IPreferences interface. * * \sa IPreferences */ class Preferences : public IPreferences { public: using Properties = std::unordered_map; Preferences(const Properties& properties, const std::string& name, Preferences* parent, IPreferencesStorage* storage); ~Preferences() override; Preferences(const Preferences&) = delete; Preferences& operator=(const Preferences&) = delete; Preferences(Preferences&&) = default; Preferences& operator=(Preferences&&) = default; std::string Get(const std::string& key, const std::string& def) const override; void Put(const std::string& key, const std::string& value) override; int GetInt(const std::string& key, int def) const override; void PutInt(const std::string& key, int value) override; bool GetBool(const std::string& key, bool def) const override; void PutBool(const std::string& key, bool value) override; float GetFloat(const std::string& key, float def) const override; void PutFloat(const std::string& key, float value) override; double GetDouble(const std::string& key, double def) const override; void PutDouble(const std::string& key, double value) override; std::vector GetByteArray(const std::string& key, const std::byte* def, size_t size) const override; void PutByteArray(const std::string& key, const std::byte* array, size_t size) override; void Remove(const std::string& key) override; void Clear() override; std::vector Keys() const override; std::vector ChildrenNames() const override; IPreferences* Parent() override; const IPreferences* Parent() const override; IPreferences* Root() override; const IPreferences* Root() const override; IPreferences* Node(const std::string& path) override; void RemoveNode() override; std::string Name() const override; std::string AbsolutePath() const override; void Flush() override; const Properties& GetProperties() const; const std::vector>& GetChildren() const; private: template void Put(const std::string& key, const T& value, const std::function& toString) { const auto oldValue = m_Properties[key]; const auto newValue = toString(value); m_Properties[key] = newValue; if (oldValue != newValue) + { + this->OnChanged(this); this->OnPropertyChanged(ChangeEvent(this, key, oldValue, newValue)); + } } Properties m_Properties; std::vector> m_Children; std::string m_Path; std::string m_Name; Preferences* m_Parent; Preferences* m_Root; IPreferencesStorage* m_Storage; }; } #endif diff --git a/Modules/Core/src/Rendering/mitkBaseRenderer.cpp b/Modules/Core/src/Rendering/mitkBaseRenderer.cpp index e4777c3b35..d0685e131f 100644 --- a/Modules/Core/src/Rendering/mitkBaseRenderer.cpp +++ b/Modules/Core/src/Rendering/mitkBaseRenderer.cpp @@ -1,772 +1,776 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkBaseRenderer.h" #include "mitkBaseRendererHelper.h" #include "mitkMapper.h" #include "mitkResliceMethodProperty.h" // Geometries #include "mitkSlicedGeometry3D.h" #include "mitkVtkLayerController.h" #include "mitkInteractionConst.h" #include "mitkProperties.h" #include "mitkWeakPointerProperty.h" // VTK #include #include #include #include #include namespace mitk { itkEventMacroDefinition(RendererResetEvent, itk::AnyEvent); } mitk::BaseRenderer::BaseRendererMapType mitk::BaseRenderer::baseRendererMap; mitk::BaseRenderer *mitk::BaseRenderer::GetInstance(vtkRenderWindow *renWin) { for (auto mapit = baseRendererMap.begin(); mapit != baseRendererMap.end(); ++mapit) { if ((*mapit).first == renWin) return (*mapit).second; } return nullptr; } void mitk::BaseRenderer::AddInstance(vtkRenderWindow *renWin, BaseRenderer *baseRenderer) { if (renWin == nullptr || baseRenderer == nullptr) return; // ensure that no BaseRenderer is managed twice mitk::BaseRenderer::RemoveInstance(renWin); baseRendererMap.insert(BaseRendererMapType::value_type(renWin, baseRenderer)); } void mitk::BaseRenderer::RemoveInstance(vtkRenderWindow *renWin) { auto mapit = baseRendererMap.find(renWin); if (mapit != baseRendererMap.end()) baseRendererMap.erase(mapit); } mitk::BaseRenderer *mitk::BaseRenderer::GetByName(const std::string &name) { for (auto mapit = baseRendererMap.begin(); mapit != baseRendererMap.end(); ++mapit) { if ((*mapit).second->m_Name == name) return (*mapit).second; } return nullptr; } vtkRenderWindow *mitk::BaseRenderer::GetRenderWindowByName(const std::string &name) { for (auto mapit = baseRendererMap.begin(); mapit != baseRendererMap.end(); ++mapit) { if ((*mapit).second->m_Name == name) return (*mapit).first; } return nullptr; } mitk::BaseRenderer::BaseRendererMapType mitk::BaseRenderer::GetSpecificRenderWindows(MapperSlotId mapper) { BaseRendererMapType allRenderWindows; for (auto mapit = baseRendererMap.begin(); mapit != baseRendererMap.end(); ++mapit) { if (mapper == mapit->second->GetMapperID()) { allRenderWindows.insert(BaseRendererMapType::value_type(mapit->first, mapit->second)); } } return allRenderWindows; } mitk::BaseRenderer::BaseRendererMapType mitk::BaseRenderer::GetAll2DRenderWindows() { return GetSpecificRenderWindows(BaseRenderer::Standard2D); } mitk::BaseRenderer::BaseRendererMapType mitk::BaseRenderer::GetAll3DRenderWindows() { return GetSpecificRenderWindows(BaseRenderer::Standard3D); } mitk::BaseRenderer::BaseRenderer(const char *name, vtkRenderWindow *renWin) : m_RenderWindow(nullptr), m_VtkRenderer(nullptr), m_MapperID(StandardMapperSlot::Standard2D), m_DataStorage(nullptr), m_LastUpdateTime(0), m_CameraController(nullptr), m_CameraRotationController(nullptr), m_SliceNavigationController(nullptr), m_WorldTimeGeometry(nullptr), + m_InteractionReferenceGeometry(nullptr), m_CurrentWorldGeometry(nullptr), m_CurrentWorldPlaneGeometry(nullptr), m_Slice(0), m_TimeStep(), m_CurrentWorldPlaneGeometryUpdateTime(), m_TimeStepUpdateTime(), m_KeepDisplayedRegion(true), + m_ReferenceGeometryAligned(true), m_CurrentWorldPlaneGeometryData(nullptr), m_CurrentWorldPlaneGeometryNode(nullptr), m_CurrentWorldPlaneGeometryTransformTime(0), m_Name(name), m_EmptyWorldGeometry(true), m_NumberOfVisibleLODEnabledMappers(0) { m_Bounds[0] = 0; m_Bounds[1] = 0; m_Bounds[2] = 0; m_Bounds[3] = 0; m_Bounds[4] = 0; m_Bounds[5] = 0; if (name != nullptr) { m_Name = name; } else { m_Name = "unnamed renderer"; itkWarningMacro(<< "Created unnamed renderer. Bad for serialization. Please choose a name."); } if (renWin != nullptr) { m_RenderWindow = renWin; m_RenderWindow->Register(nullptr); } else { itkWarningMacro(<< "Created mitkBaseRenderer without vtkRenderWindow present."); } // instances.insert( this ); // adding this BaseRenderer to the List of all BaseRenderer m_BindDispatcherInteractor = new mitk::BindDispatcherInteractor(GetName()); WeakPointerProperty::Pointer rendererProp = WeakPointerProperty::New((itk::Object *)this); m_CurrentWorldPlaneGeometry = mitk::PlaneGeometry::New(); m_CurrentWorldPlaneGeometryData = mitk::PlaneGeometryData::New(); m_CurrentWorldPlaneGeometryData->SetPlaneGeometry(m_CurrentWorldPlaneGeometry); m_CurrentWorldPlaneGeometryNode = mitk::DataNode::New(); m_CurrentWorldPlaneGeometryNode->SetData(m_CurrentWorldPlaneGeometryData); m_CurrentWorldPlaneGeometryNode->GetPropertyList()->SetProperty("renderer", rendererProp); m_CurrentWorldPlaneGeometryNode->GetPropertyList()->SetProperty("layer", IntProperty::New(1000)); m_CurrentWorldPlaneGeometryNode->SetProperty("reslice.thickslices", mitk::ResliceMethodProperty::New()); m_CurrentWorldPlaneGeometryNode->SetProperty("reslice.thickslices.num", mitk::IntProperty::New(1)); m_CurrentWorldPlaneGeometryTransformTime = m_CurrentWorldPlaneGeometryNode->GetVtkTransform()->GetMTime(); m_SliceNavigationController = mitk::SliceNavigationController::New(); m_SliceNavigationController->SetRenderer(this); m_SliceNavigationController->ConnectGeometrySendEvent(this); m_SliceNavigationController->ConnectGeometryUpdateEvent(this); m_SliceNavigationController->ConnectGeometrySliceEvent(this); m_SliceNavigationController->ConnectGeometryTimeEvent(this); m_CameraRotationController = mitk::CameraRotationController::New(); m_CameraRotationController->SetRenderWindow(m_RenderWindow); m_CameraRotationController->AcquireCamera(); m_CameraController = mitk::CameraController::New(); m_CameraController->SetRenderer(this); m_VtkRenderer = vtkRenderer::New(); m_VtkRenderer->SetMaximumNumberOfPeels(16); if (AntiAliasing::FastApproximate == RenderingManager::GetInstance()->GetAntiAliasing()) m_VtkRenderer->UseFXAAOn(); if (nullptr == mitk::VtkLayerController::GetInstance(m_RenderWindow)) mitk::VtkLayerController::AddInstance(m_RenderWindow, m_VtkRenderer); mitk::VtkLayerController::GetInstance(m_RenderWindow)->InsertSceneRenderer(m_VtkRenderer); } mitk::BaseRenderer::~BaseRenderer() { if (m_VtkRenderer != nullptr) { m_VtkRenderer->Delete(); m_VtkRenderer = nullptr; } if (m_CameraController.IsNotNull()) m_CameraController->SetRenderer(nullptr); mitk::VtkLayerController::RemoveInstance(m_RenderWindow); RemoveAllLocalStorages(); m_DataStorage = nullptr; if (m_BindDispatcherInteractor != nullptr) { delete m_BindDispatcherInteractor; } if (m_RenderWindow != nullptr) { m_RenderWindow->Delete(); m_RenderWindow = nullptr; } } void mitk::BaseRenderer::RemoveAllLocalStorages() { this->InvokeEvent(RendererResetEvent()); std::list::iterator it; for (it = m_RegisteredLocalStorageHandlers.begin(); it != m_RegisteredLocalStorageHandlers.end(); ++it) (*it)->ClearLocalStorage(this, false); m_RegisteredLocalStorageHandlers.clear(); } void mitk::BaseRenderer::RegisterLocalStorageHandler(mitk::BaseLocalStorageHandler *lsh) { m_RegisteredLocalStorageHandlers.push_back(lsh); } void mitk::BaseRenderer::UnregisterLocalStorageHandler(mitk::BaseLocalStorageHandler *lsh) { m_RegisteredLocalStorageHandlers.remove(lsh); } void mitk::BaseRenderer::SetDataStorage(DataStorage *storage) { if (storage != m_DataStorage && storage != nullptr) { m_DataStorage = storage; m_BindDispatcherInteractor->SetDataStorage(m_DataStorage); this->Modified(); } } mitk::Dispatcher::Pointer mitk::BaseRenderer::GetDispatcher() const { return m_BindDispatcherInteractor->GetDispatcher(); } void mitk::BaseRenderer::Resize(int w, int h) { m_RenderWindow->SetSize(w, h); } void mitk::BaseRenderer::InitRenderer(vtkRenderWindow *renderwindow) { if (m_RenderWindow != renderwindow) { if (m_RenderWindow != nullptr) { m_RenderWindow->Delete(); } m_RenderWindow = renderwindow; if (m_RenderWindow != nullptr) { m_RenderWindow->Register(nullptr); } } RemoveAllLocalStorages(); if (m_CameraController.IsNotNull()) { m_CameraController->SetRenderer(this); } } void mitk::BaseRenderer::InitSize(int w, int h) { m_RenderWindow->SetSize(w, h); } void mitk::BaseRenderer::SetWorldTimeGeometry(const mitk::TimeGeometry* geometry) { if (m_WorldTimeGeometry == geometry) { return; } m_WorldTimeGeometry = geometry; this->UpdateCurrentGeometries(); } void mitk::BaseRenderer::SetInteractionReferenceGeometry(const TimeGeometry* geometry) { if (m_InteractionReferenceGeometry == geometry) { return; } m_InteractionReferenceGeometry = geometry; this->UpdateCurrentGeometries(); } void mitk::BaseRenderer::SetSlice(unsigned int slice) { if (m_Slice == slice) { return; } m_Slice = slice; this->UpdateCurrentGeometries(); } void mitk::BaseRenderer::SetTimeStep(unsigned int timeStep) { if (m_TimeStep == timeStep) { return; } m_TimeStep = timeStep; m_TimeStepUpdateTime.Modified(); this->UpdateCurrentGeometries(); } mitk::TimeStepType mitk::BaseRenderer::GetTimeStep(const mitk::BaseData* data) const { if ((data == nullptr) || (data->IsInitialized() == false)) { return -1; } return data->GetTimeGeometry()->TimePointToTimeStep(GetTime()); } mitk::ScalarType mitk::BaseRenderer::GetTime() const { if (m_WorldTimeGeometry.IsNull()) { return 0; } else { ScalarType timeInMS = m_WorldTimeGeometry->TimeStepToTimePoint(GetTimeStep()); if (timeInMS == itk::NumericTraits::NonpositiveMin()) return 0; else return timeInMS; } } void mitk::BaseRenderer::SetGeometry(const itk::EventObject& geometrySendEvent) { const auto* sendEvent = dynamic_cast(&geometrySendEvent); if (nullptr == sendEvent) { return; } SetWorldTimeGeometry(sendEvent->GetTimeGeometry()); } void mitk::BaseRenderer::UpdateGeometry(const itk::EventObject& geometryUpdateEvent) { const auto* updateEvent = dynamic_cast(&geometryUpdateEvent); if (nullptr == updateEvent) { return; } if (m_CurrentWorldGeometry.IsNull()) { return; } const auto* slicedWorldGeometry = dynamic_cast(m_CurrentWorldGeometry.GetPointer()); if (slicedWorldGeometry) { PlaneGeometry* geometry2D = slicedWorldGeometry->GetPlaneGeometry(m_Slice); SetCurrentWorldPlaneGeometry(geometry2D); // calls Modified() } } void mitk::BaseRenderer::SetGeometrySlice(const itk::EventObject& geometrySliceEvent) { const auto* sliceEvent = dynamic_cast(&geometrySliceEvent); if (nullptr == sliceEvent) { return; } this->SetSlice(sliceEvent->GetPos()); } void mitk::BaseRenderer::SetGeometryTime(const itk::EventObject& geometryTimeEvent) { const auto* timeEvent = dynamic_cast(&geometryTimeEvent); if (nullptr == timeEvent) { return; } this->SetTimeStep(timeEvent->GetPos()); } void mitk::BaseRenderer::SendUpdateSlice() { m_CurrentWorldPlaneGeometryUpdateTime.Modified(); } void mitk::BaseRenderer::SetMapperID(MapperSlotId id) { if (m_MapperID != id) { bool useDepthPeeling = Standard3D == id; m_VtkRenderer->SetUseDepthPeeling(useDepthPeeling); m_VtkRenderer->SetUseDepthPeelingForVolumes(useDepthPeeling); m_MapperID = id; this->Modified(); } } int* mitk::BaseRenderer::GetSize() const { return m_RenderWindow->GetSize(); } int* mitk::BaseRenderer::GetViewportSize() const { return m_VtkRenderer->GetSize(); } const double* mitk::BaseRenderer::GetBounds() const { return m_Bounds; } void mitk::BaseRenderer::RequestUpdate() { SetConstrainZoomingAndPanning(true); RenderingManager::GetInstance()->RequestUpdate(m_RenderWindow); } void mitk::BaseRenderer::ForceImmediateUpdate() { RenderingManager::GetInstance()->ForceImmediateUpdate(m_RenderWindow); } unsigned int mitk::BaseRenderer::GetNumberOfVisibleLODEnabledMappers() const { return m_NumberOfVisibleLODEnabledMappers; } void mitk::BaseRenderer::SetSliceNavigationController(mitk::SliceNavigationController *SlicenavigationController) { if (SlicenavigationController == nullptr) return; // copy worldgeometry SlicenavigationController->SetInputWorldTimeGeometry(SlicenavigationController->GetCreatedWorldGeometry()); SlicenavigationController->Update(); // set new m_SliceNavigationController = SlicenavigationController; m_SliceNavigationController->SetRenderer(this); if (m_SliceNavigationController.IsNotNull()) { m_SliceNavigationController->ConnectGeometrySendEvent(this); m_SliceNavigationController->ConnectGeometryUpdateEvent(this); m_SliceNavigationController->ConnectGeometrySliceEvent(this); m_SliceNavigationController->ConnectGeometryTimeEvent(this); } } void mitk::BaseRenderer::DisplayToWorld(const Point2D& displayPoint, Point3D& worldIndex) const { if (m_MapperID == BaseRenderer::Standard2D) { double display[3], * world; // For the right z-position in display coordinates, take the focal point, convert it to display and use it for // correct depth. double* displayCoord; double cameraFP[4]; // Get camera focal point and position. Convert to display (screen) // coordinates. We need a depth value for z-buffer. this->GetVtkRenderer()->GetActiveCamera()->GetFocalPoint(cameraFP); cameraFP[3] = 0.0; this->GetVtkRenderer()->SetWorldPoint(cameraFP[0], cameraFP[1], cameraFP[2], cameraFP[3]); this->GetVtkRenderer()->WorldToDisplay(); displayCoord = this->GetVtkRenderer()->GetDisplayPoint(); // now convert the display point to world coordinates display[0] = displayPoint[0]; display[1] = displayPoint[1]; display[2] = displayCoord[2]; this->GetVtkRenderer()->SetDisplayPoint(display); this->GetVtkRenderer()->DisplayToWorld(); world = this->GetVtkRenderer()->GetWorldPoint(); for (int i = 0; i < 3; i++) { worldIndex[i] = world[i] / world[3]; } } else if (m_MapperID == BaseRenderer::Standard3D) { // Seems to be the same code as above, but subclasses may contain different implementations. PickWorldPoint(displayPoint, worldIndex); } return; } void mitk::BaseRenderer::DisplayToPlane(const Point2D &displayPoint, Point2D &planePointInMM) const { if (m_MapperID == BaseRenderer::Standard2D) { Point3D worldPoint; this->DisplayToWorld(displayPoint, worldPoint); m_CurrentWorldPlaneGeometry->Map(worldPoint, planePointInMM); } else if (m_MapperID == BaseRenderer::Standard3D) { MITK_WARN << "No conversion possible with 3D mapper."; return; } return; } void mitk::BaseRenderer::WorldToDisplay(const Point3D &worldIndex, Point2D &displayPoint) const { double world[4], *display; world[0] = worldIndex[0]; world[1] = worldIndex[1]; world[2] = worldIndex[2]; world[3] = 1.0; this->GetVtkRenderer()->SetWorldPoint(world); this->GetVtkRenderer()->WorldToDisplay(); display = this->GetVtkRenderer()->GetDisplayPoint(); displayPoint[0] = display[0]; displayPoint[1] = display[1]; return; } void mitk::BaseRenderer::WorldToView(const mitk::Point3D &worldIndex, mitk::Point2D &viewPoint) const { double world[4], *view; world[0] = worldIndex[0]; world[1] = worldIndex[1]; world[2] = worldIndex[2]; world[3] = 1.0; this->GetVtkRenderer()->SetWorldPoint(world); this->GetVtkRenderer()->WorldToView(); view = this->GetVtkRenderer()->GetViewPoint(); this->GetVtkRenderer()->ViewToNormalizedViewport(view[0], view[1], view[2]); viewPoint[0] = view[0] * this->GetViewportSize()[0]; viewPoint[1] = view[1] * this->GetViewportSize()[1]; return; } void mitk::BaseRenderer::PlaneToDisplay(const Point2D &planePointInMM, Point2D &displayPoint) const { Point3D worldPoint; m_CurrentWorldPlaneGeometry->Map(planePointInMM, worldPoint); this->WorldToDisplay(worldPoint, displayPoint); return; } void mitk::BaseRenderer::PlaneToView(const Point2D &planePointInMM, Point2D &viewPoint) const { Point3D worldPoint; m_CurrentWorldPlaneGeometry->Map(planePointInMM, worldPoint); this->WorldToView(worldPoint,viewPoint); return; } double mitk::BaseRenderer::GetScaleFactorMMPerDisplayUnit() const { if (this->GetMapperID() == BaseRenderer::Standard2D) { // GetParallelScale returns half of the height of the render window in mm. // Divided by the half size of the Display size in pixel givest the mm per pixel. return this->GetVtkRenderer()->GetActiveCamera()->GetParallelScale() * 2.0 / GetViewportSize()[1]; } else return 1.0; } mitk::Point2D mitk::BaseRenderer::GetDisplaySizeInMM() const { Point2D dispSizeInMM; dispSizeInMM[0] = GetSizeX() * GetScaleFactorMMPerDisplayUnit(); dispSizeInMM[1] = GetSizeY() * GetScaleFactorMMPerDisplayUnit(); return dispSizeInMM; } mitk::Point2D mitk::BaseRenderer::GetViewportSizeInMM() const { Point2D dispSizeInMM; dispSizeInMM[0] = GetViewportSize()[0] * GetScaleFactorMMPerDisplayUnit(); dispSizeInMM[1] = GetViewportSize()[1] * GetScaleFactorMMPerDisplayUnit(); return dispSizeInMM; } mitk::Point2D mitk::BaseRenderer::GetOriginInMM() const { Point2D originPx; originPx[0] = m_VtkRenderer->GetOrigin()[0]; originPx[1] = m_VtkRenderer->GetOrigin()[1]; Point2D displayGeometryOriginInMM; DisplayToPlane(originPx, displayGeometryOriginInMM); // top left of the render window (Origin) return displayGeometryOriginInMM; } void mitk::BaseRenderer::SetConstrainZoomingAndPanning(bool constrain) { m_ConstrainZoomingAndPanning = constrain; if (m_ConstrainZoomingAndPanning) { this->GetCameraController()->AdjustCameraToPlane(); } } void mitk::BaseRenderer::UpdateCurrentGeometries() { + m_ReferenceGeometryAligned = true; + if (m_WorldTimeGeometry.IsNull()) { // simply mark the base renderer as modified Modified(); return; } if (m_TimeStep >= m_WorldTimeGeometry->CountTimeSteps()) { m_TimeStep = m_WorldTimeGeometry->CountTimeSteps() - 1; } auto slicedWorldGeometry = dynamic_cast(m_WorldTimeGeometry->GetGeometryForTimeStep(m_TimeStep).GetPointer()); if (slicedWorldGeometry != nullptr) { if (m_Slice >= slicedWorldGeometry->GetSlices()) { m_Slice = slicedWorldGeometry->GetSlices() - 1; } SetCurrentWorldGeometry(slicedWorldGeometry); SetCurrentWorldPlaneGeometry(slicedWorldGeometry->GetPlaneGeometry(m_Slice)); m_ReferenceGeometryAligned = BaseRendererHelper::IsRendererGeometryAlignedWithGeometry(this, m_InteractionReferenceGeometry); } } void mitk::BaseRenderer::SetCurrentWorldPlaneGeometry(const mitk::PlaneGeometry* geometry2d) { if (m_CurrentWorldPlaneGeometry == geometry2d) { return; } m_CurrentWorldPlaneGeometry = geometry2d->Clone(); m_CurrentWorldPlaneGeometryData->SetPlaneGeometry(m_CurrentWorldPlaneGeometry); m_CurrentWorldPlaneGeometryUpdateTime.Modified(); Modified(); } void mitk::BaseRenderer::SetCurrentWorldGeometry(const mitk::BaseGeometry* geometry) { if (m_CurrentWorldGeometry == geometry) { return; } m_CurrentWorldGeometry = geometry; if (geometry == nullptr) { m_Bounds[0] = 0; m_Bounds[1] = 0; m_Bounds[2] = 0; m_Bounds[3] = 0; m_Bounds[4] = 0; m_Bounds[5] = 0; m_EmptyWorldGeometry = true; return; } BoundingBox::Pointer boundingBox = m_CurrentWorldGeometry->CalculateBoundingBoxRelativeToTransform(nullptr); const BoundingBox::BoundsArrayType& worldBounds = boundingBox->GetBounds(); m_Bounds[0] = worldBounds[0]; m_Bounds[1] = worldBounds[1]; m_Bounds[2] = worldBounds[2]; m_Bounds[3] = worldBounds[3]; m_Bounds[4] = worldBounds[4]; m_Bounds[5] = worldBounds[5]; if (boundingBox->GetDiagonalLength2() <= mitk::eps) { m_EmptyWorldGeometry = true; } else { m_EmptyWorldGeometry = false; } } void mitk::BaseRenderer::PrintSelf(std::ostream &os, itk::Indent indent) const { os << indent << " MapperID: " << m_MapperID << std::endl; os << indent << " Slice: " << m_Slice << std::endl; os << indent << " TimeStep: " << m_TimeStep << std::endl; os << indent << " CurrentWorldPlaneGeometry: "; if (m_CurrentWorldPlaneGeometry.IsNull()) os << "nullptr" << std::endl; else m_CurrentWorldPlaneGeometry->Print(os, indent); os << indent << " CurrentWorldPlaneGeometryUpdateTime: " << m_CurrentWorldPlaneGeometryUpdateTime << std::endl; os << indent << " CurrentWorldPlaneGeometryTransformTime: " << m_CurrentWorldPlaneGeometryTransformTime << std::endl; Superclass::PrintSelf(os, indent); } diff --git a/Plugins/org.blueberry.ui.qt/src/berryQtStyleManager.cpp b/Plugins/org.blueberry.ui.qt/src/berryQtStyleManager.cpp index 3b508115c7..2bf59d3112 100644 --- a/Plugins/org.blueberry.ui.qt/src/berryQtStyleManager.cpp +++ b/Plugins/org.blueberry.ui.qt/src/berryQtStyleManager.cpp @@ -1,403 +1,399 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "berryQtStyleManager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "berryWorkbenchPlugin.h" #include namespace berry { static QString ParseColor(const QString &subject, const QString &pattern, const QString &fallback) { QRegularExpression re(pattern, QRegularExpression::CaseInsensitiveOption); auto match = re.match(subject); return match.hasMatch() ? match.captured(1) : fallback; } QIcon QtStyleManager::ThemeIcon(const QByteArray &originalSVG) { auto styleSheet = qApp->styleSheet(); if (styleSheet.isEmpty()) return QPixmap::fromImage(QImage::fromData(originalSVG)); auto iconColor = ParseColor(styleSheet, QStringLiteral("iconColor\\s*[=:]\\s*(#[0-9a-f]{6})"), QStringLiteral("#000000")); auto iconAccentColor = ParseColor(styleSheet, QStringLiteral("iconAccentColor\\s*[=:]\\s*(#[0-9a-f]{6})"), QStringLiteral("#ffffff")); auto themedSVG = QString(originalSVG).replace(QStringLiteral("#00ff00"), iconColor, Qt::CaseInsensitive); themedSVG = themedSVG.replace(QStringLiteral("#ff00ff"), iconAccentColor, Qt::CaseInsensitive); return QPixmap::fromImage(QImage::fromData(themedSVG.toLatin1())); } QIcon QtStyleManager::ThemeIcon(const QString &resourcePath) { QFile resourceFile(resourcePath); if (resourceFile.open(QIODevice::ReadOnly)) { auto originalSVG = resourceFile.readAll(); return ThemeIcon(originalSVG); } BERRY_WARN << "Could not read " << resourcePath; return QIcon(); } QtStyleManager::QtStyleManager() { AddDefaultStyle(); AddDefaultFonts(); ReadPreferences(); } void QtStyleManager::ReadPreferences() { auto* stylePref = WorkbenchPlugin::GetDefault()->GetPreferences()->Node(QtPreferences::QT_STYLES_NODE); QString paths = QString::fromStdString(stylePref->Get(QtPreferences::QT_STYLE_SEARCHPATHS, "")); QStringList pathList = paths.split(";", QString::SkipEmptyParts); QStringListIterator it(pathList); while (it.hasNext()) { AddStyles(it.next()); } QString styleName = QString::fromStdString(stylePref->Get(QtPreferences::QT_STYLE_NAME, "")); // if a style is contributed via the Qt resource mechanism, it may not be // registered yet. if (Contains(styleName)) - // do not update the style in the QApplication instance, - // since it might not be created yet - SetStyle(styleName, false); + SetStyle(styleName); else - SetDefaultStyle(false); + SetDefaultStyle(); } QtStyleManager::~QtStyleManager() { for (FileNameToStyleMap::const_iterator i = styles.begin(); i != styles.end(); ++i) { delete i.value(); } } void QtStyleManager::AddDefaultStyle() { #ifndef _APPLE_ AddStyle(":/org.blueberry.ui.qt/darkstyle.qss", "Dark"); AddStyle(":/org.blueberry.ui.qt/lightstyle.qss", "Light"); defaultStyle = styles[":/org.blueberry.ui.qt/darkstyle.qss"]; #endif } void QtStyleManager::AddDefaultFonts() { m_customFontNames.append(QString("<>")); m_customFontNames.append(QString("Fira Sans")); QFontDatabase::addApplicationFont(":/org.blueberry.ui.qt/fonts/FiraSans/FiraSans.ttf"); m_customFontNames.append(QString("Light Fira Sans")); QFontDatabase::addApplicationFont(":/org.blueberry.ui.qt/fonts/LightFiraSans/LightFiraSans.ttf"); m_customFontNames.append(QString("Roboto")); QFontDatabase::addApplicationFont(":/org.blueberry.ui.qt/fonts/Roboto/Roboto.ttf"); m_customFontNames.push_back(QString("Open Sans")); QFontDatabase::addApplicationFont(":/org.blueberry.ui.qt/fonts/OpenSans/OpenSans-Regular.ttf"); m_customFontNames.push_back(QString("xkcd")); QFontDatabase::addApplicationFont(":/org.blueberry.ui.qt/fonts/xkcd/xkcd.ttf"); } void QtStyleManager::ClearStyles() { for (FileNameToStyleMap::iterator i = styles.begin(); i != styles.end(); ) { if (!i.value()->fileName.startsWith(':')) { delete i.value(); i = styles.erase(i); } else ++i; } SetDefaultStyle(); } QtStyleManager::Style QtStyleManager::GetStyle() const { return Style(currentStyle->name, currentStyle->fileName); } QString QtStyleManager::GetStylesheet() const { return currentStyle->stylesheet; } QString QtStyleManager::GetActiveTabStylesheet() const { return currentStyle->activeTabStylesheet; } QString QtStyleManager::GetTabStylesheet() const { return currentStyle->tabStylesheet; } void QtStyleManager::AddStyle(const QString& styleFileName, const QString& styleName) { auto newStyle = new ExtStyle(); if (styleName.isEmpty()) { QFileInfo info(styleFileName); newStyle->name = info.completeBaseName(); } else { newStyle->name = styleName; } newStyle->fileName = styleFileName; styles.insert(newStyle->fileName, newStyle); } void QtStyleManager::GetFonts(QStringList& fontNames) const { fontNames = m_customFontNames; } QString QtStyleManager::GetFont() const { return m_currentFont; } void QtStyleManager::AddStyles(const QString& path) { QDirIterator dirIt(path); while (dirIt.hasNext()) { QString current = dirIt.next(); QFileInfo info = dirIt.fileInfo(); if (info.isFile() && info.isReadable()) { QString fileName = info.fileName(); if (fileName.endsWith("-tab.qss") || fileName.endsWith("-activetab.qss")) continue; if (fileName.endsWith(".qss")) AddStyle(current); } } } void QtStyleManager::ReadStyleData(ExtStyle* style) { QString tabStyleFileName(style->fileName); QString activeTabStyleFileName(style->fileName); int index = style->fileName.lastIndexOf(".qss"); tabStyleFileName.replace(index, 4, "-tab.qss"); activeTabStyleFileName.replace(index, 4, "-activetab.qss"); QFile styleFile(style->fileName); if (styleFile.open(QIODevice::ReadOnly)) { QTextStream in(&styleFile); style->stylesheet = in.readAll(); } else { BERRY_WARN << "Could not read " << style->fileName.toStdString(); } QFile tabStyleFile(tabStyleFileName); if (tabStyleFile.open(QIODevice::ReadOnly)) { QTextStream in(&tabStyleFile); style->tabStylesheet = in.readAll(); } else { BERRY_WARN << "Could not read " << tabStyleFileName.toStdString(); } QFile activeTabStyleFile(activeTabStyleFileName); if (activeTabStyleFile.open(QIODevice::ReadOnly)) { QTextStream in(&activeTabStyleFile); style->activeTabStylesheet = in.readAll(); } else { BERRY_WARN << "Could not read " << activeTabStyleFileName.toStdString(); } } void QtStyleManager::RemoveStyle(const QString& styleFileName) { if (currentStyle->fileName == styleFileName) { SetDefaultStyle(); } delete styles.take(styleFileName); } void QtStyleManager::RemoveStyles(const QString& repo) { if (repo.isEmpty()) { ClearStyles(); return; } for (FileNameToStyleMap::iterator i = styles.begin(); i != styles.end();) { ExtStyle* style = i.value(); QFileInfo info(style->fileName); if (info.absolutePath() == repo) { if (style->name == currentStyle->name) { SetDefaultStyle(); } i = styles.erase(i); delete style; } else { ++i; } } } void QtStyleManager::GetStyles(StyleList& styleNames) const { for (FileNameToStyleMap::const_iterator i = styles.begin(); i != styles.end(); ++i) styleNames.push_back(Style(i.value()->name, i.value()->fileName)); } void QtStyleManager::SetStyle(const QString& fileName) -{ - SetStyle(fileName, true); -} - -void QtStyleManager::SetStyle(const QString& fileName, bool update) { if (fileName.isEmpty()) { SetDefaultStyle(); return; } FileNameToStyleMap::const_iterator i = styles.find(fileName); ExtStyle* style = nullptr; if (i == styles.end()) { BERRY_WARN << "Style " + fileName.toStdString() << " does not exist"; style = defaultStyle; } else { style = i.value(); } currentStyle = style; ReadStyleData(style); - if (update) + qApp->setStyleSheet(currentStyle->stylesheet); + + try { - qApp->setStyleSheet(currentStyle->stylesheet); PlatformUI::GetWorkbench()->UpdateTheme(); } + catch (...) + { + // Swallow any exception if the Workbench instance has not been created yet. + // Will be called later again but for now we just want to make sure that the + // application style sheet can be at least already retrieved from qApp to + // theme icons in plugins with eager activation policy. + } } void QtStyleManager::SetFont(const QString& fontName) { m_currentFont = fontName; } void QtStyleManager::SetFontSize(const int fontSize) { m_currentFontSize = fontSize; } void QtStyleManager::UpdateWorkbenchFont() { if( m_currentFont == QString( "<>" ) || m_currentFont == QString( "" )) { qApp->setFont(QFontDatabase::systemFont(QFontDatabase::GeneralFont)); } else { QFont font; font.setFamily(m_currentFont); font.setPointSize(m_currentFontSize); qApp->setFont(font); } qApp->setStyleSheet(currentStyle->stylesheet); PlatformUI::GetWorkbench()->UpdateTheme(); } QtStyleManager::Style QtStyleManager::GetDefaultStyle() const { return Style(defaultStyle->name, defaultStyle->fileName); } void QtStyleManager::SetDefaultStyle() { - SetDefaultStyle(true); -} - -void QtStyleManager::SetDefaultStyle(bool update) -{ - SetStyle(defaultStyle->fileName, update); + SetStyle(defaultStyle->fileName); } bool QtStyleManager::Contains(const QString& fileName) const { return styles.contains(fileName); } } diff --git a/Plugins/org.blueberry.ui.qt/src/berryQtStyleManager.h b/Plugins/org.blueberry.ui.qt/src/berryQtStyleManager.h index 1426160f88..372b05f24d 100644 --- a/Plugins/org.blueberry.ui.qt/src/berryQtStyleManager.h +++ b/Plugins/org.blueberry.ui.qt/src/berryQtStyleManager.h @@ -1,98 +1,95 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef BERRYQTSTYLEMANAGER_H_ #define BERRYQTSTYLEMANAGER_H_ #include #include #include #include namespace berry { class BERRY_UI_QT QtStyleManager : public QObject, public IQtStyleManager { Q_OBJECT Q_INTERFACES(berry::IQtStyleManager) public: static QIcon ThemeIcon(const QByteArray &originalSVG); static QIcon ThemeIcon(const QString &resourcePath); QtStyleManager(); ~QtStyleManager() override; Style GetStyle() const override; QString GetStylesheet() const override; QString GetActiveTabStylesheet() const override; QString GetTabStylesheet() const override; QString GetFont() const override; void AddStyle(const QString& styleFileName, const QString& styleName = QString()) override; void AddStyles(const QString& path) override; void RemoveStyle(const QString& styleFileName) override; void RemoveStyles(const QString& path = QString()) override; void GetStyles(StyleList& styles) const override; void SetStyle(const QString& fileName) override; void GetFonts(QStringList& fontNames) const override; void SetFont(const QString& fontName) override; void SetFontSize(const int fontSize) override; void UpdateWorkbenchFont() override; Style GetDefaultStyle() const override; void SetDefaultStyle() override; bool Contains(const QString& fileName) const override; bool IsA( const std::type_info& type ) const; const std::type_info& GetType() const; private: void AddDefaultStyle(); void AddDefaultFonts(); void ClearStyles(); void ReadPreferences(); - void SetStyle(const QString& fileName, bool update); - void SetDefaultStyle(bool update); - struct ExtStyle : public Style { QString stylesheet; QString tabStylesheet; QString activeTabStylesheet; }; QStringList m_customFontNames; void ReadStyleData(ExtStyle* style); typedef QHash FileNameToStyleMap; FileNameToStyleMap styles; QString m_currentFont; int m_currentFontSize; ExtStyle const* currentStyle; ExtStyle* defaultStyle; }; } #endif /* BERRYQTSTYLEMANAGER_H_ */